//
// Copyright (c) ZeroC, Inc. All rights reserved.
//
namespace Ice
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Protocol = IceInternal.Protocol;
///
/// Interface for output streams used to write Slice types to a sequence
/// of bytes.
///
public class OutputStream
{
///
/// Constructing an OutputStream without providing a communicator means the stream will
/// use the default encoding version and the default format for class encoding.
/// You can supply a communicator later by calling initialize().
///
public OutputStream()
{
_buf = new IceInternal.Buffer();
_instance = null;
_closure = null;
_encoding = Util.currentEncoding;
_format = FormatType.CompactFormat;
}
///
/// This constructor uses the communicator's default encoding version.
///
/// The communicator to use when initializing the stream.
public OutputStream(Communicator communicator)
{
Debug.Assert(communicator != null);
IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
initialize(instance, instance.defaultsAndOverrides().defaultEncoding);
}
///
/// This constructor uses the given communicator and encoding version.
///
/// The communicator to use when initializing the stream.
/// The desired encoding version.
public OutputStream(Communicator communicator, EncodingVersion encoding)
{
Debug.Assert(communicator != null);
IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
initialize(instance, encoding);
}
public OutputStream(IceInternal.Instance instance, EncodingVersion encoding)
{
initialize(instance, encoding);
}
public OutputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, bool adopt)
{
initialize(instance, encoding, new IceInternal.Buffer(buf, adopt));
}
public OutputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data)
{
initialize(instance, encoding);
_buf = new IceInternal.Buffer(data);
}
///
/// Initializes the stream to use the communicator's default encoding version and class
/// encoding format.
///
/// The communicator to use when initializing the stream.
public void initialize(Communicator communicator)
{
Debug.Assert(communicator != null);
IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
initialize(instance, instance.defaultsAndOverrides().defaultEncoding);
}
///
/// Initializes the stream to use the given encoding version and the communicator's
/// default class encoding format.
///
/// The communicator to use when initializing the stream.
/// The desired encoding version.
public void initialize(Communicator communicator, EncodingVersion encoding)
{
Debug.Assert(communicator != null);
IceInternal.Instance instance = IceInternal.Util.getInstance(communicator);
initialize(instance, encoding);
}
private void initialize(IceInternal.Instance instance, EncodingVersion encoding)
{
initialize(instance, encoding, new IceInternal.Buffer());
}
private void initialize(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf)
{
Debug.Assert(instance != null);
_instance = instance;
_buf = buf;
_closure = null;
_encoding = encoding;
_format = _instance.defaultsAndOverrides().defaultFormat;
_encapsStack = null;
_encapsCache = null;
}
///
/// Resets this output stream. This method allows the stream to be reused, to avoid creating
/// unnecessary garbage.
///
public void reset()
{
_buf.reset();
clear();
}
///
/// Releases any data retained by encapsulations. The reset() method internally calls clear().
///
public void clear()
{
if(_encapsStack != null)
{
Debug.Assert(_encapsStack.next == null);
_encapsStack.next = _encapsCache;
_encapsCache = _encapsStack;
_encapsStack = null;
_encapsCache.reset();
}
}
public IceInternal.Instance instance()
{
return _instance;
}
///
/// Sets the encoding format for class and exception instances.
///
/// The encoding format.
public void setFormat(FormatType fmt)
{
_format = fmt;
}
///
/// Retrieves the closure object associated with this stream.
///
/// The closure object.
public object getClosure()
{
return _closure;
}
///
/// Associates a closure object with this stream.
///
/// The new closure object.
/// The previous closure object, or null.
public object setClosure(object p)
{
object prev = _closure;
_closure = p;
return prev;
}
///
/// Indicates that the marshaling of a request or reply is finished.
///
/// The byte sequence containing the encoded request or reply.
public byte[] finished()
{
IceInternal.Buffer buf = prepareWrite();
byte[] result = new byte[buf.b.limit()];
buf.b.get(result);
return result;
}
///
/// Swaps the contents of one stream with another.
///
/// The other stream.
public void swap(OutputStream other)
{
Debug.Assert(_instance == other._instance);
IceInternal.Buffer tmpBuf = other._buf;
other._buf = _buf;
_buf = tmpBuf;
EncodingVersion tmpEncoding = other._encoding;
other._encoding = _encoding;
_encoding = tmpEncoding;
object tmpClosure = other._closure;
other._closure = _closure;
_closure = tmpClosure;
//
// Swap is never called for streams that have encapsulations being written. However,
// encapsulations might still be set in case marshalling failed. We just
// reset the encapsulations if there are still some set.
//
resetEncapsulation();
other.resetEncapsulation();
}
private void resetEncapsulation()
{
_encapsStack = null;
}
///
/// Resizes the stream to a new size.
///
/// The new size.
public void resize(int sz)
{
_buf.resize(sz, false);
_buf.b.position(sz);
}
///
/// Prepares the internal data buffer to be written to a socket.
///
public IceInternal.Buffer prepareWrite()
{
_buf.b.limit(_buf.size());
_buf.b.position(0);
return _buf;
}
///
/// Retrieves the internal data buffer.
///
/// The buffer.
public IceInternal.Buffer getBuffer()
{
return _buf;
}
///
/// Marks the start of a class instance.
///
/// Preserved slices for this instance, or null.
public void startValue(SlicedData data)
{
Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
_encapsStack.encoder.startInstance(SliceType.ValueSlice, data);
}
///
/// Marks the end of a class instance.
///
public void endValue()
{
Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
_encapsStack.encoder.endInstance();
}
///
/// Marks the start of a user exception.
///
/// Preserved slices for this exception, or null.
public void startException(SlicedData data)
{
Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
_encapsStack.encoder.startInstance(SliceType.ExceptionSlice, data);
}
///
/// Marks the end of a user exception.
///
public void endException()
{
Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
_encapsStack.encoder.endInstance();
}
///
/// Writes the start of an encapsulation to the stream.
///
public void startEncapsulation()
{
//
// If no encoding version is specified, use the current write
// encapsulation encoding version if there's a current write
// encapsulation, otherwise, use the stream encoding version.
//
if(_encapsStack != null)
{
startEncapsulation(_encapsStack.encoding, _encapsStack.format);
}
else
{
startEncapsulation(_encoding, FormatType.DefaultFormat);
}
}
///
/// Writes the start of an encapsulation to the stream.
///
/// The encoding version of the encapsulation.
/// Specify the compact or sliced format.
public void startEncapsulation(EncodingVersion encoding, FormatType format)
{
Protocol.checkSupportedEncoding(encoding);
Encaps curr = _encapsCache;
if(curr != null)
{
curr.reset();
_encapsCache = _encapsCache.next;
}
else
{
curr = new Encaps();
}
curr.next = _encapsStack;
_encapsStack = curr;
_encapsStack.format = format;
_encapsStack.setEncoding(encoding);
_encapsStack.start = _buf.b.position();
writeInt(0); // Placeholder for the encapsulation length.
_encapsStack.encoding.ice_writeMembers(this);
}
///
/// Ends the previous encapsulation.
///
public void endEncapsulation()
{
Debug.Assert(_encapsStack != null);
// Size includes size and version.
int start = _encapsStack.start;
int sz = _buf.size() - start;
_buf.b.putInt(start, sz);
Encaps curr = _encapsStack;
_encapsStack = curr.next;
curr.next = _encapsCache;
_encapsCache = curr;
_encapsCache.reset();
}
///
/// Writes an empty encapsulation using the given encoding version.
///
/// The encoding version of the encapsulation.
public void writeEmptyEncapsulation(EncodingVersion encoding)
{
Protocol.checkSupportedEncoding(encoding);
writeInt(6); // Size
encoding.ice_writeMembers(this);
}
///
/// Writes a pre-encoded encapsulation.
///
/// The encapsulation data.
public void writeEncapsulation(byte[] v)
{
if(v.Length < 6)
{
throw new EncapsulationException();
}
expand(v.Length);
_buf.b.put(v);
}
///
/// Determines the current encoding version.
///
/// The encoding version.
public EncodingVersion getEncoding()
{
return _encapsStack != null ? _encapsStack.encoding : _encoding;
}
///
/// Marks the start of a new slice for a class instance or user exception.
///
/// The Slice type ID corresponding to this slice.
/// The Slice compact type ID corresponding to this slice or -1 if no compact ID
/// is defined for the type ID.
/// True if this is the last slice, false otherwise.
public void startSlice(string typeId, int compactId, bool last)
{
Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
_encapsStack.encoder.startSlice(typeId, compactId, last);
}
///
/// Marks the end of a slice for a class instance or user exception.
///
public void endSlice()
{
Debug.Assert(_encapsStack != null && _encapsStack.encoder != null);
_encapsStack.encoder.endSlice();
}
///
/// Writes the state of Slice classes whose index was previously written with writeValue() to the stream.
///
public void writePendingValues()
{
if(_encapsStack != null && _encapsStack.encoder != null)
{
_encapsStack.encoder.writePendingValues();
}
else if(_encapsStack != null ?
_encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0))
{
//
// If using the 1.0 encoding and no instances were written, we
// still write an empty sequence for pending instances if
// requested (i.e.: if this is called).
//
// This is required by the 1.0 encoding, even if no instances
// are written we do marshal an empty sequence if marshaled
// data types use classes.
//
writeSize(0);
}
}
///
/// Writes a size to the stream.
///
/// The size to write.
public void writeSize(int v)
{
if(v > 254)
{
expand(5);
_buf.b.put(255);
_buf.b.putInt(v);
}
else
{
expand(1);
_buf.b.put((byte)v);
}
}
///
/// Returns the current position and allocates four bytes for a fixed-length (32-bit) size value.
///
public int startSize()
{
int pos = _buf.b.position();
writeInt(0); // Placeholder for 32-bit size
return pos;
}
///
/// Computes the amount of data written since the previous call to startSize and writes that value
/// at the saved position.
///
/// The saved position.
public void endSize(int pos)
{
Debug.Assert(pos >= 0);
rewriteInt(_buf.b.position() - pos - 4, pos);
}
///
/// Writes a blob of bytes to the stream.
///
/// The byte array to be written. All of the bytes in the array are written.
public void writeBlob(byte[] v)
{
if(v == null)
{
return;
}
expand(v.Length);
_buf.b.put(v);
}
///
/// Writes a blob of bytes to the stream.
///
/// The byte array to be written. All of the bytes in the array are written.
/// The offset into the byte array from which to copy.
/// The number of bytes from the byte array to copy.
public void writeBlob(byte[] v, int off, int len)
{
if(v == null)
{
return;
}
expand(len);
_buf.b.put(v, off, len);
}
///
/// Write the header information for an optional value.
///
/// The numeric tag associated with the value.
/// The optional format of the value.
public bool writeOptional(int tag, OptionalFormat format)
{
Debug.Assert(_encapsStack != null);
if(_encapsStack.encoder != null)
{
return _encapsStack.encoder.writeOptional(tag, format);
}
else
{
return writeOptionalImpl(tag, format);
}
}
///
/// Writes a byte to the stream.
///
/// The byte to write to the stream.
public void writeByte(byte v)
{
expand(1);
_buf.b.put(v);
}
///
/// Writes an optional byte to the stream.
///
/// The optional tag.
/// The optional byte to write to the stream.
public void writeByte(int tag, Optional v)
{
if(v.HasValue)
{
writeByte(tag, v.Value);
}
}
///
/// Writes an optional byte to the stream.
///
/// The optional tag.
/// The byte to write to the stream.
public void writeByte(int tag, byte v)
{
if(writeOptional(tag, OptionalFormat.F1))
{
writeByte(v);
}
}
///
/// Writes a byte to the stream at the given position. The current position of the stream is not modified.
///
/// The byte to write to the stream.
/// The position at which to store the byte in the buffer.
public void rewriteByte(byte v, int dest)
{
_buf.b.put(dest, v);
}
///
/// Writes a byte sequence to the stream.
///
/// The byte sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeByteSeq(byte[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length);
_buf.b.put(v);
}
}
///
/// Writes a byte sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeByteSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeByteSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.put(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeByteSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if(value != null)
{
writeByteSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count);
foreach(byte b in v)
{
_buf.b.put(b);
}
}
///
/// Writes an optional byte sequence to the stream.
///
/// The optional tag.
/// The optional byte sequence to write to the stream.
public void writeByteSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeByteSeq(tag, v.Value);
}
}
///
/// Writes an optional byte sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional byte sequence.
public void writeByteSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeByteSeq(count, v.Value);
}
}
///
/// Writes an optional byte sequence to the stream.
///
/// The optional tag.
/// The byte sequence to write to the stream.
public void writeByteSeq(int tag, byte[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeByteSeq(v);
}
}
///
/// Writes an optional byte sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the byte sequence.
public void writeByteSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeByteSeq(count, v);
}
}
///
/// Writes a serializable object to the stream.
///
/// The serializable object to write.
public void writeSerializable(object o)
{
if(o == null)
{
writeSize(0);
return;
}
try
{
IceInternal.OutputStreamWrapper w = new IceInternal.OutputStreamWrapper(this);
IFormatter f = new BinaryFormatter();
#pragma warning disable SYSLIB0011 // Type or member is obsolete
f.Serialize(w, o);
#pragma warning restore SYSLIB0011 // Type or member is obsolete
w.Close();
}
catch(System.Exception ex)
{
throw new MarshalException("cannot serialize object:", ex);
}
}
///
/// Writes a boolean to the stream.
///
/// The boolean to write to the stream.
public void writeBool(bool v)
{
expand(1);
_buf.b.put(v ? (byte)1 : (byte)0);
}
///
/// Writes an optional boolean to the stream.
///
/// The optional tag.
/// The optional boolean to write to the stream.
public void writeBool(int tag, Optional v)
{
if(v.HasValue)
{
writeBool(tag, v.Value);
}
}
///
/// Writes an optional boolean to the stream.
///
/// The optional tag.
/// The boolean to write to the stream.
public void writeBool(int tag, bool v)
{
if(writeOptional(tag, OptionalFormat.F1))
{
writeBool(v);
}
}
///
/// Writes a boolean to the stream at the given position. The current position of the stream is not modified.
///
/// The boolean to write to the stream.
/// The position at which to store the boolean in the buffer.
public void rewriteBool(bool v, int dest)
{
_buf.b.put(dest, v ? (byte)1 : (byte)0);
}
///
/// Writes a boolean sequence to the stream.
///
/// The boolean sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeBoolSeq(bool[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length);
_buf.b.putBoolSeq(v);
}
}
///
/// Writes a boolean sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeBoolSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeBoolSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.putBool(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeBoolSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if(value != null)
{
writeBoolSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count);
foreach(bool b in v)
{
_buf.b.putBool(b);
}
}
///
/// Writes an optional boolean sequence to the stream.
///
/// The optional tag.
/// The optional boolean sequence to write to the stream.
public void writeBoolSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeBoolSeq(tag, v.Value);
}
}
///
/// Writes an optional boolean sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional boolean sequence.
public void writeBoolSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeBoolSeq(count, v.Value);
}
}
///
/// Writes an optional boolean sequence to the stream.
///
/// The optional tag.
/// The boolean sequence to write to the stream.
public void writeBoolSeq(int tag, bool[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeBoolSeq(v);
}
}
///
/// Writes an optional boolean sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the boolean sequence.
public void writeBoolSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeBoolSeq(count, v);
}
}
///
/// Writes a short to the stream.
///
/// The short to write to the stream.
public void writeShort(short v)
{
expand(2);
_buf.b.putShort(v);
}
///
/// Writes an optional short to the stream.
///
/// The optional tag.
/// The optional short to write to the stream.
public void writeShort(int tag, Optional v)
{
if(v.HasValue)
{
writeShort(tag, v.Value);
}
}
///
/// Writes an optional short to the stream.
///
/// The optional tag.
/// The short to write to the stream.
public void writeShort(int tag, short v)
{
if(writeOptional(tag, OptionalFormat.F2))
{
writeShort(v);
}
}
///
/// Writes a short sequence to the stream.
///
/// The short sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeShortSeq(short[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length * 2);
_buf.b.putShortSeq(v);
}
}
///
/// Writes a short sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeShortSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeShortSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count * 2);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.putShort(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeShortSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if(value != null)
{
writeShortSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count * 2);
foreach(short s in v)
{
_buf.b.putShort(s);
}
}
///
/// Writes an optional short sequence to the stream.
///
/// The optional tag.
/// The optional short sequence to write to the stream.
public void writeShortSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeShortSeq(tag, v.Value);
}
}
///
/// Writes an optional short sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional short sequence.
public void writeShortSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeSize(count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
writeShortSeq(count, v.Value);
}
}
///
/// Writes an optional short sequence to the stream.
///
/// The optional tag.
/// The short sequence to write to the stream.
public void writeShortSeq(int tag, short[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || v.Length == 0 ? 1 : v.Length * 2 + (v.Length > 254 ? 5 : 1));
writeShortSeq(v);
}
}
///
/// Writes an optional short sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the short sequence.
public void writeShortSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || count == 0 ? 1 : count * 2 + (count > 254 ? 5 : 1));
writeShortSeq(count, v);
}
}
///
/// Writes an int to the stream.
///
/// The int to write to the stream.
public void writeInt(int v)
{
expand(4);
_buf.b.putInt(v);
}
///
/// Writes an optional int to the stream.
///
/// The optional tag.
/// The optional int to write to the stream.
public void writeInt(int tag, Optional v)
{
if(v.HasValue)
{
writeInt(tag, v.Value);
}
}
///
/// Writes an optional int to the stream.
///
/// The optional tag.
/// The int to write to the stream.
public void writeInt(int tag, int v)
{
if(writeOptional(tag, OptionalFormat.F4))
{
writeInt(v);
}
}
///
/// Writes an int to the stream at the given position. The current position of the stream is not modified.
///
/// The int to write to the stream.
/// The position at which to store the int in the buffer.
public void rewriteInt(int v, int dest)
{
_buf.b.putInt(dest, v);
}
///
/// Writes an int sequence to the stream.
///
/// The int sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeIntSeq(int[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length * 4);
_buf.b.putIntSeq(v);
}
}
///
/// Writes an int sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeIntSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeIntSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count * 4);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.putInt(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeIntSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if(value != null)
{
writeIntSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count * 4);
foreach(int i in v)
{
_buf.b.putInt(i);
}
}
///
/// Writes an optional int sequence to the stream.
///
/// The optional tag.
/// The optional int sequence to write to the stream.
public void writeIntSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeIntSeq(tag, v.Value);
}
}
///
/// Writes an optional int sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional byte sequence.
public void writeIntSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
writeIntSeq(count, v.Value);
}
}
///
/// Writes an optional int sequence to the stream.
///
/// The optional tag.
/// The int sequence to write to the stream.
public void writeIntSeq(int tag, int[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
writeIntSeq(v);
}
}
///
/// Writes an optional int sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the int sequence.
public void writeIntSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
writeIntSeq(count, v);
}
}
///
/// Writes a long to the stream.
///
/// The long to write to the stream.
public void writeLong(long v)
{
expand(8);
_buf.b.putLong(v);
}
///
/// Writes an optional long to the stream.
///
/// The optional tag.
/// The optional long to write to the stream.
public void writeLong(int tag, Optional v)
{
if(v.HasValue)
{
writeLong(tag, v.Value);
}
}
///
/// Writes an optional long to the stream.
///
/// The optional tag.
/// The long to write to the stream.
public void writeLong(int tag, long v)
{
if(writeOptional(tag, OptionalFormat.F8))
{
writeLong(v);
}
}
///
/// Writes a long sequence to the stream.
///
/// The long sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeLongSeq(long[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length * 8);
_buf.b.putLongSeq(v);
}
}
///
/// Writes a long sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeLongSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeLongSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count * 8);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.putLong(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeLongSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if(value != null)
{
writeLongSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count * 8);
foreach(long l in v)
{
_buf.b.putLong(l);
}
}
///
/// Writes an optional long sequence to the stream.
///
/// The optional tag.
/// The optional long sequence to write to the stream.
public void writeLongSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeLongSeq(tag, v.Value);
}
}
///
/// Writes an optional long sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional long sequence.
public void writeLongSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
writeLongSeq(count, v.Value);
}
}
///
/// Writes an optional long sequence to the stream.
///
/// The optional tag.
/// The long sequence to write to the stream.
public void writeLongSeq(int tag, long[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
writeLongSeq(v);
}
}
///
/// Writes an optional long sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the long sequence.
public void writeLongSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
writeLongSeq(count, v);
}
}
///
/// Writes a float to the stream.
///
/// The float to write to the stream.
public void writeFloat(float v)
{
expand(4);
_buf.b.putFloat(v);
}
///
/// Writes an optional float to the stream.
///
/// The optional tag.
/// The optional float to write to the stream.
public void writeFloat(int tag, Optional v)
{
if(v.HasValue)
{
writeFloat(tag, v.Value);
}
}
///
/// Writes an optional float to the stream.
///
/// The optional tag.
/// The float to write to the stream.
public void writeFloat(int tag, float v)
{
if(writeOptional(tag, OptionalFormat.F4))
{
writeFloat(v);
}
}
///
/// Writes a float sequence to the stream.
///
/// The float sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeFloatSeq(float[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length * 4);
_buf.b.putFloatSeq(v);
}
}
///
/// Writes a float sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeFloatSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeFloatSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count * 4);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.putFloat(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeFloatSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if(value != null)
{
writeFloatSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count * 4);
foreach(float f in v)
{
_buf.b.putFloat(f);
}
}
///
/// Writes an optional float sequence to the stream.
///
/// The optional tag.
/// The optional float sequence to write to the stream.
public void writeFloatSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeFloatSeq(tag, v.Value);
}
}
///
/// Writes an optional float sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional float sequence.
public void writeFloatSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeSize(count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
writeFloatSeq(count, v.Value);
}
}
///
/// Writes an optional float sequence to the stream.
///
/// The optional tag.
/// The float sequence to write to the stream.
public void writeFloatSeq(int tag, float[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || v.Length == 0 ? 1 : v.Length * 4 + (v.Length > 254 ? 5 : 1));
writeFloatSeq(v);
}
}
///
/// Writes an optional float sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the float sequence.
public void writeFloatSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || count == 0 ? 1 : count * 4 + (count > 254 ? 5 : 1));
writeFloatSeq(count, v);
}
}
///
/// Writes a double to the stream.
///
/// The double to write to the stream.
public void writeDouble(double v)
{
expand(8);
_buf.b.putDouble(v);
}
///
/// Writes an optional double to the stream.
///
/// The optional tag.
/// The optional double to write to the stream.
public void writeDouble(int tag, Optional v)
{
if(v.HasValue)
{
writeDouble(tag, v.Value);
}
}
///
/// Writes an optional double to the stream.
///
/// The optional tag.
/// The double to write to the stream.
public void writeDouble(int tag, double v)
{
if(writeOptional(tag, OptionalFormat.F8))
{
writeDouble(v);
}
}
///
/// Writes a double sequence to the stream.
///
/// The double sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeDoubleSeq(double[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
expand(v.Length * 8);
_buf.b.putDoubleSeq(v);
}
}
///
/// Writes a double sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeDoubleSeq(int count, IEnumerable v)
{
if(count == 0)
{
writeSize(0);
return;
}
{
List value = v as List;
if(value != null)
{
writeDoubleSeq(value.ToArray());
return;
}
}
{
LinkedList value = v as LinkedList;
if(value != null)
{
writeSize(count);
expand(count * 8);
IEnumerator i = v.GetEnumerator();
while(i.MoveNext())
{
_buf.b.putDouble(i.Current);
}
return;
}
}
{
Queue value = v as Queue;
if(value != null)
{
writeDoubleSeq(value.ToArray());
return;
}
}
{
Stack value = v as Stack;
if (value != null)
{
writeDoubleSeq(value.ToArray());
return;
}
}
writeSize(count);
expand(count * 8);
foreach(double d in v)
{
_buf.b.putDouble(d);
}
}
///
/// Writes an optional double sequence to the stream.
///
/// The optional tag.
/// The optional double sequence to write to the stream.
public void writeDoubleSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeDoubleSeq(tag, v.Value);
}
}
///
/// Writes an optional double sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional double sequence.
public void writeDoubleSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.VSize))
{
writeSize(count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
writeDoubleSeq(count, v.Value);
}
}
///
/// Writes an optional double sequence to the stream.
///
/// The optional tag.
/// The double sequence to write to the stream.
public void writeDoubleSeq(int tag, double[] v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || v.Length == 0 ? 1 : v.Length * 8 + (v.Length > 254 ? 5 : 1));
writeDoubleSeq(v);
}
}
///
/// Writes an optional double sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the double sequence.
public void writeDoubleSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeSize(v == null || count == 0 ? 1 : count * 8 + (count > 254 ? 5 : 1));
writeDoubleSeq(count, v);
}
}
private static System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding(false, true);
///
/// Writes a string to the stream.
///
/// The string to write to the stream. Passing null causes
/// an empty string to be written to the stream.
public void writeString(string v)
{
if(v == null || v.Length == 0)
{
writeSize(0);
return;
}
byte[] arr = utf8.GetBytes(v);
writeSize(arr.Length);
expand(arr.Length);
_buf.b.put(arr);
}
///
/// Writes an optional string to the stream.
///
/// The optional tag.
/// The optional string to write to the stream.
public void writeString(int tag, Optional v)
{
if(v.HasValue)
{
writeString(tag, v.Value);
}
}
///
/// Writes an optional string to the stream.
///
/// The optional tag.
/// The string to write to the stream.
public void writeString(int tag, string v)
{
if(writeOptional(tag, OptionalFormat.VSize))
{
writeString(v);
}
}
///
/// Writes a string sequence to the stream.
///
/// The string sequence to write to the stream.
/// Passing null causes an empty sequence to be written to the stream.
public void writeStringSeq(string[] v)
{
if(v == null)
{
writeSize(0);
}
else
{
writeSize(v.Length);
for(int i = 0; i < v.Length; i++)
{
writeString(v[i]);
}
}
}
///
/// Writes a string sequence to the stream.
///
/// The number of elements in the sequence.
/// An enumerator for the container holding the sequence.
public void writeStringSeq(int count, IEnumerable v)
{
writeSize(count);
if(count != 0)
{
foreach(string s in v)
{
writeString(s);
}
}
}
///
/// Writes an optional string sequence to the stream.
///
/// The optional tag.
/// The optional string sequence to write to the stream.
public void writeStringSeq(int tag, Optional v)
{
if(v.HasValue)
{
writeStringSeq(tag, v.Value);
}
}
///
/// Writes an optional string sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the optional string sequence.
public void writeStringSeq(int tag, int count, Optional v)
where T : IEnumerable
{
if(v.HasValue && writeOptional(tag, OptionalFormat.FSize))
{
int pos = startSize();
writeStringSeq(count, v.Value);
endSize(pos);
}
}
///
/// Writes an optional string sequence to the stream.
///
/// The optional tag.
/// The string sequence to write to the stream.
public void writeStringSeq(int tag, string[] v)
{
if(writeOptional(tag, OptionalFormat.FSize))
{
int pos = startSize();
writeStringSeq(v);
endSize(pos);
}
}
///
/// Writes an optional string sequence to the stream.
///
/// The optional tag.
/// The number of elements in the sequence.
/// An enumerator for the string sequence.
public void writeStringSeq(int tag, int count, IEnumerable v)
{
if(writeOptional(tag, OptionalFormat.FSize))
{
int pos = startSize();
writeStringSeq(count, v);
endSize(pos);
}
}
///
/// Writes a proxy to the stream.
///
/// The proxy to write.
public void writeProxy(ObjectPrx v)
{
if(v != null)
{
v.iceWrite(this);
}
else
{
Identity ident = new Identity();
ident.ice_writeMembers(this);
}
}
///
/// Writes an optional proxy to the stream.
///
/// The optional tag.
/// The optional proxy to write.
public void writeProxy(int tag, Optional v)
{
if(v.HasValue)
{
writeProxy(tag, v.Value);
}
}
///
/// Writes an optional proxy to the stream.
///
/// The optional tag.
/// The proxy to write.
public void writeProxy(int tag, ObjectPrx v)
{
if(writeOptional(tag, OptionalFormat.FSize))
{
int pos = startSize();
writeProxy(v);
endSize(pos);
}
}
///
/// Writes an enumerated value.
///
/// The enumerator.
/// The maximum enumerator value in the definition.
public void writeEnum(int v, int maxValue)
{
if(isEncoding_1_0())
{
if(maxValue < 127)
{
writeByte((byte)v);
}
else if(maxValue < 32767)
{
writeShort((short)v);
}
else
{
writeInt(v);
}
}
else
{
writeSize(v);
}
}
///
/// Writes an optional enumerator to the stream.
///
/// The optional tag.
/// The enumerator.
/// The maximum enumerator value in the definition.
public void writeEnum(int tag, int v, int maxValue)
{
if(writeOptional(tag, OptionalFormat.Size))
{
writeEnum(v, maxValue);
}
}
///
/// Writes a class instance to the stream.
///
/// The value to write. This method writes the index of an instance; the state of the value is
/// written once writePendingValues() is called.
public void writeValue(Value v)
{
initEncaps();
_encapsStack.encoder.writeValue(v);
}
///
/// Writes an optional class instance to the stream.
///
/// The optional tag.
/// The optional value to write.
public void writeValue(int tag, Optional v) where T : Value
{
if(v.HasValue)
{
writeValue(tag, v.Value);
}
}
///
/// Writes an optional class instance to the stream.
///
/// The optional tag.
/// The value to write.
public void writeValue(int tag, Value v)
{
if(writeOptional(tag, OptionalFormat.Class))
{
writeValue(v);
}
}
///
/// Writes a user exception to the stream.
///
/// The user exception to write.
public void writeException(UserException v)
{
initEncaps();
_encapsStack.encoder.writeException(v);
}
private bool writeOptionalImpl(int tag, OptionalFormat format)
{
if(isEncoding_1_0())
{
return false; // Optional members aren't supported with the 1.0 encoding.
}
int v = (int)format;
if(tag < 30)
{
v |= tag << 3;
writeByte((byte)v);
}
else
{
v |= 0x0F0; // tag = 30
writeByte((byte)v);
writeSize(tag);
}
return true;
}
///
/// Determines the current position in the stream.
///
/// The current position.
public int pos()
{
return _buf.b.position();
}
///
/// Sets the current position in the stream.
///
/// The new position.
public void pos(int n)
{
_buf.b.position(n);
}
///
/// Determines the current size of the stream.
///
/// The current size.
public int size()
{
return _buf.size();
}
///
/// Determines whether the stream is empty.
///
/// True if no data has been written yet, false otherwise.
public bool isEmpty()
{
return _buf.empty();
}
///
/// Expand the stream to accept more data.
///
/// The number of bytes to accommodate in the stream.
public void expand(int n)
{
_buf.expand(n);
}
private IceInternal.Instance _instance;
private IceInternal.Buffer _buf;
private object _closure;
private FormatType _format;
private enum SliceType { NoSlice, ValueSlice, ExceptionSlice }
abstract private class EncapsEncoder
{
protected EncapsEncoder(OutputStream stream, Encaps encaps)
{
_stream = stream;
_encaps = encaps;
_typeIdIndex = 0;
_marshaledMap = new Dictionary();
}
internal abstract void writeValue(Value v);
internal abstract void writeException(UserException v);
internal abstract void startInstance(SliceType type, SlicedData data);
internal abstract void endInstance();
internal abstract void startSlice(string typeId, int compactId, bool last);
internal abstract void endSlice();
internal virtual bool writeOptional(int tag, OptionalFormat format)
{
return false;
}
internal virtual void writePendingValues()
{
}
protected int registerTypeId(string typeId)
{
if(_typeIdMap == null)
{
_typeIdMap = new Dictionary();
}
int p;
if(_typeIdMap.TryGetValue(typeId, out p))
{
return p;
}
else
{
_typeIdMap.Add(typeId, ++_typeIdIndex);
return -1;
}
}
protected readonly OutputStream _stream;
protected readonly Encaps _encaps;
// Encapsulation attributes for instance marshaling.
protected readonly Dictionary _marshaledMap;
// Encapsulation attributes for instance marshaling.
private Dictionary _typeIdMap;
private int _typeIdIndex;
}
private sealed class EncapsEncoder10 : EncapsEncoder
{
internal EncapsEncoder10(OutputStream stream, Encaps encaps) : base(stream, encaps)
{
_sliceType = SliceType.NoSlice;
_valueIdIndex = 0;
_toBeMarshaledMap = new Dictionary();
}
internal override void writeValue(Value v)
{
//
// Object references are encoded as a negative integer in 1.0.
//
if(v != null)
{
_stream.writeInt(-registerValue(v));
}
else
{
_stream.writeInt(0);
}
}
internal override void writeException(UserException v)
{
//
// User exception with the 1.0 encoding start with a bool
// flag that indicates whether or not the exception uses
// classes.
//
// This allows reading the pending instances even if some part of
// the exception was sliced.
//
bool usesClasses = v.iceUsesClasses();
_stream.writeBool(usesClasses);
v.iceWrite(_stream);
if(usesClasses)
{
writePendingValues();
}
}
internal override void startInstance(SliceType sliceType, SlicedData sliceData)
{
_sliceType = sliceType;
}
internal override void endInstance()
{
if(_sliceType == SliceType.ValueSlice)
{
//
// Write the Object slice.
//
startSlice(Value.ice_staticId(), -1, true);
_stream.writeSize(0); // For compatibility with the old AFM.
endSlice();
}
_sliceType = SliceType.NoSlice;
}
internal override void startSlice(string typeId, int compactId, bool last)
{
//
// For instance slices, encode a bool to indicate how the type ID
// is encoded and the type ID either as a string or index. For
// exception slices, always encode the type ID as a string.
//
if(_sliceType == SliceType.ValueSlice)
{
int index = registerTypeId(typeId);
if(index < 0)
{
_stream.writeBool(false);
_stream.writeString(typeId);
}
else
{
_stream.writeBool(true);
_stream.writeSize(index);
}
}
else
{
_stream.writeString(typeId);
}
_stream.writeInt(0); // Placeholder for the slice length.
_writeSlice = _stream.pos();
}
internal override void endSlice()
{
//
// Write the slice length.
//
int sz = _stream.pos() - _writeSlice + 4;
_stream.rewriteInt(sz, _writeSlice - 4);
}
internal override void writePendingValues()
{
while(_toBeMarshaledMap.Count > 0)
{
//
// Consider the to be marshalled instances as marshalled now,
// this is necessary to avoid adding again the "to be
// marshalled instances" into _toBeMarshaledMap while writing
// instances.
//
foreach(var e in _toBeMarshaledMap)
{
_marshaledMap.Add(e.Key, e.Value);
}
var savedMap = _toBeMarshaledMap;
_toBeMarshaledMap = new Dictionary();
_stream.writeSize(savedMap.Count);
foreach(var p in savedMap)
{
//
// Ask the instance to marshal itself. Any new class
// instances that are triggered by the classes marshaled
// are added to toBeMarshaledMap.
//
_stream.writeInt(p.Value);
try
{
p.Key.ice_preMarshal();
}
catch(System.Exception ex)
{
string s = "exception raised by ice_preMarshal:\n" + ex;
_stream.instance().initializationData().logger.warning(s);
}
p.Key.iceWrite(_stream);
}
}
_stream.writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
}
private int registerValue(Value v)
{
Debug.Assert(v != null);
//
// Look for this instance in the to-be-marshaled map.
//
int p;
if(_toBeMarshaledMap.TryGetValue(v, out p))
{
return p;
}
//
// Didn't find it, try the marshaled map next.
//
if(_marshaledMap.TryGetValue(v, out p))
{
return p;
}
//
// We haven't seen this instance previously, create a new
// index, and insert it into the to-be-marshaled map.
//
_toBeMarshaledMap.Add(v, ++_valueIdIndex);
return _valueIdIndex;
}
// Instance attributes
private SliceType _sliceType;
// Slice attributes
private int _writeSlice; // Position of the slice data members
// Encapsulation attributes for instance marshaling.
private int _valueIdIndex;
private Dictionary _toBeMarshaledMap;
}
private sealed class EncapsEncoder11 : EncapsEncoder
{
internal EncapsEncoder11(OutputStream stream, Encaps encaps) : base(stream, encaps)
{
_current = null;
_valueIdIndex = 1;
}
internal override void writeValue(Value v)
{
if(v == null)
{
_stream.writeSize(0);
}
else if(_current != null && _encaps.format == FormatType.SlicedFormat)
{
if(_current.indirectionTable == null)
{
_current.indirectionTable = new List();
_current.indirectionMap = new Dictionary();
}
//
// If writing an instance within a slice and using the sliced
// format, write an index from the instance indirection table.
//
int index;
if(!_current.indirectionMap.TryGetValue(v, out index))
{
_current.indirectionTable.Add(v);
int idx = _current.indirectionTable.Count; // Position + 1 (0 is reserved for nil)
_current.indirectionMap.Add(v, idx);
_stream.writeSize(idx);
}
else
{
_stream.writeSize(index);
}
}
else
{
writeInstance(v); // Write the instance or a reference if already marshaled.
}
}
internal override void writeException(UserException v)
{
v.iceWrite(_stream);
}
internal override void startInstance(SliceType sliceType, SlicedData data)
{
if(_current == null)
{
_current = new InstanceData(null);
}
else
{
_current = _current.next == null ? new InstanceData(_current) : _current.next;
}
_current.sliceType = sliceType;
_current.firstSlice = true;
if(data != null)
{
writeSlicedData(data);
}
}
internal override void endInstance()
{
_current = _current.previous;
}
internal override void startSlice(string typeId, int compactId, bool last)
{
Debug.Assert((_current.indirectionTable == null || _current.indirectionTable.Count == 0) &&
(_current.indirectionMap == null || _current.indirectionMap.Count == 0));
_current.sliceFlagsPos = _stream.pos();
_current.sliceFlags = 0;
if(_encaps.format == FormatType.SlicedFormat)
{
//
// Encode the slice size if using the sliced format.
//
_current.sliceFlags |= Protocol.FLAG_HAS_SLICE_SIZE;
}
if(last)
{
_current.sliceFlags |= Protocol.FLAG_IS_LAST_SLICE; // This is the last slice.
}
_stream.writeByte(0); // Placeholder for the slice flags
//
// For instance slices, encode the flag and the type ID either as a
// string or index. For exception slices, always encode the type
// ID a string.
//
if(_current.sliceType == SliceType.ValueSlice)
{
//
// Encode the type ID (only in the first slice for the compact
// encoding).
//
if(_encaps.format == FormatType.SlicedFormat || _current.firstSlice)
{
if(compactId >= 0)
{
_current.sliceFlags |= Protocol.FLAG_HAS_TYPE_ID_COMPACT;
_stream.writeSize(compactId);
}
else
{
int index = registerTypeId(typeId);
if(index < 0)
{
_current.sliceFlags |= Protocol.FLAG_HAS_TYPE_ID_STRING;
_stream.writeString(typeId);
}
else
{
_current.sliceFlags |= Protocol.FLAG_HAS_TYPE_ID_INDEX;
_stream.writeSize(index);
}
}
}
}
else
{
_stream.writeString(typeId);
}
if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
{
_stream.writeInt(0); // Placeholder for the slice length.
}
_current.writeSlice = _stream.pos();
_current.firstSlice = false;
}
internal override void endSlice()
{
//
// Write the optional member end marker if some optional members
// were encoded. Note that the optional members are encoded before
// the indirection table and are included in the slice size.
//
if((_current.sliceFlags & Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0)
{
_stream.writeByte(Protocol.OPTIONAL_END_MARKER);
}
//
// Write the slice length if necessary.
//
if((_current.sliceFlags & Protocol.FLAG_HAS_SLICE_SIZE) != 0)
{
int sz = _stream.pos() - _current.writeSlice + 4;
_stream.rewriteInt(sz, _current.writeSlice - 4);
}
//
// Only write the indirection table if it contains entries.
//
if(_current.indirectionTable != null && _current.indirectionTable.Count > 0)
{
Debug.Assert(_encaps.format == FormatType.SlicedFormat);
_current.sliceFlags |= Protocol.FLAG_HAS_INDIRECTION_TABLE;
//
// Write the indirect instance table.
//
_stream.writeSize(_current.indirectionTable.Count);
foreach(var v in _current.indirectionTable)
{
writeInstance(v);
}
_current.indirectionTable.Clear();
_current.indirectionMap.Clear();
}
//
// Finally, update the slice flags.
//
_stream.rewriteByte(_current.sliceFlags, _current.sliceFlagsPos);
}
internal override bool writeOptional(int tag, OptionalFormat format)
{
if(_current == null)
{
return _stream.writeOptionalImpl(tag, format);
}
else
{
if(_stream.writeOptionalImpl(tag, format))
{
_current.sliceFlags |= Protocol.FLAG_HAS_OPTIONAL_MEMBERS;
return true;
}
else
{
return false;
}
}
}
private void writeSlicedData(SlicedData slicedData)
{
Debug.Assert(slicedData != null);
//
// We only remarshal preserved slices if we are using the sliced
// format. Otherwise, we ignore the preserved slices, which
// essentially "slices" the instance into the most-derived type
// known by the sender.
//
if(_encaps.format != FormatType.SlicedFormat)
{
return;
}
foreach(var info in slicedData.slices)
{
startSlice(info.typeId, info.compactId, info.isLastSlice);
//
// Write the bytes associated with this slice.
//
_stream.writeBlob(info.bytes);
if(info.hasOptionalMembers)
{
_current.sliceFlags |= Protocol.FLAG_HAS_OPTIONAL_MEMBERS;
}
//
// Make sure to also re-write the instance indirection table.
//
if(info.instances != null && info.instances.Length > 0)
{
if(_current.indirectionTable == null)
{
_current.indirectionTable = new List();
_current.indirectionMap = new Dictionary();
}
foreach(var o in info.instances)
{
_current.indirectionTable.Add(o);
}
}
endSlice();
}
}
private void writeInstance(Value v)
{
Debug.Assert(v != null);
//
// If the instance was already marshaled, just write it's ID.
//
int p;
if(_marshaledMap.TryGetValue(v, out p))
{
_stream.writeSize(p);
return;
}
//
// We haven't seen this instance previously, create a new ID,
// insert it into the marshaled map, and write the instance.
//
_marshaledMap.Add(v, ++_valueIdIndex);
try
{
v.ice_preMarshal();
}
catch(System.Exception ex)
{
string s = "exception raised by ice_preMarshal:\n" + ex;
_stream.instance().initializationData().logger.warning(s);
}
_stream.writeSize(1); // Object instance marker.
v.iceWrite(_stream);
}
private sealed class InstanceData
{
internal InstanceData(InstanceData previous)
{
if(previous != null)
{
previous.next = this;
}
this.previous = previous;
next = null;
}
// Instance attributes
internal SliceType sliceType;
internal bool firstSlice;
// Slice attributes
internal byte sliceFlags;
internal int writeSlice; // Position of the slice data members
internal int sliceFlagsPos; // Position of the slice flags
internal List indirectionTable;
internal Dictionary indirectionMap;
internal InstanceData previous;
internal InstanceData next;
}
private InstanceData _current;
private int _valueIdIndex; // The ID of the next instance to marhsal
}
private sealed class Encaps
{
internal void reset()
{
encoder = null;
}
internal void setEncoding(EncodingVersion encoding)
{
this.encoding = encoding;
encoding_1_0 = encoding.Equals(Util.Encoding_1_0);
}
internal int start;
internal EncodingVersion encoding;
internal bool encoding_1_0;
internal FormatType format = FormatType.DefaultFormat;
internal EncapsEncoder encoder;
internal Encaps next;
}
//
// The encoding version to use when there's no encapsulation to
// read from or write to. This is for example used to read message
// headers or when the user is using the streaming API with no
// encapsulation.
//
private EncodingVersion _encoding;
private bool isEncoding_1_0()
{
return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.Equals(Util.Encoding_1_0);
}
private Encaps _encapsStack;
private Encaps _encapsCache;
private void initEncaps()
{
if(_encapsStack == null) // Lazy initialization
{
_encapsStack = _encapsCache;
if(_encapsStack != null)
{
_encapsCache = _encapsCache.next;
}
else
{
_encapsStack = new Encaps();
}
_encapsStack.setEncoding(_encoding);
}
if(_encapsStack.format == FormatType.DefaultFormat)
{
_encapsStack.format = _format;
}
if(_encapsStack.encoder == null) // Lazy initialization.
{
if(_encapsStack.encoding_1_0)
{
_encapsStack.encoder = new EncapsEncoder10(this, _encapsStack);
}
else
{
_encapsStack.encoder = new EncapsEncoder11(this, _encapsStack);
}
}
}
}
///
/// Base class for writing class instances to an output stream.
///
public abstract class ValueWriter : Value
{
///
/// Writes the state of this Slice class instance to an output stream.
///
/// The stream to write to.
public abstract void write(OutputStream outStream);
public override void iceWrite(OutputStream os)
{
write(os);
}
public override void iceRead(InputStream istr)
{
Debug.Assert(false);
}
}
}