package org.jacorb.orb;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2004 Gerald Brose.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.jacorb.config.*;
import org.slf4j.Logger;
import org.jacorb.orb.giop.CodeSet;
import org.jacorb.orb.giop.GIOPConnection;
import org.jacorb.util.ObjectUtil;
import org.jacorb.util.Stack;
import org.jacorb.util.ValueHandler;
import org.omg.CORBA.BAD_PARAM;
import org.omg.CORBA.INTERNAL;
import org.omg.CORBA.MARSHAL;
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.StructMember;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.UnionMember;
import org.omg.CORBA.ValueMember;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.TypeCodePackage.Bounds;
import org.omg.CORBA.portable.IDLEntity;
/**
* Read CDR encoded data
*
* @author Gerald Brose, FU Berlin
* $Id: CDRInputStream.java,v 1.123.2.1 2011-12-22 14:18:37 nick.cross Exp $
*/
public class CDRInputStream
extends org.omg.CORBA_2_3.portable.InputStream
implements CodeSet.InputBuffer
{
/**
* <code>encaps_stack</code> is used to saving/restoring
* encapsulation information.
*/
private Stack encaps_stack;
/**
* This Map is basically a one-entry map pool to be used in
* read_TypeCode() as the repeatedTCMap.
*/
private Map repeatedTCMap;
/**
* <code>cachedTypecodes</code> stores a mapping of ID/Typecode to
* speed reading from the stream. Do NOT access this variable directly. It
* is initialized on demand. Use the methods
* {@link #getCachedTypecode(Object id)} and
* {@link #putCachedTypecode(Object id, Pair result)}
* Skip amount is
* skip (size - ((pos - start_pos) - 4 - 4));
* EncapsulationSize -
* ( PositionAfterReadingId - start_pos
* - 4 [Size] - 4 [KindSize] ) = RemainingSizeToSkip
*/
private Map cachedTypecodes;
/** indexes to support mark/reset */
private int marked_pos;
private int marked_index;
private boolean closed;
/** configurable properties */
private Logger logger;
private boolean cometInteropFix;
private boolean laxBooleanEncoding;
private boolean cacheTypecodes;
/* character encoding code sets for char and wchar, default ISO8859_1 */
private CodeSet codeSet = CodeSet.getTCSDefault();
private CodeSet codeSetW = CodeSet.getTCSWDefault();
protected int giop_minor = 2; // needed to determine size in chars
/**
* <code>valueMap</code> maps indices within the buffer
* (java.lang.Integer) to the values that appear at these indices. Do
* NOT access this variable directly. It is initialized on demand.
* Use the method {@link #getValueMap()}
*/
private Map valueMap;
/**
* Index of the current IDL value that is being unmarshalled.
* This is kept here so that when the value object has been
* created, the value factory can immediately store it into this
* stream's valueMap by calling `register_value()'.
*/
private int currentValueIndex;
/**
* <code>repIdMap</code> maps indices within the buffer
* (java.lang.Integer) to repository ids that appear at these indices.
* Do NOT access this variable directly. It is initialized on demand.
* Use the method {@link #getRepIdMap()}
*/
private Map repIdMap;
/**
* <code>codebaseMap</code> maps indices within the buffer
* (java.lang.Integer) to codebase strings that appear at these indices.
* Do NOT access this variable directly. It is initialized on demand.
* Use the method {@link #getCodebaseMap()}
*/
private Map codebaseMap;
public boolean littleEndian = false;
/** indices into the actual buffer */
protected byte[] buffer = null;
protected int pos = 0;
protected int index = 0;
/** Last value tag read had the chunking bit on */
private boolean chunkedValue = false;
/** Nesting level of chunked valuetypes */
private int valueNestingLevel = 0;
/** Ending position of the current chunk */
private int chunk_end_pos = -1; // -1 means we're not within a chunk
/**
* <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 Map tcMap;
public CDRInputStream(final org.omg.CORBA.ORB orb, final byte[] buf)
{
super();
buffer = buf;
// orb may be null!
if (orb != null)
{
this.orb = orb;
// orb may be the singleton!
if (orb instanceof org.jacorb.orb.ORB)
{
try
{
configure(((org.jacorb.orb.ORB)orb).getConfiguration());
}
catch( ConfigurationException ce )
{
throw new INTERNAL("ConfigurationException: " + ce);
}
}
}
else
{
this.orb = org.omg.CORBA.ORB.init();
}
}
public CDRInputStream(final org.omg.CORBA.ORB orb,
final byte[] buf,
final boolean littleEndian )
{
this( orb, buf );
this.littleEndian = littleEndian;
}
public CDRInputStream(byte[] buffer)
{
this(null, buffer);
}
public CDRInputStream(byte[] buffer, boolean littleEndian)
{
this(null, buffer, littleEndian);
}
/**
* This stream is self-configuring, i.e. configure() is private
* and only called from the constructors.
*/
private void configure(Configuration configuration)
throws ConfigurationException
{
final org.jacorb.config.Configuration jacorbConfig = (org.jacorb.config.Configuration)configuration;
logger =
jacorbConfig.getLogger("jacorb.orb.cdr");
codesetEnabled =
configuration.getAttribute("jacorb.codeset","on").equals("on");
cometInteropFix =
configuration.getAttribute("jacorb.interop.comet","off").equals("on");
laxBooleanEncoding =
configuration.getAttribute("jacorb.interop.lax_boolean_encoding","off").equals("on");
cacheTypecodes =
configuration.getAttribute("jacorb.cacheTypecodes","off").equals("on");
sunInteropFix =
configuration.getAttribute("jacorb.interop.sun", "off").equalsIgnoreCase("on");
isMutatorEnabled = configuration.getAttribute("jacorb.iormutator", "").length() > 0;
if (isMutatorEnabled)
{
mutator = (IORMutator) jacorbConfig.getAttributeAsObject("jacorb.iormutator");
}
}
/**
* Gets the Map that is used to demarshal shared valuetype instances.
*
* @return a <code>Map</code> value
*/
private Map getValueMap()
{
if (valueMap == null)
{
// Unlike the valueMap in CDROutputStream, this one
// does need to be an equality-based HashMap.
valueMap = new HashMap();
}
return valueMap;
}
/**
* Gets the Map that is used to implement indirections for RepositoryIDs.
*
* @return a <code>Map</code> value
*/
private Map getRepIdMap()
{
if (repIdMap == null)
{
repIdMap = new HashMap();
}
return repIdMap;
}
/**
* Gets the Map that is used to implement sharing for codebase
* specifications.
*
* @return a <code>Map</code> value
*/
private Map getCodebaseMap()
{
if (codebaseMap == null)
{
codebaseMap = new HashMap();
}
return codebaseMap;
}
/**
* <code>getCachedTypecode</code> to retrieve a value from cachedTypecodes.
* It may initialize the value on demand.
*
* @param id a <code>Object</code> value, can be String (id) or actual TypeCode
* for sequence/array tcs
* @return a <code>org.omg.CORBA.TypeCode</code> value, possibly null.
*/
private Pair getCachedTypecode( Object id )
{
final Pair result;
if ( cacheTypecodes )
{
if ( cachedTypecodes == null )
{
cachedTypecodes = new HashMap();
result = null;
}
else
{
result = ( Pair )cachedTypecodes.get( id );
}
}
else
{
result = null;
}
return result;
}
/**
* <code>putCachedTypecode</code> is used to store typecodes within the
* cachedTypecodes. It will only do it cacheTypecodes is on.
*
* @param id a <code>String</code> or <code>TypeCode</code> value
* @param result an Pair value
*/
private void putCachedTypecode( Object id, Pair result)
{
if ( cacheTypecodes )
{
// By definition get/put should be paired so cachedTypecodes should
// never be null here.
cachedTypecodes.put (id, result);
}
}
public void setGIOPMinor(final int giop_minor )
{
this.giop_minor = giop_minor;
}
public int getGIOPMinor()
{
return giop_minor;
}
public void close()
{
// 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 (tcMap != null)
{
tcMap.clear();
}
}
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 - (this.index % 4);
int aligned_pos = (remainder != 4) ? this.pos + remainder : this.pos;
if (this.chunk_end_pos >= pos && this.chunk_end_pos <= aligned_pos)
{
this.adjust_positions();
}
}
private final void adjust_positions()
{
this.chunk_end_pos = -1;
int saved_pos = this.pos;
int saved_index = this.index;
int tag = this.read_long();
if (tag < 0)
{
// tag is an end tag
if (-tag > this.valueNestingLevel)
{
throw new INTERNAL
(
"received end tag " + tag +
" with value nesting level " +
this.valueNestingLevel
);
}
this.valueNestingLevel = -tag;
this.valueNestingLevel--;
if (this.valueNestingLevel > 0)
{
this.chunk_end_pos = pos;
this.handle_chunking();
}
}
else if (tag > 0 && tag < 0x7fffff00)
{
// tag is the chunk size tag of another chunk
this.chunk_end_pos = this.pos + tag;
}
else // (tag == 0 || tag >= 0x7fffff00)
{
// tag is the null value tag or the value tag of a nested value
this.pos = saved_pos; // "unread" the tag
this.index = saved_index;
}
}
protected final void skip(final int distance)
{
pos += distance;
index += distance;
}
/**
* close a CDR encapsulation and
* restore index and byte order information
*/
public final void closeEncapsulation()
{
if (encaps_stack == null)
{
throw new MARSHAL( "Internal Error - closeEncapsulation failed" );
}
EncapsInfo ei = (EncapsInfo)encaps_stack.pop();
littleEndian = ei.littleEndian;
int size = ei.size;
int start = ei.start;
if( pos < start + size )
{
pos = start + size;
}
index = ei.index + size;
}
/**
* open a CDR encapsulation and
* restore index and byte order information
*/
public final int openEncapsulation()
{
boolean old_endian = littleEndian;
int size = read_long();
// Check if size looks sane. If not try changing byte order.
// This is a specific fix for interoperability with the Iona
// Comet COM/CORBA bridge that has problems with size marshalling.
if (cometInteropFix && ((size < 0) || (size > buffer.length)))
{
int temp =
(
((size >> 24) & 0x000000FF) +
((size >> 8) & 0x0000FF00) +
((size << 8) & 0x00FF0000) +
((size << 24) & 0xFF000000)
);
if (logger.isDebugEnabled())
{
logger.debug("Size of CDR encapsulation larger than buffer, swapping byte order\n" +
"Size of CDR encapsulation was " + size + ", is now " + temp);
}
size = temp;
}
/* save current index plus size of the encapsulation on the stack.
When the encapsulation is closed, this value will be restored as
index */
if (encaps_stack == null)
{
encaps_stack = new Stack();
}
encaps_stack.push(new EncapsInfo(old_endian, index, pos, size ));
openEncapsulatedArray();
return size;
}
public final void openEncapsulatedArray()
{
/* reset index to zero, i.e. align relative to the beginning
of the encaps. */
resetIndex();
littleEndian = read_boolean();
}
/*
* Return a copy of the current buffer.
*
* @return a <code>byte[]</code> value.
*/
public byte[] getBufferCopy()
{
byte[] result = new byte[buffer.length];
System.arraycopy
(
buffer,
0,
result,
0,
buffer.length
);
return result;
}
/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned.
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @throws java.io.IOException if stream is closed.
*/
public int read()
throws java.io.IOException
{
if( closed )
{
throw new java.io.IOException("Stream already closed!");
}
if( available() < 1 )
{
return -1;
}
++index;
return buffer[pos++]; // read_index++];
}
/**
* @return the number of bytes that can be read (or skipped over) from this
* input stream. This is not necessarily the number of 'valid' bytes.
*/
public int available()
{
return buffer.length - index;
}
/**
* Has the effect of read(b, 0, b.length);
* @see #read(byte[], int, int)
*/
public int read(final byte[] b)
throws java.io.IOException
{
return read(b, 0, b.length);
}
/**
* Performs as described by <code>java.io.InputStream.read(byte[], int, int)</code>,
* but never blocks.
*/
public int read(final byte[] b, final int off, final int len)
throws java.io.IOException
{
if( b == null )
{
throw new java.io.IOException("buffer may not be null");
}
if( off < 0 ||
len < 0 ||
off + len > b.length )
{
throw new java.io.IOException("buffer index out of bounds");
}
if( len == 0 )
{
return 0;
}
if( available() < 1 )
{
return -1;
}
if( closed )
{
throw new java.io.IOException("Stream already closed!");
}
int min = Math.min(len, available());
System.arraycopy(buffer, index, b, off, min );
pos += min;
index += min;
return min;
}
public final org.omg.CORBA.Any read_any()
{
org.omg.CORBA.TypeCode _tc = read_TypeCode();
org.omg.CORBA.Any any = orb.create_any();
any.read_value( this, _tc );
return any;
}
public final boolean read_boolean()
{
// handle_chunking();
if (this.chunk_end_pos == this.pos)
{
this.adjust_positions();
}
index++;
byte value = buffer[pos++];
if (value == 0)
{
return false;
}
if (value == 1)
{
return true;
}
if (laxBooleanEncoding)
{
// Technically only valid values are 0 (false) and 1 (true)
// however some ORBs send values other than 1 for true.
return true;
}
throw new MARSHAL("Unexpected boolean value: " + value
+ " pos: " + pos + " index: " + index);
}
/** arrays */
public final void read_boolean_array
(final boolean[] value, final int offset, final int length)
{
handle_chunking();
byte bb;
for (int j = offset; j < offset + length; j++)
{
index++;
bb = buffer[pos++];
if (bb == 1)
{
value[j] = true;
}
else if (bb == 0)
{
value[j] = false;
}
else
{
throw new MARSHAL ("Unexpected boolean value: " + bb
+ " pos: " + pos + " index: " + index);
}
}
}
/**
* <code>read_char</code> reads a character from the stream.
*
* @return a <code>char</code> value
*/
public final char read_char()
{
handle_chunking();
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
*/
public final void read_char_array
(final char[] value, final int offset, final int length)
{
if (value == null)
{
throw new MARSHAL("Cannot marshall result into null array.");
}
else if ( offset + length > value.length || length < 0 || offset < 0 )
{
throw new MARSHAL
("Cannot marshall as indices for array are out bounds.");
}
handle_chunking();
for (int j = offset; j < offset + length; j++)
{
index++;
value[j] = (char) (0xff & buffer[pos++]);
}
}
public final double read_double()
{
return Double.longBitsToDouble (read_longlong());
}
public final void read_double_array
(final double[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = Double.longBitsToDouble (_read_longlong());
}
}
/**
* @deprecated use {@link #read_fixed(short, short)} instead
*/
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);
}
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 && (outBuffer.length() != digits))
{
throw new MARSHAL("unexpected number of digits: expected " + digits + " got " + outBuffer.length() + " " + outBuffer);
}
return c;
}
public final float read_float()
{
return Float.intBitsToFloat (read_long());
}
public final void read_float_array
(final float[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = Float.intBitsToFloat (_read_long());
}
}
public final int read_long()
{
handle_chunking();
int result;
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
result = _read4int (littleEndian, buffer, pos);
index += 4;
pos += 4;
return result;
}
public final void read_long_array
(final int[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset+length; j++)
{
value[j] = _read4int (littleEndian,buffer,pos);
pos += 4;
}
index += 4 * length;
}
public final long read_longlong()
{
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
return (_read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
}
return ((long) _read_long() << 32) + (_read_long() & 0xFFFFFFFFL);
}
public final void read_longlong_array
(final long[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
for(int j=offset; j < offset+length; j++)
{
value[j] = ( _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
}
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);
}
ParsedIOR pior = new ParsedIOR( (org.jacorb.orb.ORB)orb, ior );
if( pior.isNull() )
{
return null;
}
return ((org.jacorb.orb.ORB)orb)._getObject( pior );
}
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();
}
}
public final byte read_octet()
{
handle_chunking();
index++;
return buffer[pos++];
}
public final void read_octet_array
(final byte[] value, final int offset, final int length)
{
handle_chunking();
System.arraycopy (buffer,pos,value,offset,length);
index += length;
pos += length;
}
/*
* @deprecated
* @see org.omg.CORBA.portable.InputStream#read_Principal()
*/
public final org.omg.CORBA.Principal read_Principal()
{
throw new NO_IMPLEMENT ("Principal deprecated");
}
/**
* Read methods for big-endian as well as little endian data input
* contributed by Mark Allerton <MAllerton@img.seagatesoftware.com>
*/
public final short read_short()
{
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
short result = _read2int (littleEndian,buffer,pos);
pos += 2;
index += 2;
return result;
}
public final void read_short_array
(final short[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = _read2int (littleEndian, buffer, pos);
pos += 2;
}
index += length * 2;
}
/**
* <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.
*/
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)
{
throw new MARSHAL("invalid string size: " + size);
}
int start = pos + 4;
index += (size + 4);
pos += (size + 4);
final int stringTerminatorPosition = start + size -1;
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;
}
public final org.omg.CORBA.TypeCode read_TypeCode()
{
if (tcMap == null)
{
// Initialise tcMap. We keep it for the lifetime of this
// stream so it is possible to examine any found recursive
// typecodes.
tcMap = new TreeMap();
}
if (repeatedTCMap == null)
{
repeatedTCMap = new HashMap();
}
try
{
return read_TypeCode( tcMap, repeatedTCMap );
}
finally
{
repeatedTCMap.clear();
}
}
private final org.omg.CORBA.TypeCode read_TypeCode(final Map recursiveTCMap,
final Map repeatedTCMap )
{
final String id;
final String name;
final Pair cachedObject;
final int member_count;
final int length;
final int size;
final org.omg.CORBA.TypeCode result;
final org.omg.CORBA.TypeCode content_type;
final String[] member_names;
final int kind = read_long();
final int start_pos = pos - 4;
final Integer startPosition = ObjectUtil.newInteger( start_pos );
if (logger != null && logger.isDebugEnabled())
{
logger.debug("Read Type code of kind " + kind + " at pos: " + start_pos);
}
switch( kind )
{
case -1: //0xffffffff:
{
// recursive or repeated TC
int negative_offset = read_long();
final Integer origTCStartPos = ObjectUtil.newInteger(pos - 4 + negative_offset);
// need to check for repeated typecode first since a recursive
// typecode may also be repeated (i.e. both maps have an entry
// for the given origTCStartPos), but if we find an entry in
// the repeatedTCMap, we know the typecode must have
// completely been read already, so the marker can't indicate
// a recursive typecode
final org.omg.CORBA.TypeCode repeatedTC =
(org.omg.CORBA.TypeCode)repeatedTCMap.get(origTCStartPos);
if (repeatedTC != null)
{
result = repeatedTC;
break;
}
final String recursiveId = (String) recursiveTCMap.get(origTCStartPos);
if (recursiveId != null)
{
try
{
result = orb.create_recursive_tc(recursiveId);
break;
}
catch(org.omg.CORBA.SystemException e)
{
throw new MARSHAL(
"Failed to create recursive typecode: " +
e);
}
}
//if we end up here, we didn't find an entry in either
//repeatedTCMap and recursiveTCMap
throw new MARSHAL(
"Found indirection marker, but no corresponding "+
"original typecode (pos: " + origTCStartPos + ")" );
}
case TCKind._tk_null: // 0
case TCKind._tk_void: // 1
case TCKind._tk_short: // 2
case TCKind._tk_long: // 3
case TCKind._tk_ushort: // 4
case TCKind._tk_ulong: // 5
case TCKind._tk_float: // 6
case TCKind._tk_double: // 7
case TCKind._tk_boolean: // 8
case TCKind._tk_char: // 9
case TCKind._tk_octet: // 10
case TCKind._tk_any: // 11
case TCKind._tk_TypeCode: // 12
case TCKind._tk_Principal: // 13
{
result = orb.get_primitive_tc(org.omg.CORBA.TCKind.from_int (kind));
break;
}
case TCKind._tk_objref: // 14
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string ());
result = orb.create_interface_tc (id, name);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
skip(skipAmount);
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_struct: // 15
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
member_count = read_long();
recursiveTCMap.put( startPosition, id );
StructMember[] struct_members = new StructMember[member_count];
for( int i = 0; i < member_count; i++)
{
struct_members[i] = new StructMember
(
read_string(),
read_TypeCode (recursiveTCMap, repeatedTCMap),
null
);
}
result = ((ORBSingleton) orb).create_struct_tc(id, name, struct_members, false);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap( recursiveTCMap, start_pos, skipAmount, cachedObject.position );
skip (skipAmount);
recursiveTCMap.put( startPosition, id );
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_union: // 16
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
recursiveTCMap.put(startPosition, id );
org.omg.CORBA.TypeCode discriminator_type = read_TypeCode(recursiveTCMap, repeatedTCMap);
// Use the dealiased discriminator type for the label types.
// This works because the JacORB IDL compiler ignores any aliasing
// of label types and only the discriminator type is passed on the
// wire.
org.omg.CORBA.TypeCode orig_disc_type =
TypeCode.originalType(discriminator_type);
int default_index = read_long();
member_count = read_long();
UnionMember[] union_members = new UnionMember[member_count];
for( int i = 0; i < member_count; i++)
{
org.omg.CORBA.Any label = orb.create_any();
if( i == default_index )
{
// Default discriminator
label.insert_octet( read_octet());
}
else
{
// use the dealiased discriminator type to construct labels
label.read_value( this, orig_disc_type );
}
union_members[i] = new UnionMember
(
read_string(),
label,
read_TypeCode(recursiveTCMap, repeatedTCMap),
null
);
}
result = ((ORBSingleton)orb).create_union_tc(id, name, discriminator_type, union_members, false);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap(recursiveTCMap, start_pos, skipAmount, cachedObject.position );
skip (skipAmount);
recursiveTCMap.put( startPosition, id );
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_enum: // 17
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
member_count = read_long();
member_names = new String[member_count];
for( int i = 0; i < member_count; i++)
{
member_names[i] = read_string();
}
result = ((ORBSingleton)orb).create_enum_tc (id, name, member_names, false);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
skip (skipAmount);
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_string: // 18
{
result = orb.create_string_tc(read_long());
break;
}
case TCKind._tk_sequence: // 19
{
size = openEncapsulation();
content_type = read_TypeCode(recursiveTCMap, repeatedTCMap);
cachedObject = getCachedTypecode(content_type);
if (cachedObject == null)
{
length = read_long();
result = orb.create_sequence_tc(length, content_type);
putCachedTypecode(result, new Pair(result, startPosition));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
skip (skipAmount);
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_array: // 20
{
size = openEncapsulation();
content_type = read_TypeCode(recursiveTCMap, repeatedTCMap);
cachedObject = getCachedTypecode(content_type);
if (cachedObject == null)
{
result = orb.create_array_tc(read_long(), content_type );
// Store in cache
putCachedTypecode (result, new Pair( result, startPosition ));
}
else
{
int skipAmount = calcSkipAmount(size, start_pos);
skip (skipAmount);
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_alias: // 21
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
recursiveTCMap.put(startPosition, id );
content_type = read_TypeCode( recursiveTCMap, repeatedTCMap);
result = orb.create_alias_tc (id, name, content_type );
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap(recursiveTCMap, start_pos, skipAmount, cachedObject.position );
skip (skipAmount);
recursiveTCMap.put( startPosition, id );
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_except: // 22
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
member_count = read_long();
recursiveTCMap.put(startPosition, id );
StructMember[] members = new StructMember[member_count];
for( int i = 0; i < member_count; i++)
{
members[i] = new StructMember
(
read_string(),
read_TypeCode(recursiveTCMap, repeatedTCMap),
null
);
}
result = ((ORBSingleton)orb).create_exception_tc (id, name, members, false);
// Store in cache
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap(recursiveTCMap, start_pos, skipAmount, cachedObject.position );
skip (skipAmount);
recursiveTCMap.put( startPosition, id );
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_longlong: // 23
case TCKind._tk_ulonglong: // 24
{
result = orb.get_primitive_tc
(org.omg.CORBA.TCKind.from_int (kind));
break;
}
case TCKind._tk_longdouble: //25
{
throw new MARSHAL("Cannot handle TypeCode with kind " + kind);
}
case TCKind._tk_wchar: // 26
{
result = orb.get_primitive_tc
(org.omg.CORBA.TCKind.from_int (kind));
break;
}
case TCKind._tk_wstring: // 27
{
result = orb.create_wstring_tc(read_long());
break;
}
case TCKind._tk_fixed: // 28
{
result = orb.create_fixed_tc(read_ushort(), read_short() );
break;
}
case TCKind._tk_value: // 29
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
recursiveTCMap.put(startPosition, id);
short type_modifier = read_short();
org.omg.CORBA.TypeCode concrete_base_type = read_TypeCode( recursiveTCMap, repeatedTCMap);
member_count = read_long();
ValueMember[] vMembers = new ValueMember[member_count];
for( int i = 0; i < member_count; i++)
{
vMembers[i] = new ValueMember
(
read_string(),
null, // id
null, // defined_in
null, // version
read_TypeCode (recursiveTCMap, repeatedTCMap),
null, // type_def
read_short()
);
}
result = orb.create_value_tc
(id, name, type_modifier, concrete_base_type, vMembers);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap(recursiveTCMap, start_pos, skipAmount, cachedObject.position );
skip (skipAmount);
recursiveTCMap.put( startPosition, id );
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_value_box: // 30
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
recursiveTCMap.put(startPosition, id);
content_type = read_TypeCode( recursiveTCMap, repeatedTCMap);
result = orb.create_value_box_tc (id, name, content_type);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap(recursiveTCMap, start_pos, skipAmount, cachedObject.position );
skip (skipAmount);
recursiveTCMap.put( startPosition, id );
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
case TCKind._tk_native: //31
{
throw new MARSHAL("Cannot handle TypeCode with kind " + kind);
}
case TCKind._tk_abstract_interface: // 32
{
size = openEncapsulation();
id = validateID (read_string());
cachedObject = getCachedTypecode( id );
if (cachedObject == null)
{
name = validateName (read_string());
recursiveTCMap.put(startPosition, id);
result = orb.create_abstract_interface_tc (id, name);
putCachedTypecode (id, new Pair( result, startPosition ));
}
else
{
final int skipAmount = calcSkipAmount(size, start_pos);
updateTcMap (recursiveTCMap, start_pos, skipAmount, cachedObject.position);
skip (skipAmount);
recursiveTCMap.put (startPosition, id);
result = cachedObject.typeCode;
}
closeEncapsulation();
break;
}
default:
{
// error, dump buffer contents for diagnosis
throw new MARSHAL("Cannot handle TypeCode with kind " + kind);
}
}
repeatedTCMap.put(startPosition, result);
return result;
}
/**
* see cachedTypecodes for calculation.
* @param size
* @param start_pos
*/
private int calcSkipAmount(final int size, final int start_pos)
{
return (size - ((pos - start_pos) - 4 - 4));
}
/**
* <code>updateTcMap</code> is used during cached typecodes. As a cached
* typecode is being used we may miss placing markers for the recursive
* tcMap. Therefore, by recording the original typecodes start, and as we
* know the length it is possible find and calculate and extra positions
* that should be added.
*
* @param tcMap a <code>Map</code> value which may be updated.
* @param new_start an <code>int</code> value
* @param size an <code>int</code> value
* @param old_start an <code>Integer</code> value
*/
private void updateTcMap(final Map tcMap,
final int new_start,
final int size,
final Integer old_start )
{
final SortedMap sortedMap = ((TreeMap)tcMap).subMap
( old_start, ObjectUtil.newInteger( size + old_start.intValue() ) );
// If we have found anything between the original start position and the size.
if( sortedMap.size() > 0 )
{
final TreeMap toMerge = new TreeMap();
final Iterator iterator = sortedMap.entrySet().iterator();
while( iterator.hasNext() )
{
final Map.Entry entry = (Map.Entry)iterator.next();
int value = ((Integer)entry.getKey()).intValue();
// This calculation is the offset; the distance between the missing
// tc and the original start added onto the new start.
toMerge.put
(
ObjectUtil.newInteger( new_start + (value - old_start.intValue() ) ),
entry.getValue()
);
}
tcMap.putAll( toMerge );
}
}
public final int read_ulong()
{
handle_chunking();
int result;
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
result = _read4int (littleEndian, buffer, pos);
index += 4;
pos += 4;
return result;
}
public final void read_ulong_array
(final int[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 4 - (index % 4);
if (remainder != 4)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset+length; j++)
{
value[j] = _read4int (littleEndian,buffer,pos);
pos += 4;
}
index += 4 * length;
}
public final long read_ulonglong()
{
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
return (_read_long() & 0xFFFFFFFFL) + ((long) _read_long() << 32);
}
return ((long) _read_long() << 32) + (_read_long() & 0xFFFFFFFFL);
}
public final void read_ulonglong_array
(final long[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 8 - (index % 8);
if (remainder != 8)
{
index += remainder;
pos += remainder;
}
if (littleEndian)
{
for (int j = offset; j < offset+length; j++)
{
value[j] = ( _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
}
public final short read_ushort()
{
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
short result = _read2int (littleEndian,buffer,pos);
pos += 2;
index += 2;
return result;
}
public final void read_ushort_array
(final short[] value, final int offset, final int length)
{
if (length == 0)
{
return;
}
handle_chunking();
int remainder = 2 - (index % 2);
if (remainder != 2)
{
index += remainder;
pos += remainder;
}
for (int j = offset; j < offset + length; j++)
{
value[j] = _read2int (littleEndian, buffer, pos);
pos += 2;
}
index += length * 2;
}
public final char read_wchar()
{
handle_chunking();
if (giop_minor == 2)
{
//ignore size indicator
read_wchar_size();
boolean wchar_little_endian = readBOM();
return read_wchar (wchar_little_endian);
}
return read_wchar (littleEndian);
}
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).
*/
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;
}
}
public final void read_wchar_array
(final char[] value, final int offset, final int length)
{
handle_chunking();
for(int j=offset; j < offset+length; j++)
{
value[j] = read_wchar(); // inlining later...
}
}
public final String read_wstring()
{
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 );
}
public boolean markSupported()
{
return true;
}
public void mark(final int readLimit)
{
marked_pos = pos;
marked_index = index;
}
public void reset()
throws IOException
{
if( pos < 0 )
{
throw new MARSHAL("Mark has not been set!");
}
pos = marked_pos;
index = marked_index;
}
// JacORB-specific
private final void resetIndex()
{
index = 0;
}
public final void setLittleEndian(final boolean b)
{
littleEndian = b;
}
/**
* Reads an instance of the type described by type code <code>tc</code>
* from this CDRInputStream, and remarshals it to the given OutputStream,
* <code>out</code>. Called from Any.
*/
final void read_value(final org.omg.CORBA.TypeCode 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);
}
}
public java.io.Serializable read_value()
{
int tag = read_long();
int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag
return null;
}
String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
throw new MARSHAL ("missing value type information");
}
else if (tag == 0x7fffff02)
{
return read_typed_value(start_offset, codebase);
}
else if (tag == 0x7fffff06)
{
return read_multi_typed_value( start_offset, codebase );
}
else
{
throw new MARSHAL("unknown value tag: 0x" +
Integer.toHexString(theTag) + " (offset=0x" +
Integer.toHexString(start_offset) + ")");
}
}
/**
* Overrides read_value(java.io.Serializable value) in
* org.omg.CORBA_2_3.portable.InputStream
*/
public java.io.Serializable read_value(final String rep_id)
{
int tag = read_long();
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
*/
public java.io.Serializable read_value(java.io.Serializable value)
{
if (value instanceof org.omg.CORBA.portable.Streamable)
{
register_value(value);
((org.omg.CORBA.portable.Streamable)value)._read(this);
}
else if (value instanceof org.omg.CORBA.portable.CustomValue )
{
register_value(value);
( ( org.omg.CORBA.portable.CustomValue ) value ).unmarshal(
new DataInputStream( this ) );
}
else
{
throw new BAD_PARAM("read_value is only implemented for Streamables");
}
return value;
}
/**
* Overrides read_value(clz) in
* org.omg.CORBA_2_3.portable.InputStream
*/
public java.io.Serializable read_value(final java.lang.Class clz)
{
int tag = read_long();
int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag
return null;
}
String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
return read_untyped_value (new String[]{ValueHandler.getRMIRepositoryID(clz)},
start_offset, codebase);
}
else if (tag == 0x7fffff02)
{
return read_typed_value(start_offset, codebase);
}
else if (tag == 0x7fffff06)
{
return read_multi_typed_value(start_offset, codebase);
}
else
{
throw new MARSHAL("unknown value tag: 0x" +
Integer.toHexString(theTag) +
" (offset=0x" +
Integer.toHexString(start_offset) +
")");
}
}
/**
* Overrides read_value(factory) in
* org.omg.CORBA_2_3.portable.InputStream
*/
public java.io.Serializable read_value
(final org.omg.CORBA.portable.BoxedValueHelper factory)
{
int tag = read_long();
int start_offset = pos - 4;
if (tag == 0xffffffff)
{
// indirection
return read_indirect_value();
}
else if (tag == 0x00000000)
{
// null tag, explicit representation of null value
return null;
}
String codebase = ((tag & 1) != 0) ? read_codebase() : null;
chunkedValue = ((tag & 8) != 0);
int theTag = tag;
tag = tag & 0xfffffff6;
if (tag == 0x7fffff00)
{
java.io.Serializable result = factory.read_value (this);
if( result != null )
{
getValueMap().put(ObjectUtil.newInteger(start_offset), result);
}
return result;
}
else if (tag == 0x7fffff02)
{
final Serializable result = read_typed_value(start_offset, codebase, factory);
if (result != null)
{
getValueMap().put(ObjectUtil.newInteger(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(ObjectUtil.newInteger(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;
chunk_end_pos = -1;
}
}
/**
* 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(ObjectUtil.newInteger(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(ObjectUtil.newInteger(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(ObjectUtil.newInteger(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 (ObjectUtil.newInteger(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 (ObjectUtil.newInteger(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;
}
private String validateName(String name)
{
if (name != null && name.length() == 0)
{
return null;
}
return name;
}
private String validateID(String id)
{
if (id == null || id.length() == 0)
{
return "IDL:";
}
return id;
}
/**
* Reads an abstract interface from this stream. The abstract interface
* Reads an abstract interface from this stream. The abstract interface
* appears as a union with a boolean discriminator, which is true if the
* union contains a CORBA object reference, or false if the union contains
* a value.
*/
public java.lang.Object read_abstract_interface()
{
return read_boolean() ? (java.lang.Object)read_Object()
: (java.lang.Object)read_value();
}
/**
* Reads an abstract interface from this stream. The abstract interface
* appears as a union with a boolean discriminator, which is true if the
* union contains a CORBA object reference, or false if the union contains
* a value.
*/
public java.lang.Object read_abstract_interface(final java.lang.Class clazz)
{
return read_boolean() ? (java.lang.Object)read_Object(clazz)
: (java.lang.Object)read_value(clazz);
}
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(ObjectUtil.newInteger(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());
}
}
/**
* <code>Pair</code> is merely a private storage class used by
* {@link #cachedTypecodes}.
*/
private static final class Pair
{
/**
* <code>first</code> is the typecode we are caching.
*/
public final org.omg.CORBA.TypeCode typeCode;
/**
* <code>second</code> is the location the original typecode was found.
*/
public final Integer position;
/**
* Create a new <code>Pair</code>.
*
* @param typeCode an <code>org.omg.CORBA.TypeCode</code> value
* @param position an <code>Integer</code> value
*/
public Pair( org.omg.CORBA.TypeCode typeCode, Integer position )
{
this.typeCode = typeCode;
this.position = position;
}
/**
* <code>toString</code> used for debugging ONLY.
*
* @return a <code>String</code> value
*/
public String toString()
{
return (typeCode + " and " + position );
}
}
}