Package org.jacorb.orb

Source Code of org.jacorb.orb.CDRInputStream

package org.jacorb.orb;

/*
*        JacORB - a free Java ORB
*
*   Copyright (C) 1997-2004 Gerald Brose.
*
*   This library is free software; you can redistribute it and/or
*   modify it under the terms of the GNU Library General Public
*   License as published by the Free Software Foundation; either
*   version 2 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Library General Public License for more details.
*
*   You should have received a copy of the GNU Library General Public
*   License along with this library; if not, write to the Free
*   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

import java.io.IOException;
import java.util.*;

import org.apache.avalon.framework.configuration.*;
import org.apache.avalon.framework.logger.*;

import org.jacorb.orb.giop.CodeSet;
import org.jacorb.util.ValueHandler;

import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.StructMember;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.UnionMember;
import org.omg.CORBA.ValueMember;
import org.omg.CORBA.portable.IDLEntity;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.TypeCodePackage.Bounds;

/**
* Read CDR encoded data
*
* @author Gerald Brose, FU Berlin
* $Id: CDRInputStream.java,v 1.97 2006/05/31 13:08:14 alphonse.bendt Exp $
*/

public class CDRInputStream
    extends org.omg.CORBA_2_3.portable.InputStream
{
    /**
     * <code>encaps_stack</code> is used to saving/restoring
     * encapsulation information. Do NOT access this variable directly.
     * It is initialized on demand. Use the method {@link #getEncapsStack()}
     */
    private Stack encaps_stack;

    /**
     * <code>recursiveTCMap</code> is used to to remember the original
     * TCs for a given ID that is used in a recursive/repeated TC. Do
     * NOT access this variable directly. It is initialized on demand.
     * Use the method {@link #getRecursiveTCMap()}
     */
    private Map recursiveTCMap;

    /**
     * <code>cachedTypecodes</code> stores a mapping of ID/Typecode to
     * speed reading from the stream. Do NOT access this variable directly. It
     * is initialized on demand. Use the methods
     * {@link #getCachedTypecode(String id)} and
     * {@link #putCachedTypecode(String id, org.omg.CORBA.TypeCode result)}
     * Skip amount is
     * skip (size - ((pos - start_pos) - 4 - 4));
     * EncapsulationSize -
     * ( PositionAfterReadingId - start_pos
     *   - 4 [Size] - 4 [KindSize] ) = RemainingSizeToSkip
     */
    private Map cachedTypecodes;

    /** indexes to support mark/reset */
    private int marked_pos;
    private int marked_index;

    private boolean closed;

    /** configurable properties */
    private Logger logger;
    private boolean cometInteropFix;
    private boolean laxBooleanEncoding;
    private boolean cacheTypecodes;

    /* character encoding code sets for char and wchar, default ISO8859_1 */
    private int codeSet =  CodeSet.getTCSDefault();
    private int codeSetW = CodeSet.getTCSWDefault();
    protected int giop_minor = 2; // needed to determine size in chars

    /**
     * <code>valueMap</code> maps indices within the buffer
     * (java.lang.Integer) to the values that appear at these indices. Do
     * NOT access this variable directly. It is initialized on demand.
     * Use the method {@link #getValueMap()}
     */
    private Map valueMap;

    /**
     * Index of the current IDL value that is being unmarshalled.
     * This is kept here so that when the value object has been
     * created, the value factory can immediately store it into this
     * stream's valueMap by calling `register_value()'.
     */
    private int currentValueIndex;

    /**
     * <code>repIdMap</code> maps indices within the buffer
     * (java.lang.Integer) to repository ids that appear at these indices.
     * Do NOT access this variable directly. It is initialized on demand.
     * Use the method {@link #getRepIdMap()}
     */
    private Map repIdMap;

    /**
     * <code>codebaseMap</code> maps indices within the buffer
     * (java.lang.Integer) to codebase strings that appear at these indices.
     * Do NOT access this variable directly. It is initialized on demand.
     * Use the method {@link #getCodebaseMap()}
     */
    private Map codebaseMap;

    public boolean littleEndian = false;

    /** indices into the actual buffer */
    protected byte[] buffer = null;
    protected int pos = 0;
    protected int index = 0;

    /** Last value tag read had the chunking bit on */
    private boolean chunkedValue = false;

    /** Nesting level of chunked valuetypes */
    private int valueNestingLevel = 0;

    /** Ending position of the current chunk */
    private int chunk_end_pos = -1;   // -1 means we're not within a chunk


    /**
     * for this stream to be able to return a live object reference, a
     * full ORB (not the Singleton!) must be known. If this stream is
     * used only to demarshal base type data, the Singleton is enough
     */
    private org.omg.CORBA.ORB orb = null;

    /**
     * this is the lowest possible value_tag indicating the
     * begin of a valuetype (15.3.4)
     */
    private static final int max_block_size = 0x7fffff00;

    private boolean sunInteropFix;

    public CDRInputStream(final org.omg.CORBA.ORB orb, final byte[] buf)
    {
        buffer = buf;
        // orb may be null!
        if (orb != null)
        {
            this.orb = orb;
            // orb may be the singleton!
            if (orb instanceof org.jacorb.orb.ORB)
            {
                try
                {

                    configure(((org.jacorb.orb.ORB)orb).getConfiguration());
                }
                catch( ConfigurationException ce )
                {
                    throw new INTERNAL("ConfigurationException: " + ce);
                }
            }
        }
        else
            this.orb = org.omg.CORBA.ORB.init();
    }

    public CDRInputStream(final org.omg.CORBA.ORB orb,
                          final byte[] buf,
                          final boolean littleEndian )
    {
        this( orb, buf );
        this.littleEndian = littleEndian;
    }


    /**
     * This stream is self-configuring, i.e. configure() is private
     * and only called from the constructors.
     */

    private void configure(Configuration configuration)
        throws ConfigurationException
    {
        logger =
            ((org.jacorb.config.Configuration)configuration).getNamedLogger("jacorb.orb.cdr");

        cometInteropFix =
            configuration.getAttribute("jacorb.interop.comet","off").equals("on");
        laxBooleanEncoding =
            configuration.getAttribute("jacorb.interop.lax_boolean_encoding","off").equals("on");
        cacheTypecodes =
            configuration.getAttribute("jacorb.cacheTypecodes","off").equals("on");
        sunInteropFix =
            configuration.getAttribute("jacorb.interop.sun", "off").equalsIgnoreCase("on");
    }




    /**
     * <code>getEncapsStack</code> is used to initialize encaps_stack
     * on demand.
     *
     * @return a <code>Stack</code> value
     */
    private Stack getEncapsStack()
    {
        if (encaps_stack == null)
        {
            encaps_stack = new Stack();
        }
        return encaps_stack;
    }


    /**
     * Gets the Map that keeps track of recursive TypeCodes.
     *
     * @return a <code>Map</code> value
     */
    private Map getRecursiveTCMap()
    {
        if (recursiveTCMap == null)
        {
            recursiveTCMap = new HashMap();
        }
        return recursiveTCMap;
    }


    /**
     * Gets the Map that is used to demarshal shared valuetype instances.
     *
     * @return a <code>Map</code> value
     */
    private Map getValueMap()
    {
        if (valueMap == null)
        {
            // Unlike the valueMap in CDROutputStream, this one
            // does need to be an equality-based HashMap.
            valueMap = new HashMap();
        }
        return valueMap;
    }


    /**
     * Gets the Map that is used to implement indirections for RepositoryIDs.
     *
     * @return a <code>Map</code> value
     */
    private Map getRepIdMap()
    {
        if (repIdMap == null)
        {
            repIdMap = new HashMap();
        }
        return repIdMap;
    }


    /**
     * Gets the Map that is used to implement sharing for codebase
     * specifications.
     *
     * @return a <code>Map</code> value
     */
    private Map getCodebaseMap()
    {
        if (codebaseMap == null)
        {
            codebaseMap = new HashMap();
        }
        return codebaseMap;
    }


    /**
     * <code>getCachedTypecode</code> to retrieve a value from cachedTypecodes.
     * It may initialize the value on demand.
     *
     * @param id a <code>String</code> value
     * @return a <code>org.omg.CORBA.TypeCode</code> value, possibly null.
     */
    private org.omg.CORBA.TypeCode getCachedTypecode( String id )
    {
        org.omg.CORBA.TypeCode result = null;

        if ( cacheTypecodes )
        {
            if ( cachedTypecodes == null )
            {
                cachedTypecodes = new HashMap();
            }
            else
            {
                result = ( org.omg.CORBA.TypeCode )cachedTypecodes.get( id );
            }
        }
        return result;
    }


    /**
     * <code>putCachedTypecode</code> is used to store typecodes within the
     * cachedTypecodes. It will only do it cacheTypecodes is on.
     *
     * @param id a <code>String</code> value
     * @param result an <code>org.omg.CORBA.TypeCode</code> value
     */
    private void putCachedTypecode( String id, org.omg.CORBA.TypeCode result)
    {
        if ( cacheTypecodes )
        {
            // By definition get/put should be paired so cachedTypecodes should
            // never be null here.
            cachedTypecodes.put (id, result);
        }
    }


    public void setGIOPMinor(final  int giop_minor )
    {
        this.giop_minor = giop_minor;
    }

    public int getGIOPMinor()
    {
        return giop_minor;
    }

    public void close()
        throws IOException
    {
        // Don't need to call super.close as super is noop.
        if( closed )
        {
            return;
        }

        BufferManager.getInstance().returnBuffer(buffer);

        encaps_stack = null;
        recursiveTCMap = null;
        closed = true;
    }

    public org.omg.CORBA.ORB orb()
    {
        if (orb == null) orb = org.omg.CORBA.ORB.init(new String[]{}, null);
        return orb;
    }

    public void setCodeSet(final int codeSet, final int codeSetWide)
    {
        this.codeSet = codeSet;
        this.codeSetW = codeSetWide;
    }

    private static final int _read4int
       (final boolean _littleEndian, final byte[] _buffer, final int _pos)
    {
        if (_littleEndian)
            return (((_buffer[_pos+3] & 0xff) << 24) +
                    ((_buffer[_pos+2] & 0xff) << 16) +
                    ((_buffer[_pos+1] & 0xff) <<  8) +
                    ((_buffer[_pos]   & 0xff) <<  0));
        else
            return (((_buffer[_pos]   & 0xff) << 24) +
                    ((_buffer[_pos+1] & 0xff) << 16) +
                    ((_buffer[_pos+2] & 0xff) <<  8) +
                    ((_buffer[_pos+3] & 0xff) <<  0));
    }

    private static final short _read2int
       (final boolean _littleEndian, final byte[] _buffer, final int _pos)
    {
        if (_littleEndian)
            return  (short)(((_buffer[_pos+1] & 0xff) << 8) +
                            ((_buffer[_pos]   & 0xff) << 0));
        else
            return (short)(((_buffer[_pos ]    & 0xff) << 8) +
                           ((_buffer[_pos + 1] & 0xff) << 0));
    }

    private final int _read_long()
    {
        int result;

        result = _read4int (littleEndian, buffer, pos);

        index += 4;
        pos += 4;
        return result;
    }

    private final long _read_longlong()
    {
        if (littleEndian)
        {
            return ((long) _read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
        }
        else
        {
            return ((long) _read_long() << 32) + ((long) _read_long() & 0xFFFFFFFFL);
        }
    }

    private final void handle_chunking()
    {
        int remainder = 4 - (index % 4);
        int aligned_pos = (remainder != 4) ? pos + remainder : pos;

        if (chunk_end_pos >= pos && chunk_end_pos <= aligned_pos)
        {
            chunk_end_pos = -1;
            int saved_pos = pos;
            int saved_index = index;
            int tag = read_long();

            if (tag < 0) {

                // tag is an end tag

                if ( ! (-tag <= valueNestingLevel))
                {
                    throw new INTERNAL
                    (
                        "received end tag " + tag +
                        " with value nesting level " +
                        valueNestingLevel
                    );
                }
                valueNestingLevel = - tag;
                valueNestingLevel--;

                if (valueNestingLevel > 0)
                {
                    chunk_end_pos = pos;
                    handle_chunking();
                }
            }
            else if (tag < 0x7fffff00)
            {
                // tag is the chunk size tag of another chunk

                chunk_end_pos = pos + tag;
            }
            else // (tag >= 0x7fffff00)
            {
                // tag is the value tag of a nested value

                pos = saved_pos;      // "unread" the value tag
                index = saved_index;
            }
        }
    }

    protected final void skip(final int distance)
    {
        pos += distance;
        index += distance;
    }

    /**
     * close a CDR encapsulation and
     * restore index and byte order information
     */

    public final void closeEncapsulation()
    {
        if (encaps_stack == null)
        {
            throw new MARSHAL( "Internal Error - closeEncapsulation failed" );
        }

        EncapsInfo ei = (EncapsInfo)encaps_stack.pop();
        littleEndian = ei.littleEndian;
        int size = ei.size;
        int start = ei.start;

        if( pos < start + size )
            pos = start + size;

        index = ei.index + size;
    }

    /**
     * open a CDR encapsulation and
     * restore index and byte order information
     */

    public final int openEncapsulation()
    {
        boolean old_endian = littleEndian;
        int size = read_long();

        // Check if size looks sane. If not try changing byte order.
        // This is a specific fix for interoperability with the Iona
        // Comet COM/CORBA bridge that has problems with size marshalling.

        if (cometInteropFix && ((size < 0) || (size > buffer.length)))
        {
            int temp =
            (
                ((size >> 24) & 0x000000FF) +
                ((size >> 8& 0x0000FF00) +
                ((size << 8& 0x00FF0000) +
                ((size << 24) & 0xFF000000)
            );

            if (logger.isDebugEnabled())
            {
                logger.debug("Size of CDR encapsulation larger than buffer, swapping byte order\n" +
                             "Size of CDR encapsulation was " + size + ", is now " + temp);
            }

            size = temp;
        }
        /* save current index plus size of the encapsulation on the stack.
           When the encapsulation is closed, this value will be restored as
           index */

        if (encaps_stack == null)
        {
            encaps_stack = new Stack();
        }
        encaps_stack.push(new EncapsInfo(old_endian, index, pos, size ));

        openEncapsulatedArray();

        return size;
    }

    public final void openEncapsulatedArray()
    {
        /* reset index  to zero, i.e. align relative  to the beginning
           of the encaps. */
        resetIndex();
        littleEndian = read_boolean();
    }


    /*
     * Return a copy of the current buffer. Currently only used by ProxyImpl.
     *
     * @return a <code>byte[]</code> value.
     */
    public byte[] getBufferCopy()
    {
        byte[] result = new byte[buffer.length];
        System.arraycopy
        (
            buffer,
            0,
            result,
            0,
            buffer.length
        );
        return result;
    }

    /**
     * Reads the next byte of data from the input stream. The value byte is
     * returned as an <code>int</code> in the range <code>0</code> to
     * <code>255</code>. If no byte is available because the end of the stream
     * has been reached, the value <code>-1</code> is returned.
     * @return the next byte of data, or <code>-1</code> if the end of the
     *         stream is reached.
     * @throws java.io.IOException if stream is closed.
     */
    public int read()
        throws java.io.IOException
    {
        if( closed )
            throw new java.io.IOException("Stream already closed!");

        if( available() < 1 )
            return -1;

        ++index;
        return buffer[pos++]; // read_index++];
    }

    /**
     * @return the number of bytes that can be read (or skipped over) from this
     *         input stream.  This is not necessarily the number of 'valid' bytes.
     */
    public int available()
    {
        return buffer.length - index;
    }

    /**
     * Has the effect of read(b, 0, b.length);
     * @see #read
     */
    public int read(final byte[] b)
        throws java.io.IOException
    {
        return read(b, 0, b.length);
    }

    /**
     * Performs as described by <code>java.io.InputStream.read(byte[], int, int)</code>,
     * but never blocks.
     */
    public int read(final byte[] b, final int off, final int len)
        throws java.io.IOException
    {
        if( b == null )
        {
            throw new java.io.IOException("buffer may not be null");
        }

        if( off < 0 ||
            len < 0 ||
            off + len > b.length )
        {
            throw new java.io.IOException("buffer index out of bounds");
        }

        if( len == 0 )
        {
            return 0;
        }

        if( available() < 1 )
        {
            return -1;
        }

        if( closed )
        {
            throw new java.io.IOException("Stream already closed!");
        }

        int min = Math.min(len, available());
        System.arraycopy(buffer, index, b, off, min );
        pos += min;
        index += min;
        return min;
    }


    public final org.omg.CORBA.Any read_any()
    {
        org.omg.CORBA.TypeCode _tc = read_TypeCode();
        org.omg.CORBA.Any any = orb.create_any();
        any.read_value( this, _tc );
        return any;
    }

    public final boolean read_boolean()
    {
        handle_chunking();
        index++;
        byte bb = buffer[pos++];

        if (bb == 0)
        {
            return false;
        }
        else
        {
            if (bb == 1)
            {
                return true;
            }
            else
            {
                if (laxBooleanEncoding)
                {
                    // Technically only valid values are 0 (false) and 1 (true)
                    // however some ORBs send values other than 1 for true.
                    return true;
                }
                else
                {
                    throw new MARSHAL("Unexpected boolean value: " + bb
                                      + " pos: " + pos + " index: " + index);
                }
            }
        }
    }

    /** arrays */

    public final void read_boolean_array
       (final boolean[] value, final int offset, final int length)
    {
        handle_chunking();
        byte bb;
        for (int j = offset; j < offset + length; j++)
        {
            index++;
            bb = buffer[pos++];
            if (bb == 1)
            {
                value[j] = true;
            }
            else if (bb == 0)
            {
                value[j] = false;
            }
            else
            {
                throw new MARSHAL ("Unexpected boolean value: " + bb
                                   + " pos: " + pos + " index: " + index);
            }
        }
    }

    public final char read_char()
    {
        handle_chunking();
        index++;
        return (char)(0xff & buffer[pos++]);
    }

    public final void read_char_array
       (final char[] value, final int offset, final int length)
    {
        handle_chunking();
        for (int j = offset; j < offset + length; j++)
        {
            index++;
            value[j] = (char) (0xff & buffer[pos++]);
        }
    }

    public final double read_double()
    {
        return Double.longBitsToDouble (read_longlong());
    }

    public final void read_double_array
       (final double[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 8 - (index % 8);
        if (remainder != 8)
        {
            index += remainder;
            pos += remainder;
        }

        for (int j = offset; j < offset + length; j++)
        {
            value[j] = Double.longBitsToDouble (_read_longlong());
        }
    }

    public final java.math.BigDecimal read_fixed()
    {
        handle_chunking();

        StringBuffer sb = new StringBuffer();

        int b = buffer[pos++];
        int c = b & 0x0F; // second half byte
        index++;

        while(true)
        {
            c = (b & 0xF0) >>> 4;
            sb.append(c );
            c = b & 0x0F;
            if( c == 0xC || c == 0xD )
                break;
            sb.append(c );
            b = buffer[pos++];
            index++;
        }

        java.math.BigDecimal result =
        new java.math.BigDecimal( new java.math.BigInteger( sb.toString()));

        if( c == 0xD )
            return result.negate();
        else
            return result;

    }

    public final float read_float()
    {
        return Float.intBitsToFloat (read_long());
    }

    public final void read_float_array
       (final float[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 4 - (index % 4);
        if (remainder != 4)
        {
            index += remainder;
            pos += remainder;
        }

        for (int j = offset; j < offset + length; j++)
        {
            value[j] = Float.intBitsToFloat (_read_long());
        }
    }

    public final int read_long()
    {
        handle_chunking();

        int result;

        int remainder = 4 - (index % 4);
        if (remainder != 4)
        {
            index += remainder;
            pos += remainder;
        }

        result = _read4int (littleEndian, buffer, pos);

        index += 4;
        pos += 4;
        return result;
    }

    public final void read_long_array
       (final int[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 4 - (index % 4);
        if (remainder != 4)
        {
            index += remainder;
            pos += remainder;
        }

        for (int j = offset; j < offset+length; j++)
        {
            value[j] = _read4int (littleEndian,buffer,pos);
            pos += 4;
        }

        index += 4 * length;
    }


    public final long read_longlong()
    {
        handle_chunking();

        int remainder = 8 - (index % 8);
        if (remainder != 8)
        {
            index += remainder;
            pos += remainder;
        }

        if (littleEndian)
        {
            return ((long) _read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
        }
        else
        {
            return ((long) _read_long() << 32) + ((long) _read_long() & 0xFFFFFFFFL);
        }
    }

    public final void read_longlong_array
        (final long[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 8 - (index % 8);
        if (remainder != 8)
        {
            index += remainder;
            pos += remainder;
        }

        if (littleEndian)
        {
            for(int j=offset; j < offset+length; j++)
            {
                value[j] = ( (long) _read_long() & 0xFFFFFFFFL) +
                    ((long) _read_long() << 32);
            }
        }
        else
        {
            for(int j=offset; j < offset+length; j++)
            {
                value[j] = ((long) _read_long() << 32) +
                    ((long) _read_long() & 0xFFFFFFFFL);
            }
        }

        // Do not need to modify pos and index as use read_long above
    }

    public final org.omg.CORBA.Object read_Object()
    {
        if (! (orb instanceof org.jacorb.orb.ORB))
        {
            throw new MARSHAL
                ( "Cannot use the singleton ORB to receive object references, "
                       + "please initialize a full ORB instead.");
        }

        handle_chunking();

        org.omg.IOP.IOR ior = org.omg.IOP.IORHelper.read(this);
        ParsedIOR pior = new ParsedIOR( ior, (org.jacorb.orb.ORB)orb, logger );

        if( pior.isNull() )
        {
            return null;
        }
        else
        {
            return ((org.jacorb.orb.ORB)orb)._getObject( pior );
        }
    }

    public org.omg.CORBA.Object read_Object(final java.lang.Class clz)
    {
        if (org.omg.CORBA.portable.ObjectImpl.class.isAssignableFrom(clz))
        {
            org.omg.CORBA.Object obj = read_Object();
            if (obj instanceof org.omg.CORBA.portable.ObjectImpl)
            {
                org.omg.CORBA.portable.ObjectImpl stub = null;
                try
                {
                    stub = (org.omg.CORBA.portable.ObjectImpl)clz.newInstance();
                }
                catch (InstantiationException e)
                {
                    throw new MARSHAL("Exception in stub instantiation: " + e);
                }
                catch (IllegalAccessException e)
                {
                    throw new MARSHAL("Exception in stub instantiation: " + e);
                }
                stub._set_delegate(
                     ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate());
                return stub;
            }
            else
            {
                return obj;
            }
        }
        else if (clz.isInterface() &&
                 java.rmi.Remote.class.isAssignableFrom(clz))
        {
            return (org.omg.CORBA.Object)
                org.jacorb.util.ValueHandler.portableRemoteObject_narrow(
                                                           read_Object(), clz);
        }
        else
        {
            return read_Object();
        }
    }

    public final byte read_octet()
    {
        handle_chunking();
        index++;
        return buffer[pos++];
    }

    public final void read_octet_array
        (final byte[] value, final int offset, final int length)
    {
        handle_chunking();
        System.arraycopy (buffer,pos,value,offset,length);
        index += length;
        pos += length;
    }

    /*
     * @deprecated
     * @see org.omg.CORBA.portable.InputStream#read_Principal()
     */
    public final org.omg.CORBA.Principal read_Principal()
    {
        throw new NO_IMPLEMENT ("Principal deprecated");
    }

    /**
     *   Read methods for big-endian as well as little endian data input
     *   contributed by Mark Allerton <MAllerton@img.seagatesoftware.com>
     */

    public final short read_short()
    {
        handle_chunking();

        int remainder = 2 - (index % 2);
        if (remainder != 2)
        {
            index += remainder;
            pos += remainder;
        }

        short result = _read2int (littleEndian,buffer,pos);
        pos += 2;
        index += 2;
        return result;
    }

    public final void read_short_array
        (final short[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 2 - (index % 2);

        if (remainder != 2)
        {
            index += remainder;
            pos += remainder;
        }

        for (int j = offset; j < offset + length; j++)
        {
            value[j] = _read2int (littleEndian, buffer, pos);
            pos += 2;
        }

        index += length * 2;
    }

    public final String read_string()
    {
        String result = null;

        handle_chunking();

        int remainder = 4 - (index % 4);
        if( remainder != 4 )
        {
            index += remainder;
            pos += remainder;
        }

        // read size (#bytes)
        int size = _read4int( littleEndian, buffer, pos);
        int start = pos + 4;

        index += (size + 4);
        pos += (size + 4);
        String csname = CodeSet.csName(codeSet);

        if ((size > 0) &&
            (buffer[ start + size - 1 ] == 0))
        {
            size --;
        }

        if(start + size > buffer.length)
        {
            if (logger.isDebugEnabled())
            {
                logger.debug( "Size (" + size + ") invalid for string extraction from buffer length of " + buffer.length + " from position " + start);
            }
            throw new MARSHAL ("Invalid size for string extraction");
        }

        try {
          result = new String (buffer, start, size, csname);
        }
        catch (java.io.UnsupportedEncodingException ex) {
            if (logger != null && logger.isErrorEnabled()) {
                logger.error("Charset " + csname + " is unsupported");
                result = "";
            }
        }
        return result;
    }


    public final org.omg.CORBA.TypeCode read_TypeCode()
    {
        Map tcMap = new HashMap();
        org.omg.CORBA.TypeCode result = read_TypeCode( tcMap );

        return result;
    }

    private final org.omg.CORBA.TypeCode read_TypeCode(final Map tcMap )
    {
        String  id           = null;
        String  name         = null;
        int     member_count = 0;
        int     length       = 0;
        int     size         = 0;
        org.omg.CORBA.TypeCode result = null;
        org.omg.CORBA.TypeCode content_type = null;
        String[] member_names = null;

        int kind = read_long();
        int start_pos = pos - 4;

        if (logger != null && logger.isDebugEnabled())
        {
            logger.debug("Read Type code of kind " + kind + " at pos: " + start_pos);
        }

        switch( kind )
        {
            case TCKind._tk_null:
            case TCKind._tk_void:
            case TCKind._tk_short:
            case TCKind._tk_long:
            case TCKind._tk_ushort:
            case TCKind._tk_ulong:
            case TCKind._tk_float:
            case TCKind._tk_double:
            case TCKind._tk_boolean:
            case TCKind._tk_char:
            case TCKind._tk_octet:
            case TCKind._tk_any:
            case TCKind._tk_TypeCode:
            case TCKind._tk_longlong:
            case TCKind._tk_ulonglong:
            case TCKind._tk_wchar:
            case TCKind._tk_Principal:
            {
                result = orb.get_primitive_tc
                    (org.omg.CORBA.TCKind.from_int (kind));
                break;
            }
            case TCKind._tk_objref:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                }
                else
                {
                    name = validateName (read_string());
                    result = orb.create_interface_tc (id, name);
                    putCachedTypecode( id, result );
                }
                closeEncapsulation();
                break;
            }
            case TCKind._tk_struct:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());
                    member_count = read_long();

                    tcMap.put( new Integer( start_pos ), id );

                    StructMember[] struct_members = new StructMember[member_count];
                    for( int i = 0; i < member_count; i++)
                    {
                        struct_members[i] = new StructMember
                        (
                            read_string(),
                            read_TypeCode (tcMap),
                            null
                        );
                    }
                    result = ((ORBSingleton) orb).create_struct_tc(id, name, struct_members, false);
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put (id, result);
                closeEncapsulation();
                break;
            }
            case TCKind._tk_except:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());
                    member_count = read_long();

                    tcMap.put( new Integer( start_pos ), id );

                    StructMember[] members = new StructMember[member_count];
                    for( int i = 0; i < member_count; i++)
                    {
                        members[i] = new StructMember
                        (
                            read_string(),
                            read_TypeCode(tcMap),
                            null
                        );
                    }
                    result = ((ORBSingleton)orb).create_exception_tc (id, name, members, false);
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put (id, result);
                closeEncapsulation();
                break;
            }
            case TCKind._tk_enum:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());
                    member_count = read_long();

                    tcMap.put( new Integer( start_pos ), id );

                    member_names = new String[member_count];
                    for( int i = 0; i < member_count; i++)
                    {
                        member_names[i] = read_string();
                    }
                    result = ((ORBSingleton)orb).create_enum_tc (id, name, member_names, false);
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put (id, result);
                closeEncapsulation();
                break;
            }
            case TCKind._tk_union:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());

                    tcMap.put( new Integer( start_pos ), id );

                    org.omg.CORBA.TypeCode discriminator_type = read_TypeCode(tcMap);
                    // Use the dealiased discriminator type for the label types.
                    // This works because the JacORB IDL compiler ignores any aliasing
                    // of label types and only the discriminator type is passed on the
                    // wire.
                    org.omg.CORBA.TypeCode orig_disc_type =
                    TypeCode.originalType(discriminator_type);

                    int default_index = read_long();
                    member_count = read_long();

                    UnionMember[] union_members = new UnionMember[member_count];
                    for( int i = 0; i < member_count; i++)
                    {
                        org.omg.CORBA.Any label = orb.create_any();

                        if( i == default_index )
                        {
                            // Default discriminator
                            label.insert_octet( read_octet());
                        }
                        else
                        {
                            // use the dealiased discriminator type to construct labels
                            label.read_value( this, orig_disc_type );
                        }

                        union_members[i] = new UnionMember
                        (
                            read_string(),
                            label,
                            read_TypeCode(tcMap),
                            null
                        );
                    }

                    result = ((ORBSingleton)orb).create_union_tc(id, name, discriminator_type, union_members, false);
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put (id, result);
                closeEncapsulation();
                break;
            }
            case TCKind._tk_string:
            {
                result = orb.create_string_tc(read_long());
                break;
            }
            case TCKind._tk_wstring:
            {
                result = orb.create_wstring_tc(read_long());
                break;
            }
            case TCKind._tk_fixed:
            {
                result = orb.create_fixed_tc(read_ushort(), read_short() );
                break;
            }
            case TCKind._tk_array:
            {
                openEncapsulation();

                content_type = read_TypeCode(tcMap);
                length = read_long();

                closeEncapsulation();
                result = orb.create_array_tc(length, content_type);
                break;
            }
            case TCKind._tk_sequence:
            {
                openEncapsulation();

                content_type = read_TypeCode(tcMap);
                length = read_long();

                closeEncapsulation();

                result = orb.create_sequence_tc(length, content_type);
                break;
            }
            case TCKind._tk_alias:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());

                    tcMap.put( new Integer( start_pos ), id );

                    content_type = read_TypeCode( tcMap );
                    result = orb.create_alias_tc (id, name, content_type );
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put (id , result);
                closeEncapsulation();
                break;
            }
            case TCKind._tk_value:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());

                    tcMap.put( new Integer( start_pos ), id );

                    short type_modifier = read_short();
                    org.omg.CORBA.TypeCode concrete_base_type = read_TypeCode( tcMap );
                    member_count = read_long();
                    ValueMember[] vMembers = new ValueMember[member_count];

                    for( int i = 0; i < member_count; i++)
                    {
                        vMembers[i] = new ValueMember
                        (
                            read_string(),
                            null, // id
                            null, // defined_in
                            null, // version
                            read_TypeCode (tcMap),
                            null, // type_def
                            read_short()
                        );
                    }
                    result = orb.create_value_tc
                        (id, name, type_modifier, concrete_base_type, vMembers);
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put( id , result );
                closeEncapsulation();
                break;
            }
            case TCKind._tk_value_box:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                    tcMap.put( new Integer( start_pos ), id );
                }
                else
                {
                    name = validateName (read_string());

                    tcMap.put( new Integer( start_pos ), id );

                    content_type = read_TypeCode( tcMap );
                    result = orb.create_value_box_tc (id, name, content_type);
                    putCachedTypecode( id, result );
                }
                getRecursiveTCMap().put( id , result );
                closeEncapsulation();
                break;
            }
            case TCKind._tk_abstract_interface:
            {
                size = openEncapsulation();
                id = validateID (read_string());
                result = getCachedTypecode( id );

                if (result != null)
                {
                    // Skip buffer - see cachedTypecodes for calculation.
                    skip (size - ((pos - start_pos) - 4 - 4));
                }
                else
                {
                    name = validateName (read_string());
                    result = orb.create_abstract_interface_tc (id, name);
                    putCachedTypecode( id, result );
                }
                closeEncapsulation();
                break;
            }
            case 0xffffffff:
            {
                /* recursive TC */
                int negative_offset = read_long();
                String recursiveId =
                    (String)tcMap.get( new Integer( pos - 4 + negative_offset ) );

                if (recursiveId == null)
                {
                    throw new INTERNAL
                    (
                        "No recursive TypeCode! (pos: " +
                        (pos - 4 + negative_offset) +
                        ")"
                    );
                }

                // look up TypeCode in map to check if it's repeated
                org.omg.CORBA.TypeCode rec_tc =
                    (org.omg.CORBA.TypeCode)( getRecursiveTCMap().get( recursiveId ) );

                if (rec_tc == null)
                {
                    // TypeCode is not in map so it is recursive
                    rec_tc = orb.create_recursive_tc( recursiveId );
                }

                result = rec_tc;
                break;
            }
            default:
            {
                // error, dump buffer contents for diagnosis
                throw new MARSHAL("Cannot handle TypeCode with kind " + kind);
            }
        }
        return result;
    }

    public final int read_ulong()
    {
        handle_chunking();

        int result;

        int remainder = 4 - (index % 4);
        if (remainder != 4)
        {
            index += remainder;
            pos += remainder;
        }

        result = _read4int (littleEndian, buffer, pos);

        index += 4;
        pos += 4;
        return result;
    }

    public final void read_ulong_array
        (final int[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 4 - (index % 4);
        if (remainder != 4)
        {
            index += remainder;
            pos += remainder;
        }

        for (int j = offset; j < offset+length; j++)
        {
            value[j] = _read4int (littleEndian,buffer,pos);
            pos += 4;
        }

        index += 4 * length;
    }

    public final long read_ulonglong()
    {
        handle_chunking();

        int remainder = 8 - (index % 8);
        if (remainder != 8)
        {
            index += remainder;
            pos += remainder;
        }

        if (littleEndian)
        {
            return ((long) _read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
        }
        else
        {
            return ((long) _read_long() << 32) + ((long) _read_long() & 0xFFFFFFFFL);
        }
    }

    public final void read_ulonglong_array
        (final long[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 8 - (index % 8);
        if (remainder != 8)
        {
            index += remainder;
            pos += remainder;
        }

        if (littleEndian)
        {
            for (int j = offset; j < offset+length; j++)
            {
                value[j] = ( (long) _read_long() & 0xFFFFFFFFL) +
                    ((long) _read_long() << 32);
            }
        }
        else
        {
            for (int j = offset; j < offset+length; j++)
            {
                value[j] = ((long) _read_long() << 32) +
                    ((long) _read_long() & 0xFFFFFFFFL);
            }
        }

        // Do not need to modify pos and index as use read_long above
    }

    public final short read_ushort()
    {
        handle_chunking();

        int remainder = 2 - (index % 2);
        if (remainder != 2)
        {
            index += remainder;
            pos += remainder;
        }

        short result = _read2int (littleEndian,buffer,pos);
        pos += 2;
        index += 2;
        return result;
    }

    public final void read_ushort_array
        (final short[] value, final int offset, final int length)
    {
        if (length == 0)
            return;

        handle_chunking();

        int remainder = 2 - (index % 2);

        if (remainder != 2)
        {
            index += remainder;
            pos += remainder;
        }

        for (int j = offset; j < offset + length; j++)
        {
            value[j] = _read2int (littleEndian, buffer, pos);
            pos += 2;
        }

        index += length * 2;
    }

    public final char read_wchar()
    {
        handle_chunking();

        if (giop_minor == 2)
        {
            //ignore size indicator
            read_wchar_size();

            boolean wchar_little_endian = readBOM();

            return read_wchar (wchar_little_endian);
        }
        else
        {
            return read_wchar (littleEndian);
        }
    }

    /**
     * The number of bytes this char takes. This is actually not
     * necessary since the encodings used are either fixed-length
     * (UTF-16) or have their length encoded internally (UTF-8).
     */
    private final int read_wchar_size()
    {
        index++;

        return buffer[ pos++ ];
    }


    private final char read_wchar(final boolean wchar_little_endian)
    {
        switch( codeSetW )
        {
            case CodeSet.UTF8 :
            {
                if( giop_minor < 2 )
                {
                    throw new MARSHAL( "GIOP 1." + giop_minor +
                                       " only allows 2 Byte encodings for wchar, but the selected TCSW is UTF-8" );
                }

                short b = (short) (0xff & buffer[pos++]);
                index++;

                if( (b & 0x80) == 0 )
                {
                    return (char) b;
                }
                else if( (b & 0xe0) == 0xc0 )
                {
                    index++;
                    return (char)(((b & 0x1F) << 6) |
                                  ((short)buffer[pos++] & 0x3F));
                }
                else
                {
                    index += 2;
                    short b2 = (short)(0xff & buffer[pos++]);
                    return (char)(( ( b & 0x0F) << 12) |
                                  ( (b2 & 0x3F) << 6) |
                                  ( (short)buffer[pos++] & 0x3F));
                }
            }
            case CodeSet.UTF16 :
            {
                char c;

                if( wchar_little_endian )
                {
                    c = (char) ( (buffer[ pos++ ] & 0xFF) |
                                 (buffer[ pos++ ] << 8) );
                }
                else
                {
                    c = (char) ( (buffer[ pos++ ] << 8) |
                                 (buffer[ pos++ ] & 0xFF) );
                }

                index += 2;
                return c;
            }
        }

        throw new MARSHAL( "Bad CodeSet: " + codeSetW );
    }

    /**
     * Read the byte order marker indicating the endianess.
     *
     * @return true for little endianess, false otherwise (including
     * no BOM present. In this case, big endianess is assumed per
     * spec).
     */
    private final boolean readBOM()
    {
        /*
          if( !use_BOM )
          return false;
        */

        if( (buffer[ pos     ] == (byte) 0xFE) &&
            (buffer[ pos + 1 ] == (byte) 0xFF) )
        {
            //encountering a byte order marker indicating big
            //endianess

            pos += 2;
            index += 2;

            return false;
        }
        else if( (buffer[ pos     ] == (byte) 0xFF) &&
                 (buffer[ pos + 1 ] == (byte) 0xFE) )
        {
            //encountering a byte order marker indicating
            //little endianess

            pos += 2;
            index += 2;

            return true;
        }
        else
        {
            //no BOM so big endian per spec.
            return false;
        }
    }

    public final void read_wchar_array
        (final char[] value, final int offset, final int length)
    {
        handle_chunking();
        for(int j=offset; j < offset+length; j++)
            value[j] = read_wchar(); // inlining later...
    }

    public final String read_wstring()
    {
        String result = null;
        char buf[] = null;

        handle_chunking();

        int remainder = 4 - (index % 4);
        if( remainder != 4 )
        {
            index += remainder;
            pos += remainder;
        }
        if( giop_minor == 2 )
        {
            // read size in bytes
            int size = _read4int( littleEndian, buffer, pos);
            index += 4;
            pos += 4;

            if( size == 0 )
            {
                return "";
            }

            buf = new char[ size ];

            int i = 0;
            int endPos = pos + size;

            boolean wchar_litte_endian = readBOM();

            while( pos < endPos )
            {
                //ignore size
                //read_wchar_size();

                buf[ i++ ] = read_wchar( wchar_litte_endian );
            }

            result = new String( buf, 0, i );
        }
        else //GIOP 1.1 / 1.0
        {
            // read size
            int size = _read4int( littleEndian, buffer, pos);
            index += 4;
            pos += 4;
            buf = new char[ size ];

            int endPos = pos + size;

            if( codeSetW == CodeSet.UTF16 )
            {
                //size is in chars, but char has 2 bytes
                endPos += size;
            }

            int i = 0;

            while( pos < endPos )
            {
                //use the stream-wide endianess
                buf[ i++ ] = read_wchar( littleEndian );
            }

            if( (i != 0) &&
                (buf[ i - 1 ] == 0) )
            {
                //don't return terminating NUL
                result = new String( buf, 0, i - 1 );
            }
            else
            {
                //doesn't have a terminating NUL. This is actually not
                //allowed.
                result = new String( buf, 0, i );
            }
        }
        buf = null;
        return result;
    }

    public boolean markSupported()
    {
        return true;
    }

    public void mark(final int readLimit)
    {
        marked_pos = pos;
        marked_index = index;
    }

    public void reset()
        throws IOException
    {
        if( pos < 0 )
            throw new MARSHAL("Mark has not been set!");
        pos = marked_pos;
        index = marked_index;
    }

    // JacORB-specific

    private final void resetIndex()
    {
        index = 0;
    }

    public final void setLittleEndian(final boolean b)
    {
        littleEndian = b;
    }

    /**
     * Reads an instance of the type described by type code <code>tc</code>
     * from this CDRInputStream, and remarshals it to the given OutputStream,
     * <code>out</code>.  Called from Any.
     */
    final void read_value(final org.omg.CORBA.TypeCode tc,
                          final org.omg.CORBA.portable.OutputStream out)
    {
        if (tc == null)
        {
            throw new BAD_PARAM("TypeCode is null");
        }

        int kind = tc.kind().value();

        try
        {
            switch (kind)
            {
                case TCKind._tk_null:
                case TCKind._tk_void:
                break;
                case TCKind._tk_boolean:
                out.write_boolean( read_boolean());
                break;
                case TCKind._tk_char:
                out.write_char( read_char());
                break;
                case TCKind._tk_wchar:
                out.write_wchar( read_wchar());
                break;
                case TCKind._tk_octet:
                out.write_octet( read_octet());
                break;
                case TCKind._tk_ushort:
                out.write_ushort( read_ushort());
                break;
                case TCKind._tk_short:
                out.write_short( read_short());
                break;
                case TCKind._tk_long:
                out.write_long( read_long());
                break;
                case TCKind._tk_ulong:
                out.write_ulong( read_ulong());
                break;
                case TCKind._tk_float:
                out.write_float( read_float());
                break;
                case TCKind._tk_double:
                out.write_double( read_double());
                break;
                case TCKind._tk_longlong:
                out.write_longlong( read_longlong());
                break;
                case TCKind._tk_ulonglong:
                out.write_ulonglong( read_ulonglong());
                break;
                case TCKind._tk_any:
                out.write_any( read_any());
                break;
                case TCKind._tk_TypeCode:
                out.write_TypeCode( read_TypeCode());
                break;
                case TCKind._tk_Principal:
                throw new NO_IMPLEMENT ("Principal deprecated");
                case TCKind._tk_objref:
                out.write_Object( read_Object());
                break;
                case TCKind._tk_string:
                out.write_string( read_string());
                break;
                case TCKind._tk_wstring:
                out.write_wstring( read_wstring());
                break;
                case TCKind._tk_fixed:
                out.write_fixed (read_fixed());
                break;
                case TCKind._tk_array:
                {
                    int length = tc.length();
                    for( int i = 0; i < length; i++ )
                        read_value( tc.content_type(), out );
                    break;
                }
                case TCKind._tk_sequence:
                {
                    int len = read_long();
                    out.write_long(len);
                    for( int i = 0; i < len; i++ )
                        read_value( tc.content_type(), out );
                    break;
                }
                case TCKind._tk_except:
                out.write_string( read_string());
                // don't break, fall through to ...
                case TCKind._tk_struct:
                {
                    for( int i = 0; i < tc.member_count(); i++)
                        read_value( tc.member_type(i), out );
                    break;
                }
                case TCKind._tk_enum:
                out.write_long( read_long() );
                break;
                case TCKind._tk_alias:
                {
                    read_value( tc.content_type(), out  );
                    break;
                }
                case TCKind._tk_value_box:
                {
                    String id = tc.id();
                    org.omg.CORBA.portable.BoxedValueHelper helper =
                        ((org.jacorb.orb.ORB)orb).getBoxedValueHelper(id);
                    if (helper == null)
                    {
                        throw new MARSHAL ("No BoxedValueHelper for id " + id);
                    }
                    java.io.Serializable value = read_value(helper);
                    ((org.omg.CORBA_2_3.portable.OutputStream)out)
                    .write_value(value, helper);
                    break;
                }
                case TCKind._tk_union:
                {
                    org.omg.CORBA.TypeCode disc = tc.discriminator_type();
                    disc = TypeCode.originalType(disc);
                    int def_idx = tc.default_index();
                    int member_idx = -1;
                    switch( disc.kind().value() )
                    {
                        case TCKind._tk_short:
                        {
                            short s = read_short();
                            out.write_short(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_short())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }

                        case TCKind._tk_long:
                        {
                            int s = read_long();
                            out.write_long(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_long())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_ushort:
                        {
                            short s = read_ushort();
                            out.write_ushort(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_ushort())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }

                        case TCKind._tk_ulong:
                        {
                            int s = read_ulong();
                            out.write_ulong(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_ulong())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_longlong:
                        {
                            long s = read_longlong();
                            out.write_longlong(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_longlong())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_ulonglong:
                        {
                            long s = read_ulonglong();
                            out.write_ulonglong(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_ulonglong())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_char:
                        {
                            char s = read_char();
                            out.write_char(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_char())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_boolean:
                        {
                            boolean b = read_boolean();
                            out.write_boolean( b );
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if( i != def_idx)
                                {
                                    if( b == tc.member_label(i).extract_boolean() )
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_enum:
                        {
                            int s = read_long();
                            out.write_long(s);
                            for( int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if( i != def_idx)
                                {
                                    int label =
                                    tc.member_label(i).create_input_stream().read_long();
                                    if(s == label)
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        default:
                        throw new MARSHAL("Invalid union discriminator type: " + disc);
                    } // switch

                    if( member_idx != -1 )
                    {
                        read_value( tc.member_type( member_idx ), out );
                    }
                    else if( def_idx != -1 )
                    {
                        read_value( tc.member_type( def_idx ), out );
                    }
                    break;
                }
                case 0xffffffff:
                {
                    org.omg.CORBA.TypeCode _tc =
                        (org.omg.CORBA.TypeCode)(getRecursiveTCMap().get ( tc.id() ));


                    if( _tc == null )
                    {
                        throw new MARSHAL("No recursive TC found for " + tc.id());
                    }

                    read_value( _tc , out );
                    break;
                }
                default:
                throw new MARSHAL("Cannot handle TypeCode with kind " + kind);
            }
        }
        catch (BadKind ex)
        {
            throw new MARSHAL
                ("When processing TypeCode with kind: " + kind + " caught " + ex);
        }
        catch (Bounds ex)
        {
            throw new MARSHAL
                ("When processing TypeCode with kind: " + kind + " caught " + ex);
        }
    }


    public java.io.Serializable read_value()
    {
        int tag = read_long();
        int start_offset = pos - 4;

        if (tag == 0xffffffff)
        {
            // indirection
            return read_indirect_value();
        }
        else if (tag == 0x00000000)
        {
            // null tag
            return null;
        }

        String codebase = ((tag & 1) != 0) ? read_codebase() : null;
        chunkedValue = ((tag & 8) != 0);

        int theTag = tag;
        tag = tag & 0xfffffff6;

        if (tag == 0x7fffff00)
            throw new MARSHAL ("missing value type information");
        else if (tag == 0x7fffff02)
        {
            return read_typed_value(start_offset, codebase);
        }
        else if (tag == 0x7fffff06)
        {
            return read_multi_typed_value( start_offset, codebase );
        }
        else
            throw new MARSHAL("unknown value tag: 0x" +
                              Integer.toHexString(theTag) + " (offset=0x" +
                              Integer.toHexString(start_offset) + ")");
    }

    /**
     * Overrides read_value(java.io.Serializable value) in
     * org.omg.CORBA_2_3.portable.InputStream
     */

    public java.io.Serializable read_value(final String rep_id)
    {
        int tag = read_long();
        int start_offset = pos - 4;

        if (tag == 0xffffffff)
        {
            // indirection
            return read_indirect_value();
        }
        else if (tag == 0x00000000)
        {
            // null tag
            return null;
        }

        String codebase = ((tag & 1) != 0) ? read_codebase() : null;
        chunkedValue = ((tag & 8) != 0);

        int theTag = tag;
        tag = tag & 0xfffffff6;

        if (tag == 0x7fffff00)
        {
            return read_untyped_value ( new String[]{ rep_id }, start_offset, codebase);
        }
        else if (tag == 0x7fffff02)
        {
            return read_typed_value( start_offset, codebase );
        }
        else if (tag == 0x7fffff06)
        {
            return read_multi_typed_value( start_offset, codebase );
        }
        else
        {
            throw new MARSHAL("unknown value tag: 0x" +
                              Integer.toHexString(theTag) + " (offset=0x" +
                              Integer.toHexString(start_offset) + ")");
        }
    }

    /**
     * Unmarshals a valuetype instance from this stream.  The value returned
     * is the same value passed in, with all the data unmarshaled
     * (IDL-to-Java Mapping 1.2, August 2002, 1.13.1, p. 1-39).  The specified
     * value is an uninitialized value that is added to the ORB's indirection
     * table before unmarshaling (1.21.4.1, p. 1-117).
     *
     * This method is intended to be called from custom valuetype factories.
     * Unlike the other read_value() methods in this class, this method does
     * not expect a GIOP value tag nor a repository id in the stream.
     *
     * Overrides read_value(value) in
     * org.omg.CORBA_2_3.portable.InputStream
     */

    public java.io.Serializable read_value(java.io.Serializable value)
    {
        if (value instanceof org.omg.CORBA.portable.Streamable)
        {
            register_value(value);
            ((org.omg.CORBA.portable.Streamable)value)._read(this);
        }
        else if (value instanceof org.omg.CORBA.portable.CustomValue )
        {
            register_value(value);
            ( ( org.omg.CORBA.portable.CustomValue ) value ).unmarshal(
                    new DataInputStream( this ) );
        }
        else
        {
            throw new BAD_PARAM("read_value is only implemented for Streamables");
        }
        return value;
    }

    /**
     * Overrides read_value(clz) in
     * org.omg.CORBA_2_3.portable.InputStream
     */

    public java.io.Serializable read_value(final java.lang.Class clz)
    {
        int tag = read_long();
        int start_offset = pos - 4;

        if (tag == 0xffffffff)
        {
            // indirection
            return read_indirect_value();
        }
        else if (tag == 0x00000000)
        {
            // null tag
            return null;
        }

        String codebase = ((tag & 1) != 0) ? read_codebase() : null;
        chunkedValue = ((tag & 8) != 0);

        int theTag = tag;
        tag = tag & 0xfffffff6;

        if (tag == 0x7fffff00)
        {
            return read_untyped_value ( new String[]{ ValueHandler.getRMIRepositoryID(clz) },
                                        start_offset, codebase);
        }
        else if (tag == 0x7fffff02)
        {
            return read_typed_value(start_offset, codebase);
        }
        else if (tag == 0x7fffff06)
        {
            return read_multi_typed_value(start_offset, codebase);
        }
        else
        {
            throw new MARSHAL("unknown value tag: 0x" +
                              Integer.toHexString(theTag) + " (offset=0x" +
                              Integer.toHexString(start_offset) + ")");
        }
    }

    /**
     * Overrides read_value(factory) in
     * org.omg.CORBA_2_3.portable.InputStream
     */


    public java.io.Serializable read_value
        (final org.omg.CORBA.portable.BoxedValueHelper factory)
    {
        int tag = read_long();
        int start_offset = pos - 4;

        if (tag == 0xffffffff)
        {
            // indirection
            return read_indirect_value();
        }
        else if (tag == 0x00000000)
        {
            // null tag, explicit representation of null value
            return null;
        }

        String codebase = ((tag & 1) != 0) ? read_codebase() : null;
        chunkedValue = ((tag & 8) != 0);

        int theTag = tag;
        tag = tag & 0xfffffff6;

        if (tag == 0x7fffff00)
        {
            java.io.Serializable result = factory.read_value (this);

            if( result != null )
            {
                getValueMap().put (new Integer(start_offset), result);
            }

            return result;
        }
        else if (tag == 0x7fffff02)
        {
            // Read value according to type information.
            // Possible optimization: ignore type info and use factory for
            // reading the value anyway, since the type information is
            // most likely redundant.
            return read_typed_value(start_offset, codebase);
        }
        else
            throw new MARSHAL("unknown value tag: 0x" +
                              Integer.toHexString(theTag) + " (offset=0x" +
                              Integer.toHexString(start_offset) + ")");
    }

    /**
     * Immediately reads a value from this stream; i.e. without any
     * repository id preceding it.  The expected type of the value is given
     * by `repository_id', and the index at which the value started is
     * `index'.
     */
    private java.io.Serializable read_untyped_value(final String[] repository_ids,
                                                     final int index,
                                                     final String codebase)
    {
        java.io.Serializable result = null;

        if (chunkedValue || valueNestingLevel > 0)
        {
            valueNestingLevel++;
            int chunk_size_tag = readChunkSizeTag();
            chunk_end_pos = pos + chunk_size_tag;
        }

        for (int r = 0; r < repository_ids.length; r++)
        {
            if (repository_ids[r].equals("IDL:omg.org/CORBA/WStringValue:1.0"))
            {
                // special handling of strings, according to spec
                result = read_wstring();
                break;
            }
            else if (repository_ids[r].startsWith("RMI:javax.rmi.CORBA.ClassDesc:"))
            {
                // special handling of java.lang.Class instances
                String classCodebase = (String)read_value(String.class);
                String reposId = (String)read_value(String.class);
                String className =
                    org.jacorb.ir.RepositoryID.className(reposId, null);
                ClassLoader ctxcl =
                    Thread.currentThread().getContextClassLoader();

                try
                {
                    if (ctxcl != null)
                    {
                        try
                        {
                            result = ctxcl.loadClass(className);
                        }
                        catch (ClassNotFoundException cnfe)
                        {
                            result = ValueHandler.loadClass(className,
                                                            classCodebase,
                                                            null);
                        }
                    }
                    else
                    {
                        result = ValueHandler.loadClass(className,
                                                        classCodebase,
                                                        null);
                    }
                }
                catch (ClassNotFoundException e)
                {
                    if( r < repository_ids.length-1 )
                        continue;
                    else
                        throw new MARSHAL("class not found: " + className);
                }
                break;
            }
            else if (repository_ids[r].startsWith ("IDL:"))
            {
                org.omg.CORBA.portable.ValueFactory factory =
                    ((org.omg.CORBA_2_3.ORB)orb()).lookup_value_factory (repository_ids[r]);

                if (factory != null)
                {
                    currentValueIndex = index;
                    result = factory.read_value (this);
                    break;
                }
                else
                {
                    if( r < repository_ids.length-1 )
                        continue;
                    else
                        throw new MARSHAL ("No factory found for: " + repository_ids[0] );
                }
            }
            else // RMI
            {
                // Load the value's class, using the context class loader
                // of the current thread if possible.  Here's Francisco
                // Reverbel's <reverbel@ime.usp.br> explanation of why
                // this is needed in JBoss:

                // "It seems that ValueHandler.loadClass() uses the thread
                // context classloader only after it looks for other
                // classloaders in the call stack (weird). In some
                // situations (when EJBs are undeployed and then
                // redeployed) it finds in the call stack a classloader
                // used for an undeployed EJB. A value of class Foo is
                // then unmarshalled with type
                // classloaderOfEJB1:Foo, when the expected type is
                // classloaderOfEJB2:Foo. I am getting ClassCastExceptions is this
                // situation.
                // Explicitly using the thread context class loader in the
                // first place solves the problem."

                String className =
                org.jacorb.ir.RepositoryID.className(repository_ids[r], null);

                Class c = null;
                //#ifjdk 1.2
                ClassLoader ctxcl = Thread.currentThread().getContextClassLoader();
                //#else
                //# ClassLoader ctxcl = null;
                //#endif
                try
                {
                    if (ctxcl != null)
                    {
                        try
                        {
                            c = ctxcl.loadClass(className);
                        }
                        catch (ClassNotFoundException cnfe)
                        {
                            c = ValueHandler.loadClass(className, codebase, null);
                        }
                    }
                    else
                    {
                        c = ValueHandler.loadClass(className, codebase, null);
                    }

                    if (IDLEntity.class.isAssignableFrom(c))
                    {
                        java.lang.reflect.Method readMethod = null;
                        if (c != org.omg.CORBA.Any.class)
                        {
                            String helperClassName = c.getName() + "Helper";

                            try
                            {
                                Class helperClass =
                                c.getClassLoader().loadClass(
                                    helperClassName);
                                Class[] paramTypes = {
                                    org.omg.CORBA.portable.InputStream.class
                                };
                                readMethod =
                                helperClass.getMethod("read", paramTypes);
                            }
                            catch (ClassNotFoundException e)
                            {
                                throw new MARSHAL("Error loading class " + helperClassName
                                                  + ": " + e);
                            }
                            catch (NoSuchMethodException e)
                            {
                                throw new MARSHAL("No read method in helper class "
                                                  + helperClassName + ": " + e);
                            }
                        }

                        if (readMethod == null)
                        {
                            result = read_any();
                        }
                        else
                        {
                            try
                            {
                                result =
                                    (java.io.Serializable) readMethod.invoke(
                                        null,
                                        new java.lang.Object[] { this });
                            }
                            catch (IllegalAccessException e)
                            {
                                throw new MARSHAL("Internal error: " + e);
                            }
                            catch (java.lang.reflect.InvocationTargetException e)
                            {
                                throw new MARSHAL("Exception unmarshaling IDLEntity: "
                                                  + e.getTargetException());
                            }
                        }
                    }
                    else
                        result = ValueHandler.readValue(this, index, c,
                                                        repository_ids[r],
                                                        null);
                }
                catch (ClassNotFoundException e)
                {
                    if( r < repository_ids.length-1 )
                        continue;
                    else
                        throw new MARSHAL ("class not found: " + className);
                }

            }
        }

        // value type instances may be null...
        if( result != null )
        {
            getValueMap().put (new Integer (index), result);
        }

        return result;
    }

    /**
     * try to read in the chunk size.
     * special handling if there's no chunk size
     * in the stream.
     */
    private int readChunkSizeTag()
    {
        int savedPos = pos;
        int savedIndex = index;
        int chunk_size_tag = read_long();

        if (!sunInteropFix || chunk_size_tag > 0 && chunk_size_tag < max_block_size)
        {
            // looks like the correct chunk size
            return chunk_size_tag;
        }
        else
        {
            // reset buffer
            pos = savedPos;
            index = savedIndex;
            return max_block_size;
        }
    }

    /**
     * Reads a value with type information, i.e. one that is preceded
     * by a single RepositoryID.  It is assumed that the tag and the codebase
     * of the value have already been read.
     */

    private java.io.Serializable read_typed_value( final int index,
                                                   final String codebase)
    {
        return read_untyped_value ( new String[]{ read_repository_id() }, index, codebase);
    }

    /**
     * Reads a value with type information, i.e. one that is preceded
     * by an array of RepositoryIDs.  It is assumed that the tag and the codebase
     * of the value have already been read.
     */

    private java.io.Serializable read_multi_typed_value( final int index,
                                                         final String codebase)
    {
        int id_count = read_long();
        String[] ids = new String[ id_count ];

        for( int i = 0; i < id_count; i++ )
            ids[i] = read_repository_id();

        return read_untyped_value (ids, index, codebase);
    }


    /**
     * Reads a RepositoryID from the buffer, either directly or via
     * indirection.
     */
    private String read_repository_id()
    {
        int tag = read_long();
        if (tag == 0xffffffff)
        {
            // indirection
            int index = read_long();
            index = index + pos - 4;

            String repId = (String)getRepIdMap().get (new Integer(index));
            if (repId == null)
                throw new MARSHAL("stale RepositoryID indirection");
            else
                return repId;
        }
        else
        {
            // a new id
            pos -= 4;
            index -= 4;
            int start_offset = pos;
            String repId = read_string();

            getRepIdMap().put (new Integer(start_offset), repId);
            return repId;
        }
    }

    /**
     * Reads a codebase from the buffer, either directly or via
     * indirection.
     */
    private String read_codebase()
    {
        int tag = read_long();

        if (tag == 0xffffffff)
        {
            // indirection
            int index = read_long();
            index = index + pos - 4;
            String codebase = (String)getCodebaseMap().get (new Integer(index));
            if (codebase == null)
                throw
                new MARSHAL("stale codebase indirection");
            else
                return codebase;
        }
        else
        {
            // a new codebase string
            pos -= 4;
            index -= 4;
            int start_offset = pos;
            String codebase = read_string();
            getCodebaseMap().put (new Integer(start_offset), codebase);
            return codebase;
        }
    }

    /**
     * Reads an indirect value from this stream. It is assumed that the
     * value tag (0xffffffff) has already been read.
     */
    private java.io.Serializable read_indirect_value()
    {
        // indirection
        int index = read_long();
        index = index + pos - 4;
        java.lang.Object value = getValueMap().get (new Integer(index));
        if (value == null) {

            // Java to IDL Language Mapping, v1.1, page 1-44:
            //
            // "The ValueHandler object may receive an IndirectionException
            // from the ORB stream. The ORB input stream throws this exception
            // when it is called to unmarshal a value encoded as an indirection
            // that is in the process of being unmarshaled. This can occur when
            // the ORB stream calls the ValueHandler object to unmarshal an RMI
            // value whose state contains a recursive reference to itself.
            // Because the top-level ValueHandler.readValue call has not yet
            // returned a value, the ORB stream's indirection table contains no
            // entry for an object with the stream offset specified by the
            // indirection tag. This stream offset is returned in the
            // exception's offset field."

            throw new org.omg.CORBA.portable.IndirectionException (index);
        }
        else
            return (java.io.Serializable)value;
    }

    private String validateName (String name)
    {
        if (name != null && name.length() == 0)
        {
            return null;
        }
        return name;
    }

    private String validateID (String id)
    {
        if (id == null || id.length() == 0)
        {
            id = "IDL:";
        }
        return id;
    }


    /**
     * Reads an abstract interface from this stream. The abstract interface
     * Reads an abstract interface from this stream. The abstract interface
     * appears as a union with a boolean discriminator, which is true if the
     * union contains a CORBA object reference, or false if the union contains
     * a value.
     */

    public java.lang.Object read_abstract_interface()
    {
        return read_boolean() ? (java.lang.Object)read_Object()
        : (java.lang.Object)read_value();
    }

    /**
     * Reads an abstract interface from this stream. The abstract interface
     * appears as a union with a boolean discriminator, which is true if the
     * union contains a CORBA object reference, or false if the union contains
     * a value.
     */

    public java.lang.Object read_abstract_interface(final java.lang.Class clz)
    {
        return read_boolean() ? (java.lang.Object)read_Object(clz)
        : (java.lang.Object)read_value(clz);
    }


    public int get_pos()
    {
        return pos;
    }

    /**
     * Stores `value' into this stream's valueMap.  This is provided
     * as a callback for value factories, so that a value factory can
     * store an object into the map before actually reading its state.
     * This is essential for unmarshalling recursive values.
     */

    public void register_value(final java.io.Serializable value)
    {
        getValueMap().put(new Integer(currentValueIndex), value);
    }
}
TOP

Related Classes of org.jacorb.orb.CDRInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.