CDRInputStream_1_0.java revision 608:7e06bf1dcb09
1130803Smarcel/*
2130803Smarcel * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3130803Smarcel * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4130803Smarcel *
5130803Smarcel * This code is free software; you can redistribute it and/or modify it
6130803Smarcel * under the terms of the GNU General Public License version 2 only, as
7130803Smarcel * published by the Free Software Foundation.  Oracle designates this
8130803Smarcel * particular file as subject to the "Classpath" exception as provided
9130803Smarcel * by Oracle in the LICENSE file that accompanied this code.
10130803Smarcel *
11130803Smarcel * This code is distributed in the hope that it will be useful, but WITHOUT
12130803Smarcel * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13130803Smarcel * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14130803Smarcel * version 2 for more details (a copy is included in the LICENSE file that
15130803Smarcel * accompanied this code).
16130803Smarcel *
17130803Smarcel * You should have received a copy of the GNU General Public License version
18130803Smarcel * 2 along with this work; if not, write to the Free Software Foundation,
19130803Smarcel * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20130803Smarcel *
21130803Smarcel * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22130803Smarcel * or visit www.oracle.com if you need additional information or have any
23130803Smarcel * questions.
24130803Smarcel */
25130803Smarcel
26130803Smarcel/*
27130803Smarcel * Licensed Materials - Property of IBM
28130803Smarcel * RMI-IIOP v1.0
29130803Smarcel * Copyright IBM Corp. 1998 1999  All Rights Reserved
30130803Smarcel *
31130803Smarcel */
32130803Smarcel
33130803Smarcelpackage com.sun.corba.se.impl.encoding;
34130803Smarcel
35130803Smarcelimport java.io.IOException;
36130803Smarcelimport java.io.Serializable;
37130803Smarcelimport java.io.ByteArrayInputStream;
38130803Smarcelimport java.io.ObjectInputStream;
39130803Smarcelimport java.io.IOException;
40130803Smarcelimport java.io.StreamCorruptedException;
41130803Smarcelimport java.io.OptionalDataException;
42130803Smarcelimport java.io.IOException;
43130803Smarcel
44130803Smarcelimport java.util.Stack;
45130803Smarcel
46130803Smarcelimport java.net.URL;
47130803Smarcelimport java.net.MalformedURLException;
48130803Smarcel
49130803Smarcelimport java.nio.ByteBuffer;
50130803Smarcel
51130803Smarcelimport java.lang.reflect.InvocationTargetException;
52130803Smarcelimport java.lang.reflect.Method;
53130803Smarcel
54130803Smarcelimport java.math.BigDecimal;
55130803Smarcel
56130803Smarcelimport java.rmi.Remote;
57130803Smarcelimport java.rmi.StubNotFoundException;
58130803Smarcel
59130803Smarcelimport java.security.AccessController;
60130803Smarcelimport java.security.PrivilegedExceptionAction;
61130803Smarcelimport java.security.PrivilegedActionException;
62130803Smarcel
63130803Smarcelimport org.omg.CORBA.SystemException;
64130803Smarcelimport org.omg.CORBA.Object;
65130803Smarcelimport org.omg.CORBA.Principal;
66130803Smarcelimport org.omg.CORBA.TypeCode;
67130803Smarcelimport org.omg.CORBA.Any;
68130803Smarcelimport org.omg.CORBA.portable.Delegate;
69130803Smarcelimport org.omg.CORBA.portable.ValueBase;
70130803Smarcelimport org.omg.CORBA.portable.IndirectionException;
71130803Smarcelimport org.omg.CORBA.CompletionStatus;
72130803Smarcelimport org.omg.CORBA.TCKind;
73130803Smarcelimport org.omg.CORBA.TypeCodePackage.BadKind;
74130803Smarcelimport org.omg.CORBA.CustomMarshal;
75130803Smarcelimport org.omg.CORBA.TypeCode;
76130803Smarcelimport org.omg.CORBA.Principal;
77130803Smarcelimport org.omg.CORBA.Any;
78130803Smarcelimport org.omg.CORBA.portable.BoxedValueHelper;
79130803Smarcelimport org.omg.CORBA.portable.ValueFactory;
80130803Smarcelimport org.omg.CORBA.portable.CustomValue;
81130803Smarcelimport org.omg.CORBA.portable.StreamableValue;
82130803Smarcelimport org.omg.CORBA.MARSHAL;
83130803Smarcelimport org.omg.CORBA.portable.IDLEntity;
84130803Smarcel
85130803Smarcelimport javax.rmi.PortableRemoteObject;
86130803Smarcelimport javax.rmi.CORBA.Tie;
87130803Smarcelimport javax.rmi.CORBA.Util;
88130803Smarcelimport javax.rmi.CORBA.ValueHandler;
89130803Smarcel
90130803Smarcelimport com.sun.corba.se.pept.protocol.MessageMediator;
91130803Smarcelimport com.sun.corba.se.pept.transport.ByteBufferPool;
92130803Smarcel
93130803Smarcelimport com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
94130803Smarcelimport com.sun.corba.se.spi.protocol.CorbaClientDelegate;
95130803Smarcel
96130803Smarcelimport com.sun.corba.se.spi.ior.IOR;
97130803Smarcelimport com.sun.corba.se.spi.ior.IORFactories;
98130803Smarcelimport com.sun.corba.se.spi.ior.iiop.GIOPVersion;
99130803Smarcel
100130803Smarcelimport com.sun.corba.se.spi.orb.ORB;
101130803Smarcelimport com.sun.corba.se.spi.orb.ORBVersionFactory;
102130803Smarcelimport com.sun.corba.se.spi.orb.ORBVersion;
103130803Smarcel
104130803Smarcelimport com.sun.corba.se.spi.protocol.CorbaMessageMediator;
105130803Smarcel
106130803Smarcelimport com.sun.corba.se.spi.logging.CORBALogDomains;
107130803Smarcelimport com.sun.corba.se.spi.presentation.rmi.PresentationManager;
108130803Smarcelimport com.sun.corba.se.spi.presentation.rmi.StubAdapter;
109130803Smarcelimport com.sun.corba.se.spi.presentation.rmi.PresentationDefaults;
110130803Smarcel
111130803Smarcelimport com.sun.corba.se.impl.logging.ORBUtilSystemException;
112130803Smarcelimport com.sun.corba.se.impl.logging.OMGSystemException;
113130803Smarcel
114130803Smarcelimport com.sun.corba.se.impl.corba.PrincipalImpl;
115130803Smarcelimport com.sun.corba.se.impl.corba.TypeCodeImpl;
116130803Smarcelimport com.sun.corba.se.impl.corba.CORBAObjectImpl;
117130803Smarcel
118130803Smarcelimport com.sun.corba.se.impl.encoding.CDROutputObject;
119130803Smarcelimport com.sun.corba.se.impl.encoding.CodeSetConversion;
120130803Smarcel
121130803Smarcelimport com.sun.corba.se.impl.util.Utility;
122130803Smarcelimport com.sun.corba.se.impl.util.RepositoryId;
123130803Smarcel
124130803Smarcelimport com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
125130803Smarcelimport com.sun.corba.se.impl.orbutil.RepositoryIdInterface;
126130803Smarcelimport com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
127130803Smarcelimport com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
128130803Smarcel
129130803Smarcelimport com.sun.corba.se.impl.orbutil.ORBUtility;
130130803Smarcelimport com.sun.corba.se.impl.orbutil.CacheTable;
131130803Smarcel
132130803Smarcel
133130803Smarcelimport com.sun.org.omg.CORBA.portable.ValueHelper;
134130803Smarcel
135130803Smarcelimport com.sun.org.omg.SendingContext.CodeBase;
136130803Smarcel
137130803Smarcelpublic class CDRInputStream_1_0 extends CDRInputStreamBase
138130803Smarcel    implements RestorableInputStream
139130803Smarcel{
140130803Smarcel    private static final String kReadMethod = "read";
141130803Smarcel    private static final int maxBlockLength = 0x7fffff00;
142130803Smarcel
143130803Smarcel    protected BufferManagerRead bufferManagerRead;
144130803Smarcel    protected ByteBufferWithInfo bbwi;
145130803Smarcel
146130803Smarcel    // Set to the ORB's transportDebugFlag value.  This value is
147130803Smarcel    // used if the ORB is null.
148130803Smarcel    private boolean debug = false;
149130803Smarcel
150130803Smarcel    protected boolean littleEndian;
151130803Smarcel    protected ORB orb;
152130803Smarcel    protected ORBUtilSystemException wrapper ;
153130803Smarcel    protected OMGSystemException omgWrapper ;
154130803Smarcel    protected ValueHandler valueHandler = null;
155130803Smarcel
156130803Smarcel    // Value cache
157130803Smarcel    private CacheTable valueCache = null;
158130803Smarcel
159130803Smarcel    // Repository ID cache
160130803Smarcel    private CacheTable repositoryIdCache = null;
161130803Smarcel
162130803Smarcel    // codebase cache
163130803Smarcel    private CacheTable codebaseCache = null;
164130803Smarcel
165130803Smarcel    // Current Class Stack (repository Ids of current class being read)
166130803Smarcel    // private Stack currentStack = null;
167130803Smarcel
168130803Smarcel    // Length of current chunk, or a large positive number if not in a chunk
169130803Smarcel    protected int blockLength = maxBlockLength;
170130803Smarcel
171130803Smarcel    // Read end flag (value nesting depth)
172130803Smarcel    protected int end_flag = 0;
173130803Smarcel
174130803Smarcel    // Beginning with the resolution to interop issue 3526 (4328?),
175130803Smarcel    // only enclosing chunked valuetypes are taken into account
176130803Smarcel    // when computing the nesting level.  However, we still need
177130803Smarcel    // the old computation around for interoperability with our
178130803Smarcel    // older ORBs.
179130803Smarcel    private int chunkedValueNestingLevel = 0;
180130803Smarcel
181130803Smarcel    // Flag used to determine whether blocksize was zero
182130803Smarcel    // private int checkForNullBlock = -1;
183130803Smarcel
184130803Smarcel    // In block flag
185130803Smarcel    // private boolean inBlock = false;
186130803Smarcel
187130803Smarcel    // Indicates whether we are inside a value
188130803Smarcel    // private boolean outerValueDone = true;
189130803Smarcel
190130803Smarcel    // Int used by read_value(Serializable) that is set by this class
191130803Smarcel    // before calling ValueFactory.read_value
192130803Smarcel    protected int valueIndirection = 0;
193130803Smarcel
194130803Smarcel    // Int set by readStringOrIndirection to communicate the actual
195130803Smarcel    // offset of the string length field back to the caller
196130803Smarcel    protected int stringIndirection = 0;
197130803Smarcel
198130803Smarcel    // Flag indicating whether we are unmarshalling a chunked value
199130803Smarcel    protected boolean isChunked = false;
200130803Smarcel
201130803Smarcel    // Repository ID handlers
202130803Smarcel    private RepositoryIdUtility repIdUtil;
203130803Smarcel    private RepositoryIdStrings repIdStrs;
204130803Smarcel
205130803Smarcel    // Code set converters (created when first needed)
206130803Smarcel    private CodeSetConversion.BTCConverter charConverter;
207130803Smarcel    private CodeSetConversion.BTCConverter wcharConverter;
208130803Smarcel
209130803Smarcel    // RMI-IIOP stream format version 2 case in which we know
210130803Smarcel    // that there is no more optional data available.  If the
211130803Smarcel    // Serializable's readObject method tries to read anything,
212130803Smarcel    // we must throw a MARSHAL with the special minor code
213130803Smarcel    // so that the ValueHandler can give the correct exception
214130803Smarcel    // to readObject.  The state is cleared when the ValueHandler
215130803Smarcel    // calls end_value after the readObject method exits.
216130803Smarcel    private boolean specialNoOptionalDataState = false;
217130803Smarcel
218130803Smarcel    // Template method
219130803Smarcel    public CDRInputStreamBase dup()
220130803Smarcel    {
221130803Smarcel        CDRInputStreamBase result = null ;
222130803Smarcel
223130803Smarcel        try {
224130803Smarcel            result = (CDRInputStreamBase)this.getClass().newInstance();
225130803Smarcel        } catch (Exception e) {
226130803Smarcel            throw wrapper.couldNotDuplicateCdrInputStream( e ) ;
227130803Smarcel        }
228130803Smarcel        result.init(this.orb,
229130803Smarcel                    this.bbwi.byteBuffer,
230130803Smarcel                    this.bbwi.buflen,
231130803Smarcel                    this.littleEndian,
232130803Smarcel                    this.bufferManagerRead);
233130803Smarcel
234130803Smarcel        ((CDRInputStream_1_0)result).bbwi.position(this.bbwi.position());
235130803Smarcel        // To ensure we keep bbwi.byteBuffer.limit in sync with bbwi.buflen.
236130803Smarcel        ((CDRInputStream_1_0)result).bbwi.byteBuffer.limit(this.bbwi.buflen);
237130803Smarcel
238130803Smarcel        return result;
239130803Smarcel    }
240130803Smarcel
241130803Smarcel    /**
242130803Smarcel     * NOTE:  size passed to init means buffer size
243130803Smarcel     */
244130803Smarcel    public void init(org.omg.CORBA.ORB orb,
245130803Smarcel                     ByteBuffer byteBuffer,
246130803Smarcel                     int size,
247130803Smarcel                     boolean littleEndian,
248130803Smarcel                     BufferManagerRead bufferManager)
249130803Smarcel    {
250130803Smarcel        this.orb = (ORB)orb;
251130803Smarcel        this.wrapper = ORBUtilSystemException.get( (ORB)orb,
252130803Smarcel            CORBALogDomains.RPC_ENCODING ) ;
253130803Smarcel        this.omgWrapper = OMGSystemException.get( (ORB)orb,
254130803Smarcel            CORBALogDomains.RPC_ENCODING ) ;
255130803Smarcel        this.littleEndian = littleEndian;
256130803Smarcel        this.bufferManagerRead = bufferManager;
257130803Smarcel        this.bbwi = new ByteBufferWithInfo(orb,byteBuffer,0);
258130803Smarcel        this.bbwi.buflen = size;
259130803Smarcel        this.bbwi.byteBuffer.limit(bbwi.buflen);
260130803Smarcel        this.markAndResetHandler = bufferManagerRead.getMarkAndResetHandler();
261130803Smarcel
262130803Smarcel        debug = ((ORB)orb).transportDebugFlag;
263130803Smarcel    }
264130803Smarcel
265130803Smarcel    // See description in CDRInputStream
266130803Smarcel    void performORBVersionSpecificInit() {
267130803Smarcel        createRepositoryIdHandlers();
268130803Smarcel    }
269130803Smarcel
270130803Smarcel    private final void createRepositoryIdHandlers()
271130803Smarcel    {
272130803Smarcel        repIdUtil = RepositoryIdFactory.getRepIdUtility();
273130803Smarcel        repIdStrs = RepositoryIdFactory.getRepIdStringsFactory();
274130803Smarcel    }
275130803Smarcel
276130803Smarcel    public GIOPVersion getGIOPVersion() {
277130803Smarcel        return GIOPVersion.V1_0;
278130803Smarcel    }
279130803Smarcel
280130803Smarcel    // Called by Request and Reply message. Valid for GIOP versions >= 1.2 only.
281130803Smarcel    // Illegal for GIOP versions < 1.2.
282130803Smarcel    void setHeaderPadding(boolean headerPadding) {
283130803Smarcel        throw wrapper.giopVersionError();
284130803Smarcel    }
285130803Smarcel
286130803Smarcel    protected final int computeAlignment(int index, int align) {
287130803Smarcel        if (align > 1) {
288130803Smarcel            int incr = index & (align - 1);
289130803Smarcel            if (incr != 0)
290130803Smarcel                return align - incr;
291130803Smarcel        }
292130803Smarcel
293130803Smarcel        return 0;
294130803Smarcel    }
295130803Smarcel
296130803Smarcel    public int getSize()
297130803Smarcel    {
298130803Smarcel        return bbwi.position();
299130803Smarcel    }
300130803Smarcel
301130803Smarcel    protected void checkBlockLength(int align, int dataSize) {
302130803Smarcel        // Since chunks can end at arbitrary points (though not within
303130803Smarcel        // primitive CDR types, arrays of primitives, strings, wstrings,
304130803Smarcel        // or indirections),
305130803Smarcel        // we must check here for termination of the current chunk.
306130803Smarcel        if (!isChunked)
307130803Smarcel            return;
308130803Smarcel
309130803Smarcel        // RMI-IIOP stream format version 2 case in which we know
310130803Smarcel        // that there is no more optional data available.  If the
311130803Smarcel        // Serializable's readObject method tries to read anything,
312130803Smarcel        // we must throw a MARSHAL exception with the special minor code
313130803Smarcel        // so that the ValueHandler can give the correct exception
314130803Smarcel        // to readObject.  The state is cleared when the ValueHandler
315130803Smarcel        // calls end_value after the readObject method exits.
316130803Smarcel        if (specialNoOptionalDataState) {
317130803Smarcel            throw omgWrapper.rmiiiopOptionalDataIncompatible1() ;
318130803Smarcel        }
319130803Smarcel
320130803Smarcel        boolean checkForEndTag = false;
321130803Smarcel
322130803Smarcel        // Are we at the end of the current chunk?  If so,
323130803Smarcel        // try to interpret the next long as a chunk length.
324130803Smarcel        // (It has to be either a chunk length, end tag,
325130803Smarcel        // or valuetag.)
326130803Smarcel        //
327130803Smarcel        // If it isn't a chunk length, blockLength will
328130803Smarcel        // remain set to maxBlockLength.
329130803Smarcel        if (blockLength == get_offset()) {
330130803Smarcel
331130803Smarcel            blockLength = maxBlockLength;
332130803Smarcel            start_block();
333130803Smarcel
334130803Smarcel            // What's next is either a valuetag or
335130803Smarcel            // an end tag.  If it's a valuetag, we're
336130803Smarcel            // probably being called as part of the process
337130803Smarcel            // to read the valuetag.  If it's an end tag,
338130803Smarcel            // then there isn't enough data left in
339130803Smarcel            // this valuetype to read!
340130803Smarcel            if (blockLength == maxBlockLength)
341130803Smarcel                checkForEndTag = true;
342130803Smarcel
343130803Smarcel        } else
344130803Smarcel        if (blockLength < get_offset()) {
345130803Smarcel            // Are we already past the end of the current chunk?
346130803Smarcel            // This is always an error.
347130803Smarcel            throw wrapper.chunkOverflow() ;
348130803Smarcel        }
349130803Smarcel
350130803Smarcel        // If what's next on the wire isn't a chunk length or
351130803Smarcel        // what we want to read (which can't be split across chunks)
352130803Smarcel        // won't fit in the current chunk, throw this exception.
353130803Smarcel        // This probably means that we're in an RMI-IIOP
354130803Smarcel        // Serializable's readObject method or a custom marshaled
355130803Smarcel        // IDL type is reading too much/in an incorrect order
356130803Smarcel        int requiredNumBytes =
357130803Smarcel                            computeAlignment(bbwi.position(), align) + dataSize;
358130803Smarcel
359130803Smarcel        if (blockLength != maxBlockLength &&
360130803Smarcel            blockLength < get_offset() + requiredNumBytes) {
361130803Smarcel            throw omgWrapper.rmiiiopOptionalDataIncompatible2() ;
362130803Smarcel        }
363130803Smarcel
364130803Smarcel        // REVISIT - We should look at using the built in advancement
365130803Smarcel        //           of using ByteBuffer.get() rather than explicitly
366130803Smarcel        //           advancing the ByteBuffer's position.
367130803Smarcel        //           This is true for anywhere we are incrementing
368130803Smarcel        //           the ByteBuffer's position.
369130803Smarcel        if (checkForEndTag) {
370130803Smarcel            int nextLong = read_long();
371130803Smarcel            bbwi.position(bbwi.position() - 4);
372130803Smarcel
373130803Smarcel            // It was an end tag, so there wasn't enough data
374130803Smarcel            // left in the valuetype's encoding on the wire
375130803Smarcel            // to read what we wanted
376130803Smarcel            if (nextLong < 0)
377130803Smarcel                throw omgWrapper.rmiiiopOptionalDataIncompatible3() ;
378130803Smarcel        }
379130803Smarcel    }
380130803Smarcel
381130803Smarcel    protected void alignAndCheck(int align, int n) {
382130803Smarcel
383130803Smarcel        checkBlockLength(align, n);
384130803Smarcel
385130803Smarcel        // WARNING: Must compute real alignment after calling
386130803Smarcel        // checkBlockLength since it may move the position
387130803Smarcel        int alignResult = computeAlignment(bbwi.position(), align);
388130803Smarcel        bbwi.position(bbwi.position() + alignResult);
389130803Smarcel
390130803Smarcel        if (bbwi.position() + n > bbwi.buflen)
391130803Smarcel            grow(align, n);
392130803Smarcel    }
393130803Smarcel
394130803Smarcel    //
395130803Smarcel    // This can be overridden....
396130803Smarcel    //
397130803Smarcel    protected void grow(int align, int n) {
398130803Smarcel
399130803Smarcel        bbwi.needed = n;
400130803Smarcel
401130803Smarcel        bbwi = bufferManagerRead.underflow(bbwi);
402130803Smarcel
403130803Smarcel    }
404130803Smarcel
405130803Smarcel    //
406130803Smarcel    // Marshal primitives.
407130803Smarcel    //
408130803Smarcel
409130803Smarcel    public final void consumeEndian() {
410130803Smarcel        littleEndian = read_boolean();
411130803Smarcel    }
412130803Smarcel
413130803Smarcel    // No such type in java
414130803Smarcel    public final double read_longdouble() {
415130803Smarcel        throw wrapper.longDoubleNotImplemented( CompletionStatus.COMPLETED_MAYBE);
416130803Smarcel    }
417130803Smarcel
418130803Smarcel    public final boolean read_boolean() {
419130803Smarcel        return (read_octet() != 0);
420130803Smarcel    }
421130803Smarcel
422130803Smarcel    public final char read_char() {
423130803Smarcel        alignAndCheck(1, 1);
424130803Smarcel
425130803Smarcel        return getConvertedChars(1, getCharConverter())[0];
426130803Smarcel    }
427130803Smarcel
428130803Smarcel    public char read_wchar() {
429130803Smarcel
430130803Smarcel        // Don't allow transmission of wchar/wstring data with
431130803Smarcel        // foreign ORBs since it's against the spec.
432130803Smarcel        if (ORBUtility.isForeignORB((ORB)orb)) {
433130803Smarcel            throw wrapper.wcharDataInGiop10( CompletionStatus.COMPLETED_MAYBE);
434130803Smarcel        }
435130803Smarcel
436130803Smarcel        // If we're talking to one of our legacy ORBs, do what
437130803Smarcel        // they did:
438130803Smarcel        int b1, b2;
439130803Smarcel
440130803Smarcel        alignAndCheck(2, 2);
441130803Smarcel
442130803Smarcel        if (littleEndian) {
443130803Smarcel            b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
444130803Smarcel            bbwi.position(bbwi.position() + 1);
445130803Smarcel            b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
446130803Smarcel            bbwi.position(bbwi.position() + 1);
447130803Smarcel        } else {
448130803Smarcel            b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
449130803Smarcel            bbwi.position(bbwi.position() + 1);
450130803Smarcel            b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
451130803Smarcel            bbwi.position(bbwi.position() + 1);
452130803Smarcel        }
453130803Smarcel
454130803Smarcel        return (char)((b1 << 8) + (b2 << 0));
455130803Smarcel    }
456130803Smarcel
457130803Smarcel    public final byte read_octet() {
458130803Smarcel
459130803Smarcel        alignAndCheck(1, 1);
460130803Smarcel
461130803Smarcel        byte b = bbwi.byteBuffer.get(bbwi.position());
462130803Smarcel        bbwi.position(bbwi.position() + 1);
463130803Smarcel
464130803Smarcel        return b;
465130803Smarcel    }
466130803Smarcel
467130803Smarcel    public final short read_short() {
468130803Smarcel        int b1, b2;
469130803Smarcel
470130803Smarcel        alignAndCheck(2, 2);
471130803Smarcel
472130803Smarcel        if (littleEndian) {
473130803Smarcel            b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
474130803Smarcel            bbwi.position(bbwi.position() + 1);
475130803Smarcel            b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
476130803Smarcel            bbwi.position(bbwi.position() + 1);
477130803Smarcel        } else {
478130803Smarcel            b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
479130803Smarcel            bbwi.position(bbwi.position() + 1);
480130803Smarcel            b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
481130803Smarcel            bbwi.position(bbwi.position() + 1);
482130803Smarcel        }
483130803Smarcel
484130803Smarcel        return (short)(b1 | b2);
485130803Smarcel    }
486130803Smarcel
487130803Smarcel    public final short read_ushort() {
488130803Smarcel        return read_short();
489130803Smarcel    }
490130803Smarcel
491130803Smarcel    public final int read_long() {
492130803Smarcel        int b1, b2, b3, b4;
493130803Smarcel
494130803Smarcel        alignAndCheck(4, 4);
495130803Smarcel
496130803Smarcel        int bufPos = bbwi.position();
497130803Smarcel        if (littleEndian) {
498130803Smarcel            b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
499130803Smarcel            b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
500130803Smarcel            b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
501130803Smarcel            b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
502130803Smarcel        } else {
503130803Smarcel            b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
504130803Smarcel            b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
505130803Smarcel            b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
506130803Smarcel            b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
507130803Smarcel        }
508130803Smarcel        bbwi.position(bufPos);
509130803Smarcel
510130803Smarcel        return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
511130803Smarcel    }
512130803Smarcel
513130803Smarcel    public final int read_ulong() {
514130803Smarcel        return read_long();
515130803Smarcel    }
516130803Smarcel
517130803Smarcel    public final long read_longlong() {
518130803Smarcel        long i1, i2;
519130803Smarcel
520130803Smarcel        alignAndCheck(8, 8);
521130803Smarcel
522130803Smarcel        if (littleEndian) {
523130803Smarcel            i2 = read_long() & 0xFFFFFFFFL;
524130803Smarcel            i1 = (long)read_long() << 32;
525130803Smarcel        } else {
526130803Smarcel            i1 = (long)read_long() << 32;
527130803Smarcel            i2 = read_long() & 0xFFFFFFFFL;
528130803Smarcel        }
529130803Smarcel
530130803Smarcel        return (i1 | i2);
531130803Smarcel    }
532130803Smarcel
533130803Smarcel    public final long read_ulonglong() {
534130803Smarcel        return read_longlong();
535130803Smarcel    }
536130803Smarcel
537130803Smarcel    public final float read_float() {
538130803Smarcel        return Float.intBitsToFloat(read_long());
539130803Smarcel    }
540130803Smarcel
541130803Smarcel    public final double read_double() {
542130803Smarcel        return Double.longBitsToDouble(read_longlong());
543130803Smarcel    }
544130803Smarcel
545130803Smarcel    protected final void checkForNegativeLength(int length) {
546130803Smarcel        if (length < 0)
547130803Smarcel            throw wrapper.negativeStringLength( CompletionStatus.COMPLETED_MAYBE,
548130803Smarcel                new Integer(length) ) ;
549130803Smarcel    }
550130803Smarcel
551130803Smarcel    protected final String readStringOrIndirection(boolean allowIndirection) {
552130803Smarcel
553130803Smarcel        int len = read_long();
554130803Smarcel
555130803Smarcel        //
556130803Smarcel        // Check for indirection
557130803Smarcel        //
558130803Smarcel        if (allowIndirection) {
559130803Smarcel            if (len == 0xffffffff)
560130803Smarcel                return null;
561130803Smarcel            else
562130803Smarcel                stringIndirection = get_offset() - 4;
563130803Smarcel        }
564130803Smarcel
565130803Smarcel        checkForNegativeLength(len);
566130803Smarcel
567130803Smarcel        return internalReadString(len);
568130803Smarcel    }
569130803Smarcel
570130803Smarcel    private final String internalReadString(int len) {
571130803Smarcel        // Workaround for ORBs which send string lengths of
572130803Smarcel        // zero to mean empty string.
573130803Smarcel        //
574130803Smarcel        // IMPORTANT: Do not replace 'new String("")' with "", it may result
575130803Smarcel        // in a Serialization bug (See serialization.zerolengthstring) and
576130803Smarcel        // bug id: 4728756 for details
577130803Smarcel        if (len == 0)
578130803Smarcel            return new String("");
579130803Smarcel
580130803Smarcel        char[] result = getConvertedChars(len - 1, getCharConverter());
581130803Smarcel
582130803Smarcel        // Skip over the 1 byte null
583130803Smarcel        read_octet();
584130803Smarcel
585130803Smarcel        return new String(result, 0, getCharConverter().getNumChars());
586130803Smarcel    }
587130803Smarcel
588130803Smarcel    public final String read_string() {
589130803Smarcel        return readStringOrIndirection(false);
590130803Smarcel    }
591130803Smarcel
592130803Smarcel    public String read_wstring() {
593130803Smarcel        // Don't allow transmission of wchar/wstring data with
594130803Smarcel        // foreign ORBs since it's against the spec.
595130803Smarcel        if (ORBUtility.isForeignORB((ORB)orb)) {
596130803Smarcel            throw wrapper.wcharDataInGiop10( CompletionStatus.COMPLETED_MAYBE);
597130803Smarcel        }
598130803Smarcel
599130803Smarcel        int len = read_long();
600130803Smarcel
601130803Smarcel        //
602130803Smarcel        // Workaround for ORBs which send string lengths of
603130803Smarcel        // zero to mean empty string.
604130803Smarcel        //
605130803Smarcel        //
606130803Smarcel        // IMPORTANT: Do not replace 'new String("")' with "", it may result
607130803Smarcel        // in a Serialization bug (See serialization.zerolengthstring) and
608130803Smarcel        // bug id: 4728756 for details
609130803Smarcel        if (len == 0)
610130803Smarcel            return new String("");
611130803Smarcel
612130803Smarcel        checkForNegativeLength(len);
613130803Smarcel
614130803Smarcel        len--;
615130803Smarcel        char[] c = new char[len];
616130803Smarcel
617130803Smarcel        for (int i = 0; i < len; i++)
618130803Smarcel            c[i] = read_wchar();
619130803Smarcel
620130803Smarcel        // skip the two null terminator bytes
621130803Smarcel        read_wchar();
622130803Smarcel        // bbwi.position(bbwi.position() + 2);
623130803Smarcel
624130803Smarcel        return new String(c);
625130803Smarcel    }
626130803Smarcel
627130803Smarcel    public final void read_octet_array(byte[] b, int offset, int length) {
628130803Smarcel        if ( b == null )
629130803Smarcel            throw wrapper.nullParam() ;
630130803Smarcel
631130803Smarcel        // Must call alignAndCheck at least once to ensure
632130803Smarcel        // we aren't at the end of a chunk.  Of course, we
633130803Smarcel        // should only call it if we actually need to read
634130803Smarcel        // something, otherwise we might end up with an
635130803Smarcel        // exception at the end of the stream.
636130803Smarcel        if (length == 0)
637130803Smarcel            return;
638130803Smarcel
639130803Smarcel        alignAndCheck(1, 1);
640130803Smarcel
641130803Smarcel        int n = offset;
642130803Smarcel        while (n < length+offset) {
643130803Smarcel            int avail;
644130803Smarcel            int bytes;
645130803Smarcel            int wanted;
646130803Smarcel
647130803Smarcel            avail = bbwi.buflen - bbwi.position();
648130803Smarcel            if (avail <= 0) {
649130803Smarcel                grow(1, 1);
650130803Smarcel                avail = bbwi.buflen - bbwi.position();
651130803Smarcel            }
652130803Smarcel            wanted = (length + offset) - n;
653130803Smarcel            bytes = (wanted < avail) ? wanted : avail;
654130803Smarcel            // Microbenchmarks are showing a loop of ByteBuffer.get(int) being
655130803Smarcel            // faster than ByteBuffer.get(byte[], int, int).
656130803Smarcel            for (int i = 0; i < bytes; i++) {
657130803Smarcel                b[n+i] = bbwi.byteBuffer.get(bbwi.position() + i);
658130803Smarcel            }
659130803Smarcel
660130803Smarcel            bbwi.position(bbwi.position() + bytes);
661130803Smarcel
662130803Smarcel            n += bytes;
663130803Smarcel        }
664130803Smarcel    }
665130803Smarcel
666130803Smarcel    public Principal read_Principal() {
667130803Smarcel        int len = read_long();
668130803Smarcel        byte[] pvalue = new byte[len];
669130803Smarcel        read_octet_array(pvalue,0,len);
670130803Smarcel
671130803Smarcel        Principal p = new PrincipalImpl();
672130803Smarcel        p.name(pvalue);
673130803Smarcel        return p;
674130803Smarcel    }
675130803Smarcel
676130803Smarcel    public TypeCode read_TypeCode() {
677130803Smarcel        TypeCodeImpl tc = new TypeCodeImpl(orb);
678130803Smarcel        tc.read_value(parent);
679130803Smarcel        return tc;
680130803Smarcel    }
681130803Smarcel
682130803Smarcel    public Any read_any() {
683130803Smarcel        Any any = orb.create_any();
684130803Smarcel        TypeCodeImpl tc = new TypeCodeImpl(orb);
685130803Smarcel
686130803Smarcel        // read off the typecode
687130803Smarcel
688130803Smarcel        // REVISIT We could avoid this try-catch if we could peek the typecode
689130803Smarcel        // kind off this stream and see if it is a tk_value.  Looking at the
690130803Smarcel        // code we know that for tk_value the Any.read_value() below
691130803Smarcel        // ignores the tc argument anyway (except for the kind field).
692130803Smarcel        // But still we would need to make sure that the whole typecode,
693130803Smarcel        // including encapsulations, is read off.
694130803Smarcel        try {
695130803Smarcel            tc.read_value(parent);
696130803Smarcel        } catch (MARSHAL ex) {
697130803Smarcel            if (tc.kind().value() != TCKind._tk_value)
698130803Smarcel                throw ex;
699130803Smarcel            // We can be sure that the whole typecode encapsulation has been
700130803Smarcel            // read off.
701130803Smarcel            dprintThrowable(ex);
702130803Smarcel        }
703130803Smarcel        // read off the value of the any
704130803Smarcel        any.read_value(parent, tc);
705130803Smarcel
706130803Smarcel        return any;
707130803Smarcel    }
708130803Smarcel
709130803Smarcel    public org.omg.CORBA.Object read_Object() {
710130803Smarcel        return read_Object(null);
711130803Smarcel    }
712130803Smarcel
713130803Smarcel    // ------------ RMI related methods --------------------------
714130803Smarcel
715130803Smarcel    // IDL to Java ptc-00-01-08 1.21.4.1
716130803Smarcel    //
717130803Smarcel    // The clz argument to read_Object can be either a stub
718130803Smarcel    // Class or the "Class object for the RMI/IDL interface type
719130803Smarcel    // that is statically expected."
720130803Smarcel    // This functions as follows:
721130803Smarcel    // 1. If clz==null, just use the repository ID from the stub
722130803Smarcel    // 2. If clz is a stub class, just use it as a static factory.
723130803Smarcel    //    clz is a stub class iff StubAdapter.isStubClass( clz ).
724130803Smarcel    //    In addition, clz is a IDL stub class iff
725130803Smarcel    //    IDLEntity.class.isAssignableFrom( clz ).
726130803Smarcel    // 3. If clz is an interface, use it to create the appropriate
727130803Smarcel    //    stub factory.
728130803Smarcel    public org.omg.CORBA.Object read_Object(Class clz)
729130803Smarcel    {
730130803Smarcel        // In any case, we must first read the IOR.
731130803Smarcel        IOR ior = IORFactories.makeIOR(parent) ;
732130803Smarcel        if (ior.isNil())
733130803Smarcel            return null ;
734130803Smarcel
735130803Smarcel        PresentationManager.StubFactoryFactory sff = ORB.getStubFactoryFactory() ;
736130803Smarcel        String codeBase = ior.getProfile().getCodebase() ;
737130803Smarcel        PresentationManager.StubFactory stubFactory = null ;
738130803Smarcel
739130803Smarcel        if (clz == null) {
740130803Smarcel            RepositoryId rid = RepositoryId.cache.getId( ior.getTypeId() ) ;
741130803Smarcel            String className = rid.getClassName() ;
742130803Smarcel            boolean isIDLInterface = rid.isIDLType() ;
743130803Smarcel
744130803Smarcel            if (className == null || className.equals( "" ))
745130803Smarcel                stubFactory = null ;
746130803Smarcel            else
747130803Smarcel                try {
748130803Smarcel                    stubFactory = sff.createStubFactory( className,
749130803Smarcel                        isIDLInterface, codeBase, (Class)null,
750130803Smarcel                        (ClassLoader)null );
751130803Smarcel                } catch (Exception exc) {
752130803Smarcel                    // Could not create stubFactory, so use null.
753130803Smarcel                    // XXX stubFactory handling is still too complex:
754130803Smarcel                    // Can we resolve the stubFactory question once in
755130803Smarcel                    // a single place?
756130803Smarcel                    stubFactory = null ;
757130803Smarcel                }
758130803Smarcel        } else if (StubAdapter.isStubClass( clz )) {
759130803Smarcel            stubFactory = PresentationDefaults.makeStaticStubFactory(
760130803Smarcel                clz ) ;
761130803Smarcel        } else {
762130803Smarcel            // clz is an interface class
763130803Smarcel            boolean isIDL = IDLEntity.class.isAssignableFrom( clz ) ;
764130803Smarcel
765130803Smarcel            stubFactory = sff.createStubFactory( clz.getName(),
766130803Smarcel                isIDL, codeBase, clz, clz.getClassLoader() ) ;
767130803Smarcel        }
768130803Smarcel
769130803Smarcel        return internalIORToObject( ior, stubFactory, orb ) ;
770130803Smarcel    }
771130803Smarcel
772130803Smarcel    /*
773130803Smarcel     * This is used as a general utility (e.g., the PortableInterceptor
774130803Smarcel     * implementation uses it.   If stubFactory is null, the ior's
775130803Smarcel     * IIOPProfile must support getServant.
776130803Smarcel     */
777130803Smarcel    public static org.omg.CORBA.Object internalIORToObject(
778130803Smarcel        IOR ior, PresentationManager.StubFactory stubFactory, ORB orb)
779130803Smarcel    {
780130803Smarcel        ORBUtilSystemException wrapper = ORBUtilSystemException.get(
781130803Smarcel            (ORB)orb, CORBALogDomains.RPC_ENCODING ) ;
782130803Smarcel
783130803Smarcel        java.lang.Object servant = ior.getProfile().getServant() ;
784130803Smarcel        if (servant != null ) {
785130803Smarcel            if (servant instanceof Tie) {
786130803Smarcel                String codebase = ior.getProfile().getCodebase();
787130803Smarcel                org.omg.CORBA.Object objref = (org.omg.CORBA.Object)
788130803Smarcel                    Utility.loadStub( (Tie)servant, stubFactory, codebase,
789130803Smarcel                        false);
790130803Smarcel
791130803Smarcel                // If we managed to load a stub, return it, otherwise we
792130803Smarcel                // must fail...
793130803Smarcel                if (objref != null) {
794130803Smarcel                    return objref;
795130803Smarcel                } else {
796130803Smarcel                    throw wrapper.readObjectException() ;
797130803Smarcel                }
798130803Smarcel            } else if (servant instanceof org.omg.CORBA.Object) {
799130803Smarcel                if (!(servant instanceof
800130803Smarcel                        org.omg.CORBA.portable.InvokeHandler)) {
801130803Smarcel                    return (org.omg.CORBA.Object) servant;
802130803Smarcel                }
803130803Smarcel            } else
804130803Smarcel                throw wrapper.badServantReadObject() ;
805130803Smarcel        }
806130803Smarcel
807130803Smarcel        CorbaClientDelegate del = ORBUtility.makeClientDelegate( ior ) ;
808130803Smarcel        org.omg.CORBA.Object objref = null ;
809130803Smarcel        try {
810130803Smarcel            objref = stubFactory.makeStub() ;
811130803Smarcel        } catch (Throwable e) {
812130803Smarcel            wrapper.stubCreateError( e ) ;
813130803Smarcel
814130803Smarcel            if (e instanceof ThreadDeath) {
815130803Smarcel                throw (ThreadDeath) e;
816130803Smarcel            }
817130803Smarcel
818130803Smarcel            // Return the "default" stub...
819130803Smarcel            objref = new CORBAObjectImpl() ;
820130803Smarcel        }
821130803Smarcel
822130803Smarcel        StubAdapter.setDelegate( objref, del ) ;
823130803Smarcel        return objref;
824130803Smarcel    }
825130803Smarcel
826130803Smarcel    public java.lang.Object read_abstract_interface()
827130803Smarcel    {
828130803Smarcel        return read_abstract_interface(null);
829130803Smarcel    }
830130803Smarcel
831130803Smarcel    public java.lang.Object read_abstract_interface(java.lang.Class clz)
832130803Smarcel    {
833130803Smarcel        boolean object = read_boolean();
834130803Smarcel
835130803Smarcel        if (object) {
836130803Smarcel            return read_Object(clz);
837130803Smarcel        } else {
838130803Smarcel            return read_value();
839130803Smarcel        }
840130803Smarcel    }
841130803Smarcel
842130803Smarcel    public Serializable read_value()
843130803Smarcel    {
844130803Smarcel        return read_value((Class)null);
845130803Smarcel    }
846130803Smarcel
847130803Smarcel    private Serializable handleIndirection() {
848130803Smarcel        int indirection = read_long() + get_offset() - 4;
849130803Smarcel        if (valueCache != null && valueCache.containsVal(indirection)) {
850130803Smarcel
851130803Smarcel            java.io.Serializable cachedValue
852130803Smarcel                = (java.io.Serializable)valueCache.getKey(indirection);
853130803Smarcel            return cachedValue;
854130803Smarcel        } else {
855130803Smarcel            // In RMI-IIOP the ValueHandler will recognize this
856130803Smarcel            // exception and use the provided indirection value
857130803Smarcel            // to lookup a possible indirection to an object
858130803Smarcel            // currently on the deserialization stack.
859130803Smarcel            throw new IndirectionException(indirection);
860130803Smarcel        }
861130803Smarcel    }
862130803Smarcel
863130803Smarcel    private String readRepositoryIds(int valueTag,
864130803Smarcel                                     Class expectedType,
865130803Smarcel                                     String expectedTypeRepId) {
866130803Smarcel        return readRepositoryIds(valueTag, expectedType,
867130803Smarcel                                 expectedTypeRepId, null);
868130803Smarcel    }
869130803Smarcel
870130803Smarcel    /**
871130803Smarcel     * Examines the valuetag to see how many (if any) repository IDs
872130803Smarcel     * are present on the wire.  If no repository ID information
873130803Smarcel     * is on the wire but the expectedType or expectedTypeRepId
874130803Smarcel     * is known, it will return one of those (favoring the
875130803Smarcel     * expectedType's repId). Failing that, it uses the supplied
876130803Smarcel     * BoxedValueHelper to obtain the repository ID, as a last resort.
877130803Smarcel     */
878130803Smarcel    private String readRepositoryIds(int valueTag,
879130803Smarcel                                     Class expectedType,
880130803Smarcel                                     String expectedTypeRepId,
881130803Smarcel                                     BoxedValueHelper factory) {
882130803Smarcel        switch(repIdUtil.getTypeInfo(valueTag)) {
883130803Smarcel            case RepositoryIdUtility.NO_TYPE_INFO :
884130803Smarcel                // Throw an exception if we have no repository ID info and
885130803Smarcel                // no expectedType to work with.  Otherwise, how would we
886130803Smarcel                // know what to unmarshal?
887130803Smarcel                if (expectedType == null) {
888130803Smarcel                    if (expectedTypeRepId != null) {
889130803Smarcel                        return expectedTypeRepId;
890130803Smarcel                    } else if (factory != null) {
891130803Smarcel                        return factory.get_id();
892130803Smarcel                    } else {
893130803Smarcel                        throw wrapper.expectedTypeNullAndNoRepId(
894130803Smarcel                            CompletionStatus.COMPLETED_MAYBE);
895130803Smarcel                    }
896130803Smarcel                }
897130803Smarcel                return repIdStrs.createForAnyType(expectedType);
898130803Smarcel            case RepositoryIdUtility.SINGLE_REP_TYPE_INFO :
899130803Smarcel                return read_repositoryId();
900130803Smarcel            case RepositoryIdUtility.PARTIAL_LIST_TYPE_INFO :
901130803Smarcel                return read_repositoryIds();
902130803Smarcel            default:
903130803Smarcel                throw wrapper.badValueTag( CompletionStatus.COMPLETED_MAYBE,
904130803Smarcel                    Integer.toHexString(valueTag) ) ;
905130803Smarcel        }
906130803Smarcel    }
907130803Smarcel
908130803Smarcel    public Serializable read_value(Class expectedType) {
909130803Smarcel
910130803Smarcel        // Read value tag
911130803Smarcel        int vType = readValueTag();
912130803Smarcel
913130803Smarcel        // Is value null?
914130803Smarcel        if (vType == 0)
915130803Smarcel            return null;
916130803Smarcel
917130803Smarcel        // Is this an indirection to a previously
918130803Smarcel        // read valuetype?
919130803Smarcel        if (vType == 0xffffffff)
920130803Smarcel            return handleIndirection();
921130803Smarcel
922130803Smarcel        // Save where this valuetype started so we
923130803Smarcel        // can put it in the indirection valueCache
924130803Smarcel        // later
925130803Smarcel        int indirection = get_offset() - 4;
926130803Smarcel
927130803Smarcel        // Need to save this special marker variable
928130803Smarcel        // to restore its value during recursion
929130803Smarcel        boolean saveIsChunked = isChunked;
930130803Smarcel
931130803Smarcel        isChunked = repIdUtil.isChunkedEncoding(vType);
932130803Smarcel
933130803Smarcel        java.lang.Object value = null;
934130803Smarcel
935130803Smarcel        String codebase_URL = null;
936130803Smarcel        if (repIdUtil.isCodeBasePresent(vType)) {
937130803Smarcel            codebase_URL = read_codebase_URL();
938130803Smarcel        }
939130803Smarcel
940130803Smarcel        // Read repository id(s)
941130803Smarcel        String repositoryIDString
942130803Smarcel            = readRepositoryIds(vType, expectedType, null);
943130803Smarcel
944130803Smarcel        // If isChunked was determined to be true based
945130803Smarcel        // on the valuetag, this will read a chunk length
946130803Smarcel        start_block();
947130803Smarcel
948130803Smarcel        // Remember that end_flag keeps track of all nested
949130803Smarcel        // valuetypes and is used for older ORBs
950130803Smarcel        end_flag--;
951130803Smarcel        if (isChunked)
952130803Smarcel            chunkedValueNestingLevel--;
953130803Smarcel
954130803Smarcel        if (repositoryIDString.equals(repIdStrs.getWStringValueRepId())) {
955130803Smarcel            value = read_wstring();
956130803Smarcel        } else
957130803Smarcel        if (repositoryIDString.equals(repIdStrs.getClassDescValueRepId())) {
958130803Smarcel            // read in the class whether with the old ClassDesc or the
959130803Smarcel            // new one
960130803Smarcel            value = readClass();
961130803Smarcel        } else {
962130803Smarcel
963130803Smarcel            Class valueClass = expectedType;
964130803Smarcel
965130803Smarcel            // By this point, either the expectedType or repositoryIDString
966130803Smarcel            // is guaranteed to be non-null.
967130803Smarcel            if (expectedType == null ||
968130803Smarcel                !repositoryIDString.equals(repIdStrs.createForAnyType(expectedType))) {
969130803Smarcel
970130803Smarcel                valueClass = getClassFromString(repositoryIDString,
971130803Smarcel                                                codebase_URL,
972130803Smarcel                                                expectedType);
973130803Smarcel            }
974130803Smarcel
975130803Smarcel            if (valueClass == null) {
976130803Smarcel                // No point attempting to use value handler below, since the
977130803Smarcel                // class information is not available.
978130803Smarcel                throw wrapper.couldNotFindClass(
979130803Smarcel                    CompletionStatus.COMPLETED_MAYBE,
980130803Smarcel                    new ClassNotFoundException());
981130803Smarcel            }
982130803Smarcel
983130803Smarcel            if (valueClass != null &&
984130803Smarcel                org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(valueClass)) {
985130803Smarcel
986130803Smarcel                value =  readIDLValue(indirection,
987130803Smarcel                                      repositoryIDString,
988130803Smarcel                                      valueClass,
989130803Smarcel                                      codebase_URL);
990130803Smarcel
991130803Smarcel            } else {
992130803Smarcel
993130803Smarcel                // Must be some form of RMI-IIOP valuetype
994130803Smarcel
995130803Smarcel                try {
996130803Smarcel                    if (valueHandler == null)
997130803Smarcel                        valueHandler = ORBUtility.createValueHandler();
998130803Smarcel
999130803Smarcel                    value = valueHandler.readValue(parent,
1000130803Smarcel                                                   indirection,
1001130803Smarcel                                                   valueClass,
1002130803Smarcel                                                   repositoryIDString,
1003130803Smarcel                                                   getCodeBase());
1004130803Smarcel
1005130803Smarcel                } catch(SystemException sysEx) {
1006130803Smarcel                    // Just rethrow any CORBA system exceptions
1007130803Smarcel                    // that come out of the ValueHandler
1008130803Smarcel                    throw sysEx;
1009130803Smarcel                } catch(Exception ex) {
1010130803Smarcel                    throw wrapper.valuehandlerReadException(
1011130803Smarcel                        CompletionStatus.COMPLETED_MAYBE, ex ) ;
1012130803Smarcel                } catch(Error e) {
1013130803Smarcel                    throw wrapper.valuehandlerReadError(
1014130803Smarcel                        CompletionStatus.COMPLETED_MAYBE, e ) ;
1015130803Smarcel                }
1016130803Smarcel            }
1017130803Smarcel        }
1018130803Smarcel
1019130803Smarcel        // Skip any remaining chunks until we get to
1020130803Smarcel        // an end tag or a valuetag.  If we see a valuetag,
1021130803Smarcel        // that means there was another valuetype in the sender's
1022130803Smarcel        // version of this class that we need to skip over.
1023130803Smarcel        handleEndOfValue();
1024130803Smarcel
1025130803Smarcel        // Read and process the end tag if we're chunking.
1026130803Smarcel        // Assumes that we're at the position of the end tag
1027130803Smarcel        // (handleEndOfValue should assure this)
1028130803Smarcel        readEndTag();
1029130803Smarcel
1030130803Smarcel        // Cache the valuetype that we read
1031130803Smarcel        if (valueCache == null)
1032130803Smarcel            valueCache = new CacheTable(orb,false);
1033130803Smarcel        valueCache.put(value, indirection);
1034130803Smarcel
1035130803Smarcel        // Allow for possible continuation chunk.
1036130803Smarcel        // If we're a nested valuetype inside of a chunked
1037130803Smarcel        // valuetype, and that enclosing valuetype has
1038130803Smarcel        // more data to write, it will need to have this
1039130803Smarcel        // new chunk begin after we wrote our end tag.
1040130803Smarcel        isChunked = saveIsChunked;
1041130803Smarcel        start_block();
1042130803Smarcel
1043130803Smarcel        return (java.io.Serializable)value;
1044130803Smarcel    }
1045130803Smarcel
1046130803Smarcel    public Serializable read_value(BoxedValueHelper factory) {
1047130803Smarcel
1048130803Smarcel        // Read value tag
1049130803Smarcel        int vType = readValueTag();
1050130803Smarcel
1051130803Smarcel        if (vType == 0)
1052130803Smarcel            return null; // value is null
1053130803Smarcel        else if (vType == 0xffffffff) { // Indirection tag
1054130803Smarcel            int indirection = read_long() + get_offset() - 4;
1055130803Smarcel            if (valueCache != null && valueCache.containsVal(indirection))
1056130803Smarcel                {
1057130803Smarcel                    java.io.Serializable cachedValue =
1058130803Smarcel                           (java.io.Serializable)valueCache.getKey(indirection);
1059130803Smarcel                    return cachedValue;
1060130803Smarcel                }
1061130803Smarcel            else {
1062130803Smarcel                throw new IndirectionException(indirection);
1063130803Smarcel            }
1064130803Smarcel        }
1065130803Smarcel        else {
1066130803Smarcel            int indirection = get_offset() - 4;
1067130803Smarcel
1068130803Smarcel            // end_block();
1069130803Smarcel
1070130803Smarcel            boolean saveIsChunked = isChunked;
1071130803Smarcel            isChunked = repIdUtil.isChunkedEncoding(vType);
1072130803Smarcel
1073130803Smarcel            java.lang.Object value = null;
1074130803Smarcel
1075130803Smarcel            String codebase_URL = null;
1076130803Smarcel            if (repIdUtil.isCodeBasePresent(vType)){
1077130803Smarcel                codebase_URL = read_codebase_URL();
1078130803Smarcel            }
1079130803Smarcel
1080130803Smarcel            // Read repository id
1081130803Smarcel            String repositoryIDString
1082130803Smarcel                = readRepositoryIds(vType, null, null, factory);
1083130803Smarcel
1084130803Smarcel            // Compare rep. ids to see if we should use passed helper
1085130803Smarcel            if (!repositoryIDString.equals(factory.get_id()))
1086130803Smarcel                factory = Utility.getHelper(null, codebase_URL, repositoryIDString);
1087130803Smarcel
1088130803Smarcel            start_block();
1089130803Smarcel            end_flag--;
1090130803Smarcel            if (isChunked)
1091130803Smarcel                chunkedValueNestingLevel--;
1092130803Smarcel
1093130803Smarcel            if (factory instanceof ValueHelper) {
1094130803Smarcel                value = readIDLValueWithHelper((ValueHelper)factory, indirection);
1095130803Smarcel            } else {
1096130803Smarcel                valueIndirection = indirection;  // for callback
1097130803Smarcel                value = factory.read_value(parent);
1098130803Smarcel            }
1099130803Smarcel
1100130803Smarcel            handleEndOfValue();
1101130803Smarcel            readEndTag();
1102130803Smarcel
1103130803Smarcel            // Put into valueCache
1104130803Smarcel            if (valueCache == null)
1105130803Smarcel                valueCache = new CacheTable(orb,false);
1106130803Smarcel            valueCache.put(value, indirection);
1107130803Smarcel
1108130803Smarcel            // allow for possible continuation chunk
1109130803Smarcel            isChunked = saveIsChunked;
1110130803Smarcel            start_block();
1111130803Smarcel
1112130803Smarcel            return (java.io.Serializable)value;
1113130803Smarcel        }
1114130803Smarcel    }
1115130803Smarcel
1116130803Smarcel    private boolean isCustomType(ValueHelper helper) {
1117130803Smarcel        try{
1118130803Smarcel            TypeCode tc = helper.get_type();
1119130803Smarcel            int kind = tc.kind().value();
1120130803Smarcel            if (kind == TCKind._tk_value) {
1121130803Smarcel                return (tc.type_modifier() == org.omg.CORBA.VM_CUSTOM.value);
1122130803Smarcel            }
1123130803Smarcel        } catch(BadKind ex) {
1124130803Smarcel            throw wrapper.badKind(ex) ;
1125130803Smarcel        }
1126130803Smarcel
1127130803Smarcel        return false;
1128130803Smarcel    }
1129130803Smarcel
1130130803Smarcel    // This method is actually called indirectly by
1131130803Smarcel    // read_value(String repositoryId).
1132130803Smarcel    // Therefore, it is not a truly independent read call that handles
1133130803Smarcel    // header information itself.
1134130803Smarcel    public java.io.Serializable read_value(java.io.Serializable value) {
1135130803Smarcel
1136130803Smarcel        // Put into valueCache using valueIndirection
1137130803Smarcel        if (valueCache == null)
1138130803Smarcel            valueCache = new CacheTable(orb,false);
1139130803Smarcel        valueCache.put(value, valueIndirection);
1140130803Smarcel
1141130803Smarcel        if (value instanceof StreamableValue)
1142130803Smarcel            ((StreamableValue)value)._read(parent);
1143130803Smarcel        else if (value instanceof CustomValue)
1144130803Smarcel            ((CustomValue)value).unmarshal(parent);
1145130803Smarcel
1146130803Smarcel        return value;
1147130803Smarcel    }
1148130803Smarcel
1149130803Smarcel    public java.io.Serializable read_value(java.lang.String repositoryId) {
1150130803Smarcel
1151130803Smarcel        // if (inBlock)
1152130803Smarcel        //    end_block();
1153130803Smarcel
1154130803Smarcel        // Read value tag
1155130803Smarcel        int vType = readValueTag();
1156130803Smarcel
1157130803Smarcel        if (vType == 0)
1158130803Smarcel            return null; // value is null
1159130803Smarcel        else if (vType == 0xffffffff) { // Indirection tag
1160130803Smarcel            int indirection = read_long() + get_offset() - 4;
1161130803Smarcel            if (valueCache != null && valueCache.containsVal(indirection))
1162130803Smarcel                {
1163130803Smarcel                    java.io.Serializable cachedValue =
1164130803Smarcel                          (java.io.Serializable)valueCache.getKey(indirection);
1165130803Smarcel                    return cachedValue;
1166130803Smarcel                }
1167130803Smarcel            else {
1168130803Smarcel                throw new IndirectionException(indirection);
1169130803Smarcel            }
1170130803Smarcel        }
1171130803Smarcel        else {
1172130803Smarcel            int indirection = get_offset() - 4;
1173130803Smarcel
1174130803Smarcel            // end_block();
1175130803Smarcel
1176130803Smarcel            boolean saveIsChunked = isChunked;
1177130803Smarcel            isChunked = repIdUtil.isChunkedEncoding(vType);
1178130803Smarcel
1179130803Smarcel            java.lang.Object value = null;
1180130803Smarcel
1181130803Smarcel            String codebase_URL = null;
1182130803Smarcel            if (repIdUtil.isCodeBasePresent(vType)){
1183130803Smarcel                codebase_URL = read_codebase_URL();
1184130803Smarcel            }
1185130803Smarcel
1186130803Smarcel            // Read repository id
1187130803Smarcel            String repositoryIDString
1188130803Smarcel                = readRepositoryIds(vType, null, repositoryId);
1189130803Smarcel
1190130803Smarcel            ValueFactory factory =
1191130803Smarcel               Utility.getFactory(null, codebase_URL, orb, repositoryIDString);
1192130803Smarcel
1193130803Smarcel            start_block();
1194130803Smarcel            end_flag--;
1195130803Smarcel            if (isChunked)
1196130803Smarcel                chunkedValueNestingLevel--;
1197130803Smarcel
1198130803Smarcel            valueIndirection = indirection;  // for callback
1199130803Smarcel            value = factory.read_value(parent);
1200130803Smarcel
1201130803Smarcel            handleEndOfValue();
1202130803Smarcel            readEndTag();
1203130803Smarcel
1204130803Smarcel            // Put into valueCache
1205130803Smarcel            if (valueCache == null)
1206130803Smarcel                valueCache = new CacheTable(orb,false);
1207130803Smarcel            valueCache.put(value, indirection);
1208130803Smarcel
1209130803Smarcel            // allow for possible continuation chunk
1210130803Smarcel            isChunked = saveIsChunked;
1211130803Smarcel            start_block();
1212130803Smarcel
1213130803Smarcel            return (java.io.Serializable)value;
1214130803Smarcel        }
1215130803Smarcel    }
1216130803Smarcel
1217130803Smarcel    private Class readClass() {
1218130803Smarcel
1219130803Smarcel        String codebases = null, classRepId = null;
1220130803Smarcel
1221130803Smarcel        if (orb == null ||
1222130803Smarcel            ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
1223130803Smarcel            ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
1224130803Smarcel
1225130803Smarcel            codebases = (String)read_value(java.lang.String.class);
1226130803Smarcel            classRepId = (String)read_value(java.lang.String.class);
1227130803Smarcel        } else {
1228130803Smarcel            // Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID
1229130803Smarcel            // and codebase strings in the wrong order.
1230130803Smarcel            classRepId = (String)read_value(java.lang.String.class);
1231130803Smarcel            codebases = (String)read_value(java.lang.String.class);
1232130803Smarcel        }
1233130803Smarcel
1234130803Smarcel        if (debug) {
1235130803Smarcel            dprint("readClass codebases: "
1236130803Smarcel                   + codebases
1237130803Smarcel                   + " rep Id: "
1238130803Smarcel                   + classRepId);
1239130803Smarcel        }
1240130803Smarcel
1241130803Smarcel        Class cl = null;
1242130803Smarcel
1243130803Smarcel        RepositoryIdInterface repositoryID
1244130803Smarcel            = repIdStrs.getFromString(classRepId);
1245130803Smarcel
1246130803Smarcel        try {
1247130803Smarcel            cl = repositoryID.getClassFromType(codebases);
1248130803Smarcel        } catch(ClassNotFoundException cnfe) {
1249130803Smarcel            throw wrapper.cnfeReadClass( CompletionStatus.COMPLETED_MAYBE,
1250130803Smarcel                cnfe, repositoryID.getClassName() ) ;
1251130803Smarcel        } catch(MalformedURLException me) {
1252130803Smarcel            throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
1253130803Smarcel                me, repositoryID.getClassName(), codebases ) ;
1254130803Smarcel        }
1255130803Smarcel
1256130803Smarcel        return cl;
1257130803Smarcel    }
1258130803Smarcel
1259130803Smarcel    private java.lang.Object readIDLValueWithHelper(ValueHelper helper, int indirection)
1260130803Smarcel    {
1261130803Smarcel        // look for two-argument static read method
1262130803Smarcel        Method readMethod;
1263130803Smarcel        try {
1264130803Smarcel            Class argTypes[] = {org.omg.CORBA.portable.InputStream.class, helper.get_class()};
1265130803Smarcel            readMethod = helper.getClass().getDeclaredMethod(kReadMethod, argTypes);
1266130803Smarcel        }
1267130803Smarcel        catch(NoSuchMethodException nsme) { // must be boxed value helper
1268130803Smarcel            java.lang.Object result = helper.read_value(parent);
1269130803Smarcel            return result;
1270130803Smarcel        }
1271130803Smarcel
1272130803Smarcel        // found two-argument read method, so must be non-boxed value...
1273130803Smarcel        // ...create a blank instance
1274130803Smarcel        java.lang.Object val = null;
1275130803Smarcel        try {
1276130803Smarcel            val = helper.get_class().newInstance();
1277130803Smarcel        } catch(java.lang.InstantiationException ie) {
1278130803Smarcel            throw wrapper.couldNotInstantiateHelper( ie,
1279130803Smarcel                helper.get_class() ) ;
1280130803Smarcel        } catch(IllegalAccessException iae){
1281130803Smarcel            // Value's constructor is protected or private
1282130803Smarcel            //
1283130803Smarcel            // So, use the helper to read the value.
1284130803Smarcel            //
1285130803Smarcel            // NOTE : This means that in this particular case a recursive ref.
1286130803Smarcel            // would fail.
1287130803Smarcel            return helper.read_value(parent);
1288130803Smarcel        }
1289130803Smarcel
1290130803Smarcel        // add blank instance to cache table
1291130803Smarcel        if (valueCache == null)
1292130803Smarcel            valueCache = new CacheTable(orb,false);
1293130803Smarcel        valueCache.put(val, indirection);
1294130803Smarcel
1295130803Smarcel        // if custom type, call unmarshal method
1296130803Smarcel        if (val instanceof CustomMarshal && isCustomType(helper)) {
1297130803Smarcel            ((CustomMarshal)val).unmarshal(parent);
1298130803Smarcel            return val;
1299130803Smarcel        }
1300130803Smarcel
1301130803Smarcel        // call two-argument read method using reflection
1302130803Smarcel        try {
1303130803Smarcel            java.lang.Object args[] = {parent, val};
1304130803Smarcel            readMethod.invoke(helper, args);
1305130803Smarcel            return val;
1306130803Smarcel        } catch(IllegalAccessException iae2) {
1307130803Smarcel            throw wrapper.couldNotInvokeHelperReadMethod( iae2, helper.get_class() ) ;
1308130803Smarcel        } catch(InvocationTargetException ite){
1309130803Smarcel            throw wrapper.couldNotInvokeHelperReadMethod( ite, helper.get_class() ) ;
1310130803Smarcel        }
1311130803Smarcel    }
1312130803Smarcel
1313130803Smarcel    private java.lang.Object readBoxedIDLEntity(Class clazz, String codebase)
1314130803Smarcel    {
1315130803Smarcel        Class cls = null ;
1316130803Smarcel
1317130803Smarcel        try {
1318130803Smarcel            ClassLoader clazzLoader = (clazz == null ? null : clazz.getClassLoader());
1319130803Smarcel
1320130803Smarcel            cls = Utility.loadClassForClass(clazz.getName()+"Helper", codebase,
1321130803Smarcel                                                   clazzLoader, clazz, clazzLoader);
1322130803Smarcel            final Class helperClass = cls ;
1323130803Smarcel
1324130803Smarcel            final Class argTypes[] = {org.omg.CORBA.portable.InputStream.class};
1325130803Smarcel
1326130803Smarcel            // getDeclaredMethod requires RuntimePermission accessDeclaredMembers
1327130803Smarcel            // if a different class loader is used (even though the javadoc says otherwise)
1328130803Smarcel            Method readMethod = null;
1329130803Smarcel            try {
1330130803Smarcel                readMethod = (Method)AccessController.doPrivileged(
1331130803Smarcel                    new PrivilegedExceptionAction() {
1332130803Smarcel                        public java.lang.Object run() throws NoSuchMethodException {
1333130803Smarcel                            return helperClass.getDeclaredMethod(kReadMethod, argTypes);
1334130803Smarcel                        }
1335130803Smarcel                    }
1336130803Smarcel                );
1337130803Smarcel            } catch (PrivilegedActionException pae) {
1338130803Smarcel                // this gets caught below
1339130803Smarcel                throw (NoSuchMethodException)pae.getException();
1340130803Smarcel            }
1341130803Smarcel
1342130803Smarcel            java.lang.Object args[] = {parent};
1343130803Smarcel            return readMethod.invoke(null, args);
1344130803Smarcel
1345130803Smarcel        } catch (ClassNotFoundException cnfe) {
1346130803Smarcel            throw wrapper.couldNotInvokeHelperReadMethod( cnfe, cls ) ;
1347130803Smarcel        } catch(NoSuchMethodException nsme) {
1348130803Smarcel            throw wrapper.couldNotInvokeHelperReadMethod( nsme, cls ) ;
1349130803Smarcel        } catch(IllegalAccessException iae) {
1350130803Smarcel            throw wrapper.couldNotInvokeHelperReadMethod( iae, cls ) ;
1351130803Smarcel        } catch(InvocationTargetException ite) {
1352130803Smarcel            throw wrapper.couldNotInvokeHelperReadMethod( ite, cls ) ;
1353130803Smarcel        }
1354130803Smarcel    }
1355130803Smarcel
1356130803Smarcel    private java.lang.Object readIDLValue(int indirection, String repId,
1357130803Smarcel                                          Class clazz, String codebase)
1358130803Smarcel    {
1359130803Smarcel        ValueFactory factory ;
1360130803Smarcel
1361130803Smarcel        // Always try to find a ValueFactory first, as required by the spec.
1362130803Smarcel        // There are some complications here in the IDL 3.0 mapping (see 1.13.8),
1363130803Smarcel        // but basically we must always be able to override the DefaultFactory
1364130803Smarcel        // or Helper mappings that are also used.  This appears to be the case
1365130803Smarcel        // even in the boxed value cases.  The original code only did the lookup
1366130803Smarcel        // in the case of class implementing either StreamableValue or CustomValue,
1367130803Smarcel        // but abstract valuetypes only implement ValueBase, and really require
1368130803Smarcel        // the use of the repId to find a factory (including the DefaultFactory).
1369130803Smarcel        try {
1370130803Smarcel            // use new-style OBV support (factory object)
1371130803Smarcel            factory = Utility.getFactory(clazz, codebase, orb, repId);
1372130803Smarcel        } catch (MARSHAL marshal) {
1373130803Smarcel            // XXX log marshal at one of the INFO levels
1374130803Smarcel
1375130803Smarcel            // Could not get a factory, so try alternatives
1376130803Smarcel            if (!StreamableValue.class.isAssignableFrom(clazz) &&
1377130803Smarcel                !CustomValue.class.isAssignableFrom(clazz) &&
1378130803Smarcel                ValueBase.class.isAssignableFrom(clazz)) {
1379130803Smarcel                // use old-style OBV support (helper object)
1380130803Smarcel                BoxedValueHelper helper = Utility.getHelper(clazz, codebase, repId);
1381130803Smarcel                if (helper instanceof ValueHelper)
1382130803Smarcel                    return readIDLValueWithHelper((ValueHelper)helper, indirection);
1383130803Smarcel                else
1384130803Smarcel                    return helper.read_value(parent);
1385130803Smarcel            } else {
1386130803Smarcel                // must be a boxed IDLEntity, so make a reflective call to the
1387130803Smarcel                // helper's static read method...
1388130803Smarcel                return readBoxedIDLEntity(clazz, codebase);
1389130803Smarcel            }
1390130803Smarcel        }
1391130803Smarcel
1392130803Smarcel        // If there was no error in getting the factory, use it.
1393130803Smarcel        valueIndirection = indirection;  // for callback
1394130803Smarcel        return factory.read_value(parent);
1395130803Smarcel    }
1396130803Smarcel
1397130803Smarcel    /**
1398130803Smarcel     * End tags are only written for chunked valuetypes.
1399130803Smarcel     *
1400130803Smarcel     * Before Merlin, our ORBs wrote end tags which took into account
1401130803Smarcel     * all enclosing valuetypes.  This was changed by an interop resolution
1402130803Smarcel     * (see details around chunkedValueNestingLevel) to only include
1403130803Smarcel     * enclosing chunked types.
1404130803Smarcel     *
1405130803Smarcel     * ORB versioning and end tag compaction are handled here.
1406130803Smarcel     */
1407130803Smarcel    private void readEndTag() {
1408130803Smarcel        if (isChunked) {
1409130803Smarcel
1410130803Smarcel            // Read the end tag
1411130803Smarcel            int anEndTag = read_long();
1412130803Smarcel
1413130803Smarcel            // End tags should always be negative, and the outermost
1414130803Smarcel            // enclosing chunked valuetype should have a -1 end tag.
1415130803Smarcel            //
1416130803Smarcel            // handleEndOfValue should have assured that we were
1417130803Smarcel            // at the end tag position!
1418130803Smarcel            if (anEndTag >= 0) {
1419130803Smarcel                throw wrapper.positiveEndTag( CompletionStatus.COMPLETED_MAYBE,
1420130803Smarcel                    new Integer(anEndTag), new Integer( get_offset() - 4 ) ) ;
1421130803Smarcel            }
1422130803Smarcel
1423130803Smarcel            // If the ORB is null, or if we're sure we're talking to
1424130803Smarcel            // a foreign ORB, Merlin, or something more recent, we
1425130803Smarcel            // use the updated end tag computation, and are more strenuous
1426130803Smarcel            // about the values.
1427130803Smarcel            if (orb == null ||
1428130803Smarcel                ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
1429130803Smarcel                ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
1430130803Smarcel
1431130803Smarcel                // If the end tag we read was less than what we were expecting,
1432130803Smarcel                // then the sender must think it's sent more enclosing
1433130803Smarcel                // chunked valuetypes than we have.  Throw an exception.
1434130803Smarcel                if (anEndTag < chunkedValueNestingLevel)
1435130803Smarcel                    throw wrapper.unexpectedEnclosingValuetype(
1436130803Smarcel                        CompletionStatus.COMPLETED_MAYBE, new Integer( anEndTag ),
1437130803Smarcel                        new Integer( chunkedValueNestingLevel ) ) ;
1438130803Smarcel
1439130803Smarcel                // If the end tag is bigger than what we expected, but
1440130803Smarcel                // still negative, then the sender has done some end tag
1441130803Smarcel                // compaction.  We back up the stream 4 bytes so that the
1442130803Smarcel                // next time readEndTag is called, it will get down here
1443130803Smarcel                // again.  Even with fragmentation, we'll always be able
1444130803Smarcel                // to do this.
1445130803Smarcel                if (anEndTag != chunkedValueNestingLevel) {
1446130803Smarcel                    bbwi.position(bbwi.position() - 4);
1447130803Smarcel                 }
1448130803Smarcel
1449130803Smarcel            } else {
1450130803Smarcel
1451130803Smarcel                // When talking to Kestrel or Ladybird, we use our old
1452130803Smarcel                // end tag rules and are less strict.  If the end tag
1453130803Smarcel                // isn't what we expected, we back up, assuming
1454130803Smarcel                // compaction.
1455130803Smarcel                if (anEndTag != end_flag) {
1456130803Smarcel                    bbwi.position(bbwi.position() - 4);
1457130803Smarcel                }
1458130803Smarcel            }
1459130803Smarcel
1460130803Smarcel            // This only keeps track of the enclosing chunked
1461130803Smarcel            // valuetypes
1462130803Smarcel            chunkedValueNestingLevel++;
1463130803Smarcel        }
1464130803Smarcel
1465130803Smarcel        // This keeps track of all enclosing valuetypes
1466130803Smarcel        end_flag++;
1467130803Smarcel    }
1468130803Smarcel
1469130803Smarcel    protected int get_offset() {
1470130803Smarcel        return bbwi.position();
1471130803Smarcel    }
1472130803Smarcel
1473130803Smarcel    private void start_block() {
1474130803Smarcel
1475130803Smarcel        // if (outerValueDone)
1476130803Smarcel        if (!isChunked)
1477130803Smarcel            return;
1478130803Smarcel
1479130803Smarcel        // if called from alignAndCheck, need to reset blockLength
1480130803Smarcel        // to avoid an infinite recursion loop on read_long() call
1481130803Smarcel        blockLength = maxBlockLength;
1482130803Smarcel
1483130803Smarcel        blockLength = read_long();
1484130803Smarcel
1485130803Smarcel        // Must remember where we began the chunk to calculate how far
1486130803Smarcel        // along we are.  See notes above about chunkBeginPos.
1487130803Smarcel
1488130803Smarcel        if (blockLength > 0 && blockLength < maxBlockLength) {
1489130803Smarcel            blockLength += get_offset();  // _REVISIT_ unsafe, should use a Java long
1490130803Smarcel
1491130803Smarcel            // inBlock = true;
1492130803Smarcel        } else {
1493130803Smarcel
1494130803Smarcel            // System.out.println("start_block snooped a " + Integer.toHexString(blockLength));
1495130803Smarcel
1496130803Smarcel            // not a chunk length field
1497130803Smarcel            blockLength = maxBlockLength;
1498130803Smarcel
1499130803Smarcel            bbwi.position(bbwi.position() - 4);
1500130803Smarcel        }
1501130803Smarcel    }
1502130803Smarcel
1503130803Smarcel    // Makes sure that if we were reading a chunked value, we end up
1504130803Smarcel    // at the right place in the stream, no matter how little the
1505130803Smarcel    // unmarshalling code read.
1506130803Smarcel    //
1507130803Smarcel    // After calling this method, if we are chunking, we should be
1508130803Smarcel    // in position to read the end tag.
1509130803Smarcel    private void handleEndOfValue() {
1510130803Smarcel
1511130803Smarcel        // If we're not chunking, we don't have to worry about
1512130803Smarcel        // skipping remaining chunks or finding end tags
1513130803Smarcel        if (!isChunked)
1514130803Smarcel            return;
1515130803Smarcel
1516130803Smarcel        // Skip any remaining chunks
1517130803Smarcel        while (blockLength != maxBlockLength) {
1518130803Smarcel            end_block();
1519130803Smarcel            start_block();
1520130803Smarcel        }
1521130803Smarcel
1522130803Smarcel        // Now look for the end tag
1523130803Smarcel
1524130803Smarcel        // This is a little wasteful since we're reading
1525130803Smarcel        // this long up to 3 times in the worst cases (once
1526130803Smarcel        // in start_block, once here, and once in readEndTag
1527130803Smarcel        //
1528130803Smarcel        // Peek next long
1529130803Smarcel        int nextLong = read_long();
1530130803Smarcel        bbwi.position(bbwi.position() - 4);
1531130803Smarcel
1532130803Smarcel        // We did find an end tag, so we're done.  readEndTag
1533130803Smarcel        // should take care of making sure it's the correct
1534130803Smarcel        // end tag, etc.  Remember that since end tags,
1535130803Smarcel        // chunk lengths, and valuetags have non overlapping
1536130803Smarcel        // ranges, we can tell by the value what the longs are.
1537130803Smarcel        if (nextLong < 0)
1538130803Smarcel            return;
1539130803Smarcel
1540130803Smarcel        if (nextLong == 0 || nextLong >= maxBlockLength) {
1541130803Smarcel
1542130803Smarcel            // A custom marshaled valuetype left extra data
1543130803Smarcel            // on the wire, and that data had another
1544130803Smarcel            // nested value inside of it.  We've just
1545130803Smarcel            // read the value tag or null of that nested value.
1546130803Smarcel            //
1547130803Smarcel            // In an attempt to get by it, we'll try to call
1548130803Smarcel            // read_value() to get the nested value off of
1549130803Smarcel            // the wire.  Afterwards, we must call handleEndOfValue
1550130803Smarcel            // recursively to read any further chunks that the containing
1551130803Smarcel            // valuetype might still have after the nested
1552130803Smarcel            // value.
1553130803Smarcel            read_value();
1554130803Smarcel            handleEndOfValue();
1555130803Smarcel        } else {
1556130803Smarcel            // This probably means that the code to skip chunks has
1557130803Smarcel            // an error, and ended up setting blockLength to something
1558130803Smarcel            // other than maxBlockLength even though we weren't
1559130803Smarcel            // starting a new chunk.
1560130803Smarcel            throw wrapper.couldNotSkipBytes( CompletionStatus.COMPLETED_MAYBE,
1561130803Smarcel                new Integer( nextLong ), new Integer( get_offset() ) ) ;
1562130803Smarcel        }
1563130803Smarcel    }
1564130803Smarcel
1565130803Smarcel    private void end_block() {
1566130803Smarcel
1567130803Smarcel        // if in a chunk, check for underflow or overflow
1568130803Smarcel        if (blockLength != maxBlockLength) {
1569130803Smarcel            if (blockLength == get_offset()) {
1570130803Smarcel                // Chunk ended correctly
1571130803Smarcel                blockLength = maxBlockLength;
1572130803Smarcel            } else {
1573130803Smarcel                // Skip over anything left by bad unmarshaling code (ex:
1574130803Smarcel                // a buggy custom unmarshaler).  See handleEndOfValue.
1575130803Smarcel                if (blockLength > get_offset()) {
1576130803Smarcel                    skipToOffset(blockLength);
1577130803Smarcel                } else {
1578130803Smarcel                    throw wrapper.badChunkLength( new Integer( blockLength ),
1579130803Smarcel                        new Integer( get_offset() ) ) ;
1580130803Smarcel                }
1581130803Smarcel            }
1582130803Smarcel        }
1583130803Smarcel    }
1584130803Smarcel
1585130803Smarcel    private int readValueTag(){
1586130803Smarcel        // outerValueDone = false;
1587130803Smarcel        return read_long();
1588130803Smarcel    }
1589130803Smarcel
1590130803Smarcel    public org.omg.CORBA.ORB orb() {
1591130803Smarcel        return orb;
1592130803Smarcel    }
1593130803Smarcel
1594130803Smarcel    // ------------ End RMI related methods --------------------------
1595130803Smarcel
1596130803Smarcel    public final void read_boolean_array(boolean[] value, int offset, int length) {
1597130803Smarcel        for(int i=0; i < length; i++) {
1598130803Smarcel            value[i+offset] = read_boolean();
1599130803Smarcel        }
1600130803Smarcel    }
1601130803Smarcel
1602130803Smarcel    public final void read_char_array(char[] value, int offset, int length) {
1603130803Smarcel        for(int i=0; i < length; i++) {
1604130803Smarcel            value[i+offset] = read_char();
1605130803Smarcel        }
1606130803Smarcel    }
1607130803Smarcel
1608130803Smarcel    public final void read_wchar_array(char[] value, int offset, int length) {
1609130803Smarcel        for(int i=0; i < length; i++) {
1610130803Smarcel            value[i+offset] = read_wchar();
1611130803Smarcel        }
1612130803Smarcel    }
1613130803Smarcel
1614130803Smarcel    public final void read_short_array(short[] value, int offset, int length) {
1615130803Smarcel        for(int i=0; i < length; i++) {
1616130803Smarcel            value[i+offset] = read_short();
1617130803Smarcel        }
1618130803Smarcel    }
1619130803Smarcel
1620130803Smarcel    public final void read_ushort_array(short[] value, int offset, int length) {
1621130803Smarcel        read_short_array(value, offset, length);
1622130803Smarcel    }
1623130803Smarcel
1624130803Smarcel    public final void read_long_array(int[] value, int offset, int length) {
1625130803Smarcel        for(int i=0; i < length; i++) {
1626130803Smarcel            value[i+offset] = read_long();
1627130803Smarcel        }
1628130803Smarcel    }
1629130803Smarcel
1630130803Smarcel    public final void read_ulong_array(int[] value, int offset, int length) {
1631130803Smarcel        read_long_array(value, offset, length);
1632130803Smarcel    }
1633130803Smarcel
1634130803Smarcel    public final void read_longlong_array(long[] value, int offset, int length) {
1635130803Smarcel        for(int i=0; i < length; i++) {
1636130803Smarcel            value[i+offset] = read_longlong();
1637130803Smarcel        }
1638130803Smarcel    }
1639130803Smarcel
1640130803Smarcel    public final void read_ulonglong_array(long[] value, int offset, int length) {
1641130803Smarcel        read_longlong_array(value, offset, length);
1642130803Smarcel    }
1643130803Smarcel
1644130803Smarcel    public final void read_float_array(float[] value, int offset, int length) {
1645130803Smarcel        for(int i=0; i < length; i++) {
1646130803Smarcel            value[i+offset] = read_float();
1647130803Smarcel        }
1648130803Smarcel    }
1649130803Smarcel
1650130803Smarcel    public final void read_double_array(double[] value, int offset, int length) {
1651130803Smarcel        for(int i=0; i < length; i++) {
1652130803Smarcel            value[i+offset] = read_double();
1653130803Smarcel        }
1654130803Smarcel    }
1655130803Smarcel
1656130803Smarcel    public final void read_any_array(org.omg.CORBA.Any[] value, int offset, int length) {
1657130803Smarcel        for(int i=0; i < length; i++) {
1658130803Smarcel            value[i+offset] = read_any();
1659130803Smarcel        }
1660130803Smarcel    }
1661130803Smarcel
1662130803Smarcel    //--------------------------------------------------------------------//
1663130803Smarcel    // CDRInputStream state management.
1664130803Smarcel    //
1665130803Smarcel
1666130803Smarcel    /**
1667130803Smarcel     * Are we at the end of the input stream?
1668130803Smarcel     */
1669130803Smarcel//     public final boolean isAtEnd() {
1670130803Smarcel//      return bbwi.position() == bbwi.buflen;
1671130803Smarcel//     }
1672130803Smarcel
1673130803Smarcel//     public int available() throws IOException {
1674130803Smarcel//         return bbwi.buflen - bbwi.position();
1675130803Smarcel//     }
1676130803Smarcel
1677130803Smarcel    private String read_repositoryIds() {
1678130803Smarcel
1679130803Smarcel        // Read # of repository ids
1680130803Smarcel        int numRepIds = read_long();
1681130803Smarcel        if (numRepIds == 0xffffffff) {
1682130803Smarcel            int indirection = read_long() + get_offset() - 4;
1683130803Smarcel            if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
1684130803Smarcel                return (String)repositoryIdCache.getKey(indirection);
1685130803Smarcel            else
1686130803Smarcel                throw wrapper.unableToLocateRepIdArray( new Integer( indirection ) ) ;
1687130803Smarcel        } else {
1688130803Smarcel
1689130803Smarcel            // read first array element and store it as an indirection to the whole array
1690130803Smarcel            int indirection = get_offset();
1691130803Smarcel            String repID = read_repositoryId();
1692130803Smarcel            if (repositoryIdCache == null)
1693130803Smarcel                repositoryIdCache = new CacheTable(orb,false);
1694130803Smarcel            repositoryIdCache.put(repID, indirection);
1695130803Smarcel
1696130803Smarcel            // read and ignore the subsequent array elements, but put them in the
1697130803Smarcel            // indirection table in case there are later indirections back to them
1698130803Smarcel            for (int i = 1; i < numRepIds; i++) {
1699130803Smarcel                read_repositoryId();
1700130803Smarcel            }
1701130803Smarcel
1702130803Smarcel            return repID;
1703130803Smarcel        }
1704130803Smarcel    }
1705130803Smarcel
1706130803Smarcel    private final String read_repositoryId()
1707130803Smarcel    {
1708130803Smarcel        String result = readStringOrIndirection(true);
1709130803Smarcel
1710130803Smarcel        if (result == null) { // Indirection
1711130803Smarcel            int indirection = read_long() + get_offset() - 4;
1712130803Smarcel
1713130803Smarcel            if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
1714130803Smarcel                return (String)repositoryIdCache.getKey(indirection);
1715130803Smarcel            else
1716130803Smarcel                throw wrapper.badRepIdIndirection( CompletionStatus.COMPLETED_MAYBE,
1717130803Smarcel                    new Integer(bbwi.position()) ) ;
1718130803Smarcel        } else {
1719130803Smarcel            if (repositoryIdCache == null)
1720130803Smarcel                repositoryIdCache = new CacheTable(orb,false);
1721130803Smarcel            repositoryIdCache.put(result, stringIndirection);
1722130803Smarcel        }
1723130803Smarcel
1724130803Smarcel        return result ;
1725130803Smarcel    }
1726130803Smarcel
1727130803Smarcel    private final String read_codebase_URL()
1728130803Smarcel    {
1729130803Smarcel        String result = readStringOrIndirection(true);
1730130803Smarcel
1731130803Smarcel        if (result == null) { // Indirection
1732130803Smarcel            int indirection = read_long() + get_offset() - 4;
1733130803Smarcel
1734130803Smarcel            if (codebaseCache != null && codebaseCache.containsVal(indirection))
1735130803Smarcel                return (String)codebaseCache.getKey(indirection);
1736130803Smarcel            else
1737130803Smarcel                throw wrapper.badCodebaseIndirection(
1738130803Smarcel                    CompletionStatus.COMPLETED_MAYBE,
1739130803Smarcel                    new Integer(bbwi.position()) ) ;
1740130803Smarcel        } else {
1741130803Smarcel            if (codebaseCache == null)
1742130803Smarcel                codebaseCache = new CacheTable(orb,false);
1743130803Smarcel            codebaseCache.put(result, stringIndirection);
1744130803Smarcel        }
1745130803Smarcel
1746130803Smarcel        return result;
1747130803Smarcel    }
1748130803Smarcel
1749130803Smarcel    /* DataInputStream methods */
1750130803Smarcel
1751130803Smarcel    public java.lang.Object read_Abstract () {
1752130803Smarcel        return read_abstract_interface();
1753130803Smarcel    }
1754130803Smarcel
1755130803Smarcel    public java.io.Serializable read_Value () {
1756130803Smarcel        return read_value();
1757130803Smarcel    }
1758130803Smarcel
1759130803Smarcel    public void read_any_array (org.omg.CORBA.AnySeqHolder seq, int offset, int length) {
1760130803Smarcel        read_any_array(seq.value, offset, length);
1761130803Smarcel    }
1762130803Smarcel
1763130803Smarcel    public void read_boolean_array (org.omg.CORBA.BooleanSeqHolder seq, int offset, int length) {
1764130803Smarcel        read_boolean_array(seq.value, offset, length);
1765130803Smarcel    }
1766130803Smarcel
1767130803Smarcel    public void read_char_array (org.omg.CORBA.CharSeqHolder seq, int offset, int length) {
1768130803Smarcel        read_char_array(seq.value, offset, length);
1769130803Smarcel    }
1770130803Smarcel
1771130803Smarcel    public void read_wchar_array (org.omg.CORBA.WCharSeqHolder seq, int offset, int length) {
1772130803Smarcel        read_wchar_array(seq.value, offset, length);
1773130803Smarcel    }
1774130803Smarcel
1775130803Smarcel    public void read_octet_array (org.omg.CORBA.OctetSeqHolder seq, int offset, int length) {
1776130803Smarcel        read_octet_array(seq.value, offset, length);
1777130803Smarcel    }
1778130803Smarcel
1779130803Smarcel    public void read_short_array (org.omg.CORBA.ShortSeqHolder seq, int offset, int length) {
1780130803Smarcel        read_short_array(seq.value, offset, length);
1781130803Smarcel    }
1782130803Smarcel
1783130803Smarcel    public void read_ushort_array (org.omg.CORBA.UShortSeqHolder seq, int offset, int length) {
1784130803Smarcel        read_ushort_array(seq.value, offset, length);
1785130803Smarcel    }
1786130803Smarcel
1787130803Smarcel    public void read_long_array (org.omg.CORBA.LongSeqHolder seq, int offset, int length) {
1788130803Smarcel        read_long_array(seq.value, offset, length);
1789130803Smarcel    }
1790130803Smarcel
1791130803Smarcel    public void read_ulong_array (org.omg.CORBA.ULongSeqHolder seq, int offset, int length) {
1792130803Smarcel        read_ulong_array(seq.value, offset, length);
1793130803Smarcel    }
1794130803Smarcel
1795130803Smarcel    public void read_ulonglong_array (org.omg.CORBA.ULongLongSeqHolder seq, int offset, int length) {
1796130803Smarcel        read_ulonglong_array(seq.value, offset, length);
1797130803Smarcel    }
1798130803Smarcel
1799130803Smarcel    public void read_longlong_array (org.omg.CORBA.LongLongSeqHolder seq, int offset, int length) {
1800130803Smarcel        read_longlong_array(seq.value, offset, length);
1801130803Smarcel    }
1802130803Smarcel
1803130803Smarcel    public void read_float_array (org.omg.CORBA.FloatSeqHolder seq, int offset, int length) {
1804130803Smarcel        read_float_array(seq.value, offset, length);
1805130803Smarcel    }
1806130803Smarcel
1807130803Smarcel    public void read_double_array (org.omg.CORBA.DoubleSeqHolder seq, int offset, int length) {
1808130803Smarcel        read_double_array(seq.value, offset, length);
1809130803Smarcel    }
1810130803Smarcel
1811130803Smarcel    public java.math.BigDecimal read_fixed(short digits, short scale) {
1812130803Smarcel        // digits isn't really needed here
1813130803Smarcel        StringBuffer buffer = read_fixed_buffer();
1814130803Smarcel        if (digits != buffer.length())
1815130803Smarcel            throw wrapper.badFixed( new Integer(digits),
1816130803Smarcel                new Integer(buffer.length()) ) ;
1817130803Smarcel        buffer.insert(digits - scale, '.');
1818130803Smarcel        return new BigDecimal(buffer.toString());
1819130803Smarcel    }
1820130803Smarcel
1821130803Smarcel    // This method is unable to yield the correct scale.
1822130803Smarcel    public java.math.BigDecimal read_fixed() {
1823130803Smarcel        return new BigDecimal(read_fixed_buffer().toString());
1824130803Smarcel    }
1825130803Smarcel
1826130803Smarcel    // Each octet contains (up to) two decimal digits.
1827130803Smarcel    // If the fixed type has an odd number of decimal digits, then the representation
1828130803Smarcel    // begins with the first (most significant) digit.
1829130803Smarcel    // Otherwise, this first half-octet is all zero, and the first digit
1830130803Smarcel    // is in the second half-octet.
1831130803Smarcel    // The sign configuration, in the last half-octet of the representation,
1832130803Smarcel    // is 0xD for negative numbers and 0xC for positive and zero values.
1833130803Smarcel    private StringBuffer read_fixed_buffer() {
1834130803Smarcel        StringBuffer buffer = new StringBuffer(64);
1835130803Smarcel        byte doubleDigit;
1836130803Smarcel        int firstDigit;
1837130803Smarcel        int secondDigit;
1838130803Smarcel        boolean wroteFirstDigit = false;
1839130803Smarcel        boolean more = true;
1840130803Smarcel        while (more) {
1841130803Smarcel            doubleDigit = this.read_octet();
1842130803Smarcel            firstDigit = (int)((doubleDigit & 0xf0) >> 4);
1843130803Smarcel            secondDigit = (int)(doubleDigit & 0x0f);
1844130803Smarcel            if (wroteFirstDigit || firstDigit != 0) {
1845130803Smarcel                buffer.append(Character.forDigit(firstDigit, 10));
1846130803Smarcel                wroteFirstDigit = true;
1847130803Smarcel            }
1848130803Smarcel            if (secondDigit == 12) {
1849130803Smarcel                // positive number or zero
1850130803Smarcel                if ( ! wroteFirstDigit) {
1851130803Smarcel                    // zero
1852130803Smarcel                    return new StringBuffer("0.0");
1853130803Smarcel                } else {
1854130803Smarcel                    // positive number
1855130803Smarcel                    // done
1856130803Smarcel                }
1857130803Smarcel                more = false;
1858130803Smarcel            } else if (secondDigit == 13) {
1859130803Smarcel                // negative number
1860130803Smarcel                buffer.insert(0, '-');
1861130803Smarcel                more = false;
1862130803Smarcel            } else {
1863130803Smarcel                buffer.append(Character.forDigit(secondDigit, 10));
1864130803Smarcel                wroteFirstDigit = true;
1865130803Smarcel            }
1866130803Smarcel        }
1867130803Smarcel        return buffer;
1868130803Smarcel    }
1869130803Smarcel
1870130803Smarcel    private final static String _id = "IDL:omg.org/CORBA/DataInputStream:1.0";
1871130803Smarcel    private final static String[] _ids = { _id };
1872130803Smarcel
1873130803Smarcel    public String[] _truncatable_ids() {
1874130803Smarcel        if (_ids == null)
1875130803Smarcel            return null;
1876130803Smarcel
1877130803Smarcel        return (String[])_ids.clone();
1878130803Smarcel    }
1879130803Smarcel
1880130803Smarcel    /* for debugging */
1881130803Smarcel
1882130803Smarcel    public void printBuffer() {
1883130803Smarcel        CDRInputStream_1_0.printBuffer(this.bbwi);
1884130803Smarcel    }
1885130803Smarcel
1886130803Smarcel    public static void printBuffer(ByteBufferWithInfo bbwi) {
1887130803Smarcel
1888130803Smarcel        System.out.println("----- Input Buffer -----");
1889130803Smarcel        System.out.println();
1890130803Smarcel        System.out.println("Current position: " + bbwi.position());
1891130803Smarcel        System.out.println("Total length : " + bbwi.buflen);
1892130803Smarcel        System.out.println();
1893130803Smarcel
1894130803Smarcel        try {
1895130803Smarcel
1896130803Smarcel            char[] charBuf = new char[16];
1897130803Smarcel
1898130803Smarcel            for (int i = 0; i < bbwi.buflen; i += 16) {
1899130803Smarcel
1900130803Smarcel                int j = 0;
1901130803Smarcel
1902130803Smarcel                // For every 16 bytes, there is one line
1903130803Smarcel                // of output.  First, the hex output of
1904130803Smarcel                // the 16 bytes with each byte separated
1905130803Smarcel                // by a space.
1906130803Smarcel                while (j < 16 && j + i < bbwi.buflen) {
1907130803Smarcel                    int k = bbwi.byteBuffer.get(i + j);
1908130803Smarcel                    if (k < 0)
1909130803Smarcel                        k = 256 + k;
1910130803Smarcel                    String hex = Integer.toHexString(k);
1911130803Smarcel                    if (hex.length() == 1)
1912130803Smarcel                        hex = "0" + hex;
1913130803Smarcel                    System.out.print(hex + " ");
1914130803Smarcel                    j++;
1915130803Smarcel                }
1916130803Smarcel
1917130803Smarcel                // Add any extra spaces to align the
1918130803Smarcel                // text column in case we didn't end
1919130803Smarcel                // at 16
1920130803Smarcel                while (j < 16) {
1921130803Smarcel                    System.out.print("   ");
1922130803Smarcel                    j++;
1923130803Smarcel                }
1924130803Smarcel
1925130803Smarcel                // Now output the ASCII equivalents.  Non-ASCII
1926130803Smarcel                // characters are shown as periods.
1927130803Smarcel                int x = 0;
1928130803Smarcel                while (x < 16 && x + i < bbwi.buflen) {
1929130803Smarcel                    if (ORBUtility.isPrintable((char)bbwi.byteBuffer.get(i + x)))
1930130803Smarcel                        charBuf[x] = (char)bbwi.byteBuffer.get(i + x);
1931130803Smarcel                    else
1932130803Smarcel                        charBuf[x] = '.';
1933130803Smarcel                    x++;
1934130803Smarcel                }
1935130803Smarcel                System.out.println(new String(charBuf, 0, x));
1936130803Smarcel            }
1937130803Smarcel
1938130803Smarcel        } catch (Throwable t) {
1939130803Smarcel            t.printStackTrace();
1940130803Smarcel        }
1941130803Smarcel
1942130803Smarcel        System.out.println("------------------------");
1943130803Smarcel    }
1944130803Smarcel
1945130803Smarcel    public ByteBuffer getByteBuffer() {
1946130803Smarcel        ByteBuffer result = null;
1947130803Smarcel        if (bbwi != null) {
1948130803Smarcel            result = bbwi.byteBuffer;
1949130803Smarcel        }
1950130803Smarcel        return result;
1951130803Smarcel    }
1952130803Smarcel
1953130803Smarcel    public int getBufferLength() {
1954130803Smarcel        return bbwi.buflen;
1955130803Smarcel    }
1956130803Smarcel
1957130803Smarcel    public void setBufferLength(int value) {
1958130803Smarcel        bbwi.buflen = value;
1959130803Smarcel        bbwi.byteBuffer.limit(bbwi.buflen);
1960130803Smarcel    }
1961130803Smarcel
1962130803Smarcel    public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
1963130803Smarcel        this.bbwi = bbwi;
1964130803Smarcel    }
1965130803Smarcel
1966130803Smarcel    public void setByteBuffer(ByteBuffer byteBuffer) {
1967130803Smarcel        bbwi.byteBuffer = byteBuffer;
1968130803Smarcel    }
1969130803Smarcel
1970130803Smarcel    public int getIndex() {
1971130803Smarcel        return bbwi.position();
1972130803Smarcel    }
1973130803Smarcel
1974130803Smarcel    public void setIndex(int value) {
1975130803Smarcel        bbwi.position(value);
1976130803Smarcel    }
1977130803Smarcel
1978130803Smarcel    public boolean isLittleEndian() {
1979130803Smarcel        return littleEndian;
1980130803Smarcel    }
1981130803Smarcel
1982130803Smarcel    public void orb(org.omg.CORBA.ORB orb) {
1983130803Smarcel        this.orb = (ORB)orb;
1984130803Smarcel    }
1985130803Smarcel
1986130803Smarcel    public BufferManagerRead getBufferManager() {
1987130803Smarcel        return bufferManagerRead;
1988130803Smarcel    }
1989130803Smarcel
1990130803Smarcel    private void skipToOffset(int offset) {
1991130803Smarcel
1992130803Smarcel        // Number of bytes to skip
1993130803Smarcel        int len = offset - get_offset();
1994130803Smarcel
1995130803Smarcel        int n = 0;
1996130803Smarcel
1997130803Smarcel        while (n < len) {
1998130803Smarcel            int avail;
1999130803Smarcel            int bytes;
2000130803Smarcel            int wanted;
2001130803Smarcel
2002130803Smarcel            avail = bbwi.buflen - bbwi.position();
2003130803Smarcel            if (avail <= 0) {
2004130803Smarcel                grow(1, 1);
2005130803Smarcel                avail = bbwi.buflen - bbwi.position();
2006130803Smarcel            }
2007130803Smarcel
2008130803Smarcel            wanted = len - n;
2009130803Smarcel            bytes = (wanted < avail) ? wanted : avail;
2010130803Smarcel            bbwi.position(bbwi.position() + bytes);
2011130803Smarcel            n += bytes;
2012130803Smarcel        }
2013130803Smarcel    }
2014130803Smarcel
2015130803Smarcel
2016130803Smarcel    // Mark and reset -------------------------------------------------
2017130803Smarcel
2018130803Smarcel    protected MarkAndResetHandler markAndResetHandler = null;
2019130803Smarcel
2020130803Smarcel    protected class StreamMemento
2021130803Smarcel    {
2022130803Smarcel        // These are the fields that may change after marking
2023130803Smarcel        // the stream position, so we need to save them.
2024130803Smarcel        private int blockLength_;
2025130803Smarcel        private int end_flag_;
2026130803Smarcel        private int chunkedValueNestingLevel_;
2027130803Smarcel        private int valueIndirection_;
2028130803Smarcel        private int stringIndirection_;
2029130803Smarcel        private boolean isChunked_;
2030130803Smarcel        private javax.rmi.CORBA.ValueHandler valueHandler_;
2031130803Smarcel        private ByteBufferWithInfo bbwi_;
2032130803Smarcel        private boolean specialNoOptionalDataState_;
2033130803Smarcel
2034130803Smarcel        public StreamMemento()
2035130803Smarcel        {
2036130803Smarcel            blockLength_ = blockLength;
2037130803Smarcel            end_flag_ = end_flag;
2038130803Smarcel            chunkedValueNestingLevel_ = chunkedValueNestingLevel;
2039130803Smarcel            valueIndirection_ = valueIndirection;
2040130803Smarcel            stringIndirection_ = stringIndirection;
2041130803Smarcel            isChunked_ = isChunked;
2042130803Smarcel            valueHandler_ = valueHandler;
2043130803Smarcel            specialNoOptionalDataState_ = specialNoOptionalDataState;
2044130803Smarcel            bbwi_ = new ByteBufferWithInfo(bbwi);
2045130803Smarcel        }
2046130803Smarcel    }
2047130803Smarcel
2048130803Smarcel    public java.lang.Object createStreamMemento() {
2049130803Smarcel        return new StreamMemento();
2050130803Smarcel    }
2051130803Smarcel
2052130803Smarcel    public void restoreInternalState(java.lang.Object streamMemento) {
2053130803Smarcel
2054130803Smarcel        StreamMemento mem = (StreamMemento)streamMemento;
2055130803Smarcel
2056130803Smarcel        blockLength = mem.blockLength_;
2057130803Smarcel        end_flag = mem.end_flag_;
2058130803Smarcel        chunkedValueNestingLevel = mem.chunkedValueNestingLevel_;
2059130803Smarcel        valueIndirection = mem.valueIndirection_;
2060130803Smarcel        stringIndirection = mem.stringIndirection_;
2061130803Smarcel        isChunked = mem.isChunked_;
2062130803Smarcel        valueHandler = mem.valueHandler_;
2063130803Smarcel        specialNoOptionalDataState = mem.specialNoOptionalDataState_;
2064130803Smarcel        bbwi = mem.bbwi_;
2065130803Smarcel    }
2066130803Smarcel
2067130803Smarcel    public int getPosition() {
2068130803Smarcel        return get_offset();
2069130803Smarcel    }
2070130803Smarcel
2071130803Smarcel    public void mark(int readlimit) {
2072130803Smarcel        markAndResetHandler.mark(this);
2073130803Smarcel    }
2074130803Smarcel
2075130803Smarcel    public void reset() {
2076130803Smarcel        markAndResetHandler.reset();
2077130803Smarcel    }
2078130803Smarcel
2079130803Smarcel    // ---------------------------------- end Mark and Reset
2080130803Smarcel
2081130803Smarcel    // Provides a hook so subclasses of CDRInputStream can provide
2082130803Smarcel    // a CodeBase.  This ultimately allows us to grab a Connection
2083130803Smarcel    // instance in IIOPInputStream, the only subclass where this
2084130803Smarcel    // is actually used.
2085130803Smarcel    CodeBase getCodeBase() {
2086130803Smarcel        return parent.getCodeBase();
2087130803Smarcel    }
2088130803Smarcel
2089130803Smarcel    /**
2090130803Smarcel     * Attempts to find the class described by the given
2091130803Smarcel     * repository ID string and expected type.  The first
2092130803Smarcel     * attempt is to find the class locally, falling back
2093130803Smarcel     * on the URL that came with the value.  The second
2094130803Smarcel     * attempt is to use a URL from the remote CodeBase.
2095130803Smarcel     */
2096130803Smarcel    private Class getClassFromString(String repositoryIDString,
2097130803Smarcel                                     String codebaseURL,
2098130803Smarcel                                     Class expectedType)
2099130803Smarcel    {
2100130803Smarcel        RepositoryIdInterface repositoryID
2101130803Smarcel            = repIdStrs.getFromString(repositoryIDString);
2102130803Smarcel
2103130803Smarcel        try {
2104130803Smarcel            try {
2105130803Smarcel                // First try to load the class locally, then use
2106130803Smarcel                // the provided URL (if it isn't null)
2107130803Smarcel                return repositoryID.getClassFromType(expectedType,
2108130803Smarcel                                                     codebaseURL);
2109130803Smarcel            } catch (ClassNotFoundException cnfeOuter) {
2110130803Smarcel
2111130803Smarcel                try {
2112130803Smarcel
2113130803Smarcel                    if (getCodeBase() == null) {
2114130803Smarcel                        return null; // class cannot be loaded remotely.
2115130803Smarcel                    }
2116130803Smarcel
2117130803Smarcel                    // Get a URL from the remote CodeBase and retry
2118130803Smarcel                    codebaseURL = getCodeBase().implementation(repositoryIDString);
2119130803Smarcel
2120130803Smarcel                    // Don't bother trying to find it locally again if
2121130803Smarcel                    // we got a null URL
2122130803Smarcel                    if (codebaseURL == null)
2123130803Smarcel                        return null;
2124130803Smarcel
2125130803Smarcel                    return repositoryID.getClassFromType(expectedType,
2126130803Smarcel                                                         codebaseURL);
2127130803Smarcel                } catch (ClassNotFoundException cnfeInner) {
2128130803Smarcel                    dprintThrowable(cnfeInner);
2129130803Smarcel                    // Failed to load the class
2130130803Smarcel                    return null;
2131130803Smarcel                }
2132130803Smarcel            }
2133130803Smarcel        } catch (MalformedURLException mue) {
2134130803Smarcel            // Always report a bad URL
2135130803Smarcel            throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
2136130803Smarcel                mue, repositoryIDString, codebaseURL ) ;
2137130803Smarcel        }
2138130803Smarcel    }
2139130803Smarcel
2140130803Smarcel    /**
2141130803Smarcel     * Attempts to find the class described by the given
2142130803Smarcel     * repository ID string.  At most, three attempts are made:
2143130803Smarcel     * Try to find it locally, through the provided URL, and
2144130803Smarcel     * finally, via a URL from the remote CodeBase.
2145130803Smarcel     */
2146130803Smarcel    private Class getClassFromString(String repositoryIDString,
2147130803Smarcel                                     String codebaseURL)
2148130803Smarcel    {
2149130803Smarcel        RepositoryIdInterface repositoryID
2150130803Smarcel            = repIdStrs.getFromString(repositoryIDString);
2151130803Smarcel
2152130803Smarcel        for (int i = 0; i < 3; i++) {
2153130803Smarcel
2154130803Smarcel            try {
2155130803Smarcel
2156130803Smarcel                switch (i)
2157130803Smarcel                {
2158130803Smarcel                    case 0:
2159130803Smarcel                        // First try to load the class locally
2160130803Smarcel                        return repositoryID.getClassFromType();
2161130803Smarcel                    case 1:
2162130803Smarcel                        // Try to load the class using the provided
2163130803Smarcel                        // codebase URL (falls out below)
2164130803Smarcel                        break;
2165130803Smarcel                    case 2:
2166130803Smarcel                        // Try to load the class using a URL from the
2167130803Smarcel                        // remote CodeBase
2168130803Smarcel                        codebaseURL = getCodeBase().implementation(repositoryIDString);
2169130803Smarcel                        break;
2170130803Smarcel                }
2171130803Smarcel
2172130803Smarcel                // Don't bother if the codebaseURL is null
2173130803Smarcel                if (codebaseURL == null)
2174130803Smarcel                    continue;
2175130803Smarcel
2176130803Smarcel                return repositoryID.getClassFromType(codebaseURL);
2177130803Smarcel
2178130803Smarcel            } catch(ClassNotFoundException cnfe) {
2179130803Smarcel                // Will ultimately return null if all three
2180130803Smarcel                // attempts fail, but don't do anything here.
2181130803Smarcel            } catch (MalformedURLException mue) {
2182130803Smarcel                throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
2183130803Smarcel                    mue, repositoryIDString, codebaseURL ) ;
2184130803Smarcel            }
2185130803Smarcel        }
2186130803Smarcel
2187130803Smarcel        // If we get here, we have failed to load the class
2188130803Smarcel        dprint("getClassFromString failed with rep id "
2189130803Smarcel               + repositoryIDString
2190130803Smarcel               + " and codebase "
2191130803Smarcel               + codebaseURL);
2192130803Smarcel
2193130803Smarcel        return null;
2194130803Smarcel    }
2195130803Smarcel
2196130803Smarcel    // Utility method used to get chars from bytes
2197130803Smarcel    char[] getConvertedChars(int numBytes,
2198130803Smarcel                             CodeSetConversion.BTCConverter converter) {
2199130803Smarcel
2200130803Smarcel        // REVISIT - Look at CodeSetConversion.BTCConverter to see
2201130803Smarcel        //           if it can work with an NIO ByteBuffer. We should
2202130803Smarcel        //           avoid getting the bytes into an array if possible.
2203130803Smarcel
2204130803Smarcel        // To be honest, I doubt this saves much real time
2205130803Smarcel        if (bbwi.buflen - bbwi.position() >= numBytes) {
2206130803Smarcel            // If the entire string is in this buffer,
2207130803Smarcel            // just convert directly from the bbwi rather than
2208130803Smarcel            // allocating and copying.
2209130803Smarcel            byte[] tmpBuf;
2210130803Smarcel            if (bbwi.byteBuffer.hasArray())
2211130803Smarcel            {
2212130803Smarcel                tmpBuf = bbwi.byteBuffer.array();
2213130803Smarcel            }
2214130803Smarcel            else
2215130803Smarcel            {
2216130803Smarcel                 tmpBuf = new byte[bbwi.buflen];
2217130803Smarcel                 // Microbenchmarks are showing a loop of ByteBuffer.get(int)
2218130803Smarcel                 // being faster than ByteBuffer.get(byte[], int, int).
2219130803Smarcel                 for (int i = 0; i < bbwi.buflen; i++)
2220130803Smarcel                     tmpBuf[i] = bbwi.byteBuffer.get(i);
2221130803Smarcel            }
2222130803Smarcel            char[] result = converter.getChars(tmpBuf,bbwi.position(),numBytes);
2223130803Smarcel
2224130803Smarcel            bbwi.position(bbwi.position() + numBytes);
2225130803Smarcel            return result;
2226130803Smarcel        } else {
2227130803Smarcel            // Stretches across buffers.  Unless we provide an
2228130803Smarcel            // incremental conversion interface, allocate and
2229130803Smarcel            // copy the bytes.
2230130803Smarcel            byte[] bytes = new byte[numBytes];
2231130803Smarcel            read_octet_array(bytes, 0, bytes.length);
2232130803Smarcel
2233130803Smarcel            return converter.getChars(bytes, 0, numBytes);
2234130803Smarcel        }
2235130803Smarcel    }
2236130803Smarcel
2237130803Smarcel    protected CodeSetConversion.BTCConverter getCharConverter() {
2238130803Smarcel        if (charConverter == null)
2239130803Smarcel            charConverter = parent.createCharBTCConverter();
2240130803Smarcel
2241130803Smarcel        return charConverter;
2242130803Smarcel    }
2243130803Smarcel
2244130803Smarcel    protected CodeSetConversion.BTCConverter getWCharConverter() {
2245130803Smarcel        if (wcharConverter == null)
2246130803Smarcel            wcharConverter = parent.createWCharBTCConverter();
2247130803Smarcel
2248130803Smarcel        return wcharConverter;
2249130803Smarcel    }
2250130803Smarcel
2251130803Smarcel    protected void dprintThrowable(Throwable t) {
2252130803Smarcel        if (debug && t != null)
2253130803Smarcel            t.printStackTrace();
2254130803Smarcel    }
2255130803Smarcel
2256130803Smarcel    protected void dprint(String msg) {
2257130803Smarcel        if (debug) {
2258130803Smarcel            ORBUtility.dprint(this, msg);
2259130803Smarcel        }
2260130803Smarcel    }
2261130803Smarcel
2262130803Smarcel    /**
2263130803Smarcel     * Aligns the current position on the given octet boundary
2264130803Smarcel     * if there are enough bytes available to do so.  Otherwise,
2265130803Smarcel     * it just returns.  This is used for some (but not all)
2266130803Smarcel     * GIOP 1.2 message headers.
2267130803Smarcel     */
2268130803Smarcel
2269130803Smarcel    void alignOnBoundary(int octetBoundary) {
2270130803Smarcel        int needed = computeAlignment(bbwi.position(), octetBoundary);
2271130803Smarcel
2272130803Smarcel        if (bbwi.position() + needed <= bbwi.buflen)
2273130803Smarcel        {
2274130803Smarcel            bbwi.position(bbwi.position() + needed);
2275130803Smarcel        }
2276130803Smarcel    }
2277130803Smarcel
2278130803Smarcel    public void resetCodeSetConverters() {
2279130803Smarcel        charConverter = null;
2280130803Smarcel        wcharConverter = null;
2281130803Smarcel    }
2282130803Smarcel
2283130803Smarcel    public void start_value() {
2284130803Smarcel        // Read value tag
2285130803Smarcel        int vType = readValueTag();
2286130803Smarcel
2287130803Smarcel        if (vType == 0) {
2288130803Smarcel            // Stream needs to go into a state where it
2289130803Smarcel            // throws standard exception until end_value
2290130803Smarcel            // is called.  This means the sender didn't
2291130803Smarcel            // send any custom data.  If the reader here
2292130803Smarcel            // tries to read more, we need to throw an
2293130803Smarcel            // exception before reading beyond where
2294130803Smarcel            // we're supposed to
2295130803Smarcel            specialNoOptionalDataState = true;
2296130803Smarcel
2297130803Smarcel            return;
2298130803Smarcel        }
2299130803Smarcel
2300130803Smarcel        if (vType == 0xffffffff) {
2301130803Smarcel            // One should never indirect to a custom wrapper
2302130803Smarcel            throw wrapper.customWrapperIndirection(
2303130803Smarcel                CompletionStatus.COMPLETED_MAYBE);
2304130803Smarcel        }
2305130803Smarcel
2306130803Smarcel        if (repIdUtil.isCodeBasePresent(vType)) {
2307130803Smarcel            throw wrapper.customWrapperWithCodebase(
2308130803Smarcel                CompletionStatus.COMPLETED_MAYBE);
2309130803Smarcel        }
2310130803Smarcel
2311130803Smarcel        if (repIdUtil.getTypeInfo(vType)
2312130803Smarcel            != RepositoryIdUtility.SINGLE_REP_TYPE_INFO) {
2313130803Smarcel            throw wrapper.customWrapperNotSingleRepid(
2314130803Smarcel                CompletionStatus.COMPLETED_MAYBE);
2315130803Smarcel        }
2316130803Smarcel
2317130803Smarcel
2318130803Smarcel        // REVISIT - Could verify repository ID even though
2319130803Smarcel        // it isn't used elsewhere
2320130803Smarcel        read_repositoryId();
2321130803Smarcel
2322130803Smarcel        // Note: isChunked should be true here.  Should have
2323130803Smarcel        // been set to true in the containing value's read_value
2324130803Smarcel        // method.
2325130803Smarcel
2326130803Smarcel        start_block();
2327130803Smarcel        end_flag--;
2328130803Smarcel        chunkedValueNestingLevel--;
2329130803Smarcel    }
2330130803Smarcel
2331130803Smarcel    public void end_value() {
2332130803Smarcel
2333130803Smarcel        if (specialNoOptionalDataState) {
2334130803Smarcel            specialNoOptionalDataState = false;
2335130803Smarcel            return;
2336130803Smarcel        }
2337130803Smarcel
2338130803Smarcel        handleEndOfValue();
2339130803Smarcel        readEndTag();
2340130803Smarcel
2341130803Smarcel        // Note that isChunked should still be true here.
2342130803Smarcel        // If the containing valuetype is the highest
2343130803Smarcel        // chunked value, it will get set to false
2344130803Smarcel        // at the end of read_value.
2345130803Smarcel
2346130803Smarcel        // allow for possible continuation chunk
2347130803Smarcel        start_block();
2348130803Smarcel    }
2349130803Smarcel
2350130803Smarcel    public void close() throws IOException
2351130803Smarcel    {
2352130803Smarcel
2353130803Smarcel        // tell BufferManagerRead to release any ByteBuffers
2354130803Smarcel        getBufferManager().close(bbwi);
2355130803Smarcel
2356130803Smarcel        // It's possible bbwi.byteBuffer is shared between
2357130803Smarcel        // this InputStream and an OutputStream. Thus, we check
2358130803Smarcel        // if the Input/Output streams are using the same ByteBuffer.
2359130803Smarcel        // If they sharing the same ByteBuffer we need to ensure only
2360130803Smarcel        // one of those ByteBuffers are released to the ByteBufferPool.
2361130803Smarcel
2362130803Smarcel        if (bbwi != null && getByteBuffer() != null)
2363130803Smarcel        {
2364130803Smarcel            MessageMediator messageMediator = parent.getMessageMediator();
2365130803Smarcel            if (messageMediator != null)
2366130803Smarcel            {
2367130803Smarcel                CDROutputObject outputObj =
2368130803Smarcel                             (CDROutputObject)messageMediator.getOutputObject();
2369130803Smarcel                if (outputObj != null)
2370130803Smarcel                {
2371130803Smarcel                    if (outputObj.isSharing(getByteBuffer()))
2372130803Smarcel                    {
2373130803Smarcel                        // Set OutputStream's ByteBuffer and bbwi to null
2374130803Smarcel                        // so its ByteBuffer cannot be released to the pool
2375130803Smarcel                        outputObj.setByteBuffer(null);
2376130803Smarcel                        outputObj.setByteBufferWithInfo(null);
2377130803Smarcel                    }
2378130803Smarcel                }
2379130803Smarcel            }
2380130803Smarcel
2381130803Smarcel            // release this stream's ByteBuffer to the pool
2382130803Smarcel            ByteBufferPool byteBufferPool = orb.getByteBufferPool();
2383130803Smarcel            if (debug)
2384130803Smarcel            {
2385130803Smarcel                // print address of ByteBuffer being released
2386130803Smarcel                int bbAddress = System.identityHashCode(bbwi.byteBuffer);
2387130803Smarcel                StringBuffer sb = new StringBuffer(80);
2388130803Smarcel                sb.append(".close - releasing ByteBuffer id (");
2389130803Smarcel                sb.append(bbAddress).append(") to ByteBufferPool.");
2390130803Smarcel                String msg = sb.toString();
2391130803Smarcel                dprint(msg);
2392130803Smarcel            }
2393130803Smarcel            byteBufferPool.releaseByteBuffer(bbwi.byteBuffer);
2394130803Smarcel            bbwi.byteBuffer = null;
2395130803Smarcel            bbwi = null;
2396130803Smarcel        }
2397130803Smarcel    }
2398130803Smarcel}
2399130803Smarcel