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.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.jacorb.config.Configuration;
import org.jacorb.config.ConfigurationException;
import org.jacorb.orb.giop.GIOPConnection;
import org.jacorb.orb.giop.Messages;
import org.jacorb.orb.typecode.DelegatingTypeCodeReader;
import org.jacorb.orb.typecode.TypeCodeCache;
import org.jacorb.util.ObjectUtil;
import org.jacorb.util.ValueHandler;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.CompletionStatus;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.TypeCodePackage.Bounds;
import org.omg.CORBA.portable.IDLEntity;
import org.omg.CORBA.portable.ValueInputStream;
import org.omg.GIOP.MsgType_1_1;
import org.slf4j.Logger;
/**
* Read CDR encoded data
*
* @author Gerald Brose
*/
public class CDRInputStream
extends org.omg.CORBA_2_3.portable.InputStream
implements CodeSet.InputBuffer, ValueInputStream
{
/**
* <code>encaps_stack</code> is used to saving/restoring
* encapsulation information.
*/
private Deque<EncapsInfo> encaps_stack;
/**
* This Map is basically a one-entry map pool to be used in
* read_TypeCode() as the repeatedTCMap.
*/
private SortedMap repeatedTCMap;
private Map recursiveTCMap;
/** indexes to support mark/reset */
private int marked_pos;
private int marked_index;
private int marked_chunk_end_pos;
private int marked_valueNestingLevel;
private boolean closed;
/** configurable properties */
Logger logger;
private boolean cometInteropFix;
private boolean laxBooleanEncoding;
private boolean nullStringEncoding;
/* character encoding code sets for char and wchar, default ISO8859_1 */
private CodeSet codeSet;
private CodeSet codeSetW;
protected int giop_minor = 2; // needed to determine size in chars
/**
* <code>valueMap</code> maps indices within the buffer
* (java.lang.Integer) to the values that appear at these indices. Do
* NOT access this variable directly. It is initialized on demand.
* Use the method {@link #getValueMap()}
*/
private Map valueMap;
/**
* Index of the current IDL value that is being unmarshalled.
* This is kept here so that when the value object has been
* created, the value factory can immediately store it into this
* stream's valueMap by calling `register_value()'.
*/
private int currentValueIndex;
/**
* <code>repIdMap</code> maps indices within the buffer
* (java.lang.Integer) to repository ids that appear at these indices.
* Do NOT access this variable directly. It is initialized on demand.
* Use the method {@link #getRepIdMap()}
*/
private Map repIdMap;
/**
* <code>codebaseMap</code> maps indices within the buffer
* (java.lang.Integer) to codebase strings that appear at these indices.
* Do NOT access this variable directly. It is initialized on demand.
* Use the method {@link #getCodebaseMap()}
*/
private Map codebaseMap;
private boolean littleEndian = false;
/** indices into the actual buffer */
protected byte[] buffer = null;
protected int pos = 0;
protected int index = 0;
/** Last value tag read had the chunking bit on */
private boolean chunkedValue = false;
/** Nesting level of chunked valuetypes */
private int valueNestingLevel = 0;
/** Ending position of the current chunk */
private int chunk_end_pos = -1; // -1 means we're not within a chunk
/**
* <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;
/**
* for this stream to be able to return a live object reference, a
* full ORB (not the Singleton!) must be known. If this stream is
* used only to demarshal base type data, the Singleton is enough
*/
private final org.omg.CORBA.ORB orb;
/**
* this is the lowest possible value_tag indicating the
* begin of a valuetype (15.3.4)
*/
private static final int MAX_BLOCK_SIZE = 0x7fffff00;
/**
* fixes RMI/IIOP related interoperability issues with the
* sun the orb that occured
* while receiving serialized collections.
* see <a href="http://lists.spline.inf.fu-berlin.de/mailman/htdig/jacorb-developer/2006-May/008251.html">mailing list</a>
* for details.
*/
private boolean sunInteropFix;
private static final DelegatingTypeCodeReader typeCodeReader = new DelegatingTypeCodeReader();
private final TypeCodeCache typeCodeCache;
private int typeCodeNestingLevel = -1;
private CDRInputStream(org.omg.CORBA.ORB orb)
{
super();
if (orb == null)
{
this.orb = org.omg.CORBA.ORBSingleton.init();
}
else
{
this.orb = orb;
}
if (! (this.orb instanceof ORBSingleton))
{
throw new BAD_PARAM("don't pass in a non JacORB ORB");
}
try
{
configure(((ORBSingleton)this.orb).getConfiguration());
}
catch( ConfigurationException e )
{
throw new INTERNAL("ConfigurationException: " + e);
}
typeCodeCache = ((ORBSingleton)this.orb).getTypeCodeCache();
}
private CDRInputStream(org.omg.CORBA.ORB orb, byte[] buffer, Object ignored)
{
this(orb);
if (buffer == null)
{
throw new IllegalArgumentException();
}
this.buffer = buffer;
}
public CDRInputStream(byte[] buffer)
{
this(null, buffer, null);
}
public CDRInputStream(final org.omg.CORBA.ORB orb, final byte[] buf)
{
this(orb, buf, null);
if (orb == null)
{
throw new BAD_PARAM("don't pass in a null ORB");
}
}
public CDRInputStream(final org.omg.CORBA.ORB orb,
final byte[] buf,
final boolean littleEndian )
{
this( orb, buf );
this.littleEndian = littleEndian;
}
/**
* This stream is self-configuring, i.e. configure() is private
* and only called from the constructors.
*/
private void configure(Configuration configuration)
throws ConfigurationException
{
logger = configuration.getLogger("org.jacorb.orb.cdr");
codesetEnabled = configuration.getAttributeAsBoolean ("jacorb.codeset", true);
cometInteropFix = configuration.getAttributeAsBoolean ("jacorb.interop.comet",false);
laxBooleanEncoding = configuration.getAttributeAsBoolean("jacorb.interop.lax_boolean_encoding", false);
sunInteropFix = configuration.getAttributeAsBoolean("jacorb.interop.sun", false);
nullStringEncoding = configuration.getAttributeAsBoolean("jacorb.interop.null_string_encoding", false);
mutator = (IORMutator) configuration.getAttributeAsObject("jacorb.iormutator");
isMutatorEnabled = (mutator != null);
codeSet = ((ORBSingleton)orb).getTCSDefault();
codeSetW = ((ORBSingleton) orb).getTCSWDefault();
}
/**
* Gets the Map that is used to demarshal shared valuetype instances.
*
* @return a <code>Map</code> value
*/
private Map getValueMap()
{
if (valueMap == null)
{
// Unlike the valueMap in CDROutputStream, this one
// does need to be an equality-based HashMap.
valueMap = new HashMap();
}
return valueMap;
}
/**
* Gets the Map that is used to implement indirections for RepositoryIDs.
*
* @return a <code>Map</code> value
*/
private Map getRepIdMap()
{
if (repIdMap == null)
{
repIdMap = new HashMap();
}
return repIdMap;
}
/**
* Gets the Map that is used to implement sharing for codebase
* specifications.
*
* @return a <code>Map</code> value
*/
private Map getCodebaseMap()
{
if (codebaseMap == null)
{
codebaseMap = new HashMap();
}
return codebaseMap;
}
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;
}
// commented out as this caused test failures.
// as the buffer has been passed into this CDRInputStream
// we cannot assume ownership of the buffer here (alphonse).
// BufferManager.getInstance().returnBuffer(buffer);
buffer = null;
encaps_stack = null;
closed = true;
if (recursiveTCMap != null)
{
recursiveTCMap.clear();
}
}
@Override
public org.omg.CORBA.ORB orb()
{
return orb;
}
public void setCodeSet( CodeSet codeSet, CodeSet codeSetWide )
{
this.codeSet = codeSet;
this.codeSetW = codeSetWide;
}
private static final int _read4int
(final boolean _littleEndian, final byte[] _buffer, final int _pos)
{
if (_littleEndian)
{
return (((_buffer[_pos+3] & 0xff) << 24) +
((_buffer[_pos+2] & 0xff) << 16) +
((_buffer[_pos+1] & 0xff) << 8) +
((_buffer[_pos] & 0xff) << 0));
}
return (((_buffer[_pos] & 0xff) << 24) +
((_buffer[_pos+1] & 0xff) << 16) +
((_buffer[_pos+2] & 0xff) << 8) +
((_buffer[_pos+3] & 0xff) << 0));
}
private static final short _read2int
(final boolean _littleEndian, final byte[] _buffer, final int _pos)
{
if (_littleEndian)
{
return (short)(((_buffer[_pos+1] & 0xff) << 8) +
((_buffer[_pos] & 0xff) << 0));
}
return (short)(((_buffer[_pos ] & 0xff) << 8) +
((_buffer[_pos + 1] & 0xff) << 0));
}
private final int _read_long()
{
int result;
result = _read4int (littleEndian, buffer, pos);
index += 4;
pos += 4;
return result;
}
private final long _read_longlong()
{
if (littleEndian)
{
return (_read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
}
return ((long) _read_long() << 32) + (_read_long() & 0xFFFFFFFFL);
}
private final void handle_chunking()
{
int remainder = 4 - (index % 4);
int aligned_pos = (remainder != 4) ? pos + remainder : pos;
if (chunk_end_pos >= pos && chunk_end_pos <= aligned_pos)
{
adjust_positions ();
}
}
private final void adjust_positions()
{
chunk_end_pos = -1;
int saved_pos = pos;
int saved_index = index;
int tag = read_long();
if (tag < 0)
{
// tag is an end tag
if (-tag > valueNestingLevel)
{
throw new INTERNAL
(
"received end tag " + tag +
" with value nesting level " +
valueNestingLevel
);
}
valueNestingLevel = -tag;
valueNestingLevel--;
if (valueNestingLevel > 0)
{
chunk_end_pos = pos;
handle_chunking();
}
}
else if (tag > 0 && tag < 0x7fffff00)
{
// tag is the chunk size tag of another chunk
chunk_end_pos = pos + tag;
}
else // (tag == 0 || tag >= 0x7fffff00)
{
// tag is the null value tag or the value tag of a nested value
pos = saved_pos; // "unread" the tag
index = saved_index;
}
}
public final void skip(final int distance)
{
pos += distance;
index += distance;
}
/**
* close a CDR encapsulation and
* restore index and byte order information
*/
public final void closeEncapsulation()
{
if (encaps_stack == null)
{
throw new MARSHAL( "Internal Error - closeEncapsulation failed" );
}
EncapsInfo ei = encaps_stack.removeFirst();
littleEndian = ei.littleEndian;
int size = ei.size;
int start = ei.start;
if( pos < start + size )
{
pos = start + size;
}
index = ei.index + size;
}
/**
* open a CDR encapsulation and
* restore index and byte order information
*/
public final int openEncapsulation()
{
boolean old_endian = littleEndian;
int size = read_long();
// Check if size looks sane. If not try changing byte order.
// This is a specific fix for interoperability with the Iona
// Comet COM/CORBA bridge that has problems with size marshalling.
if (cometInteropFix && ((size < 0) || (size > buffer.length)))
{
int temp =
(
((size >> 24) & 0x000000FF) +
((size >> 8) & 0x0000FF00) +
((size << 8) & 0x00FF0000) +
((size << 24) & 0xFF000000)
);
if (logger.isDebugEnabled())
{
logger.debug("Size of CDR encapsulation larger than buffer, swapping byte order. " +
"Size of CDR encapsulation was " + size + ", is now " + temp);
}
size = temp;
}
/* save current index plus size of the encapsulation on the stack.
When the encapsulation is closed, this value will be restored as
index */
if (encaps_stack == null)
{
encaps_stack = new ArrayDeque<EncapsInfo>();
}
encaps_stack.addFirst(new EncapsInfo(old_endian, index, pos, size ));
openEncapsulatedArray();
return size;
}
public final void openEncapsulatedArray()
{
/* reset index to zero, i.e. align relative to the beginning
of the encaps. */
resetIndex();
littleEndian = read_boolean();
}
/*
* Return a copy of the current buffer.
*
* @return a <code>byte[]</code> value.
*/
public byte[] getBufferCopy()
{
byte[] result = new byte[buffer.length];
System.arraycopy
(
buffer,
0,
result,
0,
buffer.length
);
return result;
}
/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned.
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @throws java.io.IOException if stream is closed.
*/
@Override
public int read()
throws java.io.IOException
{
if( closed )
{
throw new java.io.IOException("Stream already closed!");
}
if( available() < 1 )
{
return -1;
}
++index;
return buffer[pos++]; // read_index++];
}
/**
* @return the number of bytes that can be read (or skipped over) from this
* input stream. This is not necessarily the number of 'valid' bytes.
*/
@Override
public int available()
{
return buffer.length - index;
}
/**
* Has the effect of read(b, 0, b.length);
* @see #read(byte[], int, int)
*/
@Override
public int read(final byte[] b)
throws java.io.IOException
{
return read(b, 0, b.length);
}
/**
* Performs as described by <code>java.io.InputStream.read(byte[], int, int)</code>,
* but never blocks.
*/
@Override
public int read(final byte[] b, final int off, final int len)
throws java.io.IOException
{
if( b == null )
{
throw new java.io.IOException("buffer may not be null");
}
if( off < 0 ||
len < 0 ||
off + len > b.length )
{
throw new java.io.IOException("buffer index out of bounds");
}
if( len == 0 )
{
return 0;
}
if( available() < 1 )
{
return -1;
}
if( closed )
{
throw new java.io.IOException("Stream already closed!");
}
int min = Math.min(len, available());
System.arraycopy(buffer, index, b, off, min );
pos += min;
index += min;
return min;
}
@Override
public final org.omg.CORBA.Any read_any()
{
org.omg.CORBA.TypeCode _tc = read_TypeCode();
org.omg.CORBA.Any any = orb.create_any();
any.read_value( this, _tc );
return any;
}
@Override
public final boolean read_boolean()
{
if (this.chunk_end_pos == this.pos)
{
this.adjust_positions();
}
index++;
byte value = buffer[pos++];
return parseBoolean(value);
}
/** arrays */
@Override
public final void read_boolean_array
(final boolean[] value, final int offset, final int length)
{
handle_chunking();
if (length == 0)
{
return;
}
final int until = offset + length;
int j = offset;
do
{
final byte bb = buffer[pos++];
value[j] = parseBoolean(bb);
++j;
}
while(j < until);
index += length;
}
private final boolean parseBoolean(final byte value)
{
if (value == 0)
{
return false;
}
else
{
if (value == 1)
{
return true;
}
else if (laxBooleanEncoding)
{
// Technically only valid values are 0 (false) and 1 (true)
// however some ORBs send values other than 1 for true.
return true;
}
else
{
throw new MARSHAL ("Unexpected boolean value: " + value
+ " pos: " + pos);
}
}
}
/**
* <code>read_char</code> reads a character from the stream.
*
* @return a <code>char</code> value
*/
@Override
public final char read_char()
{
if (this.chunk_end_pos == this.pos)
{
this.adjust_positions();
}
index++;
return (char)(buffer[pos++] & 0xFF);
}
/**
* <code>read_char_array</code> reads an character array from the stream.
*
* @param value a <code>char[]</code>, the result array.
* @param offset an <code>int</code>, an offset into <code>value</code>
* @param length an <code>int</code>, the length of the array to read
*/
@Override
public final void read_char_array
(final char[] value, final int offset, final int length)
{
if (value == null)
{
throw new MARSHAL("Cannot marshal result into null array.");
}
else if ( offset + length > value.length || length < 0 || offset < 0 )
{
throw new MARSHAL
("Cannot marshal as indices for array are out bounds.");
}
handle_chunking();
for (int j = offset; j < offset + length; j++)
{
index++;
value[j] = (char) (0xff & buffer[pos++]);
}
}
@Override
public final double read_double()
{
return Double.longBitsToDouble (read_longlong());
}
@Override
public final void read_double_array
(final double[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = Double.longBitsToDouble (_read_longlong());
}
}
/**
* @deprecated use {@link #read_fixed(short, short)} instead
*/
@Override
@Deprecated
public BigDecimal read_fixed()
{
handle_chunking();
final StringBuffer sb = new StringBuffer();
final int signum = read_fixed_internal(sb, (short)-1);
final BigDecimal result = new BigDecimal( new BigInteger( sb.toString()));
return read_fixed_negate(signum, result);
}
@Override
public BigDecimal read_fixed(short digits, short scale)
{
if (digits < 1)
{
throw new BAD_PARAM("digits must be a positive value: " + digits + ".");
}
if (scale < 0)
{
throw new BAD_PARAM("scale must be a non-negative value: " + scale +".");
}
if (scale > digits)
{
throw new BAD_PARAM("scale factor " + scale + " must be less than or equal to the total number of digits " + digits + ".");
}
handle_chunking();
final StringBuffer sb = new StringBuffer();
final int c = read_fixed_internal(sb, digits);
final BigDecimal result = new BigDecimal( new BigInteger( sb.toString()), scale);
return read_fixed_negate(c, result);
}
private BigDecimal read_fixed_negate(final int signum, final BigDecimal result)
{
if( signum == 0xD )
{
return result.negate();
}
return result;
}
/**
* @param outBuffer a string representation of the read in fixed will be appended to the buffer.
* @param digits the number of expected digits the read in fixed should have. -1 means unlimited.
* @return the signum of the read in fixed (0xC or 0xD).
*/
private int read_fixed_internal(StringBuffer outBuffer, short digits)
{
int b = buffer[pos++];
int c = b & 0x0F; // second half byte
index++;
while(true)
{
c = (b & 0xF0) >>> 4;
if (outBuffer.length() > 0 || c != 0)
{
outBuffer.append(c);
}
c = b & 0x0F;
if( c == 0xC || c == 0xD )
{
break;
}
outBuffer.append(c);
b = buffer[pos++];
index++;
}
if ( (digits == 1 || digits == -1) && outBuffer.length() == 0)
{
outBuffer.append ('0');
}
if (digits != -1 && (outBuffer.length() > digits))
{
throw new MARSHAL("unexpected number of digits: expected " + digits + " got " + outBuffer.length() + " " + outBuffer);
}
return c;
}
@Override
public final float read_float()
{
return Float.intBitsToFloat (read_long());
}
@Override
public final void read_float_array
(final float[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = Float.intBitsToFloat (_read_long());
}
}
@Override
public final int read_long()
{
handle_chunking();
int result;
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
result = _read4int (littleEndian, buffer, pos);
index += 4;
pos += 4;
return result;
}
@Override
public final void read_long_array
(final int[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset+length; j++)
{
value[j] = _read4int (littleEndian,buffer,pos);
pos += 4;
}
index += 4 * length;
}
@Override
public final long read_longlong()
{
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
return _read_longlong();
}
@Override
public final void read_longlong_array
(final long[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
for(int j=offset; j < offset+length; j++)
{
value[j] = ( _read_long() & 0xFFFFFFFFL) +
((long) _read_long() << 32);
}
}
else
{
for(int j=offset; j < offset+length; j++)
{
value[j] = ((long) _read_long() << 32) +
(_read_long() & 0xFFFFFFFFL);
}
}
// Do not need to modify pos and index as use read_long above
}
@Override
public final org.omg.CORBA.Object read_Object()
{
if (! (orb instanceof org.jacorb.orb.ORB))
{
throw new MARSHAL
( "Cannot use the singleton ORB to receive object references, "
+ "please initialize a full ORB instead.");
}
handle_chunking();
org.omg.IOP.IOR ior = org.omg.IOP.IORHelper.read(this);
if (isMutatorEnabled)
{
ior = mutator.mutateIncoming (ior);
}
if (ParsedIOR.isNull(ior))
{
return null;
}
else
{
return ((org.jacorb.orb.ORB)orb)._getObject(ior);
}
}
@Override
public org.omg.CORBA.Object read_Object(final java.lang.Class clazz)
{
if (org.omg.CORBA.portable.ObjectImpl.class.isAssignableFrom(clazz))
{
org.omg.CORBA.Object obj = read_Object();
if (obj instanceof org.omg.CORBA.portable.ObjectImpl)
{
org.omg.CORBA.portable.ObjectImpl stub = null;
try
{
stub = (org.omg.CORBA.portable.ObjectImpl)clazz.newInstance();
}
catch (InstantiationException e)
{
throw new MARSHAL("Exception in stub instantiation: " + e);
}
catch (IllegalAccessException e)
{
throw new MARSHAL("Exception in stub instantiation: " + e);
}
stub._set_delegate(
((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate());
return stub;
}
return obj;
}
else if (clazz.isInterface() &&
java.rmi.Remote.class.isAssignableFrom(clazz))
{
return (org.omg.CORBA.Object)
org.jacorb.util.ValueHandler.portableRemoteObject_narrow(
read_Object(), clazz);
}
else
{
return read_Object();
}
}
@Override
public final byte read_octet()
{
if (this.chunk_end_pos == this.pos)
{
this.adjust_positions();
}
index++;
return buffer[pos++];
}
@Override
public final void read_octet_array
(final byte[] value, final int offset, final int length)
{
handle_chunking();
System.arraycopy (buffer,pos,value,offset,length);
index += length;
pos += length;
}
/*
* @deprecated
* @see org.omg.CORBA.portable.InputStream#read_Principal()
*/
@Override
public final org.omg.CORBA.Principal read_Principal()
{
throw new NO_IMPLEMENT ("Principal deprecated");
}
@Override
public final short read_short()
{
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
short result = _read2int (littleEndian,buffer,pos);
pos += 2;
index += 2;
return result;
}
@Override
public final void read_short_array
(final short[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = _read2int (littleEndian, buffer, pos);
pos += 2;
}
index += length * 2;
}
/**
* <code>read_string</code> reads a string from the buffer. It is optimized
* for whether it is reading a blank string, and whether codeset translation
* is active.
*
* @return a <code>String</code> value, possibly blank, never null.
*/
@Override
public final String read_string()
{
String result = null;
handle_chunking();
int remainder = 4 - (index % 4);
if( remainder != 4 )
{
index += remainder;
pos += remainder;
}
// read size (#bytes)
int size = _read4int( littleEndian, buffer, pos);
if (size < 1 && ! nullStringEncoding)
{
throw new MARSHAL("invalid string size: " + size);
}
int start = pos + 4;
index += (size + 4);
pos += (size + 4);
final int stringTerminatorPosition = start + size -1;
if (nullStringEncoding && size == 0)
{
// Some ORBs wrongly encode empty string with a size 0
return null;
}
else if (buffer.length < stringTerminatorPosition + 1)
{
throw new MARSHAL("buffer too small");
}
if ((buffer[stringTerminatorPosition] == 0))
{
size --;
}
else
{
throw new MARSHAL("unexpected string terminator value " + Integer.toHexString(buffer[stringTerminatorPosition]) + " at buffer index " + stringTerminatorPosition);
}
// Optimize for empty strings.
if (size == 0)
{
return "";
}
if(start + size > buffer.length)
{
final String message = "Size (" + size + ") invalid for string extraction from buffer length of " + buffer.length + " from position " + start;
if (logger.isDebugEnabled())
{
logger.debug(message);
}
throw new MARSHAL(message);
}
if (codesetEnabled)
{
try
{
result = new String (buffer, start, size, codeSet.getName() );
}
catch (java.io.UnsupportedEncodingException ex)
{
if (logger.isErrorEnabled())
{
logger.error("Charset " + codeSet.getName() + " is unsupported");
result = "";
}
}
}
else
{
char[] buf = new char[size];
for (int i=0; i<size; i++)
{
buf[i] = (char)(0xff & buffer[start + i]);
}
result = new String(buf);
}
return result;
}
@Override
public final org.omg.CORBA.TypeCode read_TypeCode()
{
if (recursiveTCMap == null)
{
recursiveTCMap = new HashMap();
}
if (repeatedTCMap == null)
{
repeatedTCMap = new TreeMap();
}
try
{
return read_TypeCode(recursiveTCMap, repeatedTCMap);
}
finally
{
recursiveTCMap.clear();
repeatedTCMap.clear();
}
}
public final org.omg.CORBA.TypeCode read_TypeCode(Map recursiveTCMap, Map repeatedTCMap)
{
try
{
++typeCodeNestingLevel;
return typeCodeReader.readTypeCode(logger, this, recursiveTCMap, repeatedTCMap);
}
finally
{
--typeCodeNestingLevel;
}
}
/**
* Skip amount is
* skip (size - ((pos - start_pos) - 4 - 4));
* EncapsulationSize -
* ( PositionAfterReadingId - start_pos
* - 4 [Size] - 4 [KindSize] ) = RemainingSizeToSkip
* @param start_pos
* @param size
*/
public void skipRemainingTypeCode(final Integer start_pos, final int size)
{
skip (size - ((pos - start_pos.intValue()) - 4 - 4));
}
@Override
public final int read_ulong()
{
handle_chunking();
int result;
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
result = _read4int (littleEndian, buffer, pos);
index += 4;
pos += 4;
return result;
}
@Override
public final void read_ulong_array
(final int[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset+length; j++)
{
value[j] = _read4int (littleEndian,buffer,pos);
pos += 4;
}
index += 4 * length;
}
@Override
public final long read_ulonglong()
{
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
return (_read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
}
return ((long) _read_long() << 32) + (_read_long() & 0xFFFFFFFFL);
}
@Override
public final void read_ulonglong_array
(final long[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
for (int j = offset; j < offset+length; j++)
{
value[j] = ( _read_long() & 0xFFFFFFFFL) +
((long) _read_long() << 32);
}
}
else
{
for (int j = offset; j < offset+length; j++)
{
value[j] = ((long) _read_long() << 32) +
(_read_long() & 0xFFFFFFFFL);
}
}
// Do not need to modify pos and index as use read_long above
}
@Override
public final short read_ushort()
{
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
short result = _read2int (littleEndian,buffer,pos);
pos += 2;
index += 2;
return result;
}
@Override
public final void read_ushort_array
(final short[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = _read2int (littleEndian, buffer, pos);
pos += 2;
}
index += length * 2;
}
@Override
public final char read_wchar()
{
if (giop_minor == 0)
{
final int minor = Messages.getMsgType( buffer ) == MsgType_1_1._Reply ? 6 : 5;
throw new MARSHAL("GIOP 1.0 does not support the type wchar", minor, CompletionStatus.COMPLETED_NO);
}
handle_chunking();
if (giop_minor == 2)
{
//ignore size indicator
read_wchar_size();
boolean wchar_little_endian = readBOM();
return read_wchar (wchar_little_endian);
}
return read_wchar (littleEndian);
}
@Override
public byte readByte()
{
index++;
return buffer[ pos++ ];
}
/**
* The number of bytes this char takes. This is actually not
* necessary since the encodings used are either fixed-length
* (UTF-16) or have their length encoded internally (UTF-8).
*/
private final int read_wchar_size()
{
index++;
return buffer[ pos++ ];
}
private final char read_wchar(final boolean wchar_little_endian)
{
return codeSetW.read_wchar( this, giop_minor, wchar_little_endian );
}
/**
* Read the byte order marker indicating the endianess.
*
* @return true for little endianess, false otherwise (including
* no BOM present. In this case, big endianess is assumed per
* spec).
*/
@Override
public final boolean readBOM()
{
if( (buffer[ pos ] == (byte) 0xFE) &&
(buffer[ pos + 1 ] == (byte) 0xFF) )
{
//encountering a byte order marker indicating big
//endianess
pos += 2;
index += 2;
return false;
}
else if( (buffer[ pos ] == (byte) 0xFF) &&
(buffer[ pos + 1 ] == (byte) 0xFE) )
{
//encountering a byte order marker indicating
//little endianess
pos += 2;
index += 2;
return true;
}
else
{
//no BOM so big endian per spec.
return false;
}
}
@Override
public final void read_wchar_array
(final char[] value, final int offset, final int length)
{
handle_chunking();
for(int j=offset; j < offset+length; j++)
{
value[j] = read_wchar(); // inlining later...
}
}
@Override
public final String read_wstring()
{
if (giop_minor == 0)
{
final int minor = Messages.getMsgType( buffer ) == MsgType_1_1._Reply ? 6 : 5;
throw new MARSHAL("GIOP 1.0 does not support the IDL type wstring", minor, CompletionStatus.COMPLETED_NO);
}
handle_chunking();
int remainder = 4 - (index % 4);
if( remainder != 4 )
{
index += remainder;
pos += remainder;
}
// read length indicator
int size = _read4int( littleEndian, buffer, pos);
index += 4;
pos += 4;
if (size == 0) return "";
return codeSetW.read_wstring( this, size, this.giop_minor, this.littleEndian );
}
@Override
public boolean markSupported()
{
return true;
}
@Override
public void mark(final int readLimit)
{
marked_pos = pos;
marked_index = index;
marked_chunk_end_pos = chunk_end_pos;
marked_valueNestingLevel = valueNestingLevel;
}
@Override
public void reset()
throws IOException
{
if( pos < 0 )
{
throw new MARSHAL("Mark has not been set!");
}
pos = marked_pos;
index = marked_index;
chunk_end_pos = marked_chunk_end_pos;
valueNestingLevel = marked_valueNestingLevel;
}
// JacORB-specific
private final void resetIndex()
{
index = 0;
}
public final void setLittleEndian(final boolean b)
{
littleEndian = b;
}
protected boolean getLittleEndian ()
{
return littleEndian;
}
/**
* Reads an instance of the type described by type code <code>tc</code>
* from this CDRInputStream, and remarshals it to the given OutputStream,
* <code>out</code>. Called from Any.
*/
final void read_value(final org.omg.CORBA.TypeCode typeCode,
final org.omg.CORBA.portable.OutputStream out)
{
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
{
out.write_short( read_short());
break;
}
case TCKind._tk_long: // 3
{
out.write_long( read_long());
break;
}
case TCKind._tk_ushort: // 4
{
out.write_ushort( read_ushort());
break;
}
case TCKind._tk_ulong: // 5
{
out.write_ulong( read_ulong());
break;
}
case TCKind._tk_float: // 6
{
out.write_float( read_float());
break;
}
case TCKind._tk_double: // 7
{
out.write_double( read_double());
break;
}
case TCKind._tk_boolean: // 8
{
out.write_boolean( read_boolean());
break;
}
case TCKind._tk_char: // 9
{
out.write_char( read_char());
break;
}
case TCKind._tk_octet: // 10
{
out.write_octet( read_octet());
break;
}
case TCKind._tk_any: // 11
{
out.write_any( read_any());
break;
}
case TCKind._tk_TypeCode: // 12
{
out.write_TypeCode( read_TypeCode());
break;
}
case TCKind._tk_Principal: // 13
{
throw new NO_IMPLEMENT ("Principal deprecated");
}
case TCKind._tk_objref: // 14
{
out.write_Object( read_Object());
break;
}
case TCKind._tk_struct: // 15
{
for( int i = 0; i < typeCode.member_count(); i++)
{
read_value( typeCode.member_type(i), out );
}
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 = read_short();
out.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 = read_long();
out.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 = read_ushort();
out.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 = read_ulong();
out.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 b = read_boolean();
out.write_boolean( b );
for(int i = 0 ; i < typeCode.member_count() ; i++)
{
if( i != def_idx)
{
if( b == typeCode.member_label(i).extract_boolean() )
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_char: // 9
{
char s = read_char();
out.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
// fallthrough
case TCKind._tk_any: // 11
// fallthrough
case TCKind._tk_TypeCode: // 12
// fallthrough
case TCKind._tk_Principal: // 13
// fallthrough
case TCKind._tk_objref: // 14
// fallthrough
case TCKind._tk_struct: // 15
// fallthrough
case TCKind._tk_union: // 16
{
throw new MARSHAL(
"Invalid union discriminator type: " + disc);
}
case TCKind._tk_enum: // 17
{
int s = read_long();
out.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();
if(s == label)
{
member_idx = i;
break;
}
}
}
break;
}
case TCKind._tk_string: // 18
// fallthrough
case TCKind._tk_sequence: // 19
// fallthrough
case TCKind._tk_array: // 20
// fallthrough
case TCKind._tk_alias: // 21
// fallthrough
case TCKind._tk_except: // 22
{
throw new MARSHAL(
"Invalid union discriminator type: " + disc);
}
case TCKind._tk_longlong: // 23
{
long s = read_longlong();
out.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 = read_ulonglong();
out.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);
}
} // switch
if( member_idx != -1 )
{
read_value( typeCode.member_type( member_idx ), out );
}
else if( def_idx != -1 )
{
read_value( typeCode.member_type( def_idx ), out );
}
break;
}
case TCKind._tk_enum: // 17
{
out.write_long( read_long() );
break;
}
case TCKind._tk_string: // 18
{
out.write_string( read_string());
break;
}
case TCKind._tk_sequence: // 19
{
int len = read_long();
out.write_long(len);
for( int i = 0; i < len; i++ )
{
read_value( typeCode.content_type(), out );
}
break;
}
case TCKind._tk_array: // 20
{
int length = typeCode.length();
for( int i = 0; i < length; i++ )
{
read_value( typeCode.content_type(), out );
}
break;
}
case TCKind._tk_alias: // 21
{
read_value( typeCode.content_type(), out );
break;
}
case TCKind._tk_except: // 22
{
out.write_string( read_string());
for( int i = 0; i < typeCode.member_count(); i++)
{
read_value( typeCode.member_type(i), out );
}
break;
}
case TCKind._tk_longlong: // 23
{
out.write_longlong( read_longlong());
break;
}
case TCKind._tk_ulonglong: // 24
{
out.write_ulonglong( 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
{
out.write_wchar( read_wchar());
break;
}
case TCKind._tk_wstring: // 27
{
out.write_wstring( read_wstring());
break;
}
case TCKind._tk_fixed: // 28
{
final short digits = typeCode.fixed_digits();
final short scale = typeCode.fixed_scale();
final BigDecimal value = read_fixed(digits, scale);
if (out instanceof CDROutputStream)
{
CDROutputStream cdrOut = (CDROutputStream) out;
cdrOut.write_fixed(value, digits, scale);
}
else
{
// TODO can we remove this? mixed usage orb classes from different vendors ...
out.write_fixed (value);
}
break;
}
case TCKind._tk_value: // 29
{
Serializable val = read_value();
((org.omg.CORBA_2_3.portable.OutputStream)out).write_value(val, typeCode.id());
break;
}
case TCKind._tk_value_box: // 30
{
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 = read_value(helper);
((org.omg.CORBA_2_3.portable.OutputStream)out).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);
}
}
@Override
public java.io.Serializable read_value()
{
int tag = read_long();
int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag
return null;
}
String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
throw new MARSHAL ("missing value type information");
}
else if (tag == 0x7fffff02)
{
return read_typed_value(start_offset, codebase);
}
else if (tag == 0x7fffff06)
{
return read_multi_typed_value( start_offset, codebase );
}
else
{
throw new MARSHAL("unknown value tag: 0x" +
Integer.toHexString(theTag) + " (offset=0x" +
Integer.toHexString(start_offset) + ")");
}
}
/**
* Overrides read_value(java.io.Serializable value) in
* org.omg.CORBA_2_3.portable.InputStream
*/
@Override
public java.io.Serializable read_value(final String rep_id)
{
int tag = read_long();
final int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag
return null;
}
final String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
return read_untyped_value ( new String[]{ rep_id }, start_offset, codebase);
}
else if (tag == 0x7fffff02)
{
return read_typed_value( start_offset, codebase );
}
else if (tag == 0x7fffff06)
{
return read_multi_typed_value( start_offset, codebase );
}
else
{
throw new MARSHAL("unknown value tag: 0x" +
Integer.toHexString(theTag) + " (offset=0x" +
Integer.toHexString(start_offset) + ")");
}
}
/**
* Unmarshals a valuetype instance from this stream. The value returned
* is the same value passed in, with all the data unmarshaled
* (IDL-to-Java Mapping 1.2, August 2002, 1.13.1, p. 1-39). The specified
* value is an uninitialized value that is added to the ORB's indirection
* table before unmarshaling (1.21.4.1, p. 1-117).
*
* This method is intended to be called from custom valuetype factories.
* Unlike the other read_value() methods in this class, this method does
* not expect a GIOP value tag nor a repository id in the stream.
*
* Overrides read_value(value) in
* org.omg.CORBA_2_3.portable.InputStream
*/
@Override
public java.io.Serializable read_value(java.io.Serializable value)
{
if (value instanceof org.omg.CORBA.portable.Streamable)
{
register_value(value);
((org.omg.CORBA.portable.Streamable)value)._read(this);
}
else if (value instanceof org.omg.CORBA.portable.CustomValue )
{
register_value(value);
( ( org.omg.CORBA.portable.CustomValue ) value ).unmarshal(
new DataInputStream( this ) );
}
else
{
throw new BAD_PARAM("read_value is only implemented for Streamables");
}
return value;
}
/**
* Overrides read_value(clz) in
* org.omg.CORBA_2_3.portable.InputStream
*/
@Override
public java.io.Serializable read_value(final java.lang.Class clz)
{
int tag = read_long();
int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag
return null;
}
String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
return read_untyped_value (new String[]{ValueHandler.getRMIRepositoryID(clz)},
start_offset, codebase);
}
else if (tag == 0x7fffff02)
{
return read_typed_value(start_offset, codebase);
}
else if (tag == 0x7fffff06)
{
return read_multi_typed_value(start_offset, codebase);
}
else
{
throw new MARSHAL("unknown value tag: 0x" +
Integer.toHexString(theTag) +
" (offset=0x" +
Integer.toHexString(start_offset) +
")");
}
}
/**
* Overrides read_value(factory) in
* org.omg.CORBA_2_3.portable.InputStream
*/
@Override
public java.io.Serializable read_value
(final org.omg.CORBA.portable.BoxedValueHelper factory)
{
int tag = read_long();
int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag, explicit representation of null value
return null;
}
String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
java.io.Serializable result = factory.read_value (this);
if( result != null )
{
getValueMap().put(Integer.valueOf(start_offset), result);
}
return result;
}
else if (tag == 0x7fffff02)
{
final Serializable result = read_typed_value(start_offset, codebase, factory);
if (result != null)
{
getValueMap().put(Integer.valueOf(start_offset), result);
}
return result;
}
else
{
throw new MARSHAL("unknown value tag: 0x" +
Integer.toHexString(theTag) + " (offset=0x" +
Integer.toHexString(start_offset) + ")");
}
}
/**
* Immediately reads a value from this stream; i.e. without any
* repository id preceding it. The expected type of the value is given
* by `repository_id', and the index at which the value started is
* `index'.
*/
private java.io.Serializable read_untyped_value(final String[] repository_ids,
final int index,
final String codebase)
{
java.io.Serializable result = null;
if (chunkedValue || (valueNestingLevel > 0 && !sunInteropFix))
{
valueNestingLevel++;
readChunkSizeTag();
}
for (int i = 0; i < repository_ids.length; i++)
{
if (repository_ids[i].equals(org.omg.CORBA.WStringValueHelper.id()))
{
// special handling of strings, according to spec
result = read_wstring();
break;
}
else if(repository_ids[i].equals(org.omg.CORBA.StringValueHelper.id()))
{
// special handling of strings, according to spec
result = read_string();
break;
}
else if (repository_ids[i].startsWith("RMI:javax.rmi.CORBA.ClassDesc:"))
{
// special handling of java.lang.Class instances
final String classCodebase = (String)read_value(String.class);
final String reposId = (String)read_value(String.class);
final String className =
org.jacorb.ir.RepositoryID.className(reposId, null);
try
{
result = loadClass(className, classCodebase);
}
catch (ClassNotFoundException e)
{
if( i < repository_ids.length-1 )
{
continue;
}
throw new MARSHAL("class not found: " + className);
}
break;
}
else if (repository_ids[i].startsWith ("IDL:"))
{
org.omg.CORBA.portable.ValueFactory factory =
((org.omg.CORBA_2_3.ORB)orb()).lookup_value_factory (repository_ids[i]);
if (factory != null)
{
currentValueIndex = index;
result = factory.read_value (this);
break;
}
if( i < repository_ids.length-1 )
{
continue;
}
throw new MARSHAL ("No factory found for: " + repository_ids[0] );
}
else // RMI
{
final String className =
org.jacorb.ir.RepositoryID.className(repository_ids[i], null);
try
{
final Class clazz = loadClass(className, codebase);
if (IDLEntity.class.isAssignableFrom(clazz))
{
java.lang.reflect.Method readMethod = null;
if (clazz != org.omg.CORBA.Any.class)
{
String helperClassName = clazz.getName() + "Helper";
try
{
final ClassLoader classLoader = clazz.getClassLoader();
final Class helperClass;
if (classLoader == null)
{
helperClass = ObjectUtil.classForName(helperClassName);
}
else
{
helperClass =
classLoader.loadClass(helperClassName);
}
Class[] paramTypes = {
org.omg.CORBA.portable.InputStream.class
};
readMethod =
helperClass.getMethod("read", paramTypes);
}
catch (ClassNotFoundException e)
{
throw new MARSHAL("Error loading class " + helperClassName
+ ": " + e);
}
catch (NoSuchMethodException e)
{
throw new MARSHAL("No read method in helper class "
+ helperClassName + ": " + e);
}
}
if (readMethod == null)
{
result = read_any();
}
else
{
try
{
result =
(java.io.Serializable) readMethod.invoke(
null,
new java.lang.Object[] { this });
}
catch (IllegalAccessException e)
{
throw new MARSHAL("Internal error: " + e);
}
catch (java.lang.reflect.InvocationTargetException e)
{
throw new MARSHAL("Exception unmarshaling IDLEntity: "
+ e.getTargetException());
}
}
}
else
{
result = ValueHandler.readValue(this, index, clazz,
repository_ids[i],
null);
}
}
catch (ClassNotFoundException e)
{
if( i < repository_ids.length-1 )
{
continue;
}
throw new MARSHAL ("class not found: " + className);
}
}
}
// value type instances may be null...
if( result != null )
{
getValueMap().put(Integer.valueOf(index), result);
}
return result;
}
/** Load the value's class, using the context class loader
* of the current thread if possible. Here's Francisco
* Reverbel's <reverbel@ime.usp.br> explanation of why
* this is needed in JBoss:
*
* "It seems that ValueHandler.loadClass() uses the thread
* context classloader only after it looks for other
* classloaders in the call stack (weird). In some
* situations (when EJBs are undeployed and then
* redeployed) it finds in the call stack a classloader
* used for an undeployed EJB. A value of class Foo is
* then unmarshalled with type
* classloaderOfEJB1:Foo, when the expected type is
* classloaderOfEJB2:Foo. I am getting ClassCastExceptions is this
* situation.
* Explicitly using the thread context class loader in the
* first place solves the problem."
*/
private Class loadClass(String className, final String codebase) throws ClassNotFoundException
{
Class clazz;
ClassLoader clazzLoader = Thread.currentThread().getContextClassLoader();
if (clazzLoader == null)
{
clazz = ValueHandler.loadClass(className, codebase, null);
}
else
{
try
{
clazz = clazzLoader.loadClass(className);
}
catch (ClassNotFoundException e)
{
clazz = ValueHandler.loadClass(className, codebase, null);
}
}
return clazz;
}
/**
* try to read in the chunk size.
* special handling if there's no chunk size
* in the stream.
*/
private void readChunkSizeTag()
{
int savedPos = pos;
int savedIndex = index;
int chunk_size_tag = read_long();
if (!sunInteropFix || chunk_size_tag > 0 && chunk_size_tag < MAX_BLOCK_SIZE)
{
// valid chunk size: set the ending position of the chunk
chunk_end_pos = pos + chunk_size_tag;
}
else
{
// reset buffer and remember that we're not within a chunk
pos = savedPos;
index = savedIndex;
adjust_positions();
}
}
/**
* Reads a value with type information, i.e. one that is preceded
* by a single RepositoryID. It is assumed that the tag and the codebase
* of the value have already been read.
*/
private java.io.Serializable read_typed_value( final int index,
final String codebase)
{
return read_untyped_value ( new String[]{ read_repository_id() }, index, codebase);
}
/**
* Reads a value using the specified factory. The preceeding single RepositoryID is ignored.
* since the type information is most likely redundant.
* It is assumed that the tag and the codebase
* of the value have already been read.
*/
private java.io.Serializable read_typed_value( final int index,
final String codebase,
final org.omg.CORBA.portable.BoxedValueHelper factory)
{
String repId = read_repository_id();
if (!factory.get_id().equals(repId))
{
// just to be sure.
throw new MARSHAL("unexpected RepositoryID. expected: " + factory.get_id() + " got: " + repId);
}
return factory.read_value(this);
}
/**
* Reads a value with type information, i.e. one that is preceded
* by an array of RepositoryIDs. It is assumed that the tag and the codebase
* of the value have already been read.
*/
private java.io.Serializable read_multi_typed_value( final int index,
final String codebase)
{
int id_count = read_long();
String[] ids = new String[ id_count ];
for( int i = 0; i < id_count; i++ )
{
ids[i] = read_repository_id();
}
return read_untyped_value (ids, index, codebase);
}
/**
* Reads a RepositoryID from the buffer, either directly or via
* indirection.
*/
private String read_repository_id()
{
int tag = read_long();
if (tag == 0xffffffff)
{
// indirection
int index = read_long();
index = index + pos - 4;
String repId = (String)getRepIdMap().get(Integer.valueOf(index));
if (repId == null)
{
throw new MARSHAL("stale RepositoryID indirection");
}
return repId;
}
// a new id
pos -= 4;
index -= 4;
int start_offset = pos;
String repId = read_string();
getRepIdMap().put(Integer.valueOf(start_offset), repId);
return repId;
}
/**
* Reads a codebase from the buffer, either directly or via
* indirection.
*/
private String read_codebase()
{
int tag = read_long();
if (tag == 0xffffffff)
{
// indirection
int index = read_long();
index = index + pos - 4;
String codebase = (String)getCodebaseMap().get(Integer.valueOf(index));
if (codebase == null)
{
throw
new MARSHAL("stale codebase indirection");
}
return codebase;
}
// a new codebase string
pos -= 4;
index -= 4;
int start_offset = pos;
String codebase = read_string();
getCodebaseMap().put (Integer.valueOf(start_offset), codebase);
return codebase;
}
/**
* Reads an indirect value from this stream. It is assumed that the
* value tag (0xffffffff) has already been read.
*/
private java.io.Serializable read_indirect_value()
{
// indirection
int index = read_long();
index = index + pos - 4;
java.lang.Object value = getValueMap().get (Integer.valueOf(index));
if (value == null)
{
// Java to IDL Language Mapping, v1.1, page 1-44:
//
// "The ValueHandler object may receive an IndirectionException
// from the ORB stream. The ORB input stream throws this exception
// when it is called to unmarshal a value encoded as an indirection
// that is in the process of being unmarshaled. This can occur when
// the ORB stream calls the ValueHandler object to unmarshal an RMI
// value whose state contains a recursive reference to itself.
// Because the top-level ValueHandler.readValue call has not yet
// returned a value, the ORB stream's indirection table contains no
// entry for an object with the stream offset specified by the
// indirection tag. This stream offset is returned in the
// exception's offset field."
throw new org.omg.CORBA.portable.IndirectionException (index);
}
return (java.io.Serializable)value;
}
/**
* Reads an abstract interface from this stream. The abstract interface
* Reads an abstract interface from this stream. The abstract interface
* appears as a union with a boolean discriminator, which is true if the
* union contains a CORBA object reference, or false if the union contains
* a value.
*/
@Override
public java.lang.Object read_abstract_interface()
{
return read_boolean() ? (java.lang.Object)read_Object()
: (java.lang.Object)read_value();
}
/**
* Reads an abstract interface from this stream. The abstract interface
* appears as a union with a boolean discriminator, which is true if the
* union contains a CORBA object reference, or false if the union contains
* a value.
*/
@Override
public java.lang.Object read_abstract_interface(final java.lang.Class clazz)
{
return read_boolean() ? (java.lang.Object)read_Object(clazz)
: (java.lang.Object)read_value(clazz);
}
@Override
public int get_pos()
{
return pos;
}
/**
* Stores `value' into this stream's valueMap. This is provided
* as a callback for value factories, so that a value factory can
* store an object into the map before actually reading its state.
* This is essential for unmarshalling recursive values.
*/
public void register_value(final java.io.Serializable value)
{
getValueMap().put(Integer.valueOf(currentValueIndex), value);
}
/**
* <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());
}
}
/**
* update the TypeCodeCache with the contents of the current repeatedTCMap using the
* entries between startPosition and (startPosition + size).
* the entries are stored using repositoryID as a key.
*/
public void updateTypeCodeCache(String repositoryID, Integer startPosition, int size)
{
final Integer from = startPosition; //Integer.valueOf(startPosition.intValue());
final Integer to = Integer.valueOf (startPosition + size);
final SortedMap sortedMap = repeatedTCMap.subMap(from, to);
final List toBeCached = new ArrayList();
// If we have found anything between the original start position and the size.
for (Iterator j = sortedMap.keySet().iterator(); j.hasNext(); )
{
final Integer key = (Integer) j.next();
final TypeCode value = (TypeCode) sortedMap.get(key);
// only remember the offset between the start of the nested TypeCode
// and the start of the parent TypeCode here.
final Integer offset = Integer.valueOf(key.intValue() - startPosition.intValue());
toBeCached.add(new TypeCodeCache.Pair(value, offset));
}
typeCodeCache.cacheTypeCode(repositoryID, (TypeCodeCache.Pair[])toBeCached.toArray(new TypeCodeCache.Pair[toBeCached.size()]));
}
/**
* try to locate a TypeCode identified by its repository id in the TypeCodeCache.
* as cached complex TypeCodes may contain nested TypeCodes. the repeatedTCMap
* will be updated with entries for these TypeCodes. this is necessary so that
* later indirections pointing to these nested TypeCodes can be resolved.
*
* @param repositoryID repository id of the TypeCode that should be looked up in the cache
* @param startPosition start position in the buffer of the TypeCode that should be looked up in the cache
* @return the cached TypeCode or null
*/
public org.omg.CORBA.TypeCode readTypeCodeCache(String repositoryID, Integer startPosition)
{
final TypeCodeCache.Pair[] result = typeCodeCache.getCachedTypeCodes(repositoryID);
if (result == null)
{
return null;
}
if (result.length == 0)
{
return null;
}
for (int i = 0; i < result.length; i++)
{
// calculate the position of the nested TypeCode by adding its offset
// to the startPosition of the parent TypeCode
final Integer position = Integer.valueOf(startPosition.intValue() + result[i].position.intValue());
repeatedTCMap.put(position, result[i].typeCode);
}
return result[0].typeCode;
}
/**
* used for debug/informational output
*/
public String getIndentString()
{
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < typeCodeNestingLevel; i++)
{
buffer.append(" ");
}
return buffer.toString();
}
/**
* <code>start_value</code> implements ValueInputStream JavaToIDL mapping 02-01-12.
* It should read a valuetype header for a nested custom valuetype and increment
* the valuetype nesting depth.
*/
@Override
public void start_value ()
{
int valueTag = read_long ();
if (valueTag == 0x00000000)
{
// null tag, just do nothing
return;
}
// check that codebase is null
String codebase = ((valueTag & 1) != 0) ? read_codebase() : null;
if (codebase != null)
{
throw new MARSHAL ("Custom marshaled value should have null codebase");
}
chunkedValue = ((valueTag & 0x00000008) != 0);
// single repository ID
read_repository_id ();
if (chunkedValue || (valueNestingLevel > 0 && !sunInteropFix))
{
valueNestingLevel++;
readChunkSizeTag();
handle_chunking();
}
}
/**
* <code>end_value</code> implements ValueInputStream JavaToIDL mapping 02-01-12.
* It should read the end tag for the nested custom valuetype (after skipping
* any data that precedes the end tag) and decrements the valuetype nesting depth.
*
*/
@Override
public void end_value ()
{
// skip rest of chunk to its end
if (chunk_end_pos != -1 && pos > chunk_end_pos)
{
skip (pos - chunk_end_pos);
}
handle_chunking ();
}
}