package org.jacorb.orb;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* 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.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.jacorb.config.Configuration;
import org.jacorb.config.ConfigurationException;
import org.jacorb.orb.giop.GIOPConnection;
import org.jacorb.orb.typecode.DelegatingTypeCodeWriter;
import org.jacorb.orb.typecode.TypeCodeCompactor;
import org.jacorb.util.ObjectUtil;
import org.jacorb.util.ValueHandler;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.DATA_CONVERSION;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.StringValueHelper;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.WStringValueHelper;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.TypeCodePackage.Bounds;
import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA.portable.ValueOutputStream;
import org.omg.IOP.IOR;
import org.omg.IOP.IORHelper;
import org.omg.IOP.TaggedProfile;
/**
* @author Gerald Brose
*
* A stream for CDR marshalling.
*
*/
public class CDROutputStream
extends org.omg.CORBA_2_3.portable.OutputStream implements CodeSet.OutputBuffer, ValueOutputStream
{
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;
private final IBufferManager bufMgr;
protected byte[] buffer;
private boolean closed;
/* character encoding code sets for char and wchar, default ISO8859_1 */
private CodeSet codeSet;
private CodeSet codeSetW;
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 ArrayDeque<EncapsInfo> encaps_stack;
/**
* <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;
/**
* This Map is basically a one-entry map pool to be used in
* write_TypeCode() as the repeatedTCMap.
*/
private Map repeatedTCMap;
/**
* This Map is basically a one-entry map pool to be used in
* write_TypeCode() as the recursiveTCMap.
*/
private Map recursiveTCMap;
/** 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;
protected final org.jacorb.orb.ORBSingleton orb;
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;
/**
* <code>mutator</code> is a pluggable IOR mutator.
*/
private IORMutator mutator;
private boolean isMutatorEnabled;
/**
* <code>codesetEnabled</code> denotes whether codeset marshalling is enabled.
*/
private boolean codesetEnabled;
/** configurable properties */
private boolean useBOM = false;
private boolean chunkCustomRmiValuetypes = false;
private boolean useIndirection = true;
private boolean nullStringEncoding;
// by default stream version is 1 for GIOP v1.2 messages
private byte maxStreamFormatVersion = ValueHandler.STREAM_FORMAT_VERSION_1;
private final TypeCodeCompactor typeCodeCompactor;
private final static DelegatingTypeCodeWriter typeCodeWriter = new DelegatingTypeCodeWriter();
/**
* size selecting c'tor
* @param orb must be a JacORB ORB
* @param bufferSize -1 to fetch the default buffer size,
* value > 0 to specify a specific size
*/
public CDROutputStream(org.omg.CORBA.ORB orb, int bufferSize)
{
super();
if (! (orb instanceof ORBSingleton))
{
throw new BAD_PARAM("don't pass in a non JacORB ORB");
}
this.orb = (ORBSingleton) orb;
bufMgr = this.orb.getBufferManager();
typeCodeCompactor = this.orb.getTypeCodeCompactor();
try
{
configure(((ORBSingleton)orb).getConfiguration());
}
catch(ConfigurationException e)
{
throw new INTERNAL(e.getMessage());
}
if (bufferSize == -1)
{
buffer = bufMgr.getPreferredMemoryBuffer();
}
else
{
buffer = bufMgr.getBuffer(bufferSize);
}
}
/**
* 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(orb, -1);
}
/**
* OutputStreams created using the empty constructor are used for
* in memory marshaling. A stream created with this c'tor is not explicitly
* configured, i.e. it will use default configuration only
*/
public CDROutputStream()
{
this(org.omg.CORBA.ORBSingleton.init());
}
@Override
public org.omg.CORBA.ORB orb()
{
return orb;
}
/**
* This stream is self-configuring, i.e. configure() is private
* and only called from the constructor
*/
private void configure(Configuration configuration) throws ConfigurationException
{
codesetEnabled = configuration.getAttributeAsBoolean ("jacorb.codeset", true);
useBOM = configuration.getAttributeAsBoolean("jacorb.use_bom",false);
chunkCustomRmiValuetypes = configuration.getAttributeAsBoolean("jacorb.interop.chunk_custom_rmi_valuetypes", false);
useIndirection = !( configuration.getAttributeAsBoolean("jacorb.interop.indirection_encoding_disable", false));
nullStringEncoding =
configuration.getAttributeAsBoolean("jacorb.interop.null_string_encoding", false);
mutator = (IORMutator) configuration.getAttributeAsObject("jacorb.iormutator");
isMutatorEnabled = (mutator != null);
maxStreamFormatVersion = (byte) configuration.getAttributeAsInteger("jacorb.interop.maximum_stream_format_version", 1);
codeSet = orb.getTCSDefault();
codeSetW = orb.getTCSWDefault();
}
/**
* <code>getEncapsStack</code> is used to initialize encaps_stack
* on demand.
*
* @return a <code>ArrayDeque</code> value
*/
private ArrayDeque<EncapsInfo> getEncapsStack()
{
if (encaps_stack == null)
{
encaps_stack = new ArrayDeque<EncapsInfo>();
}
return encaps_stack;
}
/**
* Gets the Map that is used to detect reference sharing when
* marshaling valuetype instances.
*
* @return a <code>Map</code> value
*/
private Map<Serializable, Integer> getValueMap()
{
if (valueMap == null)
{
valueMap = new IdentityHashMap<Serializable, Integer>();
}
return valueMap;
}
/**
* Gets the Map that is used to implement indirections for RepositoryIDs.
*
* @return a <code>Map</code> value
*/
private Map<String, Integer> getRepIdMap()
{
if (repIdMap == null)
{
repIdMap = new HashMap<String, Integer>();
}
return repIdMap;
}
/**
* Gets the Map that is used to implement indirections for Codebase
* specifications.
*
* @return a <code>Map</code> value
*/
private Map<String, Integer> getCodebaseMap()
{
if (codebaseMap == null)
{
codebaseMap = new HashMap<String, Integer>();
}
return codebaseMap;
}
/**
* write the contents of this CDR stream to the output stream
* called by, e.g. GIOPConnection to write directly to the
* wire.
*/
public void write( OutputStream out, int start, int length )
throws IOException
{
if( start < start + length )
{
out.write( buffer, start, length );
}
}
public void setCodeSets(CodeSet codeSet, CodeSet 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;
}
@Override
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;
}
/**
* This version of check does both array length checking and
* data type alignment. It is a convenience method.
*/
public final void check(final int i, final int align)
{
final int remainder = align - (index % align);
check (i + remainder);
if (remainder != align)
{
// Clear padding. Allowing for possible buffer end.
final int blp = buffer.length - pos;
final int topad = (blp <= 8 ? blp : 8);
Arrays.fill(buffer, pos, pos + topad, (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)
{
final int requiredSize = pos + i + 2;
if (buffer == null || requiredSize > buffer.length)
{
final byte[] new_buf = bufMgr.getExpandedBuffer(requiredSize);
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;
}
}
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 = new IdentityHashMap();
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 */
index = 0;
// 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 = getEncapsStack().pop();
encaps_start = ei.start;
index = ei.index + encaps_size;
valueMap = ei.valueMap;
repIdMap = ei.repIdMap;
codebaseMap = ei.codebaseMap;
}
public byte[] getBufferCopy()
{
final ByteArrayOutputStream bos =
new ByteArrayOutputStream(size());
try
{
write( bos, 0, size());
}
catch( IOException e )
{
throw new INTERNAL("should not happen: " + e.toString());
}
return bos.toByteArray();
}
public int size()
{
return pos;
}
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;
}
/**
* Replace existing buffer by a new one and reset indices.
*
* @param b the new buffer
*/
public void setBuffer(final byte[] b)
{
bufMgr.returnBuffer( buffer, true );
buffer = b;
pos = 0;
index = 0;
}
/**
* Give up the buffer to the caller and mark the stream closed. It is
* up to the caller to eventually return the buffer to the manager.
*/
public byte[] releaseBuffer ()
{
byte [] retn = buffer;
buffer = null;
close ();
return retn;
}
/**************************************************
* The following operations are from OutputStream *
**************************************************/
@Override
public org.omg.CORBA.portable.InputStream create_input_stream()
{
final byte[] result = new byte[index];
System.arraycopy(buffer, 0, result, 0, result.length);
return new CDRInputStream(orb, result);
}
@Override
public final void write_any(final org.omg.CORBA.Any value)
{
if( value == null )
{
throw new MARSHAL("Cannot marshall null value.");
}
write_TypeCode( value.type() );
value.write_value( this ) ;
}
@Override
public final void write_boolean(final boolean value)
{
check(1);
if( value )
{
buffer[pos++] = 1;
}
else
{
buffer[pos++] = 0;
}
index++;
}
@Override
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;
}
}
/**
* <code>write_char</code> writes a character to the output stream. If
* codeset translation is active then it will use String and an encoding to
* get the bytes. It can then do a test for whether to throw DATA_CONVERSION.
*
* @param c a <code>char</code> value
*/
@Override
public final void write_char (final char c)
{
// According to 15.3.1.6 of CORBA 3.0 'a single instance of the char type
// may only hold one octet of any multi-byte character encoding.'
// Therefore we ensure that we are in the single byte range i.e.
// less than 0xFF or \377.
if (c > '\377')
{
throw new DATA_CONVERSION ("Char " + c + " out of range");
}
check( 1 );
buffer[pos++] = (byte)c;
index++;
}
@Override
public final void write_char_array
(final char[] value, final int offset, final int length)
{
if( value == null )
{
throw new MARSHAL("Cannot marshall null array.");
}
else if ( offset + length > value.length || length < 0 || offset < 0 )
{
throw new MARSHAL
("Cannot marshall as indices for array are out bounds.");
}
check( length );
for (int i=offset; i < length+offset; i++)
{
if (value[i] > '\377')
{
throw new DATA_CONVERSION ("Char " + value[i] + " out of range");
}
buffer[pos++] = (byte)value[i];
}
index+=length;
}
/**
* <code>write_string</code> writes a string to the output stream. It is
* optimised for whether it is writing a blank string or for whether codeset
* translation is active.
*
* @param value a <code>String</code> value
*/
@Override
public final void write_string(final String value)
{
if( value == null )
{
if (nullStringEncoding)
{
write_long(0);
return;
}
else
{
throw new MARSHAL("Cannot marshall null string.");
}
}
final int valueLength = value.length();
// size leaves room for ulong, plus the string itself (one or more
// bytes per char in the string, depending on the codeset), plus the
// terminating NUL char
int size;
// sizePosition is the position in the buffer for the size to be
// written.
int sizePosition;
if (valueLength == 0)
{
// Blank string; just write size and terminator. Don't need to
// align here as these methods will do it for us.
write_long( 1 );
write_octet( (byte)0 );
}
else
{
if (codesetEnabled)
{
// in the worst case (UTF-8) a string char might take up to 4 bytes
size = 4 + ( 4 * valueLength ) + 1;
}
else
{
// just one byte per string char
size = 4 + valueLength + 1;
}
check(size, 4);
sizePosition = pos;
pos += 4;
index += 4;
if (codesetEnabled)
{
codeSet.write_string(this, value, false, false, giop_minor);
}
else
{
// If not using codesets then use the deprecated getBytes for speed.
value.getBytes(0, valueLength, buffer, pos);
index += valueLength;
pos += valueLength;
}
buffer[ pos++ ] = (byte) 0; //terminating NUL char
index ++;
// Now write the size back in.
size = pos - (sizePosition + 4); // compute translated size
_write4int( buffer, sizePosition, size);
}
}
@Override
public final void write_wchar(final char c)
{
check(6); // maximum is UTF-16 handling non-BPM character with BOM
// alignment/check must happen prior to calling.
codeSetW.write_char( this, c, codeSetW.write_bom( useBOM ), true, giop_minor );
}
@Override
public void write_byte( byte b )
{
buffer[pos++] = b;
index ++;
}
@Override
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] );
}
}
@Override
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( this.giop_minor == 2 && codeSetW.write_bom( 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++ )
{
codeSetW.write_char( this, s.charAt(i), false, false, this.giop_minor );
}
int str_size;
if (this.giop_minor >= 2)
{
//size in bytes (without the size ulong)
str_size = pos - startPos - 4;
}
else
{
//terminating NUL char
codeSetW.write_char( this, (char)0, false, false, giop_minor );
str_size = codeSetW.get_wstring_size( s, startPos, pos );
}
// write length indicator
_write4int( buffer, startPos, str_size );
}
@Override
public final void write_double(final double value)
{
write_longlong (Double.doubleToLongBits (value));
}
@Override
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 void write_fixed(BigDecimal value, short digits, short scale)
{
String v = value.unscaledValue().toString();
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;
}
/**
* @deprecated
*/
@Override
@Deprecated
public void write_fixed(final java.math.BigDecimal value)
{
write_fixed(value, (short)-1, (short)-1);
}
@Override
public final void write_float(final float value)
{
write_long(Float.floatToIntBits(value));
}
@Override
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;
}
}
@Override
public final void write_long(final int value)
{
check(7,4);
_write4int(buffer,pos,value);
pos += 4; index += 4;
}
@Override
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);
final 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;
}
}
@Override
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;
}
@Override
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;
}
}
@Override
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;
IOR intermediary = ((Delegate)obj._get_delegate()).getIOR();
if (isMutatorEnabled)
{
intermediary = mutator.mutateOutgoing (intermediary);
}
IORHelper.write(this, intermediary);
}
}
////////////////////////////////////////////// NEW!
public void write_IOR(final IOR ior)
{
if( ior == null )
{
IORHelper.write(this, null_ior );
}
else
{
IORHelper.write(this, ior);
}
}
////////////////////////////////////////////// NEW!
@Override
public final void write_octet(final byte value)
{
check(1);
index++;
buffer[pos++] = value;
}
@Override
public final void write_octet_array( final byte[] value,
final int offset,
final int length)
{
if( value != null )
{
check(length);
System.arraycopy(value,offset,buffer,pos,length);
index += length;
pos += length;
}
}
@Override
public final void write_Principal(final org.omg.CORBA.Principal value)
{
throw new NO_IMPLEMENT ("Principal deprecated");
}
@Override
public final void write_short(final short value)
{
check(3,2);
buffer[pos++] = (byte)((value >> 8) & 0xFF);
buffer[pos++] = (byte)( value & 0xFF);
index += 2;
}
@Override
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);
final 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++] = (byte)( value[i] & 0xFF );
}
index += 2*length;
}
}
@Override
public final void write_TypeCode (org.omg.CORBA.TypeCode typeCode)
{
if (typeCode == null)
{
throw new BAD_PARAM("TypeCode is null");
}
typeCode = typeCodeCompactor.getCompactTypeCode(typeCode);
if (repeatedTCMap == null)
{
repeatedTCMap = new HashMap();
}
if (recursiveTCMap == null)
{
recursiveTCMap = new HashMap();
}
try
{
write_TypeCode(typeCode, recursiveTCMap, repeatedTCMap);
}
finally
{
repeatedTCMap.clear();
recursiveTCMap.clear();
}
}
public final void write_TypeCode(final org.omg.CORBA.TypeCode typeCode,
final Map recursiveTCMap,
final Map repeatedTCMap)
{
typeCodeWriter.writeTypeCode(typeCode, this, recursiveTCMap, repeatedTCMap);
}
@Override
public final void write_ulong(final int value)
{
write_long (value);
}
@Override
public final void write_ulong_array
(final int[] value, final int offset, final int length)
{
write_long_array (value, offset, length);
}
@Override
public final void write_ulonglong(final long value)
{
write_longlong (value);
}
@Override
public final void write_ulonglong_array
(final long[] value, final int offset, final int length)
{
write_longlong_array (value, offset, length);
}
@Override
public final void write_ushort(final short value)
{
write_short (value);
}
@Override
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 typeCode,
final org.omg.CORBA.portable.InputStream input )
{
if (typeCode == null)
{
throw new BAD_PARAM("TypeCode is null");
}
int kind = typeCode.kind().value();
try
{
switch (kind)
{
case TCKind._tk_null: // 0
// fallthrough
case TCKind._tk_void: // 1
{
break;
}
case TCKind._tk_short: // 2
{
write_short( input.read_short());
break;
}
case TCKind._tk_long: // 3
{
write_long( input.read_long());
break;
}
case TCKind._tk_ushort: // 4
{
write_ushort(input.read_ushort());
break;
}
case TCKind._tk_ulong: // 5
{
write_ulong( input.read_ulong());
break;
}
case TCKind._tk_float: // 6
{
write_float( input.read_float());
break;
}
case TCKind._tk_double: // 7
{
write_double(input.read_double());
break;
}
case TCKind._tk_boolean: // 8
{
write_boolean( input.read_boolean());
break;
}
case TCKind._tk_char: // 9
{
write_char( input.read_char());
break;
}
case TCKind._tk_octet: // 10
{
write_octet( input.read_octet());
break;
}
case TCKind._tk_any: // 11
{
write_any( input.read_any());
break;
}
case TCKind._tk_TypeCode: // 12
{
write_TypeCode(input.read_TypeCode());
break;
}
case TCKind._tk_Principal: // 13
{
throw new NO_IMPLEMENT ("Principal deprecated");
}
case TCKind._tk_objref: // 14
{
write_Object( input.read_Object());
break;
}
case TCKind._tk_struct: // 15
{
for( int i = 0; i < typeCode.member_count(); i++)
{
write_value( typeCode.member_type(i), input );
}
break;
}
case TCKind._tk_union: // 16
{
org.omg.CORBA.TypeCode disc = typeCode.discriminator_type();
disc = TypeCode.originalType(disc);
int def_idx = typeCode.default_index();
int member_idx = -1;
switch( disc.kind().value() )
{
case TCKind._tk_short: // 2
{
short s = input.read_short();
write_short(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_short())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_long: // 3
{
int s = input.read_long();
write_long(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_long())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_ushort: // 4
{
short s = input.read_ushort();
write_ushort(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_ushort())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_ulong: // 5
{
int s = input.read_ulong();
write_ulong(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_ulong())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_float: // 6
// fallthrough
case TCKind._tk_double: // 7
{
throw new MARSHAL(
"Invalid union discriminator type: " + disc);
}
case TCKind._tk_boolean: // 8
{
boolean s = input.read_boolean();
write_boolean(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_boolean())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_char: // 9
{
char s = input.read_char();
write_char(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_char())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_octet: // 10
case TCKind._tk_any: // 11
case TCKind._tk_TypeCode: // 12
case TCKind._tk_Principal: // 13
case TCKind._tk_objref: // 14
case TCKind._tk_struct: // 15
case TCKind._tk_union: // 16
{
throw new MARSHAL(
"Invalid union discriminator type: " + disc);
}
case TCKind._tk_enum: // 17
{
int s = input.read_long();
write_long(s);
for( int i = 0 ; i < typeCode.member_count(); i++ )
{
if( i != def_idx)
{
int label =
typeCode.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_string: // 18
case TCKind._tk_sequence: // 19
case TCKind._tk_array: // 20
case TCKind._tk_alias: // 21
case TCKind._tk_except: // 22
{
throw new MARSHAL(
"Invalid union discriminator type: " + disc);
}
case TCKind._tk_longlong: // 23
{
long s = input.read_longlong();
write_longlong(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_longlong())
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_ulonglong: // 24
{
long s = input.read_ulonglong();
write_ulonglong(s);
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if(i != def_idx)
{
if(s == typeCode.member_label(i).extract_ulonglong())
{
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( typeCode.member_type( member_idx ), input );
}
else if( def_idx != -1 )
{
write_value( typeCode.member_type( def_idx ), input );
}
break;
}
case TCKind._tk_enum: // 17
{
write_long( input.read_long() );
break;
}
case TCKind._tk_string: // 18
{
write_string( input.read_string());
break;
}
case TCKind._tk_sequence: // 19
{
int len = input.read_long();
write_long(len);
org.omg.CORBA.TypeCode content_tc = typeCode.content_type();
for( int i = 0; i < len; i++ )
{
write_value(content_tc, input);
}
break;
}
case TCKind._tk_array: // 20
{
int length = typeCode.length();
if( typeCode.content_type().kind().value() == TCKind._tk_octet )
{
check( length );
input.read_octet_array( buffer, pos, length);
index+= length;
pos += length;
}
else
{
for( int i = 0; i < length; i++ )
{
write_value( typeCode.content_type(), input );
}
}
break;
}
case TCKind._tk_alias: // 21
{
write_value( typeCode.content_type(), input );
break;
}
case TCKind._tk_except: // 22
{
write_string( input.read_string());
for (int i = 0; i < typeCode.member_count(); i++)
{
write_value(typeCode.member_type(i), input);
}
break;
}
case TCKind._tk_longlong: // 23
{
write_longlong(input.read_longlong());
break;
}
case TCKind._tk_ulonglong: // 24
{
write_ulonglong( input.read_ulonglong());
break;
}
case TCKind._tk_longdouble: // 25
{
throw new org.omg.CORBA.BAD_TYPECODE(
"type longdouble not supported in java");
}
case TCKind._tk_wchar: // 26
{
write_wchar( input.read_wchar());
break;
}
case TCKind._tk_wstring: // 27
{
write_wstring( input.read_wstring());
break;
}
case TCKind._tk_fixed: // 28
{
final short digits = typeCode.fixed_digits();
final short scale = typeCode.fixed_scale();
final BigDecimal value;
if (input instanceof CDRInputStream)
{
value = ((CDRInputStream)input).read_fixed(digits, scale);
}
else
{
// TODO can we remove this? mixed usage orb classes from different vendors ...
value = input.read_fixed();
}
write_fixed(value, digits, scale);
break;
}
case TCKind._tk_value: // 29
{
final Serializable val = ((org.omg.CORBA_2_3.portable.InputStream)input).read_value();
write_value(val, typeCode.id());
break;
}
case TCKind._tk_value_box:
{
String id = typeCode.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 =
((org.omg.CORBA_2_3.portable.InputStream)input).read_value(helper);
write_value (value, helper);
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.
*/
@Override
public void write_value(final java.io.Serializable value)
{
if (!write_special_value (value))
{
write_value_internal (value,
ValueHandler.getRMIRepositoryID (value.getClass()));
}
}
@Override
public void write_value(final java.io.Serializable value,
final org.omg.CORBA.portable.BoxedValueHelper factory)
{
if (!write_special_value (value))
{
write_previous_chunk_size();
check(7,4);
getValueMap().put (value, Integer.valueOf(size()));
if (((value instanceof org.omg.CORBA.portable.IDLEntity) ||
isSimpleString(value, factory)))
{
write_long (0x7fffff00 | chunkingFlag);
}
else
{
// repository id is required for RMI: types
write_long (0x7fffff02 | chunkingFlag);
final String repId = factory.get_id();
write_repository_id (repId);
}
start_chunk();
factory.write_value (this, value);
end_chunk();
}
}
/**
* check if the specified value may be marshalled as a simple string (length, value)
* or it should be encoded as a valuetype.
*/
private boolean isSimpleString(Serializable value, BoxedValueHelper factory)
{
if (!(value instanceof String))
{
return false;
}
if (factory.get_id().equals(StringValueHelper.id()))
{
return false;
}
if (factory.get_id().equals(WStringValueHelper.id()))
{
return false;
}
return true;
}
@Override
public void write_value(final java.io.Serializable value,
final java.lang.Class clazz)
{
if (!write_special_value (value))
{
final Class _clazz = value.getClass();
final String repId = ValueHandler.getRMIRepositoryID(_clazz);
if (_clazz == clazz && !repId.startsWith("RMI:"))
{
// the repository id is required for "RMI:" valuetypes
write_value_internal (value, null);
}
else if (clazz.isInstance (value))
{
write_value_internal (value, repId);
}
else
{
throw new BAD_PARAM();
}
}
}
@Override
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;
}
Integer index = getValueMap().get (value);
if (index != null)
{
// value has already been written -- make an indirection
write_long (0xffffffff);
write_long (index.intValue() - size());
return true;
}
return false;
}
/**
* Writes `repository_id' to this stream, perhaps via indirection.
*/
private void write_repository_id(final String repository_id)
{
Integer _index = 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, Integer.valueOf(size()));
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 = 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, Integer.valueOf(size()));
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)
{
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)
{
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)
{
write_previous_chunk_size();
check(7,4);
getValueMap().put(value, Integer.valueOf(size()));
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 clazz = value.getClass();
String codebase = ValueHandler.getCodebase(clazz);
if (value instanceof org.omg.CORBA.portable.IDLEntity)
{
java.lang.reflect.Method writeMethod = null;
if (clazz != org.omg.CORBA.Any.class)
{
String helperClassName = clazz.getName() + "Helper";
try
{
Class helperClass =
(clazz.getClassLoader() != null)
? clazz.getClassLoader().loadClass(helperClassName)
: ObjectUtil.classForName(helperClassName);
Class[] paramTypes =
{ org.omg.CORBA.portable.OutputStream.class, clazz };
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(clazz))
{
chunkingFlag = 0x00000008;
}
Serializable newValue = value;
if (!writeReplaceCalled)
{
// writeReplace must be called only once for this value
newValue = ValueHandler.writeReplace(value);
writeReplaceCalled = true; // won't call it again
}
if (newValue != value)
{
// recompute codebase and/or repositoryID as might have changed
String new_rep_id =
ValueHandler.getRMIRepositoryID(newValue.getClass());
repository_ids =
(new_rep_id == null) ? null : new String []{new_rep_id};
clazz = newValue.getClass();
codebase = ValueHandler.getCodebase(clazz);
}
write_value_header( repository_ids, codebase );
start_chunk();
if (newValue != value)
{
// look at the new value
Integer index = getValueMap().get(newValue);
if (index != null)
{
// previously marshaled value -- make an indirection
write_long (0xffffffff);
write_long (index.intValue() - size());
}
else if (newValue instanceof org.omg.CORBA.Object)
{
write_Object((org.omg.CORBA.Object)newValue);
}
else
{
ValueHandler.writeValue(this, newValue);
}
}
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
{
// go to the beginning of the chunk and write the size tag
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_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.
*/
@Override
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);
}
}
/**
* <code>start_value</code> implements ValueOutputStream JavaToIDL mapping 02-01-12.
* It should end any currently open chunk, write a valuetype header for a nested custom valuetype
* (with a null codebase and the specified repository ID), and increment the valuetype nesting depth.
*
* @param rep_id
*/
@Override
public void start_value (String rep_id)
{
write_value_header (new String[] {rep_id});
start_chunk();
}
/**
* <code>end_value</code> implements ValueOutputStream JavaToIDL mapping 02-01-12.
* It should end any currently open chunk, write the end tag for the nested custom valuetype,
* and decrement the valuetype nesting depth.
*/
@Override
public void end_value ()
{
end_chunk();
}
public byte getMaximumStreamFormatVersion ()
{
return maxStreamFormatVersion;
}
/**
* <code>updateMutatorConnection</code> is an accessor that updates the
* ior mutator.
*
* By making callers pass in a GIOPConnection not a transport this allows
* callers to not have to call getTransport which would require a synchronized
* lock. Therefore if the mutator has not been enabled this is effectively a
* NOP.
*
* @param connection an <code>org.omg.ETF.Connection</code> value
*/
public void updateMutatorConnection(GIOPConnection connection)
{
if (isMutatorEnabled)
{
mutator.updateConnection (connection.getTransport());
}
}
public int get_pos()
{
return pos;
}
public boolean isIndirectionEnabled()
{
return useIndirection;
}
}