summaryrefslogtreecommitdiff
path: root/matlab/lib/+IceInternal/EncapsDecoder11.m
diff options
context:
space:
mode:
Diffstat (limited to 'matlab/lib/+IceInternal/EncapsDecoder11.m')
-rw-r--r--matlab/lib/+IceInternal/EncapsDecoder11.m407
1 files changed, 324 insertions, 83 deletions
diff --git a/matlab/lib/+IceInternal/EncapsDecoder11.m b/matlab/lib/+IceInternal/EncapsDecoder11.m
index d1ced40e930..aa01b8e5c02 100644
--- a/matlab/lib/+IceInternal/EncapsDecoder11.m
+++ b/matlab/lib/+IceInternal/EncapsDecoder11.m
@@ -11,10 +11,46 @@ ICE_LICENSE file included in this distribution.
classdef EncapsDecoder11 < IceInternal.EncapsDecoder
methods
- function obj = EncapsDecoder11(is, encaps)
- obj = obj@IceInternal.EncapsDecoder(is, encaps);
+ function obj = EncapsDecoder11(is, encaps, sliceValues, valueFactoryManager, compactIdResolver)
+ obj = obj@IceInternal.EncapsDecoder(is, encaps, sliceValues, valueFactoryManager);
+ obj.compactIdResolver = compactIdResolver;
+ obj.current = [];
+ obj.valueIdIndex = 1;
end
+
+ function readValue(obj, cb)
+ import IceInternal.Protocol;
+ index = obj.is.readSize();
+ if index < 0
+ throw(Ice.MarshalException('', '', 'invalid object id'));
+ elseif index == 0
+ if ~isempty(cb)
+ cb([]);
+ end
+ elseif ~isempty(obj.current) && bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_INDIRECTION_TABLE)
+ %
+ % When reading a class instance within a slice and there's an
+ % indirect instance table, always read an indirect reference
+ % that points to an instance from the indirect instance 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 ~isempty(cb)
+ sz = length(obj.current.indirectPatchList);
+ obj.current.indirectPatchList(sz + 1).index = index - 1;
+ obj.current.indirectPatchList(sz + 1).cb = cb;
+ end
+ else
+ obj.readInstance(index, cb);
+ end
+ end
+
function throwException(obj)
+ import IceInternal.Protocol;
assert(isempty(obj.current));
obj.push(IceInternal.SliceType.ExceptionSlice);
@@ -28,7 +64,7 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
%
% Translate the type ID into a class name.
%
- cls = Ice.Util.idToClass(obj.current.typeId);
+ cls = IceInternal.Util.idToClass(obj.current.typeId);
%
% Try to instantiate the class.
@@ -54,7 +90,7 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
%
% If this is the last slice, raise an exception and stop unmarshaling.
%
- if bitand(obj.current.sliceFlags, obj.FLAG_IS_LAST_SLICE)
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_IS_LAST_SLICE)
throw(Ice.UnknownUserException('', '', mostDerivedId));
end
@@ -62,26 +98,25 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
end
end
end
+
function startInstance(obj, sliceType)
assert(obj.current.sliceType == sliceType);
obj.current.skipFirstSlice = true;
end
- function endInstance(obj) % TODO: SlicedData
- %{
- SlicedDataPtr slicedData;
- if(preserve)
- {
- slicedData = readSlicedData();
- }
- _current->slices.clear();
- _current->indirectionTables.clear();
- _current = _current->previous;
- return slicedData;
- %}
- obj.current.slices = [];
+
+ function r = endInstance(obj, preserve)
+ slicedData = [];
+ if preserve
+ slicedData = obj.readSlicedData();
+ end
+ obj.current.slices = {};
+ obj.current.indirectionTables = {};
obj.current = obj.current.previous;
+ r = slicedData;
end
+
function r = startSlice(obj)
+ import IceInternal.Protocol;
%
% If first slice, don't read the header, it was already read in
% readInstance or throwException to find the factory.
@@ -101,11 +136,11 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
%
if obj.current.sliceType == IceInternal.SliceType.ValueSlice
% Must be checked first!
- if bitand(obj.current.sliceFlags, obj.FLAG_HAS_TYPE_ID_COMPACT) == obj.FLAG_HAS_TYPE_ID_COMPACT
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_TYPE_ID_COMPACT) == Protocol.FLAG_HAS_TYPE_ID_COMPACT
obj.current.typeId = '';
obj.current.compactId = obj.is.readSize();
- elseif bitand(obj.current.sliceFlags, bitor(obj.FLAG_HAS_TYPE_ID_STRING, obj.FLAG_HAS_TYPE_ID_INDEX))
- obj.current.typeId = obj.readTypeId(bitand(obj.current.sliceFlags, obj.FLAG_HAS_TYPE_ID_INDEX) > 0);
+ elseif bitand(obj.current.sliceFlags, bitor(Protocol.FLAG_HAS_TYPE_ID_STRING, Protocol.FLAG_HAS_TYPE_ID_INDEX))
+ obj.current.typeId = obj.readTypeId(bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_TYPE_ID_INDEX) > 0);
obj.current.compactId = -1;
else
% Only the most derived slice encodes the type ID for the compact format.
@@ -119,7 +154,7 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
%
% Read the slice size if necessary.
%
- if bitand(obj.current.sliceFlags, obj.FLAG_HAS_SLICE_SIZE)
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_SLICE_SIZE)
obj.current.sliceSize = obj.is.readInt();
if obj.current.sliceSize < 4
throw(Ice.UnmarshalOutOfBoundsException());
@@ -130,60 +165,63 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
r = obj.current.typeId;
end
+
function endSlice(obj)
- if bitand(obj.current.sliceFlags, obj.FLAG_HAS_OPTIONAL_MEMBERS)
+ import IceInternal.Protocol;
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_OPTIONAL_MEMBERS)
obj.is.skipOptionals();
end
%
- % Read the indirect object table if one is present.
+ % Read the indirection table if one is present and transform the
+ % indirect patch list into patch entries with direct references.
%
- if bitand(obj.current.sliceFlags, obj.FLAG_HAS_INDIRECTION_TABLE)
- %{
- % TODO
- IndexList indirectionTable(obj.is.readAndCheckSeqSize(1));
- for(IndexList::iterator p = indirectionTable.begin(); p != indirectionTable.end(); ++p)
- {
- *p = readInstance(obj.is.readSize(), 0, 0);
- }
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_INDIRECTION_TABLE)
+ %
+ % The table is written as a sequence<size> to conserve space.
+ %
+ sz = obj.is.readAndCheckSeqSize(1);
+ indirectionTable = cell(1, sz);
+ for i = 1:sz
+ indirectionTable{i} = obj.readInstance(obj.is.readSize(), []);
+ end
%
% Sanity checks. If there are optional members, it's possible
- % that not all object references were read if they are from
+ % that not all instance references were read if they are from
% unknown optional data members.
%
- if(indirectionTable.empty())
- {
- throw MarshalException(__FILE__, __LINE__, "empty indirection table");
- }
- if(obj.current.indirectPatchList.empty() && !(obj.current.sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS))
- {
- throw MarshalException(__FILE__, __LINE__, "no references to indirection table");
- }
+ if length(indirectionTable) == 0
+ throw(Ice.MarshalException('', '', 'empty indirection table'));
+ end
+ if isempty(obj.current.indirectPatchList) && ...
+ bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_OPTIONAL_MEMBERS) == 0
+ throw(Ice.MarshalException('', '', 'no references to indirection table'));
+ end
%
% Convert indirect references into direct references.
%
- IndirectPatchList::iterator p;
- for(p = obj.current.indirectPatchList.begin(); p != obj.current.indirectPatchList.end(); ++p)
- {
- assert(p->index >= 0);
- if(p->index >= static_cast<Int>(indirectionTable.size()))
- {
- throw MarshalException(__FILE__, __LINE__, "indirection out of range");
- }
- addPatchEntry(indirectionTable[p->index], p->patchFunc, p->patchAddr);
- }
- obj.current.indirectPatchList.clear();
- %}
+ if ~isempty(obj.current.indirectPatchList)
+ for e = obj.current.indirectPatchList
+ assert(e.index >= 0);
+ if e.index >= length(indirectionTable)
+ throw(Ice.MarshalException('', '', 'indirection out of range'));
+ end
+ obj.addPatchEntry(indirectionTable{e.index}, e.cb);
+ end
+ obj.current.indirectPatchList = [];
+ end
end
end
+
function skipSlice(obj)
+ import IceInternal.Protocol;
%obj.is.traceSkipSlice(obj.current.typeId, obj.current.sliceType);
start = obj.is.pos();
- if bitand(obj.current.sliceFlags, obj.FLAG_HAS_SLICE_SIZE)
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_SLICE_SIZE)
assert(obj.current.sliceSize >= 4);
obj.is.skip(obj.current.sliceSize - 4);
else
@@ -202,8 +240,8 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
info = Ice.SliceInfo();
info.typeId = obj.current.typeId;
info.compactId = obj.current.compactId;
- info.hasOptionalMembers = bitand(obj.current.sliceFlags, obj.FLAG_HAS_OPTIONAL_MEMBERS) > 0;
- info.isLastSlice = bitand(obj.current.sliceFlags, obj.FLAG_IS_LAST_SLICE) > 0;
+ info.hasOptionalMembers = bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_OPTIONAL_MEMBERS) > 0;
+ info.isLastSlice = bitand(obj.current.sliceFlags, Protocol.FLAG_IS_LAST_SLICE) > 0;
if info.hasOptionalMembers
%
% Don't include the optional member end marker. It will be re-written by
@@ -214,57 +252,260 @@ classdef EncapsDecoder11 < IceInternal.EncapsDecoder
info.bytes = obj.is.getBytes(start, obj.is.pos());
end
- %{
- % TODO
- obj.current.indirectionTables.push_back(IndexList());
-
%
- % Read the indirect object table. We read the instances or their
+ % Read the indirect instance 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 bitand(obj.current.sliceFlags, obj.FLAG_HAS_INDIRECTION_TABLE)
- IndexList& table = obj.current.indirectionTables.back();
- table.resize(obj.is.readAndCheckSeqSize(1));
- for(IndexList::iterator p = table.begin(); p != table.end(); ++p)
- {
- *p = readInstance(obj.is.readSize(), 0, 0);
- }
-
- obj.current.slices.push_back(info);
- %}
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_INDIRECTION_TABLE)
+ sz = obj.is.readAndCheckSeqSize(1);
+ indirectionTable = cell(1, sz);
+ for i = 1:sz
+ indirectionTable{i} = obj.readInstance(obj.is.readSize(), []);
+ end
+ obj.current.indirectionTables{end + 1} = indirectionTable;
+ else
+ obj.current.indirectionTables{end + 1} = {};
+ end
+
+ obj.current.slices{end + 1} = info;
end
+
function r = readOptional(obj, readTag, expectedFormat)
+ import IceInternal.Protocol;
if isempty(obj.current)
- r = obj.is.readOptImpl(readTag, expectedFormat);
+ r = obj.is.readOptionalImpl(readTag, expectedFormat);
return;
- elseif bitand(obj.current.sliceFlags, obj.FLAG_HAS_OPTIONAL_MEMBERS)
- r = obj.is.readOptImpl(readTag, expectedFormat);
+ elseif bitand(obj.current.sliceFlags, Protocol.FLAG_HAS_OPTIONAL_MEMBERS)
+ r = obj.is.readOptionalImpl(readTag, expectedFormat);
return;
end
r = false;
end
+
end
methods(Access=private)
+ function r = readInstance(obj, index, cb)
+ import IceInternal.Protocol;
+ assert(index > 0);
+
+ if index > 1
+ if ~isempty(cb)
+ obj.addPatchEntry(index, cb);
+ end
+ r = index;
+ return;
+ end
+
+ obj.push(IceInternal.SliceType.ValueSlice);
+
+ %
+ % Get the instance ID before we start reading slices. If some
+ % slices are skipped, the indirect instance table is still read and
+ % might read other instances.
+ %
+ obj.valueIdIndex = obj.valueIdIndex + 1;
+ index = obj.valueIdIndex;
+
+ %
+ % Read the first slice header.
+ %
+ obj.startSlice();
+ mostDerivedId = obj.current.typeId;
+ v = [];
+ while true
+ updateCache = false;
+
+ if obj.current.compactId >= 0
+ updateCache = true;
+
+ %
+ % Translate a compact (numeric) type ID into a class.
+ %
+ if isempty(obj.compactIdCache) % Lazy initialization.
+ obj.compactIdCache = containers.Map('KeyType', 'int32', 'ValueType', 'char');
+ else
+ %
+ % Check the cache to see if we've already translated the compact type ID into a class.
+ %
+ if obj.compactIdCache.isKey(obj.current.compactId)
+ cls = obj.compactIdCache(obj.current.compactId);
+ try
+ v = eval(cls);
+ updateCache = false;
+ catch e
+ throw(Ice.NoValueFactoryException('', 'no value factory', ...
+ sprintf('compact ID %d', obj.current.compactId)));
+ end
+ end
+ end
+
+ %
+ % If we haven't already cached a class for the compact ID, then try to translate the
+ % compact ID into a type ID.
+ %
+ if isempty(v)
+ obj.current.typeId = '';
+ if ~isempty(obj.compactIdResolver)
+ try
+ obj.current.typeId = obj.compactIdResolver(obj.current.compactId);
+ catch ex
+ if isa(ex, 'Ice.LocalException')
+ rethrow(ex);
+ else
+ throw(Ice.MarshalException('', '', ...
+ sprintf('exception in compact ID resolver for ID %d', ...
+ obj.current.compactId)));
+ end
+ end
+ end
+
+ if isempty(obj.current.typeId)
+ obj.current.typeId = obj.resolveCompactId(obj.current.compactId);
+ end
+ end
+ end
+
+ if isempty(v) && ~isempty(obj.current.typeId)
+ v = obj.newInstance(obj.current.typeId);
+ end
+
+ if ~isempty(v)
+ if updateCache
+ assert(obj.current.compactId >= 0);
+ obj.compactIdCache(obj.current.compactId) = class(v);
+ end
+
+ %
+ % We have an instance, get out of this loop.
+ %
+ break;
+ end
+
+ %
+ % If slicing is disabled, stop unmarshaling.
+ %
+ if ~obj.sliceValues
+ throw(Ice.NoValueFactoryException('', '', 'no value factory found and slicing is disabled', ...
+ obj.current.typeId));
+ end
+
+ %
+ % Slice off what we don't understand.
+ %
+ obj.skipSlice();
+
+ %
+ % If this is the last slice, keep the instance as an opaque
+ % UnknownSlicedValue object.
+ %
+ if bitand(obj.current.sliceFlags, Protocol.FLAG_IS_LAST_SLICE)
+ %
+ % Provide a factory with an opportunity to supply the instance.
+ % We pass the "::Ice::Object" ID to indicate that this is the
+ % last chance to preserve the instance.
+ %
+ v = obj.newInstance(Ice.Value.ice_staticId());
+ if isempty(v)
+ v = Ice.UnknownSlicedValue(mostDerivedId);
+ end
+
+ break;
+ end
+
+ obj.startSlice(); % Read next Slice header for next iteration.
+ end
+
+ %
+ % Unmarshal the instance.
+ %
+ obj.unmarshal(index, v);
+
+ if isempty(obj.current) && ~isempty(obj.patchMap)
+ %
+ % If any entries remain in the patch map, the sender has sent an index for an instance, but failed
+ % to supply the instance.
+ %
+ throw(Ice.MarshalException('', '', 'index for class received, but no instance'));
+ end
+
+ if ~isempty(cb)
+ cb(v);
+ end
+
+ r = index;
+ end
+
+ function r = readSlicedData(obj)
+ if isempty(obj.current.slices) % No preserved slices.
+ r = [];
+ end
+
+ %
+ % The _indirectionTables member holds the indirection table for each slice
+ % in _slices.
+ %
+ assert(length(obj.current.slices) == length(obj.current.indirectionTables));
+ function setInstance(si, n, v)
+ si.instances{n} = v;
+ end
+ for n = 1:length(obj.current.slices)
+ %
+ % We use the "instances" list in SliceInfo to hold references
+ % to the target instances. Note that the instances might not have
+ % been read yet in the case of a circular reference to an
+ % enclosing instance.
+ %
+ table = obj.current.indirectionTables{n};
+ info = obj.current.slices{n};
+ info.instances = cell(1, length(table));
+ for j = 1:length(info.instances)
+ obj.addPatchEntry(table{j}, @(v) setInstance(info, j, v));
+ end
+ end
+
+ r = obj.current.slices; % Makes a copy
+ end
+
+ function r = resolveCompactId(obj, id)
+ type = '';
+
+ if ~isempty(obj.compactIdResolver)
+ try
+ type = obj.compactIdResolver(id);
+ catch ex
+ if isa(ex, 'Ice.LocalException')
+ rethrow(ex);
+ else
+ throw(Ice.MarshalException('', '', sprintf('exception in compact ID resolver for ID %d', id)));
+ end
+ end
+ end
+
+ if isempty(type)
+ prop = sprintf('IceCompactId.TypeId_%d.typeId', id);
+ try
+ type = eval(prop);
+ catch ex
+ end
+ end
+
+ r = type;
+ end
+
function push(obj, sliceType)
- obj.current = IceInternal.InstanceData(obj.current);
+ obj.current = IceInternal.EncapsDecoder11_InstanceData(obj.current);
obj.current.sliceType = sliceType;
obj.current.skipFirstSlice = false;
end
end
properties(Access=private)
+ compactIdResolver
current
- end
- properties(Constant,Access=private)
- FLAG_HAS_TYPE_ID_STRING = bitshift(1, 0)
- FLAG_HAS_TYPE_ID_INDEX = bitshift(1, 1)
- FLAG_HAS_TYPE_ID_COMPACT = bitor(bitshift(1, 0), bitshift(1, 1))
- FLAG_HAS_OPTIONAL_MEMBERS = bitshift(1, 2)
- FLAG_HAS_INDIRECTION_TABLE = bitshift(1, 3)
- FLAG_HAS_SLICE_SIZE = bitshift(1, 4)
- FLAG_IS_LAST_SLICE = bitshift(1, 5)
+ valueIdIndex
+ compactIdCache
end
end