summaryrefslogtreecommitdiff
path: root/js/src/Ice/BasicStream.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/Ice/BasicStream.js')
-rw-r--r--js/src/Ice/BasicStream.js2961
1 files changed, 2961 insertions, 0 deletions
diff --git a/js/src/Ice/BasicStream.js b/js/src/Ice/BasicStream.js
new file mode 100644
index 00000000000..db423be4c91
--- /dev/null
+++ b/js/src/Ice/BasicStream.js
@@ -0,0 +1,2961 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+(function(global){
+ require("Ice/Class");
+ require("Ice/Debug");
+ require("Ice/ExUtil");
+ require("Ice/FormatType");
+ require("Ice/HashMap");
+ require("Ice/Object");
+ require("Ice/OptionalFormat");
+ require("Ice/Protocol");
+ require("Ice/TraceUtil");
+ require("Ice/Buffer");
+ require("Ice/Exception");
+ require("Ice/LocalException");
+ require("Ice/Version");
+ require("Ice/CompactIdRegistry");
+ require("Ice/ArrayUtil");
+ require("Ice/UnknownSlicedObject");
+
+ var Ice = global.Ice || {};
+
+ var Debug = Ice.Debug;
+ var ExUtil = Ice.ExUtil;
+ var FormatType = Ice.FormatType;
+ var HashMap = Ice.HashMap;
+ var IceObject = Ice.Object;
+ var OptionalFormat = Ice.OptionalFormat;
+ var Protocol = Ice.Protocol;
+ var TraceUtil = Ice.TraceUtil;
+ var ArrayUtil = Ice.ArrayUtil;
+ var SlicedData = Ice.SlicedData;
+
+ var SliceType = {};
+ SliceType.NoSlice = 0;
+ SliceType.ObjectSlice = 1;
+ SliceType.ExceptionSlice = 2;
+
+ var OPTIONAL_END_MARKER = 0xFF;
+ var FLAG_HAS_TYPE_ID_STRING = (1<<0);
+ var FLAG_HAS_TYPE_ID_INDEX = (1<<1);
+ var FLAG_HAS_TYPE_ID_COMPACT = (1<<1 | 1<<0);
+ var FLAG_HAS_OPTIONAL_MEMBERS = (1<<2);
+ var FLAG_HAS_INDIRECTION_TABLE = (1<<3);
+ var FLAG_HAS_SLICE_SIZE = (1<<4);
+ var FLAG_IS_LAST_SLICE = (1<<5);
+
+ var IndirectPatchEntry = function(index, patcher)
+ {
+ this.index = index;
+ this.patcher = patcher;
+ };
+
+ var Class = Ice.Class;
+
+ var EncapsDecoder = Class({
+ __init__: function(stream, encaps, sliceObjects, f)
+ {
+ this._stream = stream;
+ this._encaps = encaps;
+ this._sliceObjects = sliceObjects;
+ this._servantFactoryManager = f;
+ this._patchMap = null; // Lazy initialized, HashMap<int, Patcher[] >()
+ this._unmarshaledMap = new HashMap(); // HashMap<int, Ice.Object>()
+ this._typeIdMap = null; // Lazy initialized, HashMap<int, String>
+ this._typeIdIndex = 0;
+ this._objectList = null; // Lazy initialized. Ice.Object[]
+ },
+ readOpt: function()
+ {
+ return false;
+ },
+ readPendingObjects: function()
+ {
+ },
+ readTypeId: function(isIndex)
+ {
+ var typeId, index;
+ if(this._typeIdMap === null) // Lazy initialization
+ {
+ this._typeIdMap = new HashMap(); // Map<int, String>();
+ }
+
+ if(isIndex)
+ {
+ index = this._stream.readSize();
+ typeId = this._typeIdMap.get(index);
+ if(typeId === undefined)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+ else
+ {
+ typeId = this._stream.readString();
+ this._typeIdMap.set(++this._typeIdIndex, typeId);
+ }
+ return typeId;
+ },
+ newInstance: function(typeId)
+ {
+ //
+ // Try to find a factory registered for the specific type.
+ //
+ var userFactory = this._servantFactoryManager.find(typeId);
+ var v = null;
+
+ if(userFactory !== undefined)
+ {
+ v = userFactory.create(typeId);
+ }
+
+ //
+ // If that fails, invoke the default factory if one has been
+ // registered.
+ //
+ if(v === null || v === undefined)
+ {
+ userFactory = this._servantFactoryManager.find("");
+ if(userFactory !== undefined)
+ {
+ v = userFactory.create(typeId);
+ }
+ }
+
+ //
+ // Last chance: try to instantiate the class dynamically.
+ //
+ if(v === null || v === undefined)
+ {
+ v = this._stream.createObject(typeId);
+ }
+
+ return v;
+ },
+ addPatchEntry: function(index, patcher)
+ {
+ Debug.assert(index > 0);
+ //
+ // Check if already un-marshalled the object. If that's the case,
+ // just patch the object smart pointer and we're done.
+ //
+ var obj = this._unmarshaledMap.get(index);
+ if(obj !== undefined && obj !== null)
+ {
+ patcher.call(null, obj);
+ return;
+ }
+
+ if(this._patchMap === null) // Lazy initialization
+ {
+ this._patchMap = new HashMap(); // HashMap<Integer, Patcher[] >();
+ }
+
+ //
+ // Add patch entry if the object isn't un-marshalled yet,
+ // the smart pointer will be patched when the instance is
+ // un-marshalled.
+ //
+ var l = this._patchMap.get(index);
+ if(l === undefined)
+ {
+ //
+ // We have no outstanding instances to be patched for this
+ // index, so make a new entry in the patch map.
+ //
+ l = []; // Patcher[];
+ this._patchMap.set(index, l);
+ }
+
+ //
+ // Append a patch entry for this instance.
+ //
+ l.push(patcher);
+ },
+ unmarshal: function(index, v)
+ {
+ var i, length, l;
+ //
+ // Add the object to the map of un-marshalled objects, this must
+ // be done before reading the objects (for circular references).
+ //
+ this._unmarshaledMap.set(index, v);
+
+ //
+ // Read the object.
+ //
+ v.__read(this._stream);
+ if(this._patchMap !== null)
+ {
+ //
+ // Patch all instances now that the object is un-marshalled.
+ //
+ l = this._patchMap.get(index);
+ if(l !== undefined)
+ {
+ Debug.assert(l.length > 0);
+ //
+ // Patch all pointers that refer to the instance.
+ //
+ for(i = 0, length = l.length; i < length; ++i)
+ {
+ l[i](v);
+ }
+ //
+ // Clear out the patch map for that index -- there is nothing left
+ // to patch for that index for the time being.
+ //
+ this._patchMap.delete(index);
+ }
+ }
+
+ if((this._patchMap === null || this._patchMap.size === 0) && this._objectList === null)
+ {
+ try
+ {
+ v.ice_postUnmarshal();
+ }
+ catch(ex)
+ {
+ this._stream.instance.initializationData().logger.warning("exception raised by ice_postUnmarshal:\n" +
+ ExUtil.toString(ex));
+ }
+ }
+ else
+ {
+ if(this._objectList === null) // Lazy initialization
+ {
+ this._objectList = []; // Ice.Object[]
+ }
+ this._objectList.push(v);
+
+ if(this._patchMap === null || this._patchMap.size === 0)
+ {
+ //
+ // Iterate over the object list and invoke ice_postUnmarshal on
+ // each object. We must do this after all objects have been
+ // unmarshaled in order to ensure that any object data members
+ // have been properly patched.
+ //
+ for(i = 0, length = this._objectList.length; i < length; i++)
+ {
+ try
+ {
+ this._objectList[i].ice_postUnmarshal();
+ }
+ catch(ex)
+ {
+ this._stream.instance.initializationData().logger.warning(
+ "exception raised by ice_postUnmarshal:\n" + ExUtil.toString(ex));
+ }
+ }
+ this._objectList = [];
+ }
+ }
+ }
+ });
+
+ var EncapsDecoder10 = Class(EncapsDecoder, {
+ __init__: function(stream, encaps, sliceObjects, f)
+ {
+ EncapsDecoder.call(this, stream, encaps, sliceObjects, f);
+ this._sliceType = SliceType.NoSlice;
+ },
+ readObject: function(patcher)
+ {
+ Debug.assert(patcher !== null);
+
+ //
+ // Object references are encoded as a negative integer in 1.0.
+ //
+ var index = this._stream.readInt();
+ if(index > 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+ index = -index;
+
+ if(index === 0)
+ {
+ patcher.call(null, null);
+ }
+ else
+ {
+ this.addPatchEntry(index, patcher);
+ }
+ },
+ throwException: function()
+ {
+ Debug.assert(this._sliceType === SliceType.NoSlice);
+
+ //
+ // User exception with the 1.0 encoding start with a boolean flag
+ // that indicates whether or not the exception has classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ var usesClasses = this._stream.readBool();
+ this._sliceType = SliceType.ExceptionSlice;
+ this._skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ this.startSlice();
+ var mostDerivedId = this._typeId;
+ while(true)
+ {
+ var userEx = this._stream.createUserException(this._typeId);
+
+ //
+ // We found the exception.
+ //
+ if(userEx !== null)
+ {
+ userEx.__read(this._stream);
+ if(usesClasses)
+ {
+ this.readPendingObjects();
+ }
+ throw userEx;
+
+ // Never reached.
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ this.skipSlice();
+ try
+ {
+ this.startSlice();
+ }
+ catch(ex)
+ {
+ //
+ // An oversight in the 1.0 encoding means there is no marker to indicate
+ // the last slice of an exception. As a result, we just try to read the
+ // next type ID, which raises UnmarshalOutOfBoundsException when the
+ // input buffer underflows.
+ //
+ // Set the reason member to a more helpful message.
+ //
+ if(ex instanceof Ice.UnmarshalOutOfBoundsException)
+ {
+ ex.reason = "unknown exception type `" + mostDerivedId + "'";
+ }
+ throw ex;
+ }
+ }
+ },
+ startInstance: function(sliceType)
+ {
+ Debug.assert(this._sliceType === sliceType);
+ this._skipFirstSlice = true;
+ },
+ endInstance: function(/*preserve*/)
+ {
+ var sz;
+ //
+ // Read the Ice::Object slice.
+ //
+ if(this._sliceType === SliceType.ObjectSlice)
+ {
+ this.startSlice();
+ sz = this._stream.readSize(); // For compatibility with the old AFM.
+ if(sz !== 0)
+ {
+ throw new Ice.MarshalException("invalid Object slice");
+ }
+ this.endSlice();
+ }
+
+ this._sliceType = SliceType.NoSlice;
+ return null;
+ },
+ startSlice: function()
+ {
+ var isIndex;
+ //
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
+ //
+ if(this._skipFirstSlice)
+ {
+ this._skipFirstSlice = false;
+ return this._typeId;
+ }
+
+ //
+ // For objects, first read the type ID boolean which indicates
+ // whether or not the type ID is encoded as a string or as an
+ // index. For exceptions, the type ID is always encoded as a
+ // string.
+ //
+ if(this._sliceType === SliceType.ObjectSlice) // For exceptions, the type ID is always encoded as a string
+ {
+ isIndex = this._stream.readBool();
+ this._typeId = this.readTypeId(isIndex);
+ }
+ else
+ {
+ this._typeId = this._stream.readString();
+ }
+
+ this._sliceSize = this._stream.readInt();
+ if(this._sliceSize < 4)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ return this._typeId;
+ },
+ endSlice: function()
+ {
+ },
+ skipSlice: function()
+ {
+ if(this._stream.instance.traceLevels().slicing > 0)
+ {
+ var logger = this._stream.instance.initializationData().logger;
+ if(this._sliceType === SliceType.ObjectSlice)
+ {
+ TraceUtil.traceSlicing("object", this._typeId, this._stream.instance.traceLevels().slicingCat, logger);
+ }
+ else
+ {
+ TraceUtil.traceSlicing("exception", this._typeId, this._stream.instance.traceLevels().slicingCat, logger);
+ }
+ }
+ Debug.assert(this._sliceSize >= 4);
+ this._stream.skip(this._sliceSize - 4);
+ },
+ readPendingObjects: function()
+ {
+ var k, num;
+ do
+ {
+ num = this._stream.readSize();
+ for(k = num; k > 0; --k)
+ {
+ this.readInstance();
+ }
+ }
+ while(num > 0);
+
+ if(this._patchMap !== null && this._patchMap.size !== 0)
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw new Ice.MarshalException("index for class received, but no instance");
+ }
+ },
+ readInstance: function()
+ {
+ var index = this._stream.readInt(),
+ mostDerivedId,
+ v = null;
+
+ if(index <= 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+
+ this._sliceType = SliceType.ObjectSlice;
+ this._skipFirstSlice = false;
+
+ //
+ // Read the first slice header.
+ //
+ this.startSlice();
+ mostDerivedId = this._typeId;
+ while(true)
+ {
+ //
+ // For the 1.0 encoding, the type ID for the base Object class
+ // marks the last slice.
+ //
+ if(this._typeId == IceObject.ice_staticId())
+ {
+ throw new Ice.NoObjectFactoryException("", mostDerivedId);
+ }
+
+ v = this.newInstance(this._typeId);
+
+ //
+ // We found a factory, we get out of this loop.
+ //
+ if(v)
+ {
+ break;
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!this._sliceObjects)
+ {
+ throw new Ice.NoObjectFactoryException("object slicing is disabled", this._typeId);
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ this.skipSlice();
+ this.startSlice(); // Read next Slice header for next iteration.
+ }
+
+ //
+ // Un-marshal the object and add-it to the map of un-marshaled objects.
+ //
+ this.unmarshal(index, v);
+ }
+ });
+
+ var EncapsDecoder11 = Class(EncapsDecoder, {
+ __init__: function(stream, encaps, sliceObjects, f)
+ {
+ EncapsDecoder.call(this, stream, encaps, sliceObjects, f);
+ this._current = null;
+ this._objectIdIndex = 1;
+ },
+ readObject: function(patcher)
+ {
+ Debug.assert(patcher !== undefined);
+ var index = this._stream.readSize();
+
+ if(index < 0)
+ {
+ throw new Ice.MarshalException("invalid object id");
+ }
+
+ if(index === 0)
+ {
+ if(patcher !== null)
+ {
+ patcher.call(null, null);
+ }
+ }
+ else if(this._current !== null && (this._current.sliceFlags & FLAG_HAS_INDIRECTION_TABLE) !== 0)
+ {
+ //
+ // When reading an object within a slice and there's an
+ // indirect object table, always read an indirect reference
+ // that points to an object from the indirect object table
+ // marshaled at the end of the Slice.
+ //
+ // Maintain a list of indirect references. Note that the
+ // indirect index starts at 1, so we decrement it by one to
+ // derive an index into the indirection table that we'll read
+ // at the end of the slice.
+ //
+ if(patcher !== null)
+ {
+ if(this._current.indirectPatchList === null) // Lazy initialization
+ {
+ this._current.indirectPatchList = []; // IndirectPatchEntry[]
+ }
+ var e = new IndirectPatchEntry();
+ e.index = index - 1;
+ e.patcher = patcher;
+ this._current.indirectPatchList.push(e);
+ }
+ }
+ else
+ {
+ this.readInstance(index, patcher);
+ }
+ },
+ throwException: function()
+ {
+ Debug.assert(this._current === null);
+ this.push(SliceType.ExceptionSlice);
+
+ //
+ // Read the first slice header.
+ //
+ this.startSlice();
+ var mostDerivedId = this._current.typeId;
+ while(true)
+ {
+
+ var userEx = this._stream.createUserException(this._current.typeId);
+
+ //
+ // We found the exception.
+ //
+ if(userEx !== null)
+ {
+ userEx.__read(this._stream);
+ throw userEx;
+
+ // Never reached.
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ this.skipSlice();
+
+ if((this._current.sliceFlags & FLAG_IS_LAST_SLICE) !== 0)
+ {
+ if(mostDerivedId.indexOf("::") === 0)
+ {
+ throw new Ice.UnknownUserException(mostDerivedId.substr(2));
+ }
+ throw new Ice.UnknownUserException(mostDerivedId);
+ }
+
+ this.startSlice();
+ }
+ },
+ startInstance: function(sliceType)
+ {
+ Debug.assert(sliceType !== undefined);
+ Debug.assert(this._current.sliceType !== null && this._current.sliceType === sliceType);
+ this._current.skipFirstSlice = true;
+ },
+ endInstance: function(preserve)
+ {
+ var slicedData = null;
+ if(preserve)
+ {
+ slicedData = this.readSlicedData();
+ }
+ if(this._current.slices !== null)
+ {
+ this._current.slices.length = 0; // Clear the array.
+ this._current.indirectionTables.length = 0; // Clear the array.
+ }
+ this._current = this._current.previous;
+ return slicedData;
+ },
+ startSlice: function()
+ {
+ //
+ // If first slice, don't read the header, it was already read in
+ // readInstance or throwException to find the factory.
+ //
+ if(this._current.skipFirstSlice)
+ {
+ this._current.skipFirstSlice = false;
+ return this._current.typeId;
+ }
+
+ this._current.sliceFlags = this._stream.readByte();
+
+ //
+ // Read the type ID, for object slices the type ID is encoded as a
+ // string or as an index, for exceptions it's always encoded as a
+ // string.
+ //
+ if(this._current.sliceType === SliceType.ObjectSlice)
+ {
+ if((this._current.sliceFlags & FLAG_HAS_TYPE_ID_COMPACT) === FLAG_HAS_TYPE_ID_COMPACT) // Must be checked 1st!
+ {
+ this._current.typeId = "";
+ this._current.compactId = this._stream.readSize();
+ }
+ else if((this._current.sliceFlags & (FLAG_HAS_TYPE_ID_INDEX | FLAG_HAS_TYPE_ID_STRING)) !== 0)
+ {
+ this._current.typeId = this.readTypeId((this._current.sliceFlags & FLAG_HAS_TYPE_ID_INDEX) !== 0);
+ this._current.compactId = -1;
+ }
+ else
+ {
+ // Only the most derived slice encodes the type ID for the compact format.
+ this._current.typeId = "";
+ this._current.compactId = -1;
+ }
+ }
+ else
+ {
+ this._current.typeId = this._stream.readString();
+ this._current.compactId = -1;
+ }
+
+ //
+ // Read the slice size if necessary.
+ //
+ if((this._current.sliceFlags & FLAG_HAS_SLICE_SIZE) !== 0)
+ {
+ this._current.sliceSize = this._stream.readInt();
+ if(this._current.sliceSize < 4)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+ else
+ {
+ this._current.sliceSize = 0;
+ }
+ return this._current.typeId;
+ },
+ endSlice: function()
+ {
+ var e,
+ i,
+ indirectionTable = [],
+ length;
+
+ if((this._current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) !== 0)
+ {
+ this._stream.skipOpts();
+ }
+
+ //
+ // Read the indirection table if one is present and transform the
+ // indirect patch list into patch entries with direct references.
+ //
+ if((this._current.sliceFlags & FLAG_HAS_INDIRECTION_TABLE) !== 0)
+ {
+ //
+ // The table is written as a sequence<size> to conserve space.
+ //
+ length = this._stream.readAndCheckSeqSize(1);
+ for(i = 0; i < length; ++i)
+ {
+ indirectionTable[i] = this.readInstance(this._stream.readSize(), null);
+ }
+
+ //
+ // Sanity checks. If there are optional members, it's possible
+ // that not all object references were read if they are from
+ // unknown optional data members.
+ //
+ if(indirectionTable.length === 0)
+ {
+ throw new Ice.MarshalException("empty indirection table");
+ }
+ if((this._current.indirectPatchList === null || this._current.indirectPatchList.length === 0) &&
+ (this._current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) === 0)
+ {
+ throw new Ice.MarshalException("no references to indirection table");
+ }
+
+ //
+ // Convert indirect references into direct references.
+ //
+ if(this._current.indirectPatchList !== null)
+ {
+ for(i = 0, length = this._current.indirectPatchList.length; i < length; ++i)
+ {
+ e = this._current.indirectPatchList[i];
+ Debug.assert(e.index >= 0);
+ if(e.index >= indirectionTable.length)
+ {
+ throw new Ice.MarshalException("indirection out of range");
+ }
+ this.addPatchEntry(indirectionTable[e.index], e.patcher);
+ }
+ this._current.indirectPatchList.length = 0;
+ }
+ }
+ },
+ skipSlice: function()
+ {
+ if(this._stream.instance.traceLevels().slicing > 0)
+ {
+ var logger = this._stream.instance.initializationData().logger;
+ var slicingCat = this._stream.instance.traceLevels().slicingCat;
+ if(this._current.sliceType === SliceType.ExceptionSlice)
+ {
+ TraceUtil.traceSlicing("exception", this._current.typeId, slicingCat, logger);
+ }
+ else
+ {
+ TraceUtil.traceSlicing("object", this._current.typeId, slicingCat, logger);
+ }
+ }
+
+ var start = this._stream.pos;
+
+ if((this._current.sliceFlags & FLAG_HAS_SLICE_SIZE) !== 0)
+ {
+ Debug.assert(this._current.sliceSize >= 4);
+ this._stream.skip(this._current.sliceSize - 4);
+ }
+ else
+ {
+ if(this._current.sliceType === SliceType.ObjectSlice)
+ {
+ throw new Ice.NoObjectFactoryException(
+ "compact format prevents slicing (the sender should use the sliced format instead)",
+ this._current.typeId);
+ }
+
+ if(this._current.typeId.indexOf("::") === 0)
+ {
+ throw new Ice.UnknownUserException(this._current.typeId.substring(2));
+ }
+
+ throw new Ice.UnknownUserException(this._current.typeId);
+ }
+
+ //
+ // Preserve this slice.
+ //
+ var info = new Ice.SliceInfo();
+ info.typeId = this._current.typeId;
+ info.compactId = this._current.compactId;
+ info.hasOptionalMembers = (this._current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) !== 0;
+ info.isLastSlice = (this._current.sliceFlags & FLAG_IS_LAST_SLICE) !== 0;
+
+ var b = this._stream._buf;
+ var end = b.position;
+ var dataEnd = end;
+ if(info.hasOptionalMembers)
+ {
+ //
+ // Don't include the optional member end marker. It will be re-written by
+ // endSlice when the sliced data is re-written.
+ //
+ --dataEnd;
+ }
+
+ b.position = start;
+ info.bytes = b.getArray(dataEnd - start);
+ b.position = end;
+
+ if(this._current.slices === null) // Lazy initialization
+ {
+ this._current.slices = []; // Ice.SliceInfo[]
+ this._current.indirectionTables = []; // int[]
+ }
+
+ //
+ // Read the indirect object table. We read the instances or their
+ // IDs if the instance is a reference to an already un-marhsaled
+ // object.
+ //
+ // The SliceInfo object sequence is initialized only if
+ // readSlicedData is called.
+ //
+
+ if((this._current.sliceFlags & FLAG_HAS_INDIRECTION_TABLE) !== 0)
+ {
+ var length = this._stream.readAndCheckSeqSize(1);
+ var indirectionTable = [];
+ for(var i = 0; i < length; ++i)
+ {
+ indirectionTable[i] = this.readInstance(this._stream.readSize(), null);
+ }
+ this._current.indirectionTables.push(indirectionTable);
+ }
+ else
+ {
+ this._current.indirectionTables.push(null);
+ }
+ this._current.slices.push(info);
+ },
+ readOpt: function(readTag, expectedFormat)
+ {
+ if(this._current === null)
+ {
+ return this._stream.readOptImpl(readTag, expectedFormat);
+ }
+
+ if((this._current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) !== 0)
+ {
+ return this._stream.readOptImpl(readTag, expectedFormat);
+ }
+ return false;
+ },
+ readInstance: function(index, patcher)
+ {
+ Debug.assert(index > 0);
+
+ var mostDerivedId,
+ v = null;
+
+ if(index > 1)
+ {
+ if(patcher !== null)
+ {
+ this.addPatchEntry(index, patcher);
+ }
+ return index;
+ }
+
+ this.push(SliceType.ObjectSlice);
+
+ //
+ // Get the object ID before we start reading slices. If some
+ // slices are skiped, the indirect object table are still read and
+ // might read other objects.
+ //
+ index = ++this._objectIdIndex;
+
+ //
+ // Read the first slice header.
+ //
+ this.startSlice();
+ mostDerivedId = this._current.typeId;
+ while(true)
+ {
+ if(this._current.compactId >= 0)
+ {
+ //
+ // Translate a compact (numeric) type ID into a string type ID.
+ //
+ this._current.typeId = "";
+ if(this._current.typeId.length === 0)
+ {
+ this._current.typeId = this._stream.getTypeId(this._current.compactId);
+ }
+ }
+
+ if(this._current.typeId.length > 0)
+ {
+ v = this.newInstance(this._current.typeId);
+ //
+ // We found a factory, we get out of this loop.
+ //
+ if(v !== null && v !== undefined)
+ {
+ break;
+ }
+ }
+
+ //
+ // If object slicing is disabled, stop un-marshalling.
+ //
+ if(!this._sliceObjects)
+ {
+ throw new Ice.NoObjectFactoryException("object slicing is disabled", this._current.typeId);
+ }
+
+ //
+ // Slice off what we don't understand.
+ //
+ this.skipSlice();
+ //
+ // If this is the last slice, keep the object as an opaque
+ // UnknownSlicedData object.
+ //
+ if((this._current.sliceFlags & FLAG_IS_LAST_SLICE) !== 0)
+ {
+ v = new Ice.UnknownSlicedObject(mostDerivedId);
+ break;
+ }
+
+ this.startSlice(); // Read next Slice header for next iteration.
+ }
+
+ //
+ // Un-marshal the object
+ //
+ this.unmarshal(index, v);
+ if(this._current === null && this._patchMap !== null && this._patchMap.size !== 0)
+ {
+ //
+ // If any entries remain in the patch map, the sender has sent an index for an object, but failed
+ // to supply the object.
+ //
+ throw new Ice.MarshalException("index for class received, but no instance");
+ }
+
+ if(patcher !== null)
+ {
+ patcher.call(null, v);
+ }
+ return index;
+ },
+ readSlicedData: function()
+ {
+ var i, ii, table, info, j, jj;
+
+ if(this._current.slices === null) // No preserved slices.
+ {
+ return null;
+ }
+ //
+ // The _indirectionTables member holds the indirection table for each slice
+ // in _slices.
+ //
+ Debug.assert(this._current.slices.length === this._current.indirectionTables.length);
+ for(i = 0, ii = this._current.slices.length; i < ii; ++i)
+ {
+ //
+ // We use the "objects" list in SliceInfo to hold references
+ // to the target objects. Note that the objects might not have
+ // been read yet in the case of a circular reference to an
+ // enclosing object.
+ //
+ table = this._current.indirectionTables[i];
+ info = this._current.slices[i];
+ info.objects = [];
+ jj = table ? table.length : 0;
+ for(j = 0; j < jj; ++j)
+ {
+ this.addPatchEntry(table[j], sequencePatcher(info.objects, j, IceObject));
+ }
+ }
+ return new SlicedData(ArrayUtil.clone(this._current.slices));
+ },
+ push: function(sliceType)
+ {
+ if(this._current === null)
+ {
+ this._current = new EncapsDecoder11.InstanceData(null);
+ }
+ else
+ {
+ this._current = !this._current.next ? new EncapsDecoder11.InstanceData(this._current) : this._current.next;
+ }
+ this._current.sliceType = sliceType;
+ this._current.skipFirstSlice = false;
+ }
+ });
+
+ EncapsDecoder11.InstanceData = function(previous)
+ {
+ if(previous !== null)
+ {
+ previous.next = this;
+ }
+ this.previous = previous;
+ this.next = null;
+
+ // Instance attributes
+ this.sliceType = null;
+ this.skipFirstSlice = false;
+ this.slices = null; // Preserved slices. Ice.SliceInfo[]
+ this.indirectionTables = null; // int[]
+
+ // Slice attributes
+ this.sliceFlags = 0;
+ this.sliceSize = 0;
+ this.typeId = null;
+ this.compactId = 0;
+ this.indirectPatchList = null; // Lazy initialized, IndirectPatchEntry[]
+ };
+
+ var sequencePatcher = function(seq, index, T){
+ return function(v)
+ {
+ if(v !== null && !(v instanceof T))
+ {
+ ExUtil.throwUOE(T.ice_staticId(), v);
+ }
+ seq[index] = v;
+ };
+ };
+
+ var EncapsEncoder = Class({
+ __init__: function(stream, encaps)
+ {
+ this._stream = stream;
+ this._encaps = encaps;
+ this._marshaledMap = new HashMap(); // HashMap<Ice.Object, int>;
+ this._typeIdMap = null; // Lazy initialized. HashMap<String, int>
+ this._typeIdIndex = 0;
+ },
+ writeOpt: function()
+ {
+ return false;
+ },
+ writePendingObjects: function()
+ {
+ return undefined;
+ },
+ registerTypeId: function(typeId)
+ {
+ if(this._typeIdMap === null) // Lazy initialization
+ {
+ this._typeIdMap = new HashMap(); // HashMap<String, int>
+ }
+
+ var p = this._typeIdMap.get(typeId);
+ if(p !== undefined)
+ {
+ return p;
+ }
+ this._typeIdMap.set(typeId, ++this._typeIdIndex);
+ return -1;
+ }
+ });
+
+ var EncapsEncoder10 = Class(EncapsEncoder, {
+ __init__: function(stream, encaps)
+ {
+ EncapsEncoder.call(this, stream, encaps);
+ // Instance attributes
+ this._sliceType = SliceType.NoSlice;
+ this._writeSlice = 0; // Position of the slice data members
+ // Encapsulation attributes for object marshalling.
+ this._objectIdIndex = 0;
+ this._toBeMarshaledMap = new HashMap(); // HashMap<Ice.Object, Integer>();
+ },
+ writeObject: function(v)
+ {
+ Debug.assert(v !== undefined);
+ //
+ // Object references are encoded as a negative integer in 1.0.
+ //
+ if(v !== null)
+ {
+ this._stream.writeInt(-this.registerObject(v));
+ }
+ else
+ {
+ this._stream.writeInt(0);
+ }
+ },
+ writeUserException: function(v)
+ {
+ Debug.assert(v !== null && v !== undefined);
+ //
+ // User exception with the 1.0 encoding start with a boolean
+ // flag that indicates whether or not the exception uses
+ // classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ var usesClasses = v.__usesClasses();
+ this._stream.writeBool(usesClasses);
+ v.__write(this._stream);
+ if(usesClasses)
+ {
+ this.writePendingObjects();
+ }
+ },
+ startInstance: function(sliceType)
+ {
+ this._sliceType = sliceType;
+ },
+ endInstance: function()
+ {
+ if(this._sliceType === SliceType.ObjectSlice)
+ {
+ //
+ // Write the Object slice.
+ //
+ this.startSlice(IceObject.ice_staticId(), -1, true);
+ this._stream.writeSize(0); // For compatibility with the old AFM.
+ this.endSlice();
+ }
+ this._sliceType = SliceType.NoSlice;
+ },
+ startSlice: function(typeId)
+ {
+ //
+ // For object slices, encode a boolean 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(this._sliceType === SliceType.ObjectSlice)
+ {
+ var index = this.registerTypeId(typeId);
+ if(index < 0)
+ {
+ this._stream.writeBool(false);
+ this._stream.writeString(typeId);
+ }
+ else
+ {
+ this._stream.writeBool(true);
+ this._stream.writeSize(index);
+ }
+ }
+ else
+ {
+ this._stream.writeString(typeId);
+ }
+
+ this._stream.writeInt(0); // Placeholder for the slice length.
+
+ this._writeSlice = this._stream.pos;
+ },
+ endSlice: function()
+ {
+ //
+ // Write the slice length.
+ //
+ var sz = this._stream.pos - this._writeSlice + 4;
+ this._stream.rewriteInt(sz, this._writeSlice - 4);
+ },
+ writePendingObjects: function()
+ {
+ var self = this,
+ writeCB = function(key, value)
+ {
+ //
+ // Ask the instance to marshal itself. Any new class
+ // instances that are triggered by the classes marshaled
+ // are added to toBeMarshaledMap.
+ //
+ self._stream.writeInt(value);
+
+ try
+ {
+ key.ice_preMarshal();
+ }
+ catch(ex)
+ {
+ self._stream.instance.initializationData().logger.warning(
+ "exception raised by ice_preMarshal:\n" + ExUtil.toString(ex));
+ }
+
+ key.__write(self._stream);
+ },
+ savedMap;
+
+ while(this._toBeMarshaledMap.size > 0)
+ {
+ //
+ // Consider the to be marshalled objects as marshalled now,
+ // this is necessary to avoid adding again the "to be
+ // marshalled objects" into _toBeMarshaledMap while writing
+ // objects.
+ //
+ this._marshaledMap.merge(this._toBeMarshaledMap);
+
+ savedMap = this._toBeMarshaledMap;
+ this._toBeMarshaledMap = new HashMap(); // HashMap<Ice.Object, int>();
+ this._stream.writeSize(savedMap.size);
+ savedMap.forEach(writeCB);
+ }
+ this._stream.writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
+ },
+ registerObject: function(v)
+ {
+ Debug.assert(v !== null);
+
+ //
+ // Look for this instance in the to-be-marshaled map.
+ //
+ var p = this._toBeMarshaledMap.get(v);
+ if(p !== undefined)
+ {
+ return p;
+ }
+
+ //
+ // Didn't find it, try the marshaled map next.
+ //
+ p = this._marshaledMap.get(v);
+ if(p !== undefined)
+ {
+ return p;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new
+ // index, and insert it into the to-be-marshaled map.
+ //
+ this._toBeMarshaledMap.set(v, ++this._objectIdIndex);
+ return this._objectIdIndex;
+ }
+ });
+
+ var EncapsEncoder11 = Class(EncapsEncoder, {
+ __init__: function(stream, encaps)
+ {
+ EncapsEncoder.call(this, stream, encaps);
+ this._current = null;
+ this._objectIdIndex = 1;
+ },
+ writeObject: function(v)
+ {
+ Debug.assert(v !== undefined);
+ var index, idx;
+ if(v === null)
+ {
+ this._stream.writeSize(0);
+ }
+ else if(this._current !== null && this._encaps.format === FormatType.SlicedFormat)
+ {
+ if(this._current.indirectionTable === null) // Lazy initialization
+ {
+ this._current.indirectionTable = []; // Ice.Object[]
+ this._current.indirectionMap = new HashMap(); // HashMap<Ice.Object, int>
+ }
+
+ //
+ // If writting an object within a slice and using the sliced
+ // format, write an index from the object indirection
+ // table. The indirect object table is encoded at the end of
+ // each slice and is always read (even if the Slice is
+ // unknown).
+ //
+ index = this._current.indirectionMap.get(v);
+ if(index === undefined)
+ {
+ this._current.indirectionTable.push(v);
+ idx = this._current.indirectionTable.length; // Position + 1 (0 is reserved for nil)
+ this._current.indirectionMap.set(v, idx);
+ this._stream.writeSize(idx);
+ }
+ else
+ {
+ this._stream.writeSize(index);
+ }
+ }
+ else
+ {
+ this.writeInstance(v); // Write the instance or a reference if already marshaled.
+ }
+ },
+ writePendingObjects: function()
+ {
+ return undefined;
+ },
+ writeUserException: function(v)
+ {
+ Debug.assert(v !== null && v !== undefined);
+ v.__write(this._stream);
+ },
+ startInstance: function(sliceType, data)
+ {
+ if(this._current === null)
+ {
+ this._current = new EncapsEncoder11.InstanceData(null);
+ }
+ else
+ {
+ this._current = (this._current.next === null) ? new EncapsEncoder11.InstanceData(this._current) : this._current.next;
+ }
+ this._current.sliceType = sliceType;
+ this._current.firstSlice = true;
+
+ if(data !== null && data !== undefined)
+ {
+ this.writeSlicedData(data);
+ }
+ },
+ endInstance: function()
+ {
+ this._current = this._current.previous;
+ },
+ startSlice: function(typeId, compactId, last)
+ {
+ Debug.assert((this._current.indirectionTable === null || this._current.indirectionTable.length === 0) &&
+ (this._current.indirectionMap === null || this._current.indirectionMap.size === 0));
+
+ this._current.sliceFlagsPos = this._stream.pos;
+
+ this._current.sliceFlags = 0;
+ if(this._encaps.format === FormatType.SlicedFormat)
+ {
+ this._current.sliceFlags |= FLAG_HAS_SLICE_SIZE; // Encode the slice size if using the sliced format.
+ }
+ if(last)
+ {
+ this._current.sliceFlags |= FLAG_IS_LAST_SLICE; // This is the last slice.
+ }
+
+ this._stream.writeByte(0); // Placeholder for the slice flags
+
+ //
+ // For object 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(this._current.sliceType === SliceType.ObjectSlice)
+ {
+ //
+ // Encode the type ID (only in the first slice for the compact
+ // encoding).
+ //
+ if(this._encaps.format === FormatType.SlicedFormat || this._current.firstSlice)
+ {
+ if(compactId >= 0)
+ {
+ this._current.sliceFlags |= FLAG_HAS_TYPE_ID_COMPACT;
+ this._stream.writeSize(compactId);
+ }
+ else
+ {
+ var index = this.registerTypeId(typeId);
+ if(index < 0)
+ {
+ this._current.sliceFlags |= FLAG_HAS_TYPE_ID_STRING;
+ this._stream.writeString(typeId);
+ }
+ else
+ {
+ this._current.sliceFlags |= FLAG_HAS_TYPE_ID_INDEX;
+ this._stream.writeSize(index);
+ }
+ }
+ }
+ }
+ else
+ {
+ this._stream.writeString(typeId);
+ }
+
+ if((this._current.sliceFlags & FLAG_HAS_SLICE_SIZE) !== 0)
+ {
+ this._stream.writeInt(0); // Placeholder for the slice length.
+ }
+
+ this._current.writeSlice = this._stream.pos;
+ this._current.firstSlice = false;
+ },
+ endSlice: function()
+ {
+ var sz, i, length;
+
+ //
+ // 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((this._current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) !== 0)
+ {
+ this._stream.writeByte(OPTIONAL_END_MARKER);
+ }
+
+ //
+ // Write the slice length if necessary.
+ //
+ if((this._current.sliceFlags & FLAG_HAS_SLICE_SIZE) !== 0)
+ {
+ sz = this._stream.pos - this._current.writeSlice + 4;
+ this._stream.rewriteInt(sz, this._current.writeSlice - 4);
+ }
+
+ //
+ // Only write the indirection table if it contains entries.
+ //
+ if(this._current.indirectionTable !== null && this._current.indirectionTable.length !== 0)
+ {
+ Debug.assert(this._encaps.format === FormatType.SlicedFormat);
+ this._current.sliceFlags |= FLAG_HAS_INDIRECTION_TABLE;
+
+ //
+ // Write the indirection object table.
+ //
+ this._stream.writeSize(this._current.indirectionTable.length);
+ for(i = 0, length = this._current.indirectionTable.length; i < length; ++i)
+ {
+ this.writeInstance(this._current.indirectionTable[i]);
+ }
+ this._current.indirectionTable.length = 0; // Faster way to clean array in JavaScript
+ this._current.indirectionMap.clear();
+ }
+
+ //
+ // Finally, update the slice flags.
+ //
+ this._stream.rewriteByte(this._current.sliceFlags, this._current.sliceFlagsPos);
+ },
+ writeOpt: function(tag, format)
+ {
+ if(this._current === null)
+ {
+ return this._stream.writeOptImpl(tag, format);
+ }
+
+ if(this._stream.writeOptImpl(tag, format))
+ {
+ this._current.sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ return true;
+ }
+
+ return false;
+ },
+ writeSlicedData: function(slicedData)
+ {
+ Debug.assert(slicedData !== null && slicedData !== undefined);
+
+ //
+ // We only remarshal preserved slices if we are using the sliced
+ // format. Otherwise, we ignore the preserved slices, which
+ // essentially "slices" the object into the most-derived type
+ // known by the sender.
+ //
+ if(this._encaps.format !== FormatType.SlicedFormat)
+ {
+ return;
+ }
+
+ var i, ii, info,
+ j, jj;
+
+ for(i = 0, ii = slicedData.slices.length; i < ii; ++i)
+ {
+ info = slicedData.slices[i];
+ this.startSlice(info.typeId, info.compactId, info.isLastSlice);
+
+ //
+ // Write the bytes associated with this slice.
+ //
+ this._stream.writeBlob(info.bytes);
+
+ if(info.hasOptionalMembers)
+ {
+ this._current.sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ }
+
+ //
+ // Make sure to also re-write the object indirection table.
+ //
+ if(info.objects !== null && info.objects.length > 0)
+ {
+ if(this._current.indirectionTable === null) // Lazy initialization
+ {
+ this._current.indirectionTable = []; // Ice.Object[]
+ this._current.indirectionMap = new HashMap(); // HashMap<Ice.Object, int>
+ }
+
+ for(j = 0, jj = info.objects.length; j < jj; ++j)
+ {
+ this._current.indirectionTable.push(info.objects[j]);
+ }
+ }
+
+ this.endSlice();
+ }
+ },
+ writeInstance: function(v)
+ {
+ Debug.assert(v !== null && v !== undefined);
+
+ //
+ // If the instance was already marshaled, just write it's ID.
+ //
+ var p = this._marshaledMap.get(v);
+ if(p !== undefined)
+ {
+ this._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.
+ //
+ this._marshaledMap.set(v, ++this._objectIdIndex);
+
+ try
+ {
+ v.ice_preMarshal();
+ }
+ catch(ex)
+ {
+ this._stream.instance.initializationData().logger.warning("exception raised by ice_preMarshal:\n" +
+ ExUtil.toString(ex));
+ }
+
+ this._stream.writeSize(1); // Object instance marker.
+ v.__write(this._stream);
+ }
+ });
+
+ EncapsEncoder11.InstanceData = function(previous)
+ {
+ Debug.assert(previous !== undefined);
+ if(previous !== null)
+ {
+ previous.next = this;
+ }
+ this.previous = previous;
+ this.next = null;
+
+ // Instance attributes
+ this.sliceType = null;
+ this.firstSlice = false;
+
+ // Slice attributes
+ this.sliceFlags = 0;
+ this.writeSlice = 0; // Position of the slice data members
+ this.sliceFlagsPos = 0; // Position of the slice flags
+ this.indirectionTable = null; // Ice.Object[]
+ this.indirectionMap = null; // HashMap<Ice.Object, int>
+ };
+
+ var ReadEncaps = Class({
+ __init__: function()
+ {
+ this.start = 0;
+ this.sz = 0;
+ this.encoding = null;
+ this.encoding_1_0 = false;
+ this.decoder = null;
+ this.next = null;
+ },
+ reset: function()
+ {
+ this.decoder = null;
+ },
+ setEncoding: function(encoding)
+ {
+ this.encoding = encoding;
+ this.encoding_1_0 = encoding.equals(Ice.Encoding_1_0);
+ }
+ });
+
+ var WriteEncaps = Class({
+ __init__: function()
+ {
+ this.start = 0;
+ this.format = FormatType.DefaultFormat;
+ this.encoding = null;
+ this.encoding_1_0 = false;
+ this.encoder = null;
+ this.next = null;
+ },
+ reset: function()
+ {
+ this.encoder = null;
+ },
+ setEncoding: function(encoding)
+ {
+ this.encoding = encoding;
+ this.encoding_1_0 = encoding.equals(Ice.Encoding_1_0);
+ }
+ });
+
+ var BasicStream = Class({
+ __init__: function(instance, encoding, unlimited, data)
+ {
+ this._instance = instance;
+ this._closure = null;
+ this._encoding = encoding;
+
+ this._readEncapsStack = null;
+ this._writeEncapsStack = null;
+ this._readEncapsCache = null;
+ this._writeEncapsCache = null;
+
+ this._sliceObjects = true;
+
+ this._messageSizeMax = this._instance.messageSizeMax(); // Cached for efficiency.
+ this._unlimited = unlimited !== undefined ? unlimited : false;
+
+ this._startSeq = -1;
+ this._sizePos = -1;
+
+ if(data !== undefined)
+ {
+ this._buf = new Ice.Buffer(data);
+ }
+ else
+ {
+ this._buf = new Ice.Buffer();
+ }
+ },
+ //
+ // This function allows this object to be reused, rather than
+ // reallocated.
+ //
+ reset: function()
+ {
+ this._buf.reset();
+ this.clear();
+ },
+ clear: function()
+ {
+ if(this._readEncapsStack !== null)
+ {
+ Debug.assert(this._readEncapsStack.next);
+ this._readEncapsStack.next = this._readEncapsCache;
+ this._readEncapsCache = this._readEncapsStack;
+ this._readEncapsCache.reset();
+ this._readEncapsStack = null;
+ }
+
+ if(this._writeEncapsStack !== null)
+ {
+ Debug.assert(this._writeEncapsStack.next);
+ this._writeEncapsStack.next = this._writeEncapsCache;
+ this._writeEncapsCache = this._writeEncapsStack;
+ this._writeEncapsCache.reset();
+ this._writeEncapsStack = null;
+ }
+ this._startSeq = -1;
+ this._sliceObjects = true;
+ },
+ swap: function(other)
+ {
+ Debug.assert(this._instance === other._instance);
+
+ var tmpBuf, tmpClosure, tmpUnlimited, tmpStartSeq, tmpMinSeqSize, tmpSizePos;
+
+ tmpBuf = other._buf;
+ other._buf = this._buf;
+ this._buf = tmpBuf;
+
+ tmpClosure = other._closure;
+ other._closure = this._closure;
+ this._closure = tmpClosure;
+
+ //
+ // Swap is never called for BasicStreams that have encapsulations being read/write. However,
+ // encapsulations might still be set in case marshalling or un-marshalling failed. We just
+ // reset the encapsulations if there are still some set.
+ //
+ this.resetEncaps();
+ other.resetEncaps();
+
+ tmpUnlimited = other._unlimited;
+ other._unlimited = this._unlimited;
+ this._unlimited = tmpUnlimited;
+
+ tmpStartSeq = other._startSeq;
+ other._startSeq = this._startSeq;
+ this._startSeq = tmpStartSeq;
+
+ tmpMinSeqSize = other._minSeqSize;
+ other._minSeqSize = this._minSeqSize;
+ this._minSeqSize = tmpMinSeqSize;
+
+ tmpSizePos = other._sizePos;
+ other._sizePos = this._sizePos;
+ this._sizePos = tmpSizePos;
+ },
+ resetEncaps: function()
+ {
+ this._readEncapsStack = null;
+ this._writeEncapsStack = null;
+ },
+ resize: function(sz)
+ {
+ //
+ // Check memory limit if stream is not unlimited.
+ //
+ if(!this._unlimited && sz > this._messageSizeMax)
+ {
+ ExUtil.throwMemoryLimitException(sz, this._messageSizeMax);
+ }
+
+ this._buf.resize(sz);
+ this._buf.position = sz;
+ },
+ prepareWrite: function()
+ {
+ this._buf.position = 0;
+ return this._buf;
+ },
+ startWriteObject: function(data)
+ {
+ Debug.assert(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null);
+ this._writeEncapsStack.encoder.startInstance(SliceType.ObjectSlice, data);
+ },
+ endWriteObject: function()
+ {
+ Debug.assert(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null);
+ this._writeEncapsStack.encoder.endInstance();
+ },
+ startReadObject: function()
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ this._readEncapsStack.decoder.startInstance(SliceType.ObjectSlice);
+ },
+ endReadObject: function(preserve)
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ return this._readEncapsStack.decoder.endInstance(preserve);
+ },
+ startWriteException: function(data)
+ {
+ Debug.assert(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null);
+ this._writeEncapsStack.encoder.startInstance(SliceType.ExceptionSlice, data);
+ },
+ endWriteException: function()
+ {
+ Debug.assert(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null);
+ this._writeEncapsStack.encoder.endInstance();
+ },
+ startReadException: function()
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ this._readEncapsStack.decoder.startInstance(SliceType.ExceptionSlice);
+ },
+ endReadException: function(preserve)
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ return this._readEncapsStack.decoder.endInstance(preserve);
+ },
+ startWriteEncaps: function(encoding, format)
+ {
+ //
+ // 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(encoding === undefined)
+ {
+ if(this._writeEncapsStack !== null)
+ {
+ encoding = this._writeEncapsStack.encoding;
+ format = this._writeEncapsStack.format;
+ }
+ else
+ {
+ encoding = this._encoding;
+ format = FormatType.DefaultFormat;
+ }
+ }
+
+ Protocol.checkSupportedEncoding(encoding);
+
+ var curr = this._writeEncapsCache;
+ if(curr !== null)
+ {
+ curr.reset();
+ this._writeEncapsCache = this._writeEncapsCache.next;
+ }
+ else
+ {
+ curr = new WriteEncaps();
+ }
+ curr.next = this._writeEncapsStack;
+ this._writeEncapsStack = curr;
+
+ this._writeEncapsStack.format = format;
+ this._writeEncapsStack.setEncoding(encoding);
+ this._writeEncapsStack.start = this._buf.limit;
+
+ this.writeInt(0); // Placeholder for the encapsulation length.
+ this._writeEncapsStack.encoding.__write(this);
+ },
+ endWriteEncaps: function()
+ {
+ Debug.assert(this._writeEncapsStack);
+
+ // Size includes size and version.
+ var start = this._writeEncapsStack.start;
+
+ var sz = this._buf.limit - start;
+ this._buf.putIntAt(start, sz);
+
+ var curr = this._writeEncapsStack;
+ this._writeEncapsStack = curr.next;
+ curr.next = this._writeEncapsCache;
+ this._writeEncapsCache = curr;
+ this._writeEncapsCache.reset();
+ },
+ endWriteEncapsChecked: function() // Used by public stream API.
+ {
+ if(this._writeEncapsStack === null)
+ {
+ throw new Ice.EncapsulationException("not in an encapsulation");
+ }
+ this.endWriteEncaps();
+ },
+ writeEmptyEncaps: function(encoding)
+ {
+ Protocol.checkSupportedEncoding(encoding);
+ this.writeInt(6); // Size
+ encoding.__write(this);
+ },
+ writeEncaps: function(v)
+ {
+ if(v.length < 6)
+ {
+ throw new Ice.EncapsulationException();
+ }
+ this.expand(v.length);
+ this._buf.putArray(v);
+ },
+ getWriteEncoding: function()
+ {
+ return this._writeEncapsStack !== null ? this._writeEncapsStack.encoding : this._encoding;
+ },
+ startReadEncaps: function()
+ {
+ var curr = this._readEncapsCache;
+ if(curr !== null)
+ {
+ curr.reset();
+ this._readEncapsCache = this._readEncapsCache.next;
+ }
+ else
+ {
+ curr = new ReadEncaps();
+ }
+ curr.next = this._readEncapsStack;
+ this._readEncapsStack = curr;
+
+ this._readEncapsStack.start = this._buf.position;
+
+ //
+ // I don't use readSize() and writeSize() for encapsulations,
+ // because when creating an encapsulation, I must know in advance
+ // how many bytes the size information will require in the data
+ // stream. If I use an Int, it is always 4 bytes. For
+ // readSize()/writeSize(), it could be 1 or 5 bytes.
+ //
+ var sz = this.readInt();
+ if(sz < 6)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ if(sz - 4 > this._buf.remaining)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ this._readEncapsStack.sz = sz;
+
+ var encoding = new Ice.EncodingVersion();
+ encoding.__read(this);
+ Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported.
+ this._readEncapsStack.setEncoding(encoding);
+
+ return encoding;
+ },
+ endReadEncaps: function()
+ {
+ Debug.assert(this._readEncapsStack !== null);
+
+ if(!this._readEncapsStack.encoding_1_0)
+ {
+ this.skipOpts();
+ if(this._buf.position !== this._readEncapsStack.start + this._readEncapsStack.sz)
+ {
+ throw new Ice.EncapsulationException();
+ }
+ }
+ else if(this._buf.position !== this._readEncapsStack.start + this._readEncapsStack.sz)
+ {
+ if(this._buf.position + 1 !== this._readEncapsStack.start + this._readEncapsStack.sz)
+ {
+ throw new Ice.EncapsulationException();
+ }
+
+ //
+ // Ice version < 3.3 had a bug where user exceptions with
+ // class members could be encoded with a trailing byte
+ // when dispatched with AMD. So we tolerate an extra byte
+ // in the encapsulation.
+ //
+
+ try
+ {
+ this._buf.get();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ }
+
+ var curr = this._readEncapsStack;
+ this._readEncapsStack = curr.next;
+ curr.next = this._readEncapsCache;
+ this._readEncapsCache = curr;
+ this._readEncapsCache.reset();
+ },
+ skipEmptyEncaps: function(encoding)
+ {
+ Debug.assert(encoding !== undefined);
+ var sz = this.readInt();
+ if(sz !== 6)
+ {
+ throw new Ice.EncapsulationException();
+ }
+
+ var pos = this._buf.position;
+ if(pos + 2 > this._buf.limit)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ if(encoding !== null)
+ {
+ encoding.__read(this);
+ }
+ else
+ {
+ this._buf.position = pos + 2;
+ }
+ },
+ endReadEncapsChecked: function() // Used by public stream API.
+ {
+ if(this._readEncapsStack === null)
+ {
+ throw new Ice.EncapsulationException("not in an encapsulation");
+ }
+ this.endReadEncaps();
+ },
+ readEncaps: function(encoding)
+ {
+ Debug.assert(encoding !== undefined);
+ var sz = this.readInt();
+ if(sz < 6)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ if(sz - 4 > this._buf.remaining)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ if(encoding !== null)
+ {
+ encoding.__read(this);
+ this._buf.position = this._buf.position - 6;
+ }
+ else
+ {
+ this._buf.position = this._buf.position - 4;
+ }
+
+ try
+ {
+ return this._buf.getArray(sz);
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ getReadEncoding: function()
+ {
+ return this._readEncapsStack !== null ? this._readEncapsStack.encoding : this._encoding;
+ },
+ getReadEncapsSize: function()
+ {
+ Debug.assert(this._readEncapsStack !== null);
+ return this._readEncapsStack.sz - 6;
+ },
+ skipEncaps: function()
+ {
+ var sz = this.readInt();
+ if(sz < 6)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ var encoding = new Ice.EncodingVersion();
+ encoding.__read(this);
+ try
+ {
+ this._buf.position = this._buf.position + sz - 6;
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ return encoding;
+ },
+ startWriteSlice: function(typeId, compactId, last)
+ {
+ Debug.assert(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null);
+ this._writeEncapsStack.encoder.startSlice(typeId, compactId, last);
+ },
+ endWriteSlice: function()
+ {
+ Debug.assert(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null);
+ this._writeEncapsStack.encoder.endSlice();
+ },
+ startReadSlice: function() // Returns type ID of next slice
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ return this._readEncapsStack.decoder.startSlice();
+ },
+ endReadSlice: function()
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ this._readEncapsStack.decoder.endSlice();
+ },
+ skipSlice: function()
+ {
+ Debug.assert(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null);
+ this._readEncapsStack.decoder.skipSlice();
+ },
+ readPendingObjects: function()
+ {
+ if(this._readEncapsStack !== null && this._readEncapsStack.decoder !== null)
+ {
+ this._readEncapsStack.decoder.readPendingObjects();
+ }
+ else if((this._readEncapsStack !== null && this._readEncapsStack.encoding_1_0) ||
+ (this._readEncapsStack === null && this._encoding.equals(Ice.Encoding_1_0)))
+ {
+ //
+ // If using the 1.0 encoding and no objects were read, we
+ // still read an empty sequence of pending objects if
+ // requested (i.e.: if this is called).
+ //
+ // This is required by the 1.0 encoding, even if no objects
+ // are written we do marshal an empty sequence if marshaled
+ // data types use classes.
+ //
+ this.skipSize();
+ }
+ },
+ writePendingObjects: function()
+ {
+ if(this._writeEncapsStack !== null && this._writeEncapsStack.encoder !== null)
+ {
+ this._writeEncapsStack.encoder.writePendingObjects();
+ }
+ else if((this._writeEncapsStack !== null && this._writeEncapsStack.encoding_1_0) ||
+ (this._writeEncapsStack === null && this._encoding.equals(Ice.Encoding_1_0)))
+ {
+ //
+ // If using the 1.0 encoding and no objects were written, we
+ // still write an empty sequence for pending objects if
+ // requested (i.e.: if this is called).
+ //
+ // This is required by the 1.0 encoding, even if no objects
+ // are written we do marshal an empty sequence if marshaled
+ // data types use classes.
+ //
+ this.writeSize(0);
+ }
+ },
+ writeSize: function(v)
+ {
+ if(v > 254)
+ {
+ this.expand(5);
+ this._buf.put(255);
+ this._buf.putInt(v);
+ }
+ else
+ {
+ this.expand(1);
+ this._buf.put(v);
+ }
+ },
+ readSize: function()
+ {
+ try
+ {
+ var b = this._buf.get();
+ if(b === 255)
+ {
+ var v = this._buf.getInt();
+ if(v < 0)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ return v;
+ }
+ return b;
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ readAndCheckSeqSize: function(minSize)
+ {
+ var sz = this.readSize();
+
+ if(sz === 0)
+ {
+ return sz;
+ }
+
+ //
+ // The _startSeq variable points to the start of the sequence for which
+ // we expect to read at least _minSeqSize bytes from the stream.
+ //
+ // If not initialized or if we already read more data than _minSeqSize,
+ // we reset _startSeq and _minSeqSize for this sequence (possibly a
+ // top-level sequence or enclosed sequence it doesn't really matter).
+ //
+ // Otherwise, we are reading an enclosed sequence and we have to bump
+ // _minSeqSize by the minimum size that this sequence will require on
+ // the stream.
+ //
+ // The goal of this check is to ensure that when we start un-marshalling
+ // a new sequence, we check the minimal size of this new sequence against
+ // the estimated remaining buffer size. This estimatation is based on
+ // the minimum size of the enclosing sequences, it's _minSeqSize.
+ //
+ if(this._startSeq === -1 || this._buf.position > (this._startSeq + this._minSeqSize))
+ {
+ this._startSeq = this._buf.position;
+ this._minSeqSize = sz * minSize;
+ }
+ else
+ {
+ this._minSeqSize += sz * minSize;
+ }
+
+ //
+ // If there isn't enough data to read on the stream for the sequence (and
+ // possibly enclosed sequences), something is wrong with the marshalled
+ // data: it's claiming having more data that what is possible to read.
+ //
+ if(this._startSeq + this._minSeqSize > this._buf.limit)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ return sz;
+ },
+ startSize: function()
+ {
+ var pos = this._buf.position;
+ this.writeInt(0); // Placeholder for 32-bit size
+ return pos;
+ },
+ endSize: function(pos)
+ {
+ Debug.assert(pos >= 0);
+ this.rewriteInt(this._buf.position - pos - 4, pos);
+ },
+ writeBlob: function(v)
+ {
+ if(v === null)
+ {
+ return;
+ }
+ this.expand(v.length);
+ this._buf.putArray(v);
+ },
+ readBlob: function(sz)
+ {
+ if(this._buf.remaining < sz)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ try
+ {
+ return this._buf.getArray(sz);
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ // Read/write format and tag for optionals
+ writeOpt: function(tag, format)
+ {
+ Debug.assert(this._writeEncapsStack !== null);
+ if(this._writeEncapsStack.encoder !== null)
+ {
+ return this._writeEncapsStack.encoder.writeOpt(tag, format);
+ }
+ return this.writeOptImpl(tag, format);
+ },
+ readOpt: function(tag, expectedFormat)
+ {
+ Debug.assert(this._readEncapsStack !== null);
+ if(this._readEncapsStack.decoder !== null)
+ {
+ return this._readEncapsStack.decoder.readOpt(tag, expectedFormat);
+ }
+ return this.readOptImpl(tag, expectedFormat);
+ },
+ writeOptValue: function(tag, format, write, v)
+ {
+ if(v !== undefined)
+ {
+ if(this.writeOpt(tag, format))
+ {
+ write.call(this, v);
+ }
+ }
+ },
+ readOptValue: function(tag, format, read)
+ {
+ if(this.readOpt(tag, format))
+ {
+ return read.call(this);
+ }
+ else
+ {
+ return undefined;
+ }
+ },
+ writeByte: function(v)
+ {
+ this.expand(1);
+ this._buf.put(v);
+ },
+ rewriteByte: function(v, dest)
+ {
+ this._buf.putAt(dest, v);
+ },
+ readByte: function()
+ {
+ try
+ {
+ return this._buf.get();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeByteSeq: function(v)
+ {
+ if(v === null || v.length === 0)
+ {
+ this.writeSize(0);
+ }
+ else
+ {
+ this.writeSize(v.length);
+ this.expand(v.length);
+ this._buf.putArray(v);
+ }
+ },
+ readByteSeq: function()
+ {
+ return this._buf.getArray(this.readAndCheckSeqSize(1));
+ },
+ writeBool: function(v)
+ {
+ this.expand(1);
+ this._buf.put(v ? 1 : 0);
+ },
+ rewriteBool: function(v, dest)
+ {
+ this._buf.putAt(dest, v ? 1 : 0);
+ },
+ readBool: function()
+ {
+ try
+ {
+ return this._buf.get() === 1;
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeShort: function(v)
+ {
+ this.expand(2);
+ this._buf.putShort(v);
+ },
+ readShort: function()
+ {
+ try
+ {
+ return this._buf.getShort();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeInt: function(v)
+ {
+ this.expand(4);
+ this._buf.putInt(v);
+ },
+ rewriteInt: function(v, dest)
+ {
+ this._buf.putIntAt(dest, v);
+ },
+ readInt: function()
+ {
+ try
+ {
+ return this._buf.getInt();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeLong: function(v)
+ {
+ this.expand(8);
+ this._buf.putLong(v);
+ },
+ readLong: function()
+ {
+ try
+ {
+ return this._buf.getLong();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeFloat: function(v)
+ {
+ this.expand(4);
+ this._buf.putFloat(v);
+ },
+ readFloat: function()
+ {
+ try
+ {
+ return this._buf.getFloat();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeDouble: function(v)
+ {
+ this.expand(8);
+ this._buf.putDouble(v);
+ },
+ readDouble: function()
+ {
+ try
+ {
+ return this._buf.getDouble();
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeString: function(v)
+ {
+ if(v === null || v.length === 0)
+ {
+ this.writeSize(0);
+ }
+ else
+ {
+ this._buf.writeString(this, v);
+ }
+ },
+ readString: function()
+ {
+ var len = this.readSize();
+ if(len === 0)
+ {
+ return "";
+ }
+ //
+ // Check the buffer has enough bytes to read.
+ //
+ if(this._buf.remaining < len)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+
+ try
+ {
+ return this._buf.getString(len);
+ }
+ catch(ex)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ },
+ writeProxy: function(v)
+ {
+ this._instance.proxyFactory().proxyToStream(v, this);
+ },
+ writeOptProxy: function(tag, v)
+ {
+ if(v !== undefined)
+ {
+ if(this.writeOpt(tag, OptionalFormat.FSize))
+ {
+ var pos = this.startSize();
+ this.writeProxy(v);
+ this.endSize(pos);
+ }
+ }
+ },
+ readProxy: function(type)
+ {
+ return this._instance.proxyFactory().streamToProxy(this, type);
+ },
+ readOptProxy: function(tag, type)
+ {
+ if(this.readOpt(tag, OptionalFormat.FSize))
+ {
+ this.skip(4);
+ return this.readProxy(type);
+ }
+ else
+ {
+ return undefined;
+ }
+ },
+ writeEnum: function(v)
+ {
+ if(this.isWriteEncoding_1_0())
+ {
+ if(v.maxValue < 127)
+ {
+ this.writeByte(v.value);
+ }
+ else if(v.maxValue < 32767)
+ {
+ this.writeShort(v.value);
+ }
+ else
+ {
+ this.writeInt(v.value);
+ }
+ }
+ else
+ {
+ this.writeSize(v.value);
+ }
+ },
+ readEnum: function(T)
+ {
+ var v;
+ if(this.getReadEncoding().equals(Ice.Encoding_1_0))
+ {
+ if(T.maxValue < 127)
+ {
+ v = this.readByte();
+ }
+ else if(T.maxValue < 32767)
+ {
+ v = this.readShort();
+ }
+ else
+ {
+ v = this.readInt();
+ }
+ }
+ else
+ {
+ v = this.readSize();
+ }
+
+ var e = T.valueOf(v);
+ if(e === undefined)
+ {
+ throw new Ice.MarshalException("enumerator value " + v + " is out of range");
+ }
+ return e;
+ },
+ readOptEnum: function(tag, T)
+ {
+ if(this.readOpt(tag, OptionalFormat.Size))
+ {
+ return this.readEnum(T);
+ }
+ else
+ {
+ return undefined;
+ }
+ },
+ writeObject: function(v)
+ {
+ this.initWriteEncaps();
+ this._writeEncapsStack.encoder.writeObject(v);
+ },
+ writeOptObject: function(tag, v)
+ {
+ if(v !== undefined)
+ {
+ if(this.writeOpt(tag, OptionalFormat.Class))
+ {
+ this.writeObject(v);
+ }
+ }
+ },
+ readObject: function(patcher, T)
+ {
+ this.initReadEncaps();
+ //
+ // BUGFIX:
+ // With Chrome linux the invokation of readObject on the decoder some times
+ // calls BasicStream.readObject with the decoder object as this param.
+ // Use call instead of directly invoke the method to workaround this bug.
+ //
+ this._readEncapsStack.decoder.readObject.call(
+ this._readEncapsStack.decoder,
+ function(obj){
+ if(obj !== null && !(obj.ice_instanceof(T)))
+ {
+ ExUtil.throwUOE(T.ice_staticId(), obj);
+ }
+ patcher(obj);
+ });
+ },
+ readOptObject: function(tag, patcher, T)
+ {
+ if(this.readOpt(tag, OptionalFormat.Class))
+ {
+ this.readObject(patcher, T);
+ }
+ else
+ {
+ patcher(undefined);
+ }
+ },
+ writeUserException: function(e)
+ {
+ this.initWriteEncaps();
+ this._writeEncapsStack.encoder.writeUserException(e);
+ },
+ throwException: function()
+ {
+ this.initReadEncaps();
+ this._readEncapsStack.decoder.throwException();
+ },
+ sliceObjects: function(b)
+ {
+ this._sliceObjects = b;
+ },
+ readOptImpl: function(readTag, expectedFormat)
+ {
+ var b, v, format, tag, offset;
+
+ if(this.isReadEncoding_1_0())
+ {
+ return false; // Optional members aren't supported with the 1.0 encoding.
+ }
+
+ while(true)
+ {
+ if(this._buf.position >= this._readEncapsStack.start + this._readEncapsStack.sz)
+ {
+ return false; // End of encapsulation also indicates end of optionals.
+ }
+
+ v = this.readByte();
+
+ if(v === OPTIONAL_END_MARKER)
+ {
+ this._buf.position -= 1; // Rewind.
+ return false;
+ }
+
+ format = OptionalFormat.valueOf(v & 0x07); // First 3 bits.
+ tag = v >> 3;
+ if(tag === 30)
+ {
+ tag = this.readSize();
+ }
+
+ if(tag > readTag)
+ {
+ offset = tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind
+ this._buf.position -= offset;
+ return false; // No optional data members with the requested tag.
+ }
+
+ if(tag < readTag)
+ {
+ this.skipOpt(format); // Skip optional data members
+ }
+ else
+ {
+ if(format !== expectedFormat)
+ {
+ throw new Ice.MarshalException("invalid optional data member `" + tag + "': unexpected format");
+ }
+ return true;
+ }
+ }
+ },
+ writeOptImpl: function(tag, format)
+ {
+ if(this.isWriteEncoding_1_0())
+ {
+ return false; // Optional members aren't supported with the 1.0 encoding.
+ }
+
+ var v = format.value;
+ if(tag < 30)
+ {
+ v |= tag << 3;
+ this.writeByte(v);
+ }
+ else
+ {
+ v |= 0x0F0; // tag = 30
+ this.writeByte(v);
+ this.writeSize(tag);
+ }
+ return true;
+ },
+ skipOpt: function(format)
+ {
+ switch(format)
+ {
+ case OptionalFormat.F1:
+ this.skip(1);
+ break;
+ case OptionalFormat.F2:
+ this.skip(2);
+ break;
+ case OptionalFormat.F4:
+ this.skip(4);
+ break;
+ case OptionalFormat.F8:
+ this.skip(8);
+ break;
+ case OptionalFormat.Size:
+ this.skipSize();
+ break;
+ case OptionalFormat.VSize:
+ this.skip(this.readSize());
+ break;
+ case OptionalFormat.FSize:
+ this.skip(this.readInt());
+ break;
+ case OptionalFormat.Class:
+ this.readObject(null, Ice.Object);
+ break;
+ }
+ },
+ skipOpts: function()
+ {
+ var b, v, format;
+ //
+ // Skip remaining un-read optional members.
+ //
+ while(true)
+ {
+ if(this._buf.position >= this._readEncapsStack.start + this._readEncapsStack.sz)
+ {
+ return; // End of encapsulation also indicates end of optionals.
+ }
+
+ b = this.readByte();
+ v = b < 0 ? b + 256 : b;
+ if(v === OPTIONAL_END_MARKER)
+ {
+ return;
+ }
+
+ format = OptionalFormat.valueOf(v & 0x07); // Read first 3 bits.
+ if((v >> 3) === 30)
+ {
+ this.skipSize();
+ }
+ this.skipOpt(format);
+ }
+ },
+ skip: function(size)
+ {
+ if(size > this._buf.remaining)
+ {
+ throw new Ice.UnmarshalOutOfBoundsException();
+ }
+ this._buf.position += size;
+ },
+ skipSize: function()
+ {
+ var b = this.readByte();
+ if(b === 255)
+ {
+ this.skip(4);
+ }
+ },
+ isEmpty: function()
+ {
+ return this._buf.empty();
+ },
+ expand: function(n)
+ {
+ if(!this._unlimited && this._buf && this._buf.position + n > this._messageSizeMax)
+ {
+ ExUtil.throwMemoryLimitException(this._buf.position + n, this._messageSizeMax);
+ }
+ this._buf.expand(n);
+ },
+ createObject: function(id)
+ {
+ var obj = null, Class;
+ try
+ {
+ var typeId = id.length > 2 ? id.substr(2).replace("::", ".") : "";
+ /*jshint -W061 */
+ Class = eval(typeId);
+ /*jshint +W061 */
+ if(Class !== undefined)
+ {
+ obj = new Class();
+ }
+ }
+ catch(ex)
+ {
+ throw new Ice.NoObjectFactoryException("no object factory", id, ex);
+ }
+
+ return obj;
+ },
+ getTypeId: function(compactId)
+ {
+ var typeId = Ice.CompactIdRegistry.get(compactId);
+ return typeId === undefined ? "" : typeId;
+ },
+ isReadEncoding_1_0: function()
+ {
+ return this._readEncapsStack !== null ? this._readEncapsStack.encoding_1_0 : this._encoding.equals(Ice.Encoding_1_0);
+ },
+ isWriteEncoding_1_0: function()
+ {
+ return this._writeEncapsStack ? this._writeEncapsStack.encoding_1_0 : this._encoding.equals(Ice.Encoding_1_0);
+ },
+ initReadEncaps: function()
+ {
+ if(this._readEncapsStack === null) // Lazy initialization
+ {
+ this._readEncapsStack = this._readEncapsCache;
+ if(this._readEncapsStack !== null)
+ {
+ this._readEncapsCache = this._readEncapsCache.next;
+ }
+ else
+ {
+ this._readEncapsStack = new ReadEncaps();
+ }
+ this._readEncapsStack.setEncoding(this._encoding);
+ this._readEncapsStack.sz = this._buf.limit;
+ }
+
+ if(this._readEncapsStack.decoder === null) // Lazy initialization.
+ {
+ var factoryManager = this._instance.servantFactoryManager();
+ if(this._readEncapsStack.encoding_1_0)
+ {
+ this._readEncapsStack.decoder = new EncapsDecoder10(this, this._readEncapsStack, this._sliceObjects, factoryManager);
+ }
+ else
+ {
+ this._readEncapsStack.decoder = new EncapsDecoder11(this, this._readEncapsStack, this._sliceObjects, factoryManager);
+ }
+ }
+ },
+ initWriteEncaps: function()
+ {
+ if(!this._writeEncapsStack) // Lazy initialization
+ {
+ this._writeEncapsStack = this._writeEncapsCache;
+ if(this._writeEncapsStack)
+ {
+ this._writeEncapsCache = this._writeEncapsCache.next;
+ }
+ else
+ {
+ this._writeEncapsStack = new WriteEncaps();
+ }
+ this._writeEncapsStack.setEncoding(this._encoding);
+ }
+
+ if(this._writeEncapsStack.format === FormatType.DefaultFormat)
+ {
+ this._writeEncapsStack.format = this._instance.defaultsAndOverrides().defaultFormat;
+ }
+
+ if(!this._writeEncapsStack.encoder) // Lazy initialization.
+ {
+ if(this._writeEncapsStack.encoding_1_0)
+ {
+ this._writeEncapsStack.encoder = new EncapsEncoder10(this, this._writeEncapsStack);
+ }
+ else
+ {
+ this._writeEncapsStack.encoder = new EncapsEncoder11(this, this._writeEncapsStack);
+ }
+ }
+ },
+ createUserException: function(id)
+ {
+ var userEx = null, Class;
+
+ try
+ {
+ var typeId = id.length > 2 ? id.substr(2).replace("::", ".") : "";
+ /*jshint -W061 */
+ Class = eval(typeId);
+ /*jshint +W061 */
+ if(Class !== undefined)
+ {
+ userEx = new Class();
+ }
+ }
+ catch(ex)
+ {
+ throw new Ice.MarshalException(ex);
+ }
+
+ return userEx;
+ }
+ });
+
+ var defineProperty = Object.defineProperty;
+
+ defineProperty(BasicStream.prototype, "pos", {
+ get: function() { return this._buf.position; },
+ set: function(n) { this._buf.position = n; }
+ });
+
+ defineProperty(BasicStream.prototype, "size", {
+ get: function() { return this._buf.limit; }
+ });
+
+ defineProperty(BasicStream.prototype, "instance", {
+ get: function() { return this._instance; }
+ });
+
+ defineProperty(BasicStream.prototype, "closure", {
+ get: function() { return this._type; },
+ set: function(type) { this._type = type; }
+ });
+
+ defineProperty(BasicStream.prototype, "buffer", {
+ get: function() { return this._buf; }
+ });
+
+ var defineBuiltinHelper = function(write, read, sz, format)
+ {
+ var helper = {
+ write: function(os, v) { return write.call(os, v); },
+ read: function(is) { return read.call(is); },
+ writeOpt: function(os, tag, v) { os.writeOptValue(tag, format, write, v); },
+ readOpt: function(is, tag) { return is.readOptValue(tag, format, read); },
+ };
+ defineProperty(helper, "minWireSize", {
+ get: function() { return sz; }
+ });
+ return helper;
+ };
+
+ var stream = BasicStream.prototype;
+ Ice.ByteHelper = defineBuiltinHelper(stream.writeByte, stream.readByte, 1, Ice.OptionalFormat.F1);
+ Ice.BoolHelper = defineBuiltinHelper(stream.writeBool, stream.readBool, 1, Ice.OptionalFormat.F1);
+ Ice.ShortHelper = defineBuiltinHelper(stream.writeShort, stream.readShort, 2, Ice.OptionalFormat.F2);
+ Ice.IntHelper = defineBuiltinHelper(stream.writeInt, stream.readInt, 4, Ice.OptionalFormat.F4);
+ Ice.LongHelper = defineBuiltinHelper(stream.writeLong, stream.readLong, 8, Ice.OptionalFormat.F8);
+ Ice.FloatHelper = defineBuiltinHelper(stream.writeFloat, stream.readFloat, 4, Ice.OptionalFormat.F4);
+ Ice.DoubleHelper = defineBuiltinHelper(stream.writeDouble, stream.readDouble, 8, Ice.OptionalFormat.F8);
+ Ice.StringHelper = defineBuiltinHelper(stream.writeString, stream.readString, 1, Ice.OptionalFormat.VSize);
+
+ Ice.ObjectHelper = {
+ write: function(os, v)
+ {
+ os.writeObject(v);
+ },
+ read: function(is)
+ {
+ var o;
+ is.readObject(function(v) { o = v; }, Ice.Object);
+ return o;
+ },
+ writeOpt: function(os, tag, v)
+ {
+ os.writeOptValue(tag, Ice.OptionalFormat.Class, stream.writeObject, v);
+ },
+ readOpt: function(is, tag)
+ {
+ var o;
+ is.readOptObject(tag, function(v) { o = v; }, Ice.Object);
+ return o;
+ },
+ };
+
+ defineProperty(Ice.ObjectHelper, "minWireSize", {
+ get: function() { return 1; }
+ });
+
+ Ice.BasicStream = BasicStream;
+ global.Ice = Ice;
+}(typeof (global) === "undefined" ? window : global));