Package org.jacorb.orb

Source Code of org.jacorb.orb.CDROutputStream

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.*;
import java.util.*;

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

import org.jacorb.ir.RepositoryID;
import org.jacorb.orb.giop.CodeSet;
import org.jacorb.util.ValueHandler;
import org.jacorb.util.ObjectUtil;

import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CODESET_INCOMPATIBLE;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.TypeCodePackage.Bounds;
import org.omg.IOP.IOR;
import org.omg.IOP.IORHelper;
import org.omg.IOP.TaggedProfile;

/**
* @author Gerald Brose,  1999
* @version $Id: CDROutputStream.java,v 1.106 2006/05/17 13:14:37 alphonse.bendt Exp $
*
* A stream for CDR marshalling.
*
*/

public class CDROutputStream
    extends org.omg.CORBA_2_3.portable.OutputStream
{
    private final static IOR null_ior = new IOR("", new TaggedProfile[0]);

    /** needed for alignment purposes */
    private int index;

    /** the current write position in the buffer */
    private int pos;

    /** the number of bytes that will only make up the final buffer
        size, but that have not yet been written */
    private int deferred_writes;

    private BufferManager bufMgr;
    protected byte[] buffer;

    private boolean closed;

    /* character encoding code sets for char and wchar, default ISO8859_1 */
    private int codeSet =  CodeSet.getTCSDefault();
    private int codeSetW=  CodeSet.getTCSWDefault();

    private int encaps_start = -1;

    /**
     * <code>encaps_stack</code> is used to store encapsulations. Do NOT
     * access this variable directly. It is initialized on demand. Use the
     * method {@link #getEncapsStack() getEncapsStack()}
     */
    private Stack encaps_stack;

    /**
     * <code>recursiveTCMap</code> is used 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 initialised on demand. Use the method
     * {@link #getRecursiveTCMap() getRecursiveTCMap()}
     */
    private Map recursiveTCMap;

    /**
     * <code>valueMap</code> is used to maps all value objects that have
     * already been written to this stream to their position within the
     * buffer. The position is stored as a java.lang.Integer. Do NOT access
     * this variable directly. It is initialised on demand. Use the method
     * {@link #getValueMap() getValueMap()}
     */
    private Map valueMap;

    /**
     * <code>repIdMap</code> is used to map all repository ids that have already
     * been written to this stream to their position within the buffer.  The
     * position is stored as a java.lang.Integer. Do NOT access this variable
     * directly. It is initialised on demand. Use the method
     * {@link #getRepIdMap() getRepIdMap()}
     */
    private Map repIdMap;

    /**
     * <code>codebaseMap</code> is used to maps all codebase strings that have
     * already been written to this stream to their position within the buffer.
     * The position is stored as a java.lang.Integer. Do NOT access this variable
     * directly. It is initialised on demand. Use the method
     * {@link #getCodebaseMap() getCodebaseMap()}
     */
    private Map codebaseMap;

    /**
     * <code>cachedTypecodes</code> is used to cache compacted typecodes when
     * writing to the stream. This variable is initialised on demand.
     */
    private Map cachedTypecodes;

    /** Remembers the starting position of the current chunk. */
    private int chunk_size_tag_pos = -1;   // -1 means we're not within a chunk
    private int chunk_size_tag_index;
    private int chunk_octets_pos;

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

    /** Nesting level of calls write_value_internal */
    private int writeValueNestingLevel = 0;

    /** True if write_value_internal called writeReplace */
    private boolean writeReplaceCalled = false;

    private List deferredArrayQueue = new ArrayList();

    private org.omg.CORBA.ORB orb = null;

    protected int giop_minor = 2;

    /** The chunking flag is either 0 (no chunking) or 0x00000008 (chunking),
        to be bitwise or'ed into value tags. */
    private int chunkingFlag = 0;

    /** configurable properties */
    private boolean useBOM = false;
    private boolean chunkCustomRmiValuetypes = false;
    private int compactTypeCodes = 0;
    private boolean useIndirection = true;

    /**
     * This stream is self-configuring, i.e. configure() is private
     * and only called from the constructor
     *
     * TODO this led to situations were streams weren't configured properly
     * (see callers of configure) so i changed the method to be public.
     * should be fixed. alphonse 11.05.2006
     */

    public void configure(Configuration configuration)
        throws ConfigurationException
    {
        useBOM =
            configuration.getAttribute("jacorb.use_bom","off").equals("on");

        chunkCustomRmiValuetypes =
            configuration.getAttribute("jacorb.interop.chunk_custom_rmi_valuetypes","off").equals("on");
        compactTypeCodes =
            configuration.getAttributeAsInteger("jacorb.compactTypecodes", 0);

        useIndirection =
           !( configuration.getAttribute("jacorb.interop.indirection_encoding_disable","off").equals("on"));
    }

    private static class DeferredWriteFrame
    {
        public int write_pos = 0;
        public int start = 0;
        public int length = 0;
        public byte[] buf = null;

        public DeferredWriteFrame( int write_pos, int start,
                                   int length, byte[] buf )
        {
            this.write_pos = write_pos;
            this.start = start;
            this.length = length;
            this.buf = buf;
        }
    }


    /**
     * OutputStreams created using  the empty constructor are used for
     * in  memory marshaling, but do  not use the  ORB's output buffer
     * manager. A stream created with this c'tor is not explicitly
     * configured, i.e. it will use default configuration only
     */

    public CDROutputStream()
    {
        bufMgr = BufferManager.getInstance(); // the BufferManager will be configured by now!
        buffer = bufMgr.getPreferredMemoryBuffer();
    }

    /**
     * OutputStreams created using this constructor
     * are used also for in memory marshaling, but do use the
     * ORB's output buffer manager
     */
    public CDROutputStream(final org.omg.CORBA.ORB orb)
    {
        this();
        if (orb != null )
        {
            this.orb = orb;
            try
            {
                configure(((org.jacorb.orb.ORB)orb).getConfiguration());
            }
            catch( ConfigurationException ce )
            {
                throw new INTERNAL("ConfigurationException: " + ce);
            }
        }
    }

    /**
     *  Class constructor setting the buffer size for the message and
     *  the character encoding sets. A stream created with this c'tor
     *  is not explicitly configured, i.e. it will use default
     *  configuration only!
     */

    public CDROutputStream(final byte[] buf)
    {
        bufMgr = BufferManager.getInstance();
        buffer = buf;
    }

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


    /**
     * <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 is used to store 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 detect reference sharing when
     * marshaling valuetype instances.
     *
     * @return a <code>Map</code> value
     */
    private Map getValueMap()
    {
        if (valueMap == null)
        {
            valueMap = ObjectUtil.createIdentityHashMap();
        }
        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 indirections for Codebase
     * specifications.
     *
     * @return a <code>Map</code> value
     */
    private Map getCodebaseMap()
    {
        if (codebaseMap == null)
        {
            codebaseMap = new HashMap();
        }
        return codebaseMap;
    }


    /**
     * write the contents of this CDR stream to the output stream,
     * includes all deferred writes (e.g., for byte arrays)...
     * called by, e.g. GIOPConnection to write directly to the
     * wire.
     */

    public void write( OutputStream out, int start, int length )
        throws IOException
    {
        int write_idx = start;
        int read_idx = start;

        // needed to calculate the actual read position in the
        // current buffer,
        int skip_count = 0;

        int list_idx = 0;

        DeferredWriteFrame next_frame = null;

        if( deferredArrayQueue != null && deferredArrayQueue.size() > 0 )
        {
            // find the first frame that falls within the current window,
            // i.e. that need s to be written
            next_frame = (DeferredWriteFrame)deferredArrayQueue.get( list_idx++ );

            // skip all frames beginning before the current start pos, but
            // record their length
            while( next_frame.write_pos < start && list_idx < deferredArrayQueue.size() )
            {
                skip_count += next_frame.length;
                next_frame = (DeferredWriteFrame)deferredArrayQueue.get( list_idx++ );
            }

            // skip
            if( next_frame.write_pos < start && list_idx >= deferredArrayQueue.size() )
            {
                skip_count += next_frame.length;
                next_frame = null;
            }
        }

        while( write_idx < start + length )
        {

            if( next_frame != null && write_idx == next_frame.write_pos )
            {
                if ( ! (next_frame.length <= start + length - write_idx))
                {
                    throw new MARSHAL ("Deferred array does not fit");
                }

                // write a frame, i.e. a byte array
                out.write( next_frame.buf, next_frame.start, next_frame.length );

                // advance
                write_idx += next_frame.length;

                // clear the fram variable...
                next_frame = null;

                // and look up the next frame
                if( deferredArrayQueue != null &&
                    list_idx < deferredArrayQueue.size() )
                {
                    next_frame = (DeferredWriteFrame)deferredArrayQueue.get( list_idx++ );
                    if( next_frame.write_pos > start + length )
                    {
                        // unset, frame is beyond our current reach
                        next_frame = null;
                    }
                }
            }

            if( write_idx < start + length )
            {
                // write data that was previously marshaled

                int write_now =
                Math.min( start + length,
                          ( next_frame != null ? next_frame.write_pos : start + length ));

                write_now -= write_idx; // calculate length

                //
                out.write( buffer, read_idx-skip_count , write_now );

                // advance
                read_idx += write_now;
                write_idx += write_now;
            }
        }
    }

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

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

    public int getGIOPMinor()
    {
        return giop_minor;
    }

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

        bufMgr.returnBuffer( buffer, true );

        buffer = null;
        closed = true;
        if (deferredArrayQueue != null)
        {
            deferredArrayQueue.clear();
        }
        deferred_writes = 0;
    }

    /**
     * This version of check does both array length checking and
     * data type alignment. It is a convenience method.
     */
    private final void check(final int i, final int align)
    {
        int remainder = align - (index % align);

        check (i + remainder);

        if (remainder != align)
        {
            // Clear padding. Allowing for possible buffer end.
            int topad = Math.min (buffer.length - pos, 8);
            int j = 0;
            switch (topad)
            {
                case 8:
                buffer[pos + j++] = (byte)0;
                case 7:
                buffer[pos + j++] = (byte)0;
                case 6:
                buffer[pos + j++] = (byte)0;
                case 5:
                buffer[pos + j++] = (byte)0;
                case 4:
                buffer[pos + j++] = (byte)0;
                case 3:
                buffer[pos + j++] = (byte)0;
                case 2:
                buffer[pos + j++] = (byte)0;
                case 1:
                buffer[pos + j++] = (byte)0;
            }

            index += remainder;
            pos += remainder;
        }
    }

    /**
     * check whether the current buffer is big enough to receive
     * i more bytes. If it isn't, get a bigger buffer.
     */

    private final void check(final int i)
    {
        byte [] new_buf;

        if (buffer == null || (pos + i + 2) > buffer.length)
        {
            new_buf = bufMgr.getBuffer( pos+i+2, true);

            if (buffer != null)
            {
                System.arraycopy(buffer,0,new_buf,0,pos);
            }
            // Change buffer size so return the old one.
            bufMgr.returnBuffer (buffer, true);

            buffer = new_buf;
            new_buf = null;
        }
    }

    private final static void _write4int
       (final byte[] buf, final int _pos, final int value)
    {
        buf[_pos]   = (byte)((value >> 24) & 0xFF);
        buf[_pos+1] = (byte)((value >> 16) & 0xFF);
        buf[_pos+2] = (byte)((value >>  8) & 0xFF);
        buf[_pos+3] = (byte) (value        & 0xFF);
    }

    /**
     *  Start a CDR encapsulation. All subsequent writes
     *  will place data in the encapsulation until
     *  endEncapsulation is called. This will write
     *  the size of the encapsulation.
     */

    public final void beginEncapsulation()
    {
        // align to the next four byte boundary
        // as a preparation for writing the size
        // integer (which we don't know before the
        // encapsulation is closed)

        check(8,4);

        // leave 4 bytes for the encaps. size that
        // is to be written later

        pos += 4;
        index += 4;

        /* Because encapsulations can be nested, we need to
           remember the beginnning of the enclosing
           encapsulation (or -1 if we are in the outermost encapsulation)
           Also, remember the current index and the indirection maps because
           we need to restore these when closing the encapsulation */

        getEncapsStack().push
        (
            new EncapsInfo(index, encaps_start,
                           getValueMap(),
                           getRepIdMap(),
                           getCodebaseMap())
        );

        // set up new indirection maps for this encapsulation

        valueMap = ObjectUtil.createIdentityHashMap();
        repIdMap = new HashMap();
        codebaseMap = new HashMap();

        // the start of this encapsulation

        encaps_start = pos;
        beginEncapsulatedArray();
    }

    /**
     * Can be used locally for data type conversions
     * without preceeding call to beginEncapsulation, i.e.
     * without a leading long that indicates the size.
     */

    public final void beginEncapsulatedArray()
    {
        /* set the index for alignment to 0, i.e. align relative to the
           beginning of the encapsulation */
        resetIndex();

        // byte_order flag set to FALSE

        buffer[pos++] = 0;
        index++;
    }

    /**
     * Terminate the encapsulation by writing its length
     * to its beginning.
     */

    public final void endEncapsulation()
    {
        if( encaps_start == -1 )
            throw new MARSHAL("Too many end-of-encapsulations");
        if( encaps_stack == null )
        {
            throw new MARSHAL("Internal Error - closeEncapsulation failed");
        }

        // determine the size of this encapsulation

        int encaps_size = pos - encaps_start;

        // insert the size integer into the appropriate place

        buffer[encaps_start -4 = (byte)((encaps_size >>> 24) & 0xFF);
        buffer[encaps_start -3 ] = (byte)((encaps_size >>> 16) & 0xFF);
        buffer[encaps_start -2 ] = (byte)((encaps_size >>>  8) & 0xFF);
        buffer[encaps_start -1 ] = (byte)(encaps_size & 0xFF);

        /* restore index and encaps_start information and indirection maps */

        EncapsInfo ei = (EncapsInfo)getEncapsStack().pop();
        encaps_start = ei.start;
        index = ei.index + encaps_size;
        valueMap = ei.valueMap;
        repIdMap = ei.repIdMap;
        codebaseMap = ei.codebaseMap;
    }

    public byte[] getBufferCopy()
    {
        ByteArrayOutputStream bos =
            new ByteArrayOutputStream();

        try
        {
            write( bos, 0, size());
        }
        catch( IOException io )
        {
            //            Debug.output(1, io );
        }

        return bos.toByteArray();
    }

    private void resetIndex()
    {
        index = 0;
    }

    public int size()
    {
        return pos + deferred_writes;
    }

    public void reset()
    {
        if (deferredArrayQueue != null)
        {
            deferredArrayQueue.clear();
        }
        pos = 0;
        deferred_writes = 0;
        index = 0;
    }

    protected void finalize() throws Throwable
    {
        try
        {
            bufMgr.returnBuffer( buffer, true );
        }
        finally
        {
            super.finalize();
        }
    }

    public final void skip(final int step)
    {
        pos += step;
        index += step;
    }

    public final void reduceSize(final int amount)
    {
        pos -= amount;
    }

    /**
     * Add <tt>amount</tt> empty space
     */

    public final void increaseSize(final  int amount)
    {
        check( amount );

        pos += amount;
    }

    public void setBuffer(final byte[] b)
    {
        bufMgr.returnBuffer( buffer, true );

        buffer = b;

        reset();
    }

    // For appligator

    public void setBufferWithoutReset (byte[] b, int size)
    {
        close();
        buffer = b;
        pos = size;
    }

    /**************************************************
     * The following operations are from OutputStream *
     **************************************************/

    public org.omg.CORBA.portable.InputStream create_input_stream()
    {
        if (deferred_writes > 0)
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(index + 1);
            try
            {
                write(baos, 0, index);
            }
            catch (IOException e)
            {
                throw new MARSHAL(e.toString());
            }
            return new CDRInputStream(orb(), baos.toByteArray());
        }
        else
        {
            byte[] result = new byte[index + 1];
            System.arraycopy(buffer, 0, result, 0, result.length);
            return new CDRInputStream(orb, result);
        }
    }

    public final void write_any(final org.omg.CORBA.Any value)
    {
        write_TypeCode( value.type() );
        value.write_value( this ) ;
    }

    public final void write_boolean(final boolean value)
    {
        check(1);

        if( value )
            buffer[pos++] = 1;
        else
            buffer[pos++] = 0;
        index++;
    }

    public final void write_boolean_array
       (final boolean[] value, final int offset, final int length)
    {
        if (value != null )
        {
            //no alignment necessary
            check(length);

            for( int i = offset; i < offset+length; i++ )
            {
                if( value[i] )
                    buffer[pos++] = 1;
                else
                    buffer[pos++] = 0;
            }
            index += length;
        }
    }


    /**
     * Writes char according to specified encoding.
     */
    public final void write_char(final char c)
    {
        check( 1 );

        int too_large_mask =
            (codeSet == CodeSet.ISO8859_1)?
        0xFF00 : //ISO8859-1
        0xFF80; //UTF-8

        if( (c & too_large_mask) != 0 )//Are there any 1s in the MSB?
        {
            throw new org.omg.CORBA.DATA_CONVERSION(
                "char (" + c +
                ") out of range for " +
                CodeSet.csName( codeSet) );
        }

        index++;
        buffer[ pos++ ] = (byte) c;
    }

    public final void write_char_array
       (final char[] value, final int offset, final int length)
    {
        if( value == null )
            throw new MARSHAL( "Null References" );

        //no alignment necessary
        check( length );

        int too_large_mask =
            (codeSet == CodeSet.ISO8859_1)?
        0xFF00 : //ISO8859-1
        0xFF80; //UTF-8


        for( int i = offset; i < offset+length; i++)
        {
            if( (value[i] & too_large_mask) != 0 )
            {
                throw new MARSHAL("char (" + value[i] +
                                  ") out of range for " +
                                  CodeSet.csName( codeSet ));
            }

            buffer[ pos++ ] = (byte) value[i];
        }

        index += length;
    }

    public final void write_string(final String s)
    {
        if( s == null )
        {
            throw new MARSHAL("Null References");
        }

        // size leaves room for ulong, plus the string itself (3 bytes
        // per char in the string might be needed in the case of UTF-8
        // encoding), plus the terminating NUL char 
        int size = 4 + 3 * s.length() + 1;
        check( size, 4 );

        int sizepos = pos;
        pos += 4;
        index += 4;

        char ch;
        for (int i = 0; i < s.length(); i++)
            write_char_i(s.charAt(i),false,false, codeSet);

        buffer[ pos++ ] = (byte) 0; //terminating NUL char
        index ++;
        size = pos - (sizepos + 4); // compute translated size
        _write4int( buffer,sizepos,size);
    }

    public final void write_wchar(final char c)
    {
        check(3);
        write_char_i (c, useBOM, true, codeSetW);//with length indicator
    }

    // Used by both write_wchar/wstring and write_string
    private final void write_char_i (final char c,
                                     final boolean write_bom,
                                     final boolean write_length_indicator,
                                     final int cs)
    {
        // alignment/check must happen prior to calling.
        switch( cs )
        {
            case CodeSet.ISO8859_1 :
            {
                buffer[pos++] = (byte) c;
                index ++;
                break;
            }
            case CodeSet.UTF8 :
            {
                if( c <= 0x007F )
                {
                    if( giop_minor == 2 && write_length_indicator )
                    {
                        //the chars length in bytes
                        write_octet( (byte) 1 );
                    }

                    buffer[ pos++ ] = (byte) c;
                    index++;
                }
                else if( c > 0x07FF )
                {
                    if( giop_minor == 2 && write_length_indicator )
                    {
                        //the chars length in bytes
                        write_octet( (byte) 3 );
                    }

                    buffer[pos++]=(byte)(0xE0 | ((c >> 12) & 0x0F));
                    buffer[pos++]=(byte)(0x80 | ((c >>  6) & 0x3F));
                    buffer[pos++]=(byte)(0x80 | ((c >>  0) & 0x3F));

                    index += 3;
                }
                else
                {
                    if( giop_minor == 2 && write_length_indicator )
                    {
                        //the chars length in bytes
                        write_octet( (byte) 2 );
                    }

                    buffer[pos++]=(byte)(0xC0 | ((c >>  6) & 0x1F));
                    buffer[pos++]=(byte)(0x80 | ((c >>  0) & 0x3F));

                    index += 2;
                }
                break;
            }
            case CodeSet.UTF16 :
            {
                if( giop_minor == 2 )
                {
                    if( write_length_indicator )
                    {
                        //the chars length in bytes
                        write_octet( (byte) 2 );
                    }

                    if( write_bom )
                    {
                        //big endian encoding
                        buffer[ pos++ ] = (byte) 0xFE;
                        buffer[ pos++ ] = (byte) 0xFF;

                        index += 2;
                    }

                    //write unaligned
                    buffer[pos++] = (byte)((c >> 8) & 0xFF);
                    buffer[pos++] = (byte) (c       & 0xFF);
                    index += 2;
                }
                else
                {
                    //UTF-16 char is treated as an ushort (write aligned)
                    write_short( (short) c );
                }

                break;
            }
            default :
            {
                throw new CODESET_INCOMPATIBLE("Bad codeset: " + codeSet);
            }
        }
    }

    public final void write_wchar_array
       (final char[] value, final int offset, final int length)
    {
        if( value == null )
            throw new MARSHAL("Null References");

        check( length * 3 );

        for( int i = offset; i < offset+length; i++)
            write_wchar( value[i] );
    }

    public final void write_wstring(final String s)
    {
        if( s == null )
        {
            throw new MARSHAL("Null References");
        }

        //size ulong + no of bytes per char (max 3 if UTF-8) +
        //terminating NUL
        check( 4 + s.length() * 3 + 3, 4);

        int startPos = pos;         // store position for length indicator
        pos += 4;
        index += 4;                 // reserve for length indicator

        //the byte order marker
        if( giop_minor == 2 && useBOM && s.length() > 0)
        {
            //big endian encoding
            buffer[ pos++ ] = (byte) 0xFE;
            buffer[ pos++ ] = (byte) 0xFF;

            index += 2;
        }

        // write characters in current wide encoding, add null terminator
        for( int i = 0; i < s.length(); i++ )
        {
            write_char_i( s.charAt(i), false, false, codeSetW ); //no BOM
        }

        if( giop_minor < 2 )
        {
            //terminating NUL char
            write_char_i( (char)0, false, false, codeSetW ); //no BOM
        }

        int str_size = 0;
        if( giop_minor == 2 )
        {
            //size in bytes (without the size ulong)
            str_size = pos - startPos - 4;
        }
        else
        {
            if( codeSetW == CodeSet.UTF8 )
            {
                //size in bytes (without the size ulong)
                str_size = pos - startPos - 4;
            }
            else if( codeSetW == CodeSet.UTF16 )
            {
                //size in chars (+ NUL char)
                str_size = s.length() + 1;
            }
        }

        // write length indicator
        _write4int( buffer, startPos, str_size );
    }

    public final void write_double(final double value)
    {
        write_longlong (Double.doubleToLongBits (value));
    }

    public final void write_double_array
       (final double[] value, final int offset, final int length)
    {
        //if nothing has to be written, return, and especially DON'T
        //ALIGN
        if( length == 0 )
        {
            return;
        }

        /* align to 8 byte boundary */

        check(7 + length*8, 8);

        if( value != null )
        {
            for( int i = offset; i < offset+length; i++ )
            {
                long d = Double.doubleToLongBits(value[i]);
                buffer[pos]   = (byte)((d >>> 56) & 0xFF);
                buffer[pos+1] = (byte)((d >>> 48) & 0xFF);
                buffer[pos+2] = (byte)((d >>> 40) & 0xFF);
                buffer[pos+3] = (byte)((d >>> 32) & 0xFF);
                buffer[pos+4] = (byte)((d >>> 24) & 0xFF);
                buffer[pos+5] = (byte)((d >>> 16) & 0xFF);
                buffer[pos+6] = (byte)((d >>>  8) & 0xFF);
                buffer[pos+7] = (byte) (d & 0xFF);
                pos += 8;
            }
            index += 8*length;
        }
    }

    public final void write_fixed(final java.math.BigDecimal value)
    {
        //#ifjdk 1.2
        String v = value.unscaledValue().toString();
        //#else
        //# String v = value.movePointRight(value.scale()).toString();
        //#endif
        byte [] representation;
        int b, c;

        // Strip off any leading '-' from value to encode

        if (v.startsWith ("-"))
        {
            v = v.substring (1);
        }

        if( (v.length() %2) == 0)
        {
            representation = new byte[ v.length()/2 +1];
            representation[0] = 0x00;

            for( int i = 0; i < v.length(); i++ )
            {
                c = Character.digit(v.charAt(i), 10);
                b = representation[(1 + i)/2] << 4;
                b |= c;
                representation[(1 + i)/2] = (byte)b;
            }
        }
        else
        {
            representation = new byte[ (v.length()+1) /2];
            for( int i = 0; i < v.length(); i++ )
            {
                c = Character.digit(v.charAt(i), 10);
                b = representation[i/2] << 4;
                b |= c;
                representation[i/2] = (byte)b;
            }
        }
        b = representation[representation.length-1] << 4;

        representation[representation.length-1] =
            (byte)((value.signum() < 0 )? (b | 0xD) : (b | 0xC));

        check(representation.length);
        System.arraycopy(representation,0,buffer,pos,representation.length);
        index += representation.length;
        pos += representation.length;

    }

    public final void write_float(final float value)
    {
        write_long(Float.floatToIntBits(value));
    }

    public final void write_float_array
       (final float[] value, final int offset, final int length)
    {
        //if nothing has to be written, return, and especially DON'T
        //ALIGN
        if( length == 0 )
        {
            return;
        }

        /* align to 4 byte boundary */

        check(3 + length*4,4);

        if( value != null )
        {
            for( int i = offset; i < offset+length; i++ )
            {
                _write4int(buffer,pos, Float.floatToIntBits( value[i] ));
                pos += 4;
            }
            index += 4*length;
        }
    }

    public final void write_long(final int value)
    {
        check(7,4);

        _write4int(buffer,pos,value);

        pos += 4; index += 4;
    }

    public final void write_long_array
       (final int[] value, final int offset, final int length)
    {
        //if nothing has to be written, return, and especially DON'T
        //ALIGN
        if( length == 0 )
        {
            return;
        }

        /* align to 4 byte boundary */

        check(3 + length*4,4);


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

        if( value != null )
        {
            for( int i = offset; i < offset+length; i++ )
            {
                _write4int(buffer,pos,value[i]);
                pos += 4;
            }
            index += 4*length;
        }
    }

    public final void write_longlong(final long value)
    {
        check(15,8);

        buffer[pos]   = (byte)((value >>> 56) & 0xFF);
        buffer[pos+1] = (byte)((value >>> 48) & 0xFF);
        buffer[pos+2] = (byte)((value >>> 40) & 0xFF);
        buffer[pos+3] = (byte)((value >>> 32) & 0xFF);
        buffer[pos+4] = (byte)((value >>> 24) & 0xFF);
        buffer[pos+5] = (byte)((value >>> 16) & 0xFF);
        buffer[pos+6] = (byte)((value >>>  8) & 0xFF);
        buffer[pos+7] = (byte)(value & 0xFF);

        index += 8;
        pos += 8;
    }

    public final void write_longlong_array
       (final long[] value, final int offset, final int length)
    {
        //if nothing has to be written, return, and especially DON'T
        //ALIGN
        if( length == 0 )
        {
            return;
        }

        check(7 + length*8,8);

        if( value != null )
        {
            for( int i = offset; i < offset+length; i++ )
            {
                buffer[pos]   = (byte)((value[i] >>> 56) & 0xFF);
                buffer[pos+1] = (byte)((value[i] >>> 48) & 0xFF);
                buffer[pos+2] = (byte)((value[i] >>> 40) & 0xFF);
                buffer[pos+3] = (byte)((value[i] >>> 32) & 0xFF);
                buffer[pos+4] = (byte)((value[i] >>> 24) & 0xFF);
                buffer[pos+5] = (byte)((value[i] >>> 16) & 0xFF);
                buffer[pos+6] = (byte)((value[i] >>>  8) & 0xFF);
                buffer[pos+7] = (byte) (value[i] & 0xFF);
                pos += 8;
            }
            index += 8*length;
        }
    }

    public void write_Object(final org.omg.CORBA.Object value)
    {

        if( value == null )
        {
            IORHelper.write(this, null_ior );
        }
        else
        {
            if( value instanceof org.omg.CORBA.LocalObject )
                throw new MARSHAL("Attempt to serialize a locality-constrained object.");
            org.omg.CORBA.portable.ObjectImpl obj =
                (org.omg.CORBA.portable.ObjectImpl)value;
            IORHelper.write(this, ((Delegate)obj._get_delegate()).getIOR()  );
        }
    }

    ////////////////////////////////////////////// NEW!
    public void write_IOR(final IOR ior)
    {
        if( ior == null )
        {
            IORHelper.write(this, null_ior );
        }
        else
        {
            IORHelper.write(this, ior);
        }
    }
    ////////////////////////////////////////////// NEW!

    public final void write_octet(final byte value)
    {
        check(1);
        index++;
        buffer[pos++] = value;
    }

    public final void write_octet_array( final byte[] value,
                                         final int offset,
                                         final int length)
    {
        if( value != null )
        {
            if( length > 4000 )
            {
                deferredArrayQueue.add( new DeferredWriteFrame( index, offset, length, value ));
                index += length;
                deferred_writes += length;
            }
            else
            {
                check(length);
                System.arraycopy(value,offset,buffer,pos,length);
                index += length;
                pos += length;
            }
        }
    }

    public final void write_Principal(final org.omg.CORBA.Principal value)
    {
        throw new NO_IMPLEMENT ("Principal deprecated");
    }

    public final void write_short(final short value)
    {
        check(3,2);

        buffer[pos]   = (byte)((value >>  8) & 0xFF);
        buffer[pos+1] = (byte)(value & 0xFF);
        index += 2; pos+=2;
    }

    public final void write_short_array
       (final short[] value, final int offset, final int length)
    {
        //if nothing has to be written, return, and especially DON'T
        //ALIGN
        if( length == 0 )
        {
            return;
        }

        /* align to 2-byte boundary */

        check(2*length + 3);

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

        if( value != null )
        {
            for( int i = offset; i < offset+length; i++ )
            {
                buffer[pos]   = (byte)((value[i] >>>  8) & 0xFF);
                buffer[pos+1] = (byte)( value[i] & 0xFF);
                pos += 2;
            }
            index += 2*length;
        }
    }

    public final void write_TypeCode (org.omg.CORBA.TypeCode value)
    {
        String   id                   = null;
        org.omg.CORBA.TypeCode cached = null;

        try
        {
            // Get the id for this typecode.
            id = value.id();
        }
        // Masking on purpose as only determining whether to cache here.
        catch (BadKind e)
        {
        }

        if (compactTypeCodes > 0 && id != null)
        {
            if (cachedTypecodes == null)
            {
                cachedTypecodes = new HashMap();
            }
            else
            {
                // We may previously have already compacted and cached this
                // typecode.
                cached = (org.omg.CORBA.TypeCode)cachedTypecodes.get (id);
            }

            // If we don't have a cached value get the compact form and
            // cache it.
            if (cached == null)
            {
                value = value.get_compact_typecode();
                cachedTypecodes.put (id, value);
            }
            else
            {
                value = cached;
            }
        }
        write_TypeCode (value, null);
    }

    private final void writeRecursiveTypeCode
       (final org.omg.CORBA.TypeCode value, final Map tcMap) throws BadKind
    {
        write_long( -1 ); // recursion marker
        int negative_offset =
            ((Integer) tcMap.get( value.id())).intValue() - size() - 4;

        write_long( negative_offset );
    }

    private final void write_TypeCode
       (final org.omg.CORBA.TypeCode value, Map tcMap)
    {
        if (value == null)
        {
            throw new BAD_PARAM("TypeCode is null");
        }

        int _kind = value.kind().value();
        int _mc; // member count

        try
        {
            if( TypeCode.isRecursive(value) &&
                tcMap != null &&
                tcMap.containsKey( value.id()) )
            {
                writeRecursiveTypeCode( value, tcMap );
            }
            else
            {
                // regular TypeCodes
                switch( _kind )
                {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                    case 7:
                    case 8:
                    case 9:
                    case 10:
                    case 11:
                    case 12:
                    case 13:
                    case 23:
                    case 24:
                    case 25:
                    case 26:
                    write_long( _kind  );
                    break;
                    case TCKind._tk_objref:
                    write_long( _kind  );
                    beginEncapsulation();
                    write_string( value.id() );
                    write_string( value.name() );
                    endEncapsulation();
                    break;
                    case TCKind._tk_struct:
                    case TCKind._tk_except:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id(), value );

                        beginEncapsulation();
                        write_string(value.id());
                        write_string(value.name());
                        _mc = value.member_count();
                        write_long(_mc);
                        for( int i = 0; i < _mc; i++)
                        {
                            write_string( value.member_name(i) );
                            write_TypeCode( value.member_type(i), tcMap );
                        }
                        endEncapsulation();
                    }
                    break;
                    case TCKind._tk_enum:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id(), value );

                        beginEncapsulation();
                        write_string( value.id());
                        write_string( value.name());
                        _mc = value.member_count();
                        write_long(_mc);
                        for( int i = 0; i < _mc; i++)
                        {
                            write_string( value.member_name(i) );
                        }
                        endEncapsulation();
                    }
                    break;
                    case TCKind._tk_union:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id() , value );

                        beginEncapsulation();
                        write_string( value.id() );
                        write_string( value.name() );

                        write_TypeCode( value.discriminator_type());
                        write_long( value.default_index());
                        _mc = value.member_count();
                        write_long(_mc);
                        for( int i = 0; i < _mc; i++)
                        {
                            if( i == value.default_index() )
                            {
                                write_octet((byte)0);
                            }
                            else
                            {
                                value.member_label(i).write_value( this );
                            }
                            write_string( value.member_name(i));
                            write_TypeCode( value.member_type(i), tcMap );
                        }
                        endEncapsulation();
                    }
                    break;
                    case TCKind._tk_wstring:
                    case TCKind._tk_string:
                    write_long( _kind  );
                    write_long(value.length());
                    break;
                    case TCKind._tk_fixed:
                    write_long( _kind  );
                    write_ushort( value.fixed_digits() );
                    write_short( value.fixed_scale() );
                    break;
                    case TCKind._tk_array:
                    case TCKind._tk_sequence:
                    write_long( _kind  );
                    beginEncapsulation();
                    write_TypeCode( value.content_type(), tcMap);
                    write_long(value.length());
                    endEncapsulation();
                    break;
                    case TCKind._tk_alias:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id(), value );

                        beginEncapsulation();
                        write_string(value.id());
                        write_string(value.name());
                        write_TypeCode( value.content_type(), tcMap);
                        endEncapsulation();
                    }
                    break;
                    case TCKind._tk_value:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id(), value );

                        beginEncapsulation();
                        write_string(value.id());
                        write_string(value.name());
                        write_short( value.type_modifier() );
                        org.omg.CORBA.TypeCode base = value.concrete_base_type();
                        if (base != null)
                            write_TypeCode(base, tcMap);
                        else
                            write_long (TCKind._tk_null);
                        _mc = value.member_count();
                        write_long(_mc);
                        for( int i = 0; i < _mc; i++)
                        {
                            write_string( value.member_name(i) );
                            write_TypeCode( value.member_type(i), tcMap );
                            write_short( value.member_visibility(i) );
                        }
                        endEncapsulation();
                    }
                    break;
                    case TCKind._tk_value_box:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id(), value );

                        beginEncapsulation();
                        write_string(value.id());
                        write_string(value.name());
                        write_TypeCode( value.content_type(), tcMap);
                        endEncapsulation();
                    }
                    break;
                    case TCKind._tk_abstract_interface:
                    if (useIndirection && tcMap != null &&
                        tcMap.containsKey (value.id()))
                    {
                        writeRecursiveTypeCode( value, tcMap );
                    }
                    else
                    {
                        write_long( _kind  );
                        if (tcMap == null)
                        {
                            tcMap = new HashMap();
                        }
                        tcMap.put( value.id(), new Integer( pos ) );
                        getRecursiveTCMap().put( value.id(), value );

                        beginEncapsulation();
                        write_string(value.id());
                        write_string(value.name());
                        endEncapsulation();
                    }
                    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 final void write_ulong(final int value)
    {
        write_long (value);
    }

    public final void write_ulong_array
       (final int[] value, final int offset, final int length)
    {
        write_long_array (value, offset, length);
    }

    public final void write_ulonglong(final long value)
    {
        write_longlong (value);
    }

    public final void write_ulonglong_array
       (final long[] value, final int offset, final int length)
    {
        write_longlong_array (value, offset, length);
    }

    public final void write_ushort(final short value)
    {
        write_short (value);
    }

    public final void write_ushort_array
       (final short[] value, final int offset, final int length)
    {
        write_short_array (value, offset, length);
    }

    /**
     * Reads a value of the type indicated by <code>tc</code> from the
     * InputStream <code>in</code> and remarshals it to this CDROutputStream.
     * Called from Any.
     */
    public final void write_value ( final org.omg.CORBA.TypeCode tc,
                                    final org.omg.CORBA.portable.InputStream in )
    {
        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:
                write_boolean( in.read_boolean());
                break;
                case TCKind._tk_char:
                write_char( in.read_char());
                break;
                case TCKind._tk_wchar:
                write_wchar( in.read_wchar());
                break;
                case TCKind._tk_octet:
                write_octet( in.read_octet());
                break;
                case TCKind._tk_short:
                write_short( in.read_short());
                break;
                case TCKind._tk_ushort:
                write_ushort(in.read_ushort());
                break;
                case TCKind._tk_long:
                write_long( in.read_long());
                break;
                case TCKind._tk_ulong:
                write_ulong( in.read_ulong());
                break;
                case TCKind._tk_float:
                write_float( in.read_float());
                break;
                case TCKind._tk_double:
                write_double(in.read_double());
                break;
                case TCKind._tk_longlong:
                write_longlong(in.read_longlong());
                break;
                case TCKind._tk_ulonglong:
                write_ulonglong( in.read_ulonglong());
                break;
                case TCKind._tk_any:
                write_any( in.read_any());
                break;
                case TCKind._tk_TypeCode:
                write_TypeCode(in.read_TypeCode());
                break;
                case TCKind._tk_Principal:
                throw new NO_IMPLEMENT ("Principal deprecated");
                case TCKind._tk_objref:
                write_Object( in.read_Object());
                break;
                case TCKind._tk_string:
                write_string( in.read_string());
                break;
                case TCKind._tk_wstring:
                write_wstring( in.read_wstring());
                break;
                case TCKind._tk_fixed:
                write_fixed (in.read_fixed());
                break;
                case TCKind._tk_array:
                {
                    int length = tc.length();
                    if( tc.content_type().kind().value() == TCKind._tk_octet )
                    {
                        check( length );
                        in.read_octet_array( buffer, pos, length);
                        index+= length;
                        pos += length;
                    }
                    else
                    {
                        for( int i = 0; i < length; i++ )
                            write_value( tc.content_type(), in );
                    }
                    break;
                }
                case TCKind._tk_sequence:
                {
                    int len = in.read_long();
                    write_long(len);

                    org.omg.CORBA.TypeCode content_tc = tc.content_type();
                    for( int i = 0; i < len; i++ )
                        write_valuecontent_tc, in );

                    break;
                }
                case TCKind._tk_except:
                write_string( in.read_string());
                // don't break, fall through to ...
                case TCKind._tk_struct:
                {
                    for( int i = 0; i < tc.member_count(); i++)
                        write_value( tc.member_type(i), in );
                    break;
                }
                case TCKind._tk_enum:
                {
                    write_long( in.read_long() );
                    break;
                }
                case TCKind._tk_union:
                {
                    org.omg.CORBA.TypeCode disc =
                        (org.omg.CORBA.TypeCode) 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 = in.read_short();
                            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_ushort:
                        {
                            short s = in.read_ushort();
                            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_long:
                        {
                            int s = in.read_long();
                            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_ulong:
                        {
                            int s = in.read_ulong();
                            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 = in.read_longlong();
                            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 = in.read_ulonglong();
                            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_boolean:
                        {
                            boolean s = in.read_boolean();
                            write_boolean(s);
                            for(int i = 0 ; i < tc.member_count() ; i++)
                            {
                                if(i != def_idx)
                                {
                                    if(s == tc.member_label(i).extract_boolean())
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_enum:
                        {
                            int s = in.read_long();
                            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();
                                    /*  we  have to  use  the any's  input
                                        stream   because   enums  are   not
                                        inserted as longs */

                                    if( s == label)
                                    {
                                        member_idx = i;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                        case TCKind._tk_char:
                        {
                            char s = in.read_char();
                            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;
                        }
                        default:
                        throw new MARSHAL("Invalid union discriminator type: " + disc);
                    }

                    // write the member or default value, if any
                    // (if the union has no explicit default but the
                    // the case labels do not cover the range of
                    // possible discriminator values, there may be
                    // several "implicit defaults" without associated
                    // union values.

                    if( member_idx != -1 )
                    {
                        write_value( tc.member_type( member_idx ), in );
                    }
                    else if( def_idx != -1 )
                    {
                        write_value( tc.member_type( def_idx ), in );
                    }
                    break;
                }
                case TCKind._tk_alias:
                {
                    write_value( tc.content_type(), in );
                    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 RuntimeException
                            ("No BoxedValueHelper for id " + id);
                    java.io.Serializable value =
                        ((org.omg.CORBA_2_3.portable.InputStream)in).read_value(helper);
                    write_value (value, helper);
                    break;
                }
                case 0xffffffff:
                {
                    org.omg.CORBA.TypeCode _tc =
                        (org.omg.CORBA.TypeCode)( getRecursiveTCMap().get( tc.id() ) );
                    if( _tc == null )
                    {
                        throw new MARSHAL("Recursive TypeCode not found for " + tc.id());
                    }
                    write_value( _tc , in );
                    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);
        }
    }

    /**
     * Writes the serialized state of `value' to this stream.
     */

    public void write_value(final java.io.Serializable value)
    {
        if (!write_special_value (value))
            write_value_internal (value,
                                  ValueHandler.getRMIRepositoryID (value.getClass()));
    }

    public void write_value(final java.io.Serializable value,
                             final org.omg.CORBA.portable.BoxedValueHelper factory)
    {
        if (!write_special_value (value))
        {
            check(7,4);
            getValueMap().put (value, new Integer(pos));
            write_previous_chunk_size();
            if ((value instanceof org.omg.CORBA.portable.IDLEntity) ||
                (value instanceof java.lang.String))
                write_long (0x7fffff00 | chunkingFlag);
            else
            {
                // repository id is required for RMI: types
                write_long (0x7fffff02 | chunkingFlag);
                write_repository_id (RepositoryID.repId (value.getClass()));
            }
            start_chunk();
            factory.write_value (this, value);
            end_chunk();
        }
    }

    public void write_value(final java.io.Serializable value,
                             final java.lang.Class clz)
    {
        if (!write_special_value (value))
        {
            Class c = value.getClass();
            String repId = ValueHandler.getRMIRepositoryID(c);
            if (c == clz && !repId.startsWith("RMI:"))
                // the repository id is required for "RMI:" valuetypes
                write_value_internal (value, null);
            else if (clz.isInstance (value))
                write_value_internal (value, repId);
            else
                throw new BAD_PARAM();
        }
    }

    public void write_value(final java.io.Serializable value,
                             final String repository_id)
    {
        if (!write_special_value (value))
            write_value_internal (value, repository_id);
    }

    /**
     * If `value' is null, or has already been written to this stream,
     * then this method writes that information to the stream and returns
     * true, otherwise does nothing and returns false.
     */
    private boolean write_special_value(final java.io.Serializable value)
    {
        if (value == null)
        {
            // null tag
            write_long (0x00000000);
            return true;
        }
        else
        {
            Integer index = (Integer)getValueMap().get (value);
            if (index != null)
            {

                // value has already been written -- make an indirection
                write_long (0xffffffff);
                write_long (index.intValue() - size());
                return true;
            }
            else
                return false;
        }
    }

    /**
     * Writes `repository_id' to this stream, perhaps via indirection.
     */
    private void write_repository_id(final String repository_id)
    {
        Integer _index = (Integer)getRepIdMap().get (repository_id);
        if ( _index == null)
        {
            // a new repository id -- write it

            // first make sure the pos we're about to remember is
            // a correctly aligned one, i.e., the actual writing position
            int remainder = 4 - (index % 4);
            if ( remainder != 4 )
            {
                index += remainder;
                pos += remainder;
            }

            getRepIdMap().put (repository_id, new Integer(pos));
            write_string (repository_id);
        }
        else
        {
            // a previously written repository id -- make an indirection
            write_long (0xffffffff);
            write_long (_index.intValue() - size());
        }
    }

    /**
     * Writes `codebase' to this stream, perhaps via indirection.
     */
    private void write_codebase(final String codebase)
    {
        Integer _index = null;
        if (codebaseMap == null)
        {
            codebaseMap = new HashMap();
        }
        else
        {
            _index = (Integer)getCodebaseMap().get (codebase);
        }
        if ( _index == null)
        {
            // a new codebase -- write it#

            // first make sure the pos we're about to remember is
            // a correctly aligned one
            int remainder = 4 - (index % 4);
            if ( remainder != 4 )
            {
                index += remainder;
                pos += remainder;
            }

            getCodebaseMap().put (codebase, new Integer(pos));
            write_string (codebase);
        }
        else
        {
            // a previously written codebase -- make an indirection
            write_long (0xffffffff);
            write_long (_index.intValue() - size());
        }
    }

    /**
     * Writes to this stream a value header with the specified `repository_id'
     * and no codebase string.
     */
    private void write_value_header(final String[] repository_ids)
    {
        write_previous_chunk_size();
        if (repository_ids != null)
        {
            if( repository_ids.length > 1 )
            {
                // truncatable value type, must use chunking!

                chunkingFlag = 0x00000008;
                write_long (0x7fffff06 | chunkingFlag);
                write_long( repository_ids.length );
                for( int i = 0; i < repository_ids.length; i++ )
                {
                    write_repository_id (repository_ids[i]);
                }
            }
            else
            {
                write_long (0x7fffff02 | chunkingFlag);
                write_repository_id (repository_ids[0]);
            }
        }
        else
            write_long (0x7fffff00 | chunkingFlag);
    }

    /**
     * Writes to this stream a value header with the specified `repository_id'.
     * and `codebase' string.
     */

    private void write_value_header
       (final String[] repository_ids, final String codebase)
    {
        if (codebase != null)
        {
            write_previous_chunk_size();
            if ( repository_ids != null )
            {
                if( repository_ids.length > 1 )
                {
                    // truncatable value type, must use chunking!

                    chunkingFlag = 0x00000008;
                    write_long (0x7fffff07 | chunkingFlag);
                    write_codebase(codebase);
                    write_long( repository_ids.length );

                    for( int i = 0; i < repository_ids.length; i++ )
                    {
                        write_repository_id (repository_ids[i]);
                    }
                }
                else
                {
                    write_long (0x7fffff03 | chunkingFlag);
                    write_codebase(codebase);
                    write_repository_id (repository_ids[0]);
                }
            }
            else
            {
                write_long (0x7fffff01 | chunkingFlag);
                write_codebase(codebase);
            }
        }
        else
            write_value_header (repository_ids);
    }

    /**
     * This method does the actual work of writing `value' to this
     * stream.  If `repository_id' is non-null, then it is used as
     * the type information for `value' (possibly via indirection).
     * If `repository_id' is null, `value' is written without
     * type information.
     * Note: This method does not check for the special cases covered
     * by write_special_value().
     */
    private void write_value_internal(final java.io.Serializable value,
                                       final String repository_id)
    {
        check(7,4);
        getValueMap().put(value, new Integer(pos));

        if (value.getClass() == String.class)
        {
            // special handling for strings required according to spec
            String[] repository_ids =
                (repository_id == null) ? null : new String[]{ repository_id };
            write_value_header(repository_ids);
            start_chunk();
            write_wstring((String)value);
            end_chunk();
        }
        else if (value.getClass() == Class.class)
        {
            String[] repository_ids = new String[] {
                    ValueHandler.getRMIRepositoryID(javax.rmi.CORBA.ClassDesc.class)
            };
            write_value_header(repository_ids);
            start_chunk();
            write_value(ValueHandler.getCodebase((Class)value));
            write_value(ValueHandler.getRMIRepositoryID((Class)value));
            end_chunk();
        }
        else if (value instanceof org.omg.CORBA.portable.StreamableValue)
        {
            org.omg.CORBA.portable.StreamableValue streamable =
                (org.omg.CORBA.portable.StreamableValue)value;

            write_value_header( streamable._truncatable_ids() );
            start_chunk();
            ((org.omg.CORBA.portable.StreamableValue)value)._write(this);
            end_chunk();
        }
        else if (value instanceof org.omg.CORBA.portable.CustomValue )
        {
            org.omg.CORBA.DataOutputStream outputStream = new DataOutputStream( this );

            write_value_header
                ( ((org.omg.CORBA.portable.CustomValue )value )._truncatable_ids() );
            ( ( org.omg.CORBA.portable.CustomValue ) value ).marshal( outputStream );
        }
        else
        {
            String[] repository_ids =
                (repository_id == null) ? null : new String[]{ repository_id };
            Class cls = value.getClass();
            String codebase = ValueHandler.getCodebase(cls);
            if (value instanceof org.omg.CORBA.portable.IDLEntity)
            {
                java.lang.reflect.Method writeMethod = null;
                if (cls != org.omg.CORBA.Any.class)
                {
                    String helperClassName = cls.getName() + "Helper";

                    try
                    {
                        Class helperClass =
                            (cls.getClassLoader() != null)
                                ? cls.getClassLoader().loadClass(helperClassName)
                                : ObjectUtil.classForName(helperClassName);

                        Class[] paramTypes =
                            { org.omg.CORBA.portable.OutputStream.class, cls };
                        writeMethod = helperClass.getMethod("write", paramTypes);
                    }
                    catch (ClassNotFoundException e)
                    {
                        throw new MARSHAL("Error loading class " + helperClassName
                                          + ": " + e);
                    }
                    catch (NoSuchMethodException e)
                    {
                        throw new MARSHAL("No write method in helper class "
                                          + helperClassName + ": " + e);
                    }
                }
                write_value_header( repository_ids, codebase );
                start_chunk();
                if (writeMethod == null)
                {
                    write_any((org.omg.CORBA.Any)value);
                }
                else
                {
                    try
                    {
                        writeMethod.invoke(null, new Object[] { this, value });
                    }
                    catch (IllegalAccessException e)
                    {
                        throw new MARSHAL("Internal error: " + e);
                    }
                    catch (java.lang.reflect.InvocationTargetException e)
                    {
                        throw new MARSHAL("Exception marshaling IDLEntity: "
                                          + e.getTargetException());
                    }
                }
                end_chunk();

            }
            else
            {
                try
                {
                    writeValueNestingLevel++;
                    if (chunkCustomRmiValuetypes
                        && ValueHandler.isCustomMarshaled(cls))
                        chunkingFlag = 0x00000008;
                    write_value_header( repository_ids, codebase );
                    start_chunk();
                    if (!writeReplaceCalled)
                    {
                        // writeReplace must be called only once for this value
                        java.io.Serializable newValue =
                            ValueHandler.writeReplace(value);
                        writeReplaceCalled = true; // won't call it again

                        if (newValue != value)
                        {
                            // look at the new value
                            Integer index = (Integer)getValueMap().get(newValue);
                            if (index != null)
                            {
                                // previously marshaled value -- make an indirection
                                write_long (0xffffffff);
                                write_long (index.intValue() - size());
                            }
                            else if (value instanceof org.omg.CORBA.Object)
                            {
                                write_Object((org.omg.CORBA.Object)newValue);
                            }
                            else
                            {
                                ValueHandler.writeValue(this, newValue);
                            }
                        }
                        else
                        {
                            // writeReplace did't make a difference
                            ValueHandler.writeValue(this, value);
                        }
                    }
                    else
                    {
                        // Skip writeReplace call
                        // (writeReplace was already called for this value)
                        ValueHandler.writeValue(this, value);
                    }
                    end_chunk();
                }
                finally
                {
                    if (--writeValueNestingLevel == 0)
                        writeReplaceCalled = false;
                }
            }
        }
    }

    /**
     * start a new chunk, end any previously started chunk (no nesting!)
     */

    private void start_chunk()
    {
        if (chunkingFlag > 0)
        {
            write_previous_chunk_size();
            valueNestingLevel++;
            skip_chunk_size_tag();
        }
    }

    private void end_chunk()
    {
        if (chunkingFlag > 0)
        {
            write_previous_chunk_size();
            write_long(-valueNestingLevel);
            if ( --valueNestingLevel == 0 )
            {
                // ending chunk for outermost value
                chunkingFlag = 0;
            }
            else
            {
                // start continuation chunk for outer value
                skip_chunk_size_tag();
            }
        }
    }


    /**
     * writes the chunk size to the header of the previous chunk
     */
    private void write_previous_chunk_size()
    {
        if( chunk_size_tag_pos != -1 )
        {
            if ( pos == chunk_octets_pos)
            {
                // empty chunk: erase chunk size tag
                pos = chunk_size_tag_pos;      // the tag will be overwritten
                index = chunk_size_tag_index;  //            by subsequent data
            }
            else
            {
                rewrite_long(chunk_size_tag_pos,
                             chunk_size_tag_index,
                             pos - chunk_octets_pos);
            }
            chunk_size_tag_pos = -1; // no chunk is currently open
        }
    }

    private void skip_chunk_size_tag()
    {
        // remember where we are right now,
        chunk_size_tag_pos = pos;
        chunk_size_tag_index = index;

        // insert four bytes here as a place-holder
        write_long( 0 ); // need to go back later and write the actual size

        // remember starting position of chunk data
        chunk_octets_pos = pos;
    }

    /**
     * Writes a CORBA long value to (write_pos, write_index) without clearing
     * the buffer padding. In the case of a non-sequential write, clearing
     * buffer positions after the data just written is likely to erase data
     * previously written.
     */
    private final void rewrite_long(int write_pos,
                                    int write_index,
                                    final int value)
    {
        final int align = 4;
        int remainder = align - (write_index % align);
        if (remainder != align)
        {
            write_index += remainder;
            write_pos += remainder;
        }
        _write4int(buffer, write_pos, value);
    }

    /**
     * Writes an abstract interface to this stream. The abstract interface is
     * written 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 void write_abstract_interface(final java.lang.Object object)
    {
        if (object instanceof org.omg.CORBA.Object)
        {
            write_boolean(true);
            write_Object((org.omg.CORBA.Object)object);
        }
        else
        {
            write_boolean(false);
            write_value((java.io.Serializable)object);
        }
    }
}
TOP

Related Classes of org.jacorb.orb.CDROutputStream

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.