1 /*
   2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * Licensed Materials - Property of IBM
  28  * RMI-IIOP v1.0
  29  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  30  *
  31  */
  32 
  33 package com.sun.corba.se.impl.encoding;
  34 
  35 import java.io.IOException;
  36 import java.io.Serializable;
  37 import java.io.ByteArrayInputStream;
  38 import java.io.ObjectInputStream;
  39 import java.io.IOException;
  40 import java.io.StreamCorruptedException;
  41 import java.io.OptionalDataException;
  42 import java.io.IOException;
  43 
  44 import java.util.Stack;
  45 
  46 import java.net.URL;
  47 import java.net.MalformedURLException;
  48 
  49 import java.nio.ByteBuffer;
  50 
  51 import java.lang.reflect.InvocationTargetException;
  52 import java.lang.reflect.Method;
  53 
  54 import java.math.BigDecimal;
  55 
  56 import java.rmi.Remote;
  57 import java.rmi.StubNotFoundException;
  58 
  59 import java.security.AccessController;
  60 import java.security.PrivilegedExceptionAction;
  61 import java.security.PrivilegedActionException;
  62 
  63 import org.omg.CORBA.SystemException;
  64 import org.omg.CORBA.Object;
  65 import org.omg.CORBA.Principal;
  66 import org.omg.CORBA.TypeCode;
  67 import org.omg.CORBA.Any;
  68 import org.omg.CORBA.portable.Delegate;
  69 import org.omg.CORBA.portable.ValueBase;
  70 import org.omg.CORBA.portable.IndirectionException;
  71 import org.omg.CORBA.CompletionStatus;
  72 import org.omg.CORBA.TCKind;
  73 import org.omg.CORBA.TypeCodePackage.BadKind;
  74 import org.omg.CORBA.CustomMarshal;
  75 import org.omg.CORBA.TypeCode;
  76 import org.omg.CORBA.Principal;
  77 import org.omg.CORBA.Any;
  78 import org.omg.CORBA.portable.BoxedValueHelper;
  79 import org.omg.CORBA.portable.ValueFactory;
  80 import org.omg.CORBA.portable.CustomValue;
  81 import org.omg.CORBA.portable.StreamableValue;
  82 import org.omg.CORBA.MARSHAL;
  83 import org.omg.CORBA.portable.IDLEntity;
  84 
  85 import javax.rmi.PortableRemoteObject;
  86 import javax.rmi.CORBA.Tie;
  87 import javax.rmi.CORBA.Util;
  88 import javax.rmi.CORBA.ValueHandler;
  89 
  90 import com.sun.corba.se.pept.protocol.MessageMediator;
  91 import com.sun.corba.se.pept.transport.ByteBufferPool;
  92 
  93 import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
  94 import com.sun.corba.se.spi.protocol.CorbaClientDelegate;
  95 
  96 import com.sun.corba.se.spi.ior.IOR;
  97 import com.sun.corba.se.spi.ior.IORFactories;
  98 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  99 
 100 import com.sun.corba.se.spi.orb.ORB;
 101 import com.sun.corba.se.spi.orb.ORBVersionFactory;
 102 import com.sun.corba.se.spi.orb.ORBVersion;
 103 
 104 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
 105 
 106 import com.sun.corba.se.spi.logging.CORBALogDomains;
 107 import com.sun.corba.se.spi.presentation.rmi.PresentationManager;
 108 import com.sun.corba.se.spi.presentation.rmi.StubAdapter;
 109 import com.sun.corba.se.spi.presentation.rmi.PresentationDefaults;
 110 
 111 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
 112 import com.sun.corba.se.impl.logging.OMGSystemException;
 113 
 114 import com.sun.corba.se.impl.corba.PrincipalImpl;
 115 import com.sun.corba.se.impl.corba.TypeCodeImpl;
 116 import com.sun.corba.se.impl.corba.CORBAObjectImpl;
 117 
 118 import com.sun.corba.se.impl.encoding.CDROutputObject;
 119 import com.sun.corba.se.impl.encoding.CodeSetConversion;
 120 
 121 import com.sun.corba.se.impl.util.Utility;
 122 import com.sun.corba.se.impl.util.RepositoryId;
 123 
 124 import com.sun.corba.se.impl.orbutil.RepositoryIdStrings;
 125 import com.sun.corba.se.impl.orbutil.RepositoryIdInterface;
 126 import com.sun.corba.se.impl.orbutil.RepositoryIdUtility;
 127 import com.sun.corba.se.impl.orbutil.RepositoryIdFactory;
 128 
 129 import com.sun.corba.se.impl.orbutil.ORBUtility;
 130 import com.sun.corba.se.impl.orbutil.CacheTable;
 131 
 132 
 133 import com.sun.org.omg.CORBA.portable.ValueHelper;
 134 
 135 import com.sun.org.omg.SendingContext.CodeBase;
 136 
 137 public class CDRInputStream_1_0 extends CDRInputStreamBase
 138     implements RestorableInputStream
 139 {
 140     private static final String kReadMethod = "read";
 141     private static final int maxBlockLength = 0x7fffff00;
 142 
 143     protected BufferManagerRead bufferManagerRead;
 144     protected ByteBufferWithInfo bbwi;
 145 
 146     // Set to the ORB's transportDebugFlag value.  This value is
 147     // used if the ORB is null.
 148     private boolean debug = false;
 149 
 150     protected boolean littleEndian;
 151     protected ORB orb;
 152     protected ORBUtilSystemException wrapper ;
 153     protected OMGSystemException omgWrapper ;
 154     protected ValueHandler valueHandler = null;
 155 
 156     // Value cache
 157     private CacheTable valueCache = null;
 158 
 159     // Repository ID cache
 160     private CacheTable repositoryIdCache = null;
 161 
 162     // codebase cache
 163     private CacheTable codebaseCache = null;
 164 
 165     // Current Class Stack (repository Ids of current class being read)
 166     // private Stack currentStack = null;
 167 
 168     // Length of current chunk, or a large positive number if not in a chunk
 169     protected int blockLength = maxBlockLength;
 170 
 171     // Read end flag (value nesting depth)
 172     protected int end_flag = 0;
 173 
 174     // Beginning with the resolution to interop issue 3526 (4328?),
 175     // only enclosing chunked valuetypes are taken into account
 176     // when computing the nesting level.  However, we still need
 177     // the old computation around for interoperability with our
 178     // older ORBs.
 179     private int chunkedValueNestingLevel = 0;
 180 
 181     // Flag used to determine whether blocksize was zero
 182     // private int checkForNullBlock = -1;
 183 
 184     // In block flag
 185     // private boolean inBlock = false;
 186 
 187     // Indicates whether we are inside a value
 188     // private boolean outerValueDone = true;
 189 
 190     // Int used by read_value(Serializable) that is set by this class
 191     // before calling ValueFactory.read_value
 192     protected int valueIndirection = 0;
 193 
 194     // Int set by readStringOrIndirection to communicate the actual
 195     // offset of the string length field back to the caller
 196     protected int stringIndirection = 0;
 197 
 198     // Flag indicating whether we are unmarshalling a chunked value
 199     protected boolean isChunked = false;
 200 
 201     // Repository ID handlers
 202     private RepositoryIdUtility repIdUtil;
 203     private RepositoryIdStrings repIdStrs;
 204 
 205     // Code set converters (created when first needed)
 206     private CodeSetConversion.BTCConverter charConverter;
 207     private CodeSetConversion.BTCConverter wcharConverter;
 208 
 209     // RMI-IIOP stream format version 2 case in which we know
 210     // that there is no more optional data available.  If the
 211     // Serializable's readObject method tries to read anything,
 212     // we must throw a MARSHAL with the special minor code
 213     // so that the ValueHandler can give the correct exception
 214     // to readObject.  The state is cleared when the ValueHandler
 215     // calls end_value after the readObject method exits.
 216     private boolean specialNoOptionalDataState = false;
 217 
 218     // Template method
 219     public CDRInputStreamBase dup()
 220     {
 221         CDRInputStreamBase result = null ;
 222 
 223         try {
 224             result = (CDRInputStreamBase)this.getClass().newInstance();
 225         } catch (Exception e) {
 226             throw wrapper.couldNotDuplicateCdrInputStream( e ) ;
 227         }
 228         result.init(this.orb,
 229                     this.bbwi.byteBuffer,
 230                     this.bbwi.buflen,
 231                     this.littleEndian,
 232                     this.bufferManagerRead);
 233 
 234         ((CDRInputStream_1_0)result).bbwi.position(this.bbwi.position());
 235         // To ensure we keep bbwi.byteBuffer.limit in sync with bbwi.buflen.
 236         ((CDRInputStream_1_0)result).bbwi.byteBuffer.limit(this.bbwi.buflen);
 237 
 238         return result;
 239     }
 240 
 241     /**
 242      * NOTE:  size passed to init means buffer size
 243      */
 244     public void init(org.omg.CORBA.ORB orb,
 245                      ByteBuffer byteBuffer,
 246                      int size,
 247                      boolean littleEndian,
 248                      BufferManagerRead bufferManager)
 249     {
 250         this.orb = (ORB)orb;
 251         this.wrapper = ORBUtilSystemException.get( (ORB)orb,
 252             CORBALogDomains.RPC_ENCODING ) ;
 253         this.omgWrapper = OMGSystemException.get( (ORB)orb,
 254             CORBALogDomains.RPC_ENCODING ) ;
 255         this.littleEndian = littleEndian;
 256         this.bufferManagerRead = bufferManager;
 257         this.bbwi = new ByteBufferWithInfo(orb,byteBuffer,0);
 258         this.bbwi.buflen = size;
 259         this.bbwi.byteBuffer.limit(bbwi.buflen);
 260         this.markAndResetHandler = bufferManagerRead.getMarkAndResetHandler();
 261 
 262         debug = ((ORB)orb).transportDebugFlag;
 263     }
 264 
 265     // See description in CDRInputStream
 266     void performORBVersionSpecificInit() {
 267         createRepositoryIdHandlers();
 268     }
 269 
 270     private final void createRepositoryIdHandlers()
 271     {
 272         repIdUtil = RepositoryIdFactory.getRepIdUtility(orb);
 273         repIdStrs = RepositoryIdFactory.getRepIdStringsFactory(orb);
 274     }
 275 
 276     public GIOPVersion getGIOPVersion() {
 277         return GIOPVersion.V1_0;
 278     }
 279 
 280     // Called by Request and Reply message. Valid for GIOP versions >= 1.2 only.
 281     // Illegal for GIOP versions < 1.2.
 282     void setHeaderPadding(boolean headerPadding) {
 283         throw wrapper.giopVersionError();
 284     }
 285 
 286     protected final int computeAlignment(int index, int align) {
 287         if (align > 1) {
 288             int incr = index & (align - 1);
 289             if (incr != 0)
 290                 return align - incr;
 291         }
 292 
 293         return 0;
 294     }
 295 
 296     public int getSize()
 297     {
 298         return bbwi.position();
 299     }
 300 
 301     protected void checkBlockLength(int align, int dataSize) {
 302         // Since chunks can end at arbitrary points (though not within
 303         // primitive CDR types, arrays of primitives, strings, wstrings,
 304         // or indirections),
 305         // we must check here for termination of the current chunk.
 306         if (!isChunked)
 307             return;
 308 
 309         // RMI-IIOP stream format version 2 case in which we know
 310         // that there is no more optional data available.  If the
 311         // Serializable's readObject method tries to read anything,
 312         // we must throw a MARSHAL exception with the special minor code
 313         // so that the ValueHandler can give the correct exception
 314         // to readObject.  The state is cleared when the ValueHandler
 315         // calls end_value after the readObject method exits.
 316         if (specialNoOptionalDataState) {
 317             throw omgWrapper.rmiiiopOptionalDataIncompatible1() ;
 318         }
 319 
 320         boolean checkForEndTag = false;
 321 
 322         // Are we at the end of the current chunk?  If so,
 323         // try to interpret the next long as a chunk length.
 324         // (It has to be either a chunk length, end tag,
 325         // or valuetag.)
 326         //
 327         // If it isn't a chunk length, blockLength will
 328         // remain set to maxBlockLength.
 329         if (blockLength == get_offset()) {
 330 
 331             blockLength = maxBlockLength;
 332             start_block();
 333 
 334             // What's next is either a valuetag or
 335             // an end tag.  If it's a valuetag, we're
 336             // probably being called as part of the process
 337             // to read the valuetag.  If it's an end tag,
 338             // then there isn't enough data left in
 339             // this valuetype to read!
 340             if (blockLength == maxBlockLength)
 341                 checkForEndTag = true;
 342 
 343         } else
 344         if (blockLength < get_offset()) {
 345             // Are we already past the end of the current chunk?
 346             // This is always an error.
 347             throw wrapper.chunkOverflow() ;
 348         }
 349 
 350         // If what's next on the wire isn't a chunk length or
 351         // what we want to read (which can't be split across chunks)
 352         // won't fit in the current chunk, throw this exception.
 353         // This probably means that we're in an RMI-IIOP
 354         // Serializable's readObject method or a custom marshaled
 355         // IDL type is reading too much/in an incorrect order
 356         int requiredNumBytes =
 357                             computeAlignment(bbwi.position(), align) + dataSize;
 358 
 359         if (blockLength != maxBlockLength &&
 360             blockLength < get_offset() + requiredNumBytes) {
 361             throw omgWrapper.rmiiiopOptionalDataIncompatible2() ;
 362         }
 363 
 364         // REVISIT - We should look at using the built in advancement
 365         //           of using ByteBuffer.get() rather than explicitly
 366         //           advancing the ByteBuffer's position.
 367         //           This is true for anywhere we are incrementing
 368         //           the ByteBuffer's position.
 369         if (checkForEndTag) {
 370             int nextLong = read_long();
 371             bbwi.position(bbwi.position() - 4);
 372 
 373             // It was an end tag, so there wasn't enough data
 374             // left in the valuetype's encoding on the wire
 375             // to read what we wanted
 376             if (nextLong < 0)
 377                 throw omgWrapper.rmiiiopOptionalDataIncompatible3() ;
 378         }
 379     }
 380 
 381     protected void alignAndCheck(int align, int n) {
 382 
 383         checkBlockLength(align, n);
 384 
 385         // WARNING: Must compute real alignment after calling
 386         // checkBlockLength since it may move the position
 387         int alignResult = computeAlignment(bbwi.position(), align);
 388         bbwi.position(bbwi.position() + alignResult);
 389 
 390         if (bbwi.position() + n > bbwi.buflen)
 391             grow(align, n);
 392     }
 393 
 394     //
 395     // This can be overridden....
 396     //
 397     protected void grow(int align, int n) {
 398 
 399         bbwi.needed = n;
 400 
 401         bbwi = bufferManagerRead.underflow(bbwi);
 402 
 403     }
 404 
 405     //
 406     // Marshal primitives.
 407     //
 408 
 409     public final void consumeEndian() {
 410         littleEndian = read_boolean();
 411     }
 412 
 413     // No such type in java
 414     public final double read_longdouble() {
 415         throw wrapper.longDoubleNotImplemented( CompletionStatus.COMPLETED_MAYBE);
 416     }
 417 
 418     public final boolean read_boolean() {
 419         return (read_octet() != 0);
 420     }
 421 
 422     public final char read_char() {
 423         alignAndCheck(1, 1);
 424 
 425         return getConvertedChars(1, getCharConverter())[0];
 426     }
 427 
 428     public char read_wchar() {
 429 
 430         // Don't allow transmission of wchar/wstring data with
 431         // foreign ORBs since it's against the spec.
 432         if (ORBUtility.isForeignORB((ORB)orb)) {
 433             throw wrapper.wcharDataInGiop10( CompletionStatus.COMPLETED_MAYBE);
 434         }
 435 
 436         // If we're talking to one of our legacy ORBs, do what
 437         // they did:
 438         int b1, b2;
 439 
 440         alignAndCheck(2, 2);
 441 
 442         if (littleEndian) {
 443             b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
 444             bbwi.position(bbwi.position() + 1);
 445             b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
 446             bbwi.position(bbwi.position() + 1);
 447         } else {
 448             b1 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
 449             bbwi.position(bbwi.position() + 1);
 450             b2 = bbwi.byteBuffer.get(bbwi.position()) & 0x00FF;
 451             bbwi.position(bbwi.position() + 1);
 452         }
 453 
 454         return (char)((b1 << 8) + (b2 << 0));
 455     }
 456 
 457     public final byte read_octet() {
 458 
 459         alignAndCheck(1, 1);
 460 
 461         byte b = bbwi.byteBuffer.get(bbwi.position());
 462         bbwi.position(bbwi.position() + 1);
 463 
 464         return b;
 465     }
 466 
 467     public final short read_short() {
 468         int b1, b2;
 469 
 470         alignAndCheck(2, 2);
 471 
 472         if (littleEndian) {
 473             b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
 474             bbwi.position(bbwi.position() + 1);
 475             b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
 476             bbwi.position(bbwi.position() + 1);
 477         } else {
 478             b1 = (bbwi.byteBuffer.get(bbwi.position()) << 8) & 0x0000FF00;
 479             bbwi.position(bbwi.position() + 1);
 480             b2 = (bbwi.byteBuffer.get(bbwi.position()) << 0) & 0x000000FF;
 481             bbwi.position(bbwi.position() + 1);
 482         }
 483 
 484         return (short)(b1 | b2);
 485     }
 486 
 487     public final short read_ushort() {
 488         return read_short();
 489     }
 490 
 491     public final int read_long() {
 492         int b1, b2, b3, b4;
 493 
 494         alignAndCheck(4, 4);
 495 
 496         int bufPos = bbwi.position();
 497         if (littleEndian) {
 498             b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 499             b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 500             b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 501             b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 502         } else {
 503             b1 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 504             b2 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 505             b3 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 506             b4 = bbwi.byteBuffer.get(bufPos++) & 0xFF;
 507         }
 508         bbwi.position(bufPos);
 509 
 510         return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
 511     }
 512 
 513     public final int read_ulong() {
 514         return read_long();
 515     }
 516 
 517     public final long read_longlong() {
 518         long i1, i2;
 519 
 520         alignAndCheck(8, 8);
 521 
 522         if (littleEndian) {
 523             i2 = read_long() & 0xFFFFFFFFL;
 524             i1 = (long)read_long() << 32;
 525         } else {
 526             i1 = (long)read_long() << 32;
 527             i2 = read_long() & 0xFFFFFFFFL;
 528         }
 529 
 530         return (i1 | i2);
 531     }
 532 
 533     public final long read_ulonglong() {
 534         return read_longlong();
 535     }
 536 
 537     public final float read_float() {
 538         return Float.intBitsToFloat(read_long());
 539     }
 540 
 541     public final double read_double() {
 542         return Double.longBitsToDouble(read_longlong());
 543     }
 544 
 545     protected final void checkForNegativeLength(int length) {
 546         if (length < 0)
 547             throw wrapper.negativeStringLength( CompletionStatus.COMPLETED_MAYBE,
 548                 new Integer(length) ) ;
 549     }
 550 
 551     protected final String readStringOrIndirection(boolean allowIndirection) {
 552 
 553         int len = read_long();
 554 
 555         //
 556         // Check for indirection
 557         //
 558         if (allowIndirection) {
 559             if (len == 0xffffffff)
 560                 return null;
 561             else
 562                 stringIndirection = get_offset() - 4;
 563         }
 564 
 565         checkForNegativeLength(len);
 566 
 567         if (orb != null && ORBUtility.isLegacyORB((ORB)orb))
 568             return legacyReadString(len);
 569         else
 570             return internalReadString(len);
 571     }
 572 
 573     private final String internalReadString(int len) {
 574         // Workaround for ORBs which send string lengths of
 575         // zero to mean empty string.
 576         //
 577         // IMPORTANT: Do not replace 'new String("")' with "", it may result
 578         // in a Serialization bug (See serialization.zerolengthstring) and
 579         // bug id: 4728756 for details
 580         if (len == 0)
 581             return new String("");
 582 
 583         char[] result = getConvertedChars(len - 1, getCharConverter());
 584 
 585         // Skip over the 1 byte null
 586         read_octet();
 587 
 588         return new String(result, 0, getCharConverter().getNumChars());
 589     }
 590 
 591     private final String legacyReadString(int len) {
 592 
 593         //
 594         // Workaround for ORBs which send string lengths of
 595         // zero to mean empty string.
 596         //
 597         //
 598         // IMPORTANT: Do not replace 'new String("")' with "", it may result
 599         // in a Serialization bug (See serialization.zerolengthstring) and
 600         // bug id: 4728756 for details
 601         if (len == 0)
 602             return new String("");
 603 
 604         len--;
 605         char[] c = new char[len];
 606 
 607         int n = 0;
 608         while (n < len) {
 609             int avail;
 610             int bytes;
 611             int wanted;
 612 
 613             avail = bbwi.buflen - bbwi.position();
 614             if (avail <= 0) {
 615                 grow(1, 1);
 616                 avail = bbwi.buflen - bbwi.position();
 617             }
 618             wanted = len - n;
 619             bytes = (wanted < avail) ? wanted : avail;
 620             // Microbenchmarks are showing a loop of ByteBuffer.get(int) being
 621             // faster than ByteBuffer.get(byte[], int, int).
 622             for (int i=0; i<bytes; i++) {
 623                 c[n+i] = (char) (bbwi.byteBuffer.get(bbwi.position()+i) & 0xFF);
 624             }
 625             bbwi.position(bbwi.position() + bytes);
 626             n += bytes;
 627         }
 628 
 629         //
 630         // Skip past terminating null byte
 631         //
 632         if (bbwi.position() + 1 > bbwi.buflen)
 633             alignAndCheck(1, 1);
 634         bbwi.position(bbwi.position() + 1);
 635 
 636         return new String(c);
 637     }
 638 
 639     public final String read_string() {
 640         return readStringOrIndirection(false);
 641     }
 642 
 643     public String read_wstring() {
 644         // Don't allow transmission of wchar/wstring data with
 645         // foreign ORBs since it's against the spec.
 646         if (ORBUtility.isForeignORB((ORB)orb)) {
 647             throw wrapper.wcharDataInGiop10( CompletionStatus.COMPLETED_MAYBE);
 648         }
 649 
 650         int len = read_long();
 651 
 652         //
 653         // Workaround for ORBs which send string lengths of
 654         // zero to mean empty string.
 655         //
 656         //
 657         // IMPORTANT: Do not replace 'new String("")' with "", it may result
 658         // in a Serialization bug (See serialization.zerolengthstring) and
 659         // bug id: 4728756 for details
 660         if (len == 0)
 661             return new String("");
 662 
 663         checkForNegativeLength(len);
 664 
 665         len--;
 666         char[] c = new char[len];
 667 
 668         for (int i = 0; i < len; i++)
 669             c[i] = read_wchar();
 670 
 671         // skip the two null terminator bytes
 672         read_wchar();
 673         // bbwi.position(bbwi.position() + 2);
 674 
 675         return new String(c);
 676     }
 677 
 678     public final void read_octet_array(byte[] b, int offset, int length) {
 679         if ( b == null )
 680             throw wrapper.nullParam() ;
 681 
 682         // Must call alignAndCheck at least once to ensure
 683         // we aren't at the end of a chunk.  Of course, we
 684         // should only call it if we actually need to read
 685         // something, otherwise we might end up with an
 686         // exception at the end of the stream.
 687         if (length == 0)
 688             return;
 689 
 690         alignAndCheck(1, 1);
 691 
 692         int n = offset;
 693         while (n < length+offset) {
 694             int avail;
 695             int bytes;
 696             int wanted;
 697 
 698             avail = bbwi.buflen - bbwi.position();
 699             if (avail <= 0) {
 700                 grow(1, 1);
 701                 avail = bbwi.buflen - bbwi.position();
 702             }
 703             wanted = (length + offset) - n;
 704             bytes = (wanted < avail) ? wanted : avail;
 705             // Microbenchmarks are showing a loop of ByteBuffer.get(int) being
 706             // faster than ByteBuffer.get(byte[], int, int).
 707             for (int i = 0; i < bytes; i++) {
 708                 b[n+i] = bbwi.byteBuffer.get(bbwi.position() + i);
 709             }
 710 
 711             bbwi.position(bbwi.position() + bytes);
 712 
 713             n += bytes;
 714         }
 715     }
 716 
 717     public Principal read_Principal() {
 718         int len = read_long();
 719         byte[] pvalue = new byte[len];
 720         read_octet_array(pvalue,0,len);
 721 
 722         Principal p = new PrincipalImpl();
 723         p.name(pvalue);
 724         return p;
 725     }
 726 
 727     public TypeCode read_TypeCode() {
 728         TypeCodeImpl tc = new TypeCodeImpl(orb);
 729         tc.read_value(parent);
 730         return tc;
 731     }
 732 
 733     public Any read_any() {
 734         Any any = orb.create_any();
 735         TypeCodeImpl tc = new TypeCodeImpl(orb);
 736 
 737         // read off the typecode
 738 
 739         // REVISIT We could avoid this try-catch if we could peek the typecode
 740         // kind off this stream and see if it is a tk_value.  Looking at the
 741         // code we know that for tk_value the Any.read_value() below
 742         // ignores the tc argument anyway (except for the kind field).
 743         // But still we would need to make sure that the whole typecode,
 744         // including encapsulations, is read off.
 745         try {
 746             tc.read_value(parent);
 747         } catch (MARSHAL ex) {
 748             if (tc.kind().value() != TCKind._tk_value)
 749                 throw ex;
 750             // We can be sure that the whole typecode encapsulation has been
 751             // read off.
 752             dprintThrowable(ex);
 753         }
 754         // read off the value of the any
 755         any.read_value(parent, tc);
 756 
 757         return any;
 758     }
 759 
 760     public org.omg.CORBA.Object read_Object() {
 761         return read_Object(null);
 762     }
 763 
 764     // ------------ RMI related methods --------------------------
 765 
 766     // IDL to Java ptc-00-01-08 1.21.4.1
 767     //
 768     // The clz argument to read_Object can be either a stub
 769     // Class or the "Class object for the RMI/IDL interface type
 770     // that is statically expected."
 771     // This functions as follows:
 772     // 1. If clz==null, just use the repository ID from the stub
 773     // 2. If clz is a stub class, just use it as a static factory.
 774     //    clz is a stub class iff StubAdapter.isStubClass( clz ).
 775     //    In addition, clz is a IDL stub class iff
 776     //    IDLEntity.class.isAssignableFrom( clz ).
 777     // 3. If clz is an interface, use it to create the appropriate
 778     //    stub factory.
 779     public org.omg.CORBA.Object read_Object(Class clz)
 780     {
 781         // In any case, we must first read the IOR.
 782         IOR ior = IORFactories.makeIOR(parent) ;
 783         if (ior.isNil())
 784             return null ;
 785 
 786         PresentationManager.StubFactoryFactory sff = ORB.getStubFactoryFactory() ;
 787         String codeBase = ior.getProfile().getCodebase() ;
 788         PresentationManager.StubFactory stubFactory = null ;
 789 
 790         if (clz == null) {
 791             RepositoryId rid = RepositoryId.cache.getId( ior.getTypeId() ) ;
 792             String className = rid.getClassName() ;
 793             boolean isIDLInterface = rid.isIDLType() ;
 794 
 795             if (className == null || className.equals( "" ))
 796                 stubFactory = null ;
 797             else
 798                 try {
 799                     stubFactory = sff.createStubFactory( className,
 800                         isIDLInterface, codeBase, (Class)null,
 801                         (ClassLoader)null );
 802                 } catch (Exception exc) {
 803                     // Could not create stubFactory, so use null.
 804                     // XXX stubFactory handling is still too complex:
 805                     // Can we resolve the stubFactory question once in
 806                     // a single place?
 807                     stubFactory = null ;
 808                 }
 809         } else if (StubAdapter.isStubClass( clz )) {
 810             stubFactory = PresentationDefaults.makeStaticStubFactory(
 811                 clz ) ;
 812         } else {
 813             // clz is an interface class
 814             boolean isIDL = IDLEntity.class.isAssignableFrom( clz ) ;
 815 
 816             stubFactory = sff.createStubFactory( clz.getName(),
 817                 isIDL, codeBase, clz, clz.getClassLoader() ) ;
 818         }
 819 
 820         return internalIORToObject( ior, stubFactory, orb ) ;
 821     }
 822 
 823     /*
 824      * This is used as a general utility (e.g., the PortableInterceptor
 825      * implementation uses it.   If stubFactory is null, the ior's
 826      * IIOPProfile must support getServant.
 827      */
 828     public static org.omg.CORBA.Object internalIORToObject(
 829         IOR ior, PresentationManager.StubFactory stubFactory, ORB orb)
 830     {
 831         ORBUtilSystemException wrapper = ORBUtilSystemException.get(
 832             (ORB)orb, CORBALogDomains.RPC_ENCODING ) ;
 833 
 834         java.lang.Object servant = ior.getProfile().getServant() ;
 835         if (servant != null ) {
 836             if (servant instanceof Tie) {
 837                 String codebase = ior.getProfile().getCodebase();
 838                 org.omg.CORBA.Object objref = (org.omg.CORBA.Object)
 839                     Utility.loadStub( (Tie)servant, stubFactory, codebase,
 840                         false);
 841 
 842                 // If we managed to load a stub, return it, otherwise we
 843                 // must fail...
 844                 if (objref != null) {
 845                     return objref;
 846                 } else {
 847                     throw wrapper.readObjectException() ;
 848                 }
 849             } else if (servant instanceof org.omg.CORBA.Object) {
 850                 if (!(servant instanceof
 851                         org.omg.CORBA.portable.InvokeHandler)) {
 852                     return (org.omg.CORBA.Object) servant;
 853                 }
 854             } else
 855                 throw wrapper.badServantReadObject() ;
 856         }
 857 
 858         CorbaClientDelegate del = ORBUtility.makeClientDelegate( ior ) ;
 859         org.omg.CORBA.Object objref = null ;
 860         try {
 861             objref = stubFactory.makeStub() ;
 862         } catch (Throwable e) {
 863             wrapper.stubCreateError( e ) ;
 864 
 865             if (e instanceof ThreadDeath) {
 866                 throw (ThreadDeath) e;
 867             }
 868 
 869             // Return the "default" stub...
 870             objref = new CORBAObjectImpl() ;
 871         }
 872 
 873         StubAdapter.setDelegate( objref, del ) ;
 874         return objref;
 875     }
 876 
 877     public java.lang.Object read_abstract_interface()
 878     {
 879         return read_abstract_interface(null);
 880     }
 881 
 882     public java.lang.Object read_abstract_interface(java.lang.Class clz)
 883     {
 884         boolean object = read_boolean();
 885 
 886         if (object) {
 887             return read_Object(clz);
 888         } else {
 889             return read_value();
 890         }
 891     }
 892 
 893     public Serializable read_value()
 894     {
 895         return read_value((Class)null);
 896     }
 897 
 898     private Serializable handleIndirection() {
 899         int indirection = read_long() + get_offset() - 4;
 900         if (valueCache != null && valueCache.containsVal(indirection)) {
 901 
 902             java.io.Serializable cachedValue
 903                 = (java.io.Serializable)valueCache.getKey(indirection);
 904             return cachedValue;
 905         } else {
 906             // In RMI-IIOP the ValueHandler will recognize this
 907             // exception and use the provided indirection value
 908             // to lookup a possible indirection to an object
 909             // currently on the deserialization stack.
 910             throw new IndirectionException(indirection);
 911         }
 912     }
 913 
 914     private String readRepositoryIds(int valueTag,
 915                                      Class expectedType,
 916                                      String expectedTypeRepId) {
 917         return readRepositoryIds(valueTag, expectedType,
 918                                  expectedTypeRepId, null);
 919     }
 920 
 921     /**
 922      * Examines the valuetag to see how many (if any) repository IDs
 923      * are present on the wire.  If no repository ID information
 924      * is on the wire but the expectedType or expectedTypeRepId
 925      * is known, it will return one of those (favoring the
 926      * expectedType's repId). Failing that, it uses the supplied
 927      * BoxedValueHelper to obtain the repository ID, as a last resort.
 928      */
 929     private String readRepositoryIds(int valueTag,
 930                                      Class expectedType,
 931                                      String expectedTypeRepId,
 932                                      BoxedValueHelper factory) {
 933         switch(repIdUtil.getTypeInfo(valueTag)) {
 934             case RepositoryIdUtility.NO_TYPE_INFO :
 935                 // Throw an exception if we have no repository ID info and
 936                 // no expectedType to work with.  Otherwise, how would we
 937                 // know what to unmarshal?
 938                 if (expectedType == null) {
 939                     if (expectedTypeRepId != null) {
 940                         return expectedTypeRepId;
 941                     } else if (factory != null) {
 942                         return factory.get_id();
 943                     } else {
 944                         throw wrapper.expectedTypeNullAndNoRepId(
 945                             CompletionStatus.COMPLETED_MAYBE);
 946                     }
 947                 }
 948                 return repIdStrs.createForAnyType(expectedType);
 949             case RepositoryIdUtility.SINGLE_REP_TYPE_INFO :
 950                 return read_repositoryId();
 951             case RepositoryIdUtility.PARTIAL_LIST_TYPE_INFO :
 952                 return read_repositoryIds();
 953             default:
 954                 throw wrapper.badValueTag( CompletionStatus.COMPLETED_MAYBE,
 955                     Integer.toHexString(valueTag) ) ;
 956         }
 957     }
 958 
 959     public Serializable read_value(Class expectedType) {
 960 
 961         // Read value tag
 962         int vType = readValueTag();
 963 
 964         // Is value null?
 965         if (vType == 0)
 966             return null;
 967 
 968         // Is this an indirection to a previously
 969         // read valuetype?
 970         if (vType == 0xffffffff)
 971             return handleIndirection();
 972 
 973         // Save where this valuetype started so we
 974         // can put it in the indirection valueCache
 975         // later
 976         int indirection = get_offset() - 4;
 977 
 978         // Need to save this special marker variable
 979         // to restore its value during recursion
 980         boolean saveIsChunked = isChunked;
 981 
 982         isChunked = repIdUtil.isChunkedEncoding(vType);
 983 
 984         java.lang.Object value = null;
 985 
 986         String codebase_URL = null;
 987         if (repIdUtil.isCodeBasePresent(vType)) {
 988             codebase_URL = read_codebase_URL();
 989         }
 990 
 991         // Read repository id(s)
 992         String repositoryIDString
 993             = readRepositoryIds(vType, expectedType, null);
 994 
 995         // If isChunked was determined to be true based
 996         // on the valuetag, this will read a chunk length
 997         start_block();
 998 
 999         // Remember that end_flag keeps track of all nested
1000         // valuetypes and is used for older ORBs
1001         end_flag--;
1002         if (isChunked)
1003             chunkedValueNestingLevel--;
1004 
1005         if (repositoryIDString.equals(repIdStrs.getWStringValueRepId())) {
1006             value = read_wstring();
1007         } else
1008         if (repositoryIDString.equals(repIdStrs.getClassDescValueRepId())) {
1009             // read in the class whether with the old ClassDesc or the
1010             // new one
1011             value = readClass();
1012         } else {
1013 
1014             Class valueClass = expectedType;
1015 
1016             // By this point, either the expectedType or repositoryIDString
1017             // is guaranteed to be non-null.
1018             if (expectedType == null ||
1019                 !repositoryIDString.equals(repIdStrs.createForAnyType(expectedType))) {
1020 
1021                 valueClass = getClassFromString(repositoryIDString,
1022                                                 codebase_URL,
1023                                                 expectedType);
1024             }
1025 
1026             if (valueClass == null) {
1027                 // No point attempting to use value handler below, since the
1028                 // class information is not available.
1029                 throw wrapper.couldNotFindClass(
1030                     CompletionStatus.COMPLETED_MAYBE,
1031                     new ClassNotFoundException());
1032             }
1033 
1034             if (valueClass != null &&
1035                 org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(valueClass)) {
1036 
1037                 value =  readIDLValue(indirection,
1038                                       repositoryIDString,
1039                                       valueClass,
1040                                       codebase_URL);
1041 
1042             } else {
1043 
1044                 // Must be some form of RMI-IIOP valuetype
1045 
1046                 try {
1047                     if (valueHandler == null)
1048                         valueHandler = ORBUtility.createValueHandler(orb);
1049 
1050                     value = valueHandler.readValue(parent,
1051                                                    indirection,
1052                                                    valueClass,
1053                                                    repositoryIDString,
1054                                                    getCodeBase());
1055 
1056                 } catch(SystemException sysEx) {
1057                     // Just rethrow any CORBA system exceptions
1058                     // that come out of the ValueHandler
1059                     throw sysEx;
1060                 } catch(Exception ex) {
1061                     throw wrapper.valuehandlerReadException(
1062                         CompletionStatus.COMPLETED_MAYBE, ex ) ;
1063                 } catch(Error e) {
1064                     throw wrapper.valuehandlerReadError(
1065                         CompletionStatus.COMPLETED_MAYBE, e ) ;
1066                 }
1067             }
1068         }
1069 
1070         // Skip any remaining chunks until we get to
1071         // an end tag or a valuetag.  If we see a valuetag,
1072         // that means there was another valuetype in the sender's
1073         // version of this class that we need to skip over.
1074         handleEndOfValue();
1075 
1076         // Read and process the end tag if we're chunking.
1077         // Assumes that we're at the position of the end tag
1078         // (handleEndOfValue should assure this)
1079         readEndTag();
1080 
1081         // Cache the valuetype that we read
1082         if (valueCache == null)
1083             valueCache = new CacheTable(orb,false);
1084         valueCache.put(value, indirection);
1085 
1086         // Allow for possible continuation chunk.
1087         // If we're a nested valuetype inside of a chunked
1088         // valuetype, and that enclosing valuetype has
1089         // more data to write, it will need to have this
1090         // new chunk begin after we wrote our end tag.
1091         isChunked = saveIsChunked;
1092         start_block();
1093 
1094         return (java.io.Serializable)value;
1095     }
1096 
1097     public Serializable read_value(BoxedValueHelper factory) {
1098 
1099         // Read value tag
1100         int vType = readValueTag();
1101 
1102         if (vType == 0)
1103             return null; // value is null
1104         else if (vType == 0xffffffff) { // Indirection tag
1105             int indirection = read_long() + get_offset() - 4;
1106             if (valueCache != null && valueCache.containsVal(indirection))
1107                 {
1108                     java.io.Serializable cachedValue =
1109                            (java.io.Serializable)valueCache.getKey(indirection);
1110                     return cachedValue;
1111                 }
1112             else {
1113                 throw new IndirectionException(indirection);
1114             }
1115         }
1116         else {
1117             int indirection = get_offset() - 4;
1118 
1119             // end_block();
1120 
1121             boolean saveIsChunked = isChunked;
1122             isChunked = repIdUtil.isChunkedEncoding(vType);
1123 
1124             java.lang.Object value = null;
1125 
1126             String codebase_URL = null;
1127             if (repIdUtil.isCodeBasePresent(vType)){
1128                 codebase_URL = read_codebase_URL();
1129             }
1130 
1131             // Read repository id
1132             String repositoryIDString
1133                 = readRepositoryIds(vType, null, null, factory);
1134 
1135             // Compare rep. ids to see if we should use passed helper
1136             if (!repositoryIDString.equals(factory.get_id()))
1137                 factory = Utility.getHelper(null, codebase_URL, repositoryIDString);
1138 
1139             start_block();
1140             end_flag--;
1141             if (isChunked)
1142                 chunkedValueNestingLevel--;
1143 
1144             if (factory instanceof ValueHelper) {
1145                 value = readIDLValueWithHelper((ValueHelper)factory, indirection);
1146             } else {
1147                 valueIndirection = indirection;  // for callback
1148                 value = factory.read_value(parent);
1149             }
1150 
1151             handleEndOfValue();
1152             readEndTag();
1153 
1154             // Put into valueCache
1155             if (valueCache == null)
1156                 valueCache = new CacheTable(orb,false);
1157             valueCache.put(value, indirection);
1158 
1159             // allow for possible continuation chunk
1160             isChunked = saveIsChunked;
1161             start_block();
1162 
1163             return (java.io.Serializable)value;
1164         }
1165     }
1166 
1167     private boolean isCustomType(ValueHelper helper) {
1168         try{
1169             TypeCode tc = helper.get_type();
1170             int kind = tc.kind().value();
1171             if (kind == TCKind._tk_value) {
1172                 return (tc.type_modifier() == org.omg.CORBA.VM_CUSTOM.value);
1173             }
1174         } catch(BadKind ex) {
1175             throw wrapper.badKind(ex) ;
1176         }
1177 
1178         return false;
1179     }
1180 
1181     // This method is actually called indirectly by
1182     // read_value(String repositoryId).
1183     // Therefore, it is not a truly independent read call that handles
1184     // header information itself.
1185     public java.io.Serializable read_value(java.io.Serializable value) {
1186 
1187         // Put into valueCache using valueIndirection
1188         if (valueCache == null)
1189             valueCache = new CacheTable(orb,false);
1190         valueCache.put(value, valueIndirection);
1191 
1192         if (value instanceof StreamableValue)
1193             ((StreamableValue)value)._read(parent);
1194         else if (value instanceof CustomValue)
1195             ((CustomValue)value).unmarshal(parent);
1196 
1197         return value;
1198     }
1199 
1200     public java.io.Serializable read_value(java.lang.String repositoryId) {
1201 
1202         // if (inBlock)
1203         //    end_block();
1204 
1205         // Read value tag
1206         int vType = readValueTag();
1207 
1208         if (vType == 0)
1209             return null; // value is null
1210         else if (vType == 0xffffffff) { // Indirection tag
1211             int indirection = read_long() + get_offset() - 4;
1212             if (valueCache != null && valueCache.containsVal(indirection))
1213                 {
1214                     java.io.Serializable cachedValue =
1215                           (java.io.Serializable)valueCache.getKey(indirection);
1216                     return cachedValue;
1217                 }
1218             else {
1219                 throw new IndirectionException(indirection);
1220             }
1221         }
1222         else {
1223             int indirection = get_offset() - 4;
1224 
1225             // end_block();
1226 
1227             boolean saveIsChunked = isChunked;
1228             isChunked = repIdUtil.isChunkedEncoding(vType);
1229 
1230             java.lang.Object value = null;
1231 
1232             String codebase_URL = null;
1233             if (repIdUtil.isCodeBasePresent(vType)){
1234                 codebase_URL = read_codebase_URL();
1235             }
1236 
1237             // Read repository id
1238             String repositoryIDString
1239                 = readRepositoryIds(vType, null, repositoryId);
1240 
1241             ValueFactory factory =
1242                Utility.getFactory(null, codebase_URL, orb, repositoryIDString);
1243 
1244             start_block();
1245             end_flag--;
1246             if (isChunked)
1247                 chunkedValueNestingLevel--;
1248 
1249             valueIndirection = indirection;  // for callback
1250             value = factory.read_value(parent);
1251 
1252             handleEndOfValue();
1253             readEndTag();
1254 
1255             // Put into valueCache
1256             if (valueCache == null)
1257                 valueCache = new CacheTable(orb,false);
1258             valueCache.put(value, indirection);
1259 
1260             // allow for possible continuation chunk
1261             isChunked = saveIsChunked;
1262             start_block();
1263 
1264             return (java.io.Serializable)value;
1265         }
1266     }
1267 
1268     private Class readClass() {
1269 
1270         String codebases = null, classRepId = null;
1271 
1272         if (orb == null ||
1273             ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
1274             ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
1275 
1276             codebases = (String)read_value(java.lang.String.class);
1277             classRepId = (String)read_value(java.lang.String.class);
1278         } else {
1279             // Pre-Merlin/J2EE 1.3 ORBs wrote the repository ID
1280             // and codebase strings in the wrong order.
1281             classRepId = (String)read_value(java.lang.String.class);
1282             codebases = (String)read_value(java.lang.String.class);
1283         }
1284 
1285         if (debug) {
1286             dprint("readClass codebases: "
1287                    + codebases
1288                    + " rep Id: "
1289                    + classRepId);
1290         }
1291 
1292         Class cl = null;
1293 
1294         RepositoryIdInterface repositoryID
1295             = repIdStrs.getFromString(classRepId);
1296 
1297         try {
1298             cl = repositoryID.getClassFromType(codebases);
1299         } catch(ClassNotFoundException cnfe) {
1300             throw wrapper.cnfeReadClass( CompletionStatus.COMPLETED_MAYBE,
1301                 cnfe, repositoryID.getClassName() ) ;
1302         } catch(MalformedURLException me) {
1303             throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
1304                 me, repositoryID.getClassName(), codebases ) ;
1305         }
1306 
1307         return cl;
1308     }
1309 
1310     private java.lang.Object readIDLValueWithHelper(ValueHelper helper, int indirection)
1311     {
1312         // look for two-argument static read method
1313         Method readMethod;
1314         try {
1315             Class argTypes[] = {org.omg.CORBA.portable.InputStream.class, helper.get_class()};
1316             readMethod = helper.getClass().getDeclaredMethod(kReadMethod, argTypes);
1317         }
1318         catch(NoSuchMethodException nsme) { // must be boxed value helper
1319             java.lang.Object result = helper.read_value(parent);
1320             return result;
1321         }
1322 
1323         // found two-argument read method, so must be non-boxed value...
1324         // ...create a blank instance
1325         java.lang.Object val = null;
1326         try {
1327             val = helper.get_class().newInstance();
1328         } catch(java.lang.InstantiationException ie) {
1329             throw wrapper.couldNotInstantiateHelper( ie,
1330                 helper.get_class() ) ;
1331         } catch(IllegalAccessException iae){
1332             // Value's constructor is protected or private
1333             //
1334             // So, use the helper to read the value.
1335             //
1336             // NOTE : This means that in this particular case a recursive ref.
1337             // would fail.
1338             return helper.read_value(parent);
1339         }
1340 
1341         // add blank instance to cache table
1342         if (valueCache == null)
1343             valueCache = new CacheTable(orb,false);
1344         valueCache.put(val, indirection);
1345 
1346         // if custom type, call unmarshal method
1347         if (val instanceof CustomMarshal && isCustomType(helper)) {
1348             ((CustomMarshal)val).unmarshal(parent);
1349             return val;
1350         }
1351 
1352         // call two-argument read method using reflection
1353         try {
1354             java.lang.Object args[] = {parent, val};
1355             readMethod.invoke(helper, args);
1356             return val;
1357         } catch(IllegalAccessException iae2) {
1358             throw wrapper.couldNotInvokeHelperReadMethod( iae2, helper.get_class() ) ;
1359         } catch(InvocationTargetException ite){
1360             throw wrapper.couldNotInvokeHelperReadMethod( ite, helper.get_class() ) ;
1361         }
1362     }
1363 
1364     private java.lang.Object readBoxedIDLEntity(Class clazz, String codebase)
1365     {
1366         Class cls = null ;
1367 
1368         try {
1369             ClassLoader clazzLoader = (clazz == null ? null : clazz.getClassLoader());
1370 
1371             cls = Utility.loadClassForClass(clazz.getName()+"Helper", codebase,
1372                                                    clazzLoader, clazz, clazzLoader);
1373             final Class helperClass = cls ;
1374 
1375             final Class argTypes[] = {org.omg.CORBA.portable.InputStream.class};
1376 
1377             // getDeclaredMethod requires RuntimePermission accessDeclaredMembers
1378             // if a different class loader is used (even though the javadoc says otherwise)
1379             Method readMethod = null;
1380             try {
1381                 readMethod = (Method)AccessController.doPrivileged(
1382                     new PrivilegedExceptionAction() {
1383                         public java.lang.Object run() throws NoSuchMethodException {
1384                             return helperClass.getDeclaredMethod(kReadMethod, argTypes);
1385                         }
1386                     }
1387                 );
1388             } catch (PrivilegedActionException pae) {
1389                 // this gets caught below
1390                 throw (NoSuchMethodException)pae.getException();
1391             }
1392 
1393             java.lang.Object args[] = {parent};
1394             return readMethod.invoke(null, args);
1395 
1396         } catch (ClassNotFoundException cnfe) {
1397             throw wrapper.couldNotInvokeHelperReadMethod( cnfe, cls ) ;
1398         } catch(NoSuchMethodException nsme) {
1399             throw wrapper.couldNotInvokeHelperReadMethod( nsme, cls ) ;
1400         } catch(IllegalAccessException iae) {
1401             throw wrapper.couldNotInvokeHelperReadMethod( iae, cls ) ;
1402         } catch(InvocationTargetException ite) {
1403             throw wrapper.couldNotInvokeHelperReadMethod( ite, cls ) ;
1404         }
1405     }
1406 
1407     private java.lang.Object readIDLValue(int indirection, String repId,
1408                                           Class clazz, String codebase)
1409     {
1410         ValueFactory factory ;
1411 
1412         // Always try to find a ValueFactory first, as required by the spec.
1413         // There are some complications here in the IDL 3.0 mapping (see 1.13.8),
1414         // but basically we must always be able to override the DefaultFactory
1415         // or Helper mappings that are also used.  This appears to be the case
1416         // even in the boxed value cases.  The original code only did the lookup
1417         // in the case of class implementing either StreamableValue or CustomValue,
1418         // but abstract valuetypes only implement ValueBase, and really require
1419         // the use of the repId to find a factory (including the DefaultFactory).
1420         try {
1421             // use new-style OBV support (factory object)
1422             factory = Utility.getFactory(clazz, codebase, orb, repId);
1423         } catch (MARSHAL marshal) {
1424             // XXX log marshal at one of the INFO levels
1425 
1426             // Could not get a factory, so try alternatives
1427             if (!StreamableValue.class.isAssignableFrom(clazz) &&
1428                 !CustomValue.class.isAssignableFrom(clazz) &&
1429                 ValueBase.class.isAssignableFrom(clazz)) {
1430                 // use old-style OBV support (helper object)
1431                 BoxedValueHelper helper = Utility.getHelper(clazz, codebase, repId);
1432                 if (helper instanceof ValueHelper)
1433                     return readIDLValueWithHelper((ValueHelper)helper, indirection);
1434                 else
1435                     return helper.read_value(parent);
1436             } else {
1437                 // must be a boxed IDLEntity, so make a reflective call to the
1438                 // helper's static read method...
1439                 return readBoxedIDLEntity(clazz, codebase);
1440             }
1441         }
1442 
1443         // If there was no error in getting the factory, use it.
1444         valueIndirection = indirection;  // for callback
1445         return factory.read_value(parent);
1446     }
1447 
1448     /**
1449      * End tags are only written for chunked valuetypes.
1450      *
1451      * Before Merlin, our ORBs wrote end tags which took into account
1452      * all enclosing valuetypes.  This was changed by an interop resolution
1453      * (see details around chunkedValueNestingLevel) to only include
1454      * enclosing chunked types.
1455      *
1456      * ORB versioning and end tag compaction are handled here.
1457      */
1458     private void readEndTag() {
1459         if (isChunked) {
1460 
1461             // Read the end tag
1462             int anEndTag = read_long();
1463 
1464             // End tags should always be negative, and the outermost
1465             // enclosing chunked valuetype should have a -1 end tag.
1466             //
1467             // handleEndOfValue should have assured that we were
1468             // at the end tag position!
1469             if (anEndTag >= 0) {
1470                 throw wrapper.positiveEndTag( CompletionStatus.COMPLETED_MAYBE,
1471                     new Integer(anEndTag), new Integer( get_offset() - 4 ) ) ;
1472             }
1473 
1474             // If the ORB is null, or if we're sure we're talking to
1475             // a foreign ORB, Merlin, or something more recent, we
1476             // use the updated end tag computation, and are more strenuous
1477             // about the values.
1478             if (orb == null ||
1479                 ORBVersionFactory.getFOREIGN().equals(orb.getORBVersion()) ||
1480                 ORBVersionFactory.getNEWER().compareTo(orb.getORBVersion()) <= 0) {
1481 
1482                 // If the end tag we read was less than what we were expecting,
1483                 // then the sender must think it's sent more enclosing
1484                 // chunked valuetypes than we have.  Throw an exception.
1485                 if (anEndTag < chunkedValueNestingLevel)
1486                     throw wrapper.unexpectedEnclosingValuetype(
1487                         CompletionStatus.COMPLETED_MAYBE, new Integer( anEndTag ),
1488                         new Integer( chunkedValueNestingLevel ) ) ;
1489 
1490                 // If the end tag is bigger than what we expected, but
1491                 // still negative, then the sender has done some end tag
1492                 // compaction.  We back up the stream 4 bytes so that the
1493                 // next time readEndTag is called, it will get down here
1494                 // again.  Even with fragmentation, we'll always be able
1495                 // to do this.
1496                 if (anEndTag != chunkedValueNestingLevel) {
1497                     bbwi.position(bbwi.position() - 4);
1498                  }
1499 
1500             } else {
1501 
1502                 // When talking to Kestrel or Ladybird, we use our old
1503                 // end tag rules and are less strict.  If the end tag
1504                 // isn't what we expected, we back up, assuming
1505                 // compaction.
1506                 if (anEndTag != end_flag) {
1507                     bbwi.position(bbwi.position() - 4);
1508                 }
1509             }
1510 
1511             // This only keeps track of the enclosing chunked
1512             // valuetypes
1513             chunkedValueNestingLevel++;
1514         }
1515 
1516         // This keeps track of all enclosing valuetypes
1517         end_flag++;
1518     }
1519 
1520     protected int get_offset() {
1521         return bbwi.position();
1522     }
1523 
1524     private void start_block() {
1525 
1526         // if (outerValueDone)
1527         if (!isChunked)
1528             return;
1529 
1530         // if called from alignAndCheck, need to reset blockLength
1531         // to avoid an infinite recursion loop on read_long() call
1532         blockLength = maxBlockLength;
1533 
1534         blockLength = read_long();
1535 
1536         // Must remember where we began the chunk to calculate how far
1537         // along we are.  See notes above about chunkBeginPos.
1538 
1539         if (blockLength > 0 && blockLength < maxBlockLength) {
1540             blockLength += get_offset();  // _REVISIT_ unsafe, should use a Java long
1541 
1542             // inBlock = true;
1543         } else {
1544 
1545             // System.out.println("start_block snooped a " + Integer.toHexString(blockLength));
1546 
1547             // not a chunk length field
1548             blockLength = maxBlockLength;
1549 
1550             bbwi.position(bbwi.position() - 4);
1551         }
1552     }
1553 
1554     // Makes sure that if we were reading a chunked value, we end up
1555     // at the right place in the stream, no matter how little the
1556     // unmarshalling code read.
1557     //
1558     // After calling this method, if we are chunking, we should be
1559     // in position to read the end tag.
1560     private void handleEndOfValue() {
1561 
1562         // If we're not chunking, we don't have to worry about
1563         // skipping remaining chunks or finding end tags
1564         if (!isChunked)
1565             return;
1566 
1567         // Skip any remaining chunks
1568         while (blockLength != maxBlockLength) {
1569             end_block();
1570             start_block();
1571         }
1572 
1573         // Now look for the end tag
1574 
1575         // This is a little wasteful since we're reading
1576         // this long up to 3 times in the worst cases (once
1577         // in start_block, once here, and once in readEndTag
1578         //
1579         // Peek next long
1580         int nextLong = read_long();
1581         bbwi.position(bbwi.position() - 4);
1582 
1583         // We did find an end tag, so we're done.  readEndTag
1584         // should take care of making sure it's the correct
1585         // end tag, etc.  Remember that since end tags,
1586         // chunk lengths, and valuetags have non overlapping
1587         // ranges, we can tell by the value what the longs are.
1588         if (nextLong < 0)
1589             return;
1590 
1591         if (nextLong == 0 || nextLong >= maxBlockLength) {
1592 
1593             // A custom marshaled valuetype left extra data
1594             // on the wire, and that data had another
1595             // nested value inside of it.  We've just
1596             // read the value tag or null of that nested value.
1597             //
1598             // In an attempt to get by it, we'll try to call
1599             // read_value() to get the nested value off of
1600             // the wire.  Afterwards, we must call handleEndOfValue
1601             // recursively to read any further chunks that the containing
1602             // valuetype might still have after the nested
1603             // value.
1604             read_value();
1605             handleEndOfValue();
1606         } else {
1607             // This probably means that the code to skip chunks has
1608             // an error, and ended up setting blockLength to something
1609             // other than maxBlockLength even though we weren't
1610             // starting a new chunk.
1611             throw wrapper.couldNotSkipBytes( CompletionStatus.COMPLETED_MAYBE,
1612                 new Integer( nextLong ), new Integer( get_offset() ) ) ;
1613         }
1614     }
1615 
1616     private void end_block() {
1617 
1618         // if in a chunk, check for underflow or overflow
1619         if (blockLength != maxBlockLength) {
1620             if (blockLength == get_offset()) {
1621                 // Chunk ended correctly
1622                 blockLength = maxBlockLength;
1623             } else {
1624                 // Skip over anything left by bad unmarshaling code (ex:
1625                 // a buggy custom unmarshaler).  See handleEndOfValue.
1626                 if (blockLength > get_offset()) {
1627                     skipToOffset(blockLength);
1628                 } else {
1629                     throw wrapper.badChunkLength( new Integer( blockLength ),
1630                         new Integer( get_offset() ) ) ;
1631                 }
1632             }
1633         }
1634     }
1635 
1636     private int readValueTag(){
1637         // outerValueDone = false;
1638         return read_long();
1639     }
1640 
1641     public org.omg.CORBA.ORB orb() {
1642         return orb;
1643     }
1644 
1645     // ------------ End RMI related methods --------------------------
1646 
1647     public final void read_boolean_array(boolean[] value, int offset, int length) {
1648         for(int i=0; i < length; i++) {
1649             value[i+offset] = read_boolean();
1650         }
1651     }
1652 
1653     public final void read_char_array(char[] value, int offset, int length) {
1654         for(int i=0; i < length; i++) {
1655             value[i+offset] = read_char();
1656         }
1657     }
1658 
1659     public final void read_wchar_array(char[] value, int offset, int length) {
1660         for(int i=0; i < length; i++) {
1661             value[i+offset] = read_wchar();
1662         }
1663     }
1664 
1665     public final void read_short_array(short[] value, int offset, int length) {
1666         for(int i=0; i < length; i++) {
1667             value[i+offset] = read_short();
1668         }
1669     }
1670 
1671     public final void read_ushort_array(short[] value, int offset, int length) {
1672         read_short_array(value, offset, length);
1673     }
1674 
1675     public final void read_long_array(int[] value, int offset, int length) {
1676         for(int i=0; i < length; i++) {
1677             value[i+offset] = read_long();
1678         }
1679     }
1680 
1681     public final void read_ulong_array(int[] value, int offset, int length) {
1682         read_long_array(value, offset, length);
1683     }
1684 
1685     public final void read_longlong_array(long[] value, int offset, int length) {
1686         for(int i=0; i < length; i++) {
1687             value[i+offset] = read_longlong();
1688         }
1689     }
1690 
1691     public final void read_ulonglong_array(long[] value, int offset, int length) {
1692         read_longlong_array(value, offset, length);
1693     }
1694 
1695     public final void read_float_array(float[] value, int offset, int length) {
1696         for(int i=0; i < length; i++) {
1697             value[i+offset] = read_float();
1698         }
1699     }
1700 
1701     public final void read_double_array(double[] value, int offset, int length) {
1702         for(int i=0; i < length; i++) {
1703             value[i+offset] = read_double();
1704         }
1705     }
1706 
1707     public final void read_any_array(org.omg.CORBA.Any[] value, int offset, int length) {
1708         for(int i=0; i < length; i++) {
1709             value[i+offset] = read_any();
1710         }
1711     }
1712 
1713     //--------------------------------------------------------------------//
1714     // CDRInputStream state management.
1715     //
1716 
1717     /**
1718      * Are we at the end of the input stream?
1719      */
1720 //     public final boolean isAtEnd() {
1721 //      return bbwi.position() == bbwi.buflen;
1722 //     }
1723 
1724 //     public int available() throws IOException {
1725 //         return bbwi.buflen - bbwi.position();
1726 //     }
1727 
1728     private String read_repositoryIds() {
1729 
1730         // Read # of repository ids
1731         int numRepIds = read_long();
1732         if (numRepIds == 0xffffffff) {
1733             int indirection = read_long() + get_offset() - 4;
1734             if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
1735                 return (String)repositoryIdCache.getKey(indirection);
1736             else
1737                 throw wrapper.unableToLocateRepIdArray( new Integer( indirection ) ) ;
1738         } else {
1739 
1740             // read first array element and store it as an indirection to the whole array
1741             int indirection = get_offset();
1742             String repID = read_repositoryId();
1743             if (repositoryIdCache == null)
1744                 repositoryIdCache = new CacheTable(orb,false);
1745             repositoryIdCache.put(repID, indirection);
1746 
1747             // read and ignore the subsequent array elements, but put them in the
1748             // indirection table in case there are later indirections back to them
1749             for (int i = 1; i < numRepIds; i++) {
1750                 read_repositoryId();
1751             }
1752 
1753             return repID;
1754         }
1755     }
1756 
1757     private final String read_repositoryId()
1758     {
1759         String result = readStringOrIndirection(true);
1760 
1761         if (result == null) { // Indirection
1762             int indirection = read_long() + get_offset() - 4;
1763 
1764             if (repositoryIdCache != null && repositoryIdCache.containsOrderedVal(indirection))
1765                 return (String)repositoryIdCache.getKey(indirection);
1766             else
1767                 throw wrapper.badRepIdIndirection( CompletionStatus.COMPLETED_MAYBE,
1768                     new Integer(bbwi.position()) ) ;
1769         } else {
1770             if (repositoryIdCache == null)
1771                 repositoryIdCache = new CacheTable(orb,false);
1772             repositoryIdCache.put(result, stringIndirection);
1773         }
1774 
1775         return result ;
1776     }
1777 
1778     private final String read_codebase_URL()
1779     {
1780         String result = readStringOrIndirection(true);
1781 
1782         if (result == null) { // Indirection
1783             int indirection = read_long() + get_offset() - 4;
1784 
1785             if (codebaseCache != null && codebaseCache.containsVal(indirection))
1786                 return (String)codebaseCache.getKey(indirection);
1787             else
1788                 throw wrapper.badCodebaseIndirection(
1789                     CompletionStatus.COMPLETED_MAYBE,
1790                     new Integer(bbwi.position()) ) ;
1791         } else {
1792             if (codebaseCache == null)
1793                 codebaseCache = new CacheTable(orb,false);
1794             codebaseCache.put(result, stringIndirection);
1795         }
1796 
1797         return result;
1798     }
1799 
1800     /* DataInputStream methods */
1801 
1802     public java.lang.Object read_Abstract () {
1803         return read_abstract_interface();
1804     }
1805 
1806     public java.io.Serializable read_Value () {
1807         return read_value();
1808     }
1809 
1810     public void read_any_array (org.omg.CORBA.AnySeqHolder seq, int offset, int length) {
1811         read_any_array(seq.value, offset, length);
1812     }
1813 
1814     public void read_boolean_array (org.omg.CORBA.BooleanSeqHolder seq, int offset, int length) {
1815         read_boolean_array(seq.value, offset, length);
1816     }
1817 
1818     public void read_char_array (org.omg.CORBA.CharSeqHolder seq, int offset, int length) {
1819         read_char_array(seq.value, offset, length);
1820     }
1821 
1822     public void read_wchar_array (org.omg.CORBA.WCharSeqHolder seq, int offset, int length) {
1823         read_wchar_array(seq.value, offset, length);
1824     }
1825 
1826     public void read_octet_array (org.omg.CORBA.OctetSeqHolder seq, int offset, int length) {
1827         read_octet_array(seq.value, offset, length);
1828     }
1829 
1830     public void read_short_array (org.omg.CORBA.ShortSeqHolder seq, int offset, int length) {
1831         read_short_array(seq.value, offset, length);
1832     }
1833 
1834     public void read_ushort_array (org.omg.CORBA.UShortSeqHolder seq, int offset, int length) {
1835         read_ushort_array(seq.value, offset, length);
1836     }
1837 
1838     public void read_long_array (org.omg.CORBA.LongSeqHolder seq, int offset, int length) {
1839         read_long_array(seq.value, offset, length);
1840     }
1841 
1842     public void read_ulong_array (org.omg.CORBA.ULongSeqHolder seq, int offset, int length) {
1843         read_ulong_array(seq.value, offset, length);
1844     }
1845 
1846     public void read_ulonglong_array (org.omg.CORBA.ULongLongSeqHolder seq, int offset, int length) {
1847         read_ulonglong_array(seq.value, offset, length);
1848     }
1849 
1850     public void read_longlong_array (org.omg.CORBA.LongLongSeqHolder seq, int offset, int length) {
1851         read_longlong_array(seq.value, offset, length);
1852     }
1853 
1854     public void read_float_array (org.omg.CORBA.FloatSeqHolder seq, int offset, int length) {
1855         read_float_array(seq.value, offset, length);
1856     }
1857 
1858     public void read_double_array (org.omg.CORBA.DoubleSeqHolder seq, int offset, int length) {
1859         read_double_array(seq.value, offset, length);
1860     }
1861 
1862     public java.math.BigDecimal read_fixed(short digits, short scale) {
1863         // digits isn't really needed here
1864         StringBuffer buffer = read_fixed_buffer();
1865         if (digits != buffer.length())
1866             throw wrapper.badFixed( new Integer(digits),
1867                 new Integer(buffer.length()) ) ;
1868         buffer.insert(digits - scale, '.');
1869         return new BigDecimal(buffer.toString());
1870     }
1871 
1872     // This method is unable to yield the correct scale.
1873     public java.math.BigDecimal read_fixed() {
1874         return new BigDecimal(read_fixed_buffer().toString());
1875     }
1876 
1877     // Each octet contains (up to) two decimal digits.
1878     // If the fixed type has an odd number of decimal digits, then the representation
1879     // begins with the first (most significant) digit.
1880     // Otherwise, this first half-octet is all zero, and the first digit
1881     // is in the second half-octet.
1882     // The sign configuration, in the last half-octet of the representation,
1883     // is 0xD for negative numbers and 0xC for positive and zero values.
1884     private StringBuffer read_fixed_buffer() {
1885         StringBuffer buffer = new StringBuffer(64);
1886         byte doubleDigit;
1887         int firstDigit;
1888         int secondDigit;
1889         boolean wroteFirstDigit = false;
1890         boolean more = true;
1891         while (more) {
1892             doubleDigit = this.read_octet();
1893             firstDigit = (int)((doubleDigit & 0xf0) >> 4);
1894             secondDigit = (int)(doubleDigit & 0x0f);
1895             if (wroteFirstDigit || firstDigit != 0) {
1896                 buffer.append(Character.forDigit(firstDigit, 10));
1897                 wroteFirstDigit = true;
1898             }
1899             if (secondDigit == 12) {
1900                 // positive number or zero
1901                 if ( ! wroteFirstDigit) {
1902                     // zero
1903                     return new StringBuffer("0.0");
1904                 } else {
1905                     // positive number
1906                     // done
1907                 }
1908                 more = false;
1909             } else if (secondDigit == 13) {
1910                 // negative number
1911                 buffer.insert(0, '-');
1912                 more = false;
1913             } else {
1914                 buffer.append(Character.forDigit(secondDigit, 10));
1915                 wroteFirstDigit = true;
1916             }
1917         }
1918         return buffer;
1919     }
1920 
1921     private final static String _id = "IDL:omg.org/CORBA/DataInputStream:1.0";
1922     private final static String[] _ids = { _id };
1923 
1924     public String[] _truncatable_ids() {
1925         if (_ids == null)
1926             return null;
1927 
1928         return (String[])_ids.clone();
1929     }
1930 
1931     /* for debugging */
1932 
1933     public void printBuffer() {
1934         CDRInputStream_1_0.printBuffer(this.bbwi);
1935     }
1936 
1937     public static void printBuffer(ByteBufferWithInfo bbwi) {
1938 
1939         System.out.println("----- Input Buffer -----");
1940         System.out.println();
1941         System.out.println("Current position: " + bbwi.position());
1942         System.out.println("Total length : " + bbwi.buflen);
1943         System.out.println();
1944 
1945         try {
1946 
1947             char[] charBuf = new char[16];
1948 
1949             for (int i = 0; i < bbwi.buflen; i += 16) {
1950 
1951                 int j = 0;
1952 
1953                 // For every 16 bytes, there is one line
1954                 // of output.  First, the hex output of
1955                 // the 16 bytes with each byte separated
1956                 // by a space.
1957                 while (j < 16 && j + i < bbwi.buflen) {
1958                     int k = bbwi.byteBuffer.get(i + j);
1959                     if (k < 0)
1960                         k = 256 + k;
1961                     String hex = Integer.toHexString(k);
1962                     if (hex.length() == 1)
1963                         hex = "0" + hex;
1964                     System.out.print(hex + " ");
1965                     j++;
1966                 }
1967 
1968                 // Add any extra spaces to align the
1969                 // text column in case we didn't end
1970                 // at 16
1971                 while (j < 16) {
1972                     System.out.print("   ");
1973                     j++;
1974                 }
1975 
1976                 // Now output the ASCII equivalents.  Non-ASCII
1977                 // characters are shown as periods.
1978                 int x = 0;
1979                 while (x < 16 && x + i < bbwi.buflen) {
1980                     if (ORBUtility.isPrintable((char)bbwi.byteBuffer.get(i + x)))
1981                         charBuf[x] = (char)bbwi.byteBuffer.get(i + x);
1982                     else
1983                         charBuf[x] = '.';
1984                     x++;
1985                 }
1986                 System.out.println(new String(charBuf, 0, x));
1987             }
1988 
1989         } catch (Throwable t) {
1990             t.printStackTrace();
1991         }
1992 
1993         System.out.println("------------------------");
1994     }
1995 
1996     public ByteBuffer getByteBuffer() {
1997         ByteBuffer result = null;
1998         if (bbwi != null) {
1999             result = bbwi.byteBuffer;
2000         }
2001         return result;
2002     }
2003 
2004     public int getBufferLength() {
2005         return bbwi.buflen;
2006     }
2007 
2008     public void setBufferLength(int value) {
2009         bbwi.buflen = value;
2010         bbwi.byteBuffer.limit(bbwi.buflen);
2011     }
2012 
2013     public void setByteBufferWithInfo(ByteBufferWithInfo bbwi) {
2014         this.bbwi = bbwi;
2015     }
2016 
2017     public void setByteBuffer(ByteBuffer byteBuffer) {
2018         bbwi.byteBuffer = byteBuffer;
2019     }
2020 
2021     public int getIndex() {
2022         return bbwi.position();
2023     }
2024 
2025     public void setIndex(int value) {
2026         bbwi.position(value);
2027     }
2028 
2029     public boolean isLittleEndian() {
2030         return littleEndian;
2031     }
2032 
2033     public void orb(org.omg.CORBA.ORB orb) {
2034         this.orb = (ORB)orb;
2035     }
2036 
2037     public BufferManagerRead getBufferManager() {
2038         return bufferManagerRead;
2039     }
2040 
2041     private void skipToOffset(int offset) {
2042 
2043         // Number of bytes to skip
2044         int len = offset - get_offset();
2045 
2046         int n = 0;
2047 
2048         while (n < len) {
2049             int avail;
2050             int bytes;
2051             int wanted;
2052 
2053             avail = bbwi.buflen - bbwi.position();
2054             if (avail <= 0) {
2055                 grow(1, 1);
2056                 avail = bbwi.buflen - bbwi.position();
2057             }
2058 
2059             wanted = len - n;
2060             bytes = (wanted < avail) ? wanted : avail;
2061             bbwi.position(bbwi.position() + bytes);
2062             n += bytes;
2063         }
2064     }
2065 
2066 
2067     // Mark and reset -------------------------------------------------
2068 
2069     protected MarkAndResetHandler markAndResetHandler = null;
2070 
2071     protected class StreamMemento
2072     {
2073         // These are the fields that may change after marking
2074         // the stream position, so we need to save them.
2075         private int blockLength_;
2076         private int end_flag_;
2077         private int chunkedValueNestingLevel_;
2078         private int valueIndirection_;
2079         private int stringIndirection_;
2080         private boolean isChunked_;
2081         private javax.rmi.CORBA.ValueHandler valueHandler_;
2082         private ByteBufferWithInfo bbwi_;
2083         private boolean specialNoOptionalDataState_;
2084 
2085         public StreamMemento()
2086         {
2087             blockLength_ = blockLength;
2088             end_flag_ = end_flag;
2089             chunkedValueNestingLevel_ = chunkedValueNestingLevel;
2090             valueIndirection_ = valueIndirection;
2091             stringIndirection_ = stringIndirection;
2092             isChunked_ = isChunked;
2093             valueHandler_ = valueHandler;
2094             specialNoOptionalDataState_ = specialNoOptionalDataState;
2095             bbwi_ = new ByteBufferWithInfo(bbwi);
2096         }
2097     }
2098 
2099     public java.lang.Object createStreamMemento() {
2100         return new StreamMemento();
2101     }
2102 
2103     public void restoreInternalState(java.lang.Object streamMemento) {
2104 
2105         StreamMemento mem = (StreamMemento)streamMemento;
2106 
2107         blockLength = mem.blockLength_;
2108         end_flag = mem.end_flag_;
2109         chunkedValueNestingLevel = mem.chunkedValueNestingLevel_;
2110         valueIndirection = mem.valueIndirection_;
2111         stringIndirection = mem.stringIndirection_;
2112         isChunked = mem.isChunked_;
2113         valueHandler = mem.valueHandler_;
2114         specialNoOptionalDataState = mem.specialNoOptionalDataState_;
2115         bbwi = mem.bbwi_;
2116     }
2117 
2118     public int getPosition() {
2119         return get_offset();
2120     }
2121 
2122     public void mark(int readlimit) {
2123         markAndResetHandler.mark(this);
2124     }
2125 
2126     public void reset() {
2127         markAndResetHandler.reset();
2128     }
2129 
2130     // ---------------------------------- end Mark and Reset
2131 
2132     // Provides a hook so subclasses of CDRInputStream can provide
2133     // a CodeBase.  This ultimately allows us to grab a Connection
2134     // instance in IIOPInputStream, the only subclass where this
2135     // is actually used.
2136     CodeBase getCodeBase() {
2137         return parent.getCodeBase();
2138     }
2139 
2140     /**
2141      * Attempts to find the class described by the given
2142      * repository ID string and expected type.  The first
2143      * attempt is to find the class locally, falling back
2144      * on the URL that came with the value.  The second
2145      * attempt is to use a URL from the remote CodeBase.
2146      */
2147     private Class getClassFromString(String repositoryIDString,
2148                                      String codebaseURL,
2149                                      Class expectedType)
2150     {
2151         RepositoryIdInterface repositoryID
2152             = repIdStrs.getFromString(repositoryIDString);
2153 
2154         try {
2155             try {
2156                 // First try to load the class locally, then use
2157                 // the provided URL (if it isn't null)
2158                 return repositoryID.getClassFromType(expectedType,
2159                                                      codebaseURL);
2160             } catch (ClassNotFoundException cnfeOuter) {
2161 
2162                 try {
2163 
2164                     if (getCodeBase() == null) {
2165                         return null; // class cannot be loaded remotely.
2166                     }
2167 
2168                     // Get a URL from the remote CodeBase and retry
2169                     codebaseURL = getCodeBase().implementation(repositoryIDString);
2170 
2171                     // Don't bother trying to find it locally again if
2172                     // we got a null URL
2173                     if (codebaseURL == null)
2174                         return null;
2175 
2176                     return repositoryID.getClassFromType(expectedType,
2177                                                          codebaseURL);
2178                 } catch (ClassNotFoundException cnfeInner) {
2179                     dprintThrowable(cnfeInner);
2180                     // Failed to load the class
2181                     return null;
2182                 }
2183             }
2184         } catch (MalformedURLException mue) {
2185             // Always report a bad URL
2186             throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
2187                 mue, repositoryIDString, codebaseURL ) ;
2188         }
2189     }
2190 
2191     /**
2192      * Attempts to find the class described by the given
2193      * repository ID string.  At most, three attempts are made:
2194      * Try to find it locally, through the provided URL, and
2195      * finally, via a URL from the remote CodeBase.
2196      */
2197     private Class getClassFromString(String repositoryIDString,
2198                                      String codebaseURL)
2199     {
2200         RepositoryIdInterface repositoryID
2201             = repIdStrs.getFromString(repositoryIDString);
2202 
2203         for (int i = 0; i < 3; i++) {
2204 
2205             try {
2206 
2207                 switch (i)
2208                 {
2209                     case 0:
2210                         // First try to load the class locally
2211                         return repositoryID.getClassFromType();
2212                     case 1:
2213                         // Try to load the class using the provided
2214                         // codebase URL (falls out below)
2215                         break;
2216                     case 2:
2217                         // Try to load the class using a URL from the
2218                         // remote CodeBase
2219                         codebaseURL = getCodeBase().implementation(repositoryIDString);
2220                         break;
2221                 }
2222 
2223                 // Don't bother if the codebaseURL is null
2224                 if (codebaseURL == null)
2225                     continue;
2226 
2227                 return repositoryID.getClassFromType(codebaseURL);
2228 
2229             } catch(ClassNotFoundException cnfe) {
2230                 // Will ultimately return null if all three
2231                 // attempts fail, but don't do anything here.
2232             } catch (MalformedURLException mue) {
2233                 throw wrapper.malformedUrl( CompletionStatus.COMPLETED_MAYBE,
2234                     mue, repositoryIDString, codebaseURL ) ;
2235             }
2236         }
2237 
2238         // If we get here, we have failed to load the class
2239         dprint("getClassFromString failed with rep id "
2240                + repositoryIDString
2241                + " and codebase "
2242                + codebaseURL);
2243 
2244         return null;
2245     }
2246 
2247     // Utility method used to get chars from bytes
2248     char[] getConvertedChars(int numBytes,
2249                              CodeSetConversion.BTCConverter converter) {
2250 
2251         // REVISIT - Look at CodeSetConversion.BTCConverter to see
2252         //           if it can work with an NIO ByteBuffer. We should
2253         //           avoid getting the bytes into an array if possible.
2254 
2255         // To be honest, I doubt this saves much real time
2256         if (bbwi.buflen - bbwi.position() >= numBytes) {
2257             // If the entire string is in this buffer,
2258             // just convert directly from the bbwi rather than
2259             // allocating and copying.
2260             byte[] tmpBuf;
2261             if (bbwi.byteBuffer.hasArray())
2262             {
2263                 tmpBuf = bbwi.byteBuffer.array();
2264             }
2265             else
2266             {
2267                  tmpBuf = new byte[bbwi.buflen];
2268                  // Microbenchmarks are showing a loop of ByteBuffer.get(int)
2269                  // being faster than ByteBuffer.get(byte[], int, int).
2270                  for (int i = 0; i < bbwi.buflen; i++)
2271                      tmpBuf[i] = bbwi.byteBuffer.get(i);
2272             }
2273             char[] result = converter.getChars(tmpBuf,bbwi.position(),numBytes);
2274 
2275             bbwi.position(bbwi.position() + numBytes);
2276             return result;
2277         } else {
2278             // Stretches across buffers.  Unless we provide an
2279             // incremental conversion interface, allocate and
2280             // copy the bytes.
2281             byte[] bytes = new byte[numBytes];
2282             read_octet_array(bytes, 0, bytes.length);
2283 
2284             return converter.getChars(bytes, 0, numBytes);
2285         }
2286     }
2287 
2288     protected CodeSetConversion.BTCConverter getCharConverter() {
2289         if (charConverter == null)
2290             charConverter = parent.createCharBTCConverter();
2291 
2292         return charConverter;
2293     }
2294 
2295     protected CodeSetConversion.BTCConverter getWCharConverter() {
2296         if (wcharConverter == null)
2297             wcharConverter = parent.createWCharBTCConverter();
2298 
2299         return wcharConverter;
2300     }
2301 
2302     protected void dprintThrowable(Throwable t) {
2303         if (debug && t != null)
2304             t.printStackTrace();
2305     }
2306 
2307     protected void dprint(String msg) {
2308         if (debug) {
2309             ORBUtility.dprint(this, msg);
2310         }
2311     }
2312 
2313     /**
2314      * Aligns the current position on the given octet boundary
2315      * if there are enough bytes available to do so.  Otherwise,
2316      * it just returns.  This is used for some (but not all)
2317      * GIOP 1.2 message headers.
2318      */
2319 
2320     void alignOnBoundary(int octetBoundary) {
2321         int needed = computeAlignment(bbwi.position(), octetBoundary);
2322 
2323         if (bbwi.position() + needed <= bbwi.buflen)
2324         {
2325             bbwi.position(bbwi.position() + needed);
2326         }
2327     }
2328 
2329     public void resetCodeSetConverters() {
2330         charConverter = null;
2331         wcharConverter = null;
2332     }
2333 
2334     public void start_value() {
2335         // Read value tag
2336         int vType = readValueTag();
2337 
2338         if (vType == 0) {
2339             // Stream needs to go into a state where it
2340             // throws standard exception until end_value
2341             // is called.  This means the sender didn't
2342             // send any custom data.  If the reader here
2343             // tries to read more, we need to throw an
2344             // exception before reading beyond where
2345             // we're supposed to
2346             specialNoOptionalDataState = true;
2347 
2348             return;
2349         }
2350 
2351         if (vType == 0xffffffff) {
2352             // One should never indirect to a custom wrapper
2353             throw wrapper.customWrapperIndirection(
2354                 CompletionStatus.COMPLETED_MAYBE);
2355         }
2356 
2357         if (repIdUtil.isCodeBasePresent(vType)) {
2358             throw wrapper.customWrapperWithCodebase(
2359                 CompletionStatus.COMPLETED_MAYBE);
2360         }
2361 
2362         if (repIdUtil.getTypeInfo(vType)
2363             != RepositoryIdUtility.SINGLE_REP_TYPE_INFO) {
2364             throw wrapper.customWrapperNotSingleRepid(
2365                 CompletionStatus.COMPLETED_MAYBE);
2366         }
2367 
2368 
2369         // REVISIT - Could verify repository ID even though
2370         // it isn't used elsewhere
2371         read_repositoryId();
2372 
2373         // Note: isChunked should be true here.  Should have
2374         // been set to true in the containing value's read_value
2375         // method.
2376 
2377         start_block();
2378         end_flag--;
2379         chunkedValueNestingLevel--;
2380     }
2381 
2382     public void end_value() {
2383 
2384         if (specialNoOptionalDataState) {
2385             specialNoOptionalDataState = false;
2386             return;
2387         }
2388 
2389         handleEndOfValue();
2390         readEndTag();
2391 
2392         // Note that isChunked should still be true here.
2393         // If the containing valuetype is the highest
2394         // chunked value, it will get set to false
2395         // at the end of read_value.
2396 
2397         // allow for possible continuation chunk
2398         start_block();
2399     }
2400 
2401     public void close() throws IOException
2402     {
2403 
2404         // tell BufferManagerRead to release any ByteBuffers
2405         getBufferManager().close(bbwi);
2406 
2407         // It's possible bbwi.byteBuffer is shared between
2408         // this InputStream and an OutputStream. Thus, we check
2409         // if the Input/Output streams are using the same ByteBuffer.
2410         // If they sharing the same ByteBuffer we need to ensure only
2411         // one of those ByteBuffers are released to the ByteBufferPool.
2412 
2413         if (bbwi != null && getByteBuffer() != null)
2414         {
2415             MessageMediator messageMediator = parent.getMessageMediator();
2416             if (messageMediator != null)
2417             {
2418                 CDROutputObject outputObj =
2419                              (CDROutputObject)messageMediator.getOutputObject();
2420                 if (outputObj != null)
2421                 {
2422                     if (outputObj.isSharing(getByteBuffer()))
2423                     {
2424                         // Set OutputStream's ByteBuffer and bbwi to null
2425                         // so its ByteBuffer cannot be released to the pool
2426                         outputObj.setByteBuffer(null);
2427                         outputObj.setByteBufferWithInfo(null);
2428                     }
2429                 }
2430             }
2431 
2432             // release this stream's ByteBuffer to the pool
2433             ByteBufferPool byteBufferPool = orb.getByteBufferPool();
2434             if (debug)
2435             {
2436                 // print address of ByteBuffer being released
2437                 int bbAddress = System.identityHashCode(bbwi.byteBuffer);
2438                 StringBuffer sb = new StringBuffer(80);
2439                 sb.append(".close - releasing ByteBuffer id (");
2440                 sb.append(bbAddress).append(") to ByteBufferPool.");
2441                 String msg = sb.toString();
2442                 dprint(msg);
2443             }
2444             byteBufferPool.releaseByteBuffer(bbwi.byteBuffer);
2445             bbwi.byteBuffer = null;
2446             bbwi = null;
2447         }
2448     }
2449 }