diff options
Diffstat (limited to 'cpp/src/Ice/BasicStream.cpp')
-rwxr-xr-x | cpp/src/Ice/BasicStream.cpp | 1900 |
1 files changed, 1322 insertions, 578 deletions
diff --git a/cpp/src/Ice/BasicStream.cpp b/cpp/src/Ice/BasicStream.cpp index 871718941e8..199ef69d639 100755 --- a/cpp/src/Ice/BasicStream.cpp +++ b/cpp/src/Ice/BasicStream.cpp @@ -9,6 +9,7 @@ #include <IceUtil/DisableWarnings.h> #include <Ice/BasicStream.h> +#include <Ice/DefaultsAndOverrides.h> #include <Ice/Instance.h> #include <Ice/Object.h> #include <Ice/Proxy.h> @@ -22,6 +23,7 @@ #include <Ice/TraceUtil.h> #include <Ice/TraceLevels.h> #include <Ice/LoggerUtil.h> +#include <Ice/SlicedData.h> #include <Ice/StringConverter.h> #include <IceUtil/Unicode.h> #include <iterator> @@ -76,21 +78,33 @@ private: } -IceInternal::BasicStream::BasicStream(Instance* instance, bool unlimited) : +const Byte BasicStream::FLAG_HAS_TYPE_ID_STRING = (1<<0); +const Byte BasicStream::FLAG_HAS_TYPE_ID_INDEX = (1<<1); +const Byte BasicStream::FLAG_HAS_OPTIONAL_MEMBERS = (1<<2); +const Byte BasicStream::FLAG_HAS_INDIRECTION_TABLE = (1<<3); +const Byte BasicStream::FLAG_HAS_SLICE_SIZE = (1<<4); +const Byte BasicStream::FLAG_IS_LAST_SLICE = (1<<5); + +IceInternal::BasicStream::BasicStream(Instance* instance, const EncodingVersion& encoding, bool unlimited) : IceInternal::Buffer(instance->messageSizeMax()), _instance(instance), _closure(0), + _encoding(encoding), _currentReadEncaps(0), _currentWriteEncaps(0), - _traceSlicing(-1), _sliceObjects(true), _messageSizeMax(_instance->messageSizeMax()), // Cached for efficiency. _unlimited(unlimited), _stringConverter(instance->initializationData().stringConverter), _wstringConverter(instance->initializationData().wstringConverter), - _startSeq(-1), - _objectList(0) + _startSeq(-1) { + // + // Initialize the encoding members of our pre-allocated encapsulations, in case + // this stream is used without an explicit encapsulation. + // + _preAllocatedReadEncaps.encoding = encoding; + _preAllocatedWriteEncaps.encoding = encoding; } void @@ -112,8 +126,6 @@ IceInternal::BasicStream::clear() _startSeq = -1; - delete _objectList; - _objectList = 0; _sliceObjects = true; } @@ -141,81 +153,56 @@ IceInternal::BasicStream::swap(BasicStream& other) std::swap(_closure, other._closure); // - // Swap is never called for BasicStreams that have more than one - // encaps. + // Swap is never called for BasicStreams that have encapsulations being read/write. However, + // encapsulations might still be set in case marhsalling or un-marhsalling failed. We just + // reset the encapsulations if there are still some set. // - assert(!_currentReadEncaps || _currentReadEncaps == &_preAllocatedReadEncaps); - assert(!_currentWriteEncaps || _currentWriteEncaps == &_preAllocatedWriteEncaps); - assert(!other._currentReadEncaps || other._currentReadEncaps == &other._preAllocatedReadEncaps); - assert(!other._currentWriteEncaps || other._currentWriteEncaps == &other._preAllocatedWriteEncaps); - - if(_currentReadEncaps || other._currentReadEncaps) - { - _preAllocatedReadEncaps.swap(other._preAllocatedReadEncaps); - - if(!_currentReadEncaps) - { - _currentReadEncaps = &_preAllocatedReadEncaps; - other._currentReadEncaps = 0; - } - else if(!other._currentReadEncaps) - { - other._currentReadEncaps = &other._preAllocatedReadEncaps; - _currentReadEncaps = 0; - } - } - - if(_currentWriteEncaps || other._currentWriteEncaps) - { - _preAllocatedWriteEncaps.swap(other._preAllocatedWriteEncaps); - - if(!_currentWriteEncaps) - { - _currentWriteEncaps = &_preAllocatedWriteEncaps; - other._currentWriteEncaps = 0; - } - else if(!other._currentWriteEncaps) - { - other._currentWriteEncaps = &other._preAllocatedWriteEncaps; - _currentWriteEncaps = 0; - } - } + resetEncaps(); + other.resetEncaps(); + std::swap(_unlimited, other._unlimited); std::swap(_startSeq, other._startSeq); std::swap(_minSeqSize, other._minSeqSize); - std::swap(_objectList, other._objectList); - std::swap(_unlimited, other._unlimited); } void -IceInternal::BasicStream::WriteEncaps::swap(WriteEncaps& other) +IceInternal::BasicStream::resetEncaps() { - std::swap(start, other.start); + while(_currentReadEncaps && _currentReadEncaps != &_preAllocatedReadEncaps) + { + ReadEncaps* oldEncaps = _currentReadEncaps; + _currentReadEncaps = _currentReadEncaps->previous; + delete oldEncaps; + } - std::swap(writeIndex, other.writeIndex); - std::swap(toBeMarshaledMap, other.toBeMarshaledMap); - std::swap(marshaledMap, other.marshaledMap); - std::swap(typeIdMap, other.typeIdMap); - std::swap(typeIdIndex, other.typeIdIndex); + while(_currentWriteEncaps && _currentWriteEncaps != &_preAllocatedWriteEncaps) + { + WriteEncaps* oldEncaps = _currentWriteEncaps; + _currentWriteEncaps = _currentWriteEncaps->previous; + delete oldEncaps; + } - std::swap(previous, other.previous); + _preAllocatedReadEncaps.reset(); + _preAllocatedWriteEncaps.reset(); } void -IceInternal::BasicStream::ReadEncaps::swap(ReadEncaps& other) +IceInternal::BasicStream::startWriteEncaps() { - std::swap(start, other.start); - std::swap(sz, other.sz); - - std::swap(encodingMajor, other.encodingMajor); - std::swap(encodingMinor, other.encodingMinor); - - std::swap(patchMap, other.patchMap); - std::swap(unmarshaledMap, other.unmarshaledMap); - std::swap(typeIdMap, other.typeIdMap); - std::swap(typeIdIndex, other.typeIdIndex); + // + // 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. + // - std::swap(previous, other.previous); + if(_currentWriteEncaps) + { + startWriteEncaps(_currentWriteEncaps->encoding, _currentWriteEncaps->format); + } + else + { + startWriteEncaps(_encoding, Ice::DefaultFormat); + } } void @@ -245,7 +232,7 @@ IceInternal::BasicStream::getReadEncapsSize() return _currentReadEncaps->sz - static_cast<Int>(sizeof(Int)) - 2; } -void +EncodingVersion IceInternal::BasicStream::skipEncaps() { Int sz; @@ -258,77 +245,21 @@ IceInternal::BasicStream::skipEncaps() { throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); } - i += sz - sizeof(Int); -} - -void -IceInternal::BasicStream::startWriteSlice() -{ - write(Int(0)); // Placeholder for the slice length. - _writeSlice = b.size(); -} - -void -IceInternal::BasicStream::endWriteSlice() -{ - Int sz = static_cast<Int>(b.size() - _writeSlice + sizeof(Int)); - Byte* dest = &(*(b.begin() + _writeSlice - sizeof(Int))); -#ifdef ICE_BIG_ENDIAN - const Byte* src = reinterpret_cast<const Byte*>(&sz) + sizeof(Int) - 1; - *dest++ = *src--; - *dest++ = *src--; - *dest++ = *src--; - *dest = *src; -#else - const Byte* src = reinterpret_cast<const Byte*>(&sz); - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - *dest = *src; -#endif -} - -void -IceInternal::BasicStream::startReadSlice() -{ - Int sz; - read(sz); - if(sz < 4) - { - throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); - } - _readSlice = i - b.begin(); + EncodingVersion encoding; + read(encoding.major); + read(encoding.minor); + i += sz - sizeof(Int) - 2; + return encoding; } -void -IceInternal::BasicStream::endReadSlice() -{ -} - -void -IceInternal::BasicStream::skipSlice() -{ - Int sz; - read(sz); - if(sz < 4) - { - throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); - } - i += sz - sizeof(Int); - if(i > b.end()) - { - throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); - } -} - -void -IceInternal::BasicStream::readAndCheckSeqSize(int minSize, Ice::Int& sz) +Int +IceInternal::BasicStream::readAndCheckSeqSize(int minSize) { - readSize(sz); + Int sz = readSize(); if(sz == 0) { - return; + return sz; } // @@ -367,62 +298,8 @@ IceInternal::BasicStream::readAndCheckSeqSize(int minSize, Ice::Int& sz) { throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); } -} - -void -IceInternal::BasicStream::writeTypeId(const string& id) -{ - if(!_currentWriteEncaps || !_currentWriteEncaps->typeIdMap) - { - // - // write(ObjectPtr) must be called first. - // - throw MarshalException(__FILE__, __LINE__, "type ids require an encapsulation"); - } - - TypeIdWriteMap::const_iterator k = _currentWriteEncaps->typeIdMap->find(id); - if(k != _currentWriteEncaps->typeIdMap->end()) - { - write(true); - writeSize(k->second); - } - else - { - _currentWriteEncaps->typeIdMap->insert(make_pair(id, ++_currentWriteEncaps->typeIdIndex)); - write(false); - write(id, false); - } -} - -void -IceInternal::BasicStream::readTypeId(string& id) -{ - if(!_currentReadEncaps || !_currentReadEncaps->typeIdMap) - { - // - // read(PatchFunc, void*) must be called first. - // - throw MarshalException(__FILE__, __LINE__, "type ids require an encapsulation"); - } - - bool isIndex; - read(isIndex); - if(isIndex) - { - Ice::Int index; - readSize(index); - TypeIdReadMap::const_iterator k = _currentReadEncaps->typeIdMap->find(index); - if(k == _currentReadEncaps->typeIdMap->end()) - { - throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); - } - id = k->second; - } - else - { - read(id, false); - _currentReadEncaps->typeIdMap->insert(make_pair(++_currentReadEncaps->typeIdIndex, id)); - } + + return sz; } void @@ -454,15 +331,6 @@ IceInternal::BasicStream::readBlob(vector<Byte>& v, Int sz) } } -void IceInternal::BasicStream::write(Byte v, int end) -{ - if(v >= end) - { - throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); - } - write(v); -} - void IceInternal::BasicStream::write(const Byte* begin, const Byte* end) { @@ -477,20 +345,25 @@ IceInternal::BasicStream::write(const Byte* begin, const Byte* end) } void -IceInternal::BasicStream::read(Byte& b, int end) +IceInternal::BasicStream::read(std::vector<Ice::Byte>& v) { - read(b); - if(b >= end) + std::pair<const Ice::Byte*, const Ice::Byte*> p; + read(p); + if(p.first != p.second) { - throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); + v.resize(static_cast<Ice::Int>(p.second - p.first)); + copy(p.first, p.second, v.begin()); + } + else + { + v.clear(); } } void IceInternal::BasicStream::read(pair<const Byte*, const Byte*>& v) { - Int sz; - readAndCheckSeqSize(1, sz); + Int sz = readAndCheckSeqSize(1); if(sz > 0) { v.first = i; @@ -526,7 +399,7 @@ struct BasicStreamWriteBoolHelper { for(int idx = 0; idx < sz; ++idx) { - b[pos + idx] = static_cast<Ice::Byte>(*(begin + idx)); + b[pos + idx] = static_cast<Byte>(*(begin + idx)); } } }; @@ -558,8 +431,7 @@ IceInternal::BasicStream::write(const bool* begin, const bool* end) void IceInternal::BasicStream::read(vector<bool>& v) { - Int sz; - readAndCheckSeqSize(1, sz); + Int sz = readAndCheckSeqSize(1); if(sz > 0) { v.resize(sz); @@ -608,8 +480,7 @@ bool* IceInternal::BasicStream::read(pair<const bool*, const bool*>& v) { bool* result = 0; - Int sz; - readAndCheckSeqSize(1, sz); + Int sz = readAndCheckSeqSize(1); if(sz > 0) { result = BasicStreamReadBoolHelper<sizeof(bool)>::read(v, sz, i); @@ -640,16 +511,6 @@ IceInternal::BasicStream::write(Short v) } void -IceInternal::BasicStream::write(Short v, int end) -{ - if(v < 0 || v >= end) - { - throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); - } - write(v); -} - -void IceInternal::BasicStream::write(const Short* begin, const Short* end) { Int sz = static_cast<Int>(end - begin); @@ -694,20 +555,9 @@ IceInternal::BasicStream::read(Short& v) } void -IceInternal::BasicStream::read(Short& v, int end) -{ - read(v); - if(v < 0 || v >= end) - { - throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); - } -} - -void IceInternal::BasicStream::read(vector<Short>& v) { - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Short)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Short))); if(sz > 0) { Container::iterator begin = i; @@ -736,8 +586,7 @@ Short* IceInternal::BasicStream::read(pair<const Short*, const Short*>& v) { Short* result = 0; - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Short)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Short))); if(sz > 0) { #if defined(__i386) || defined(_M_IX86) @@ -773,26 +622,6 @@ IceInternal::BasicStream::read(pair<const Short*, const Short*>& v) } void -IceInternal::BasicStream::read(Int& v, int end) -{ - read(v); - if(v < 0 || v >= end) - { - throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); - } -} - -void -IceInternal::BasicStream::write(Int v, int end) -{ - if(v < 0 || v >= end) - { - throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); - } - write(v); -} - -void IceInternal::BasicStream::write(const Int* begin, const Int* end) { Int sz = static_cast<Int>(end - begin); @@ -821,8 +650,7 @@ IceInternal::BasicStream::write(const Int* begin, const Int* end) void IceInternal::BasicStream::read(vector<Int>& v) { - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Int)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Int))); if(sz > 0) { Container::iterator begin = i; @@ -853,8 +681,7 @@ Int* IceInternal::BasicStream::read(pair<const Int*, const Int*>& v) { Int* result = 0; - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Int)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Int))); if(sz > 0) { #if defined(__i386) || defined(_M_IX86) @@ -985,8 +812,7 @@ IceInternal::BasicStream::read(Long& v) void IceInternal::BasicStream::read(vector<Long>& v) { - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Long)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Long))); if(sz > 0) { Container::iterator begin = i; @@ -1021,8 +847,7 @@ Long* IceInternal::BasicStream::read(pair<const Long*, const Long*>& v) { Long* result = 0; - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Long)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Long))); if(sz > 0) { #if defined(__i386) || defined(_M_IX86) @@ -1137,8 +962,7 @@ IceInternal::BasicStream::read(Float& v) void IceInternal::BasicStream::read(vector<Float>& v) { - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Float)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Float))); if(sz > 0) { Container::iterator begin = i; @@ -1169,8 +993,7 @@ Float* IceInternal::BasicStream::read(pair<const Float*, const Float*>& v) { Float* result = 0; - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Float)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Float))); if(sz > 0) { #if defined(__i386) || defined(_M_IX86) @@ -1338,8 +1161,7 @@ IceInternal::BasicStream::read(Double& v) void IceInternal::BasicStream::read(vector<Double>& v) { - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Double)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Double))); if(sz > 0) { Container::iterator begin = i; @@ -1389,8 +1211,7 @@ Double* IceInternal::BasicStream::read(pair<const Double*, const Double*>& v) { Double* result = 0; - Int sz; - readAndCheckSeqSize(static_cast<int>(sizeof(Double)), sz); + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Double))); if(sz > 0) { #if defined(__i386) || defined(_M_IX86) @@ -1542,8 +1363,7 @@ IceInternal::BasicStream::readConverted(string& v, int sz) void IceInternal::BasicStream::read(vector<string>& v, bool convert) { - Int sz; - readAndCheckSeqSize(1, sz); + Int sz = readAndCheckSeqSize(1); if(sz > 0) { v.resize(sz); @@ -1639,8 +1459,7 @@ IceInternal::BasicStream::write(const wstring* begin, const wstring* end) void IceInternal::BasicStream::read(wstring& v) { - Ice::Int sz; - readSize(sz); + Int sz = readSize(); if(sz > 0) { if(b.end() - i < sz) @@ -1660,8 +1479,7 @@ IceInternal::BasicStream::read(wstring& v) void IceInternal::BasicStream::read(vector<wstring>& v) { - Int sz; - readAndCheckSeqSize(1, sz); + Int sz = readAndCheckSeqSize(1); if(sz > 0) { v.resize(sz); @@ -1688,8 +1506,249 @@ IceInternal::BasicStream::read(ObjectPrx& v) v = _instance->proxyFactory()->streamToProxy(this); } +Int +IceInternal::BasicStream::readEnum(Int limit) +{ + if(getReadEncoding() == Encoding_1_0) + { + if(limit <= 127) + { + Byte value; + read(value); + return value; + } + else if(limit <= 32767) + { + Short value; + read(value); + return value; + } + else + { + Int value; + read(value); + return value; + } + } + else + { + return readSize(); + } +} + +void +IceInternal::BasicStream::writeEnum(Int v, Int limit) +{ + if(getWriteEncoding() == Encoding_1_0) + { + if(limit <= 127) + { + write(static_cast<Byte>(v)); + } + else if(limit <= 32767) + { + write(static_cast<Short>(v)); + } + else + { + write(v); + } + } + else + { + writeSize(v); + } +} + +void +IceInternal::BasicStream::sliceObjects(bool doSlice) +{ + _sliceObjects = doSlice; +} + + +bool +IceInternal::BasicStream::readOptImpl(Int readTag, OptionalType expectedType) +{ + if(getReadEncoding() == Encoding_1_0) + { + return false; // Optional members aren't supported with the 1.0 encoding. + } + + Int tag = 0; + OptionalType type; + do + { + if(i >= b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz) + { + return false; // End of encapsulation also indicates end of optionals. + } + + Byte v; + read(v); + type = static_cast<OptionalType>(v & 0x07); // First 3 bits. + tag = static_cast<Int>(v >> 3); + if(tag == 31) + { + tag = readSize(); + } + } + while(type != OptionalTypeEndMarker && tag < readTag && skipOpt(type)); // Skip optional data members + + if(type == OptionalTypeEndMarker || tag > readTag) + { + // + // Rewind the stream to correctly read the next optional data + // member tag & type next time. + // + i -= tag < 31 ? 1 : (tag < 255 ? 2 : 6); + return false; // No optional data members with the requested tag. + } + + assert(readTag == tag); + if(type != expectedType) + { + ostringstream os; + os << "invalid optional data member `" << tag << "': unexpected type"; + throw MarshalException(__FILE__, __LINE__, os.str()); + } + + // + // We have an optional data member with the requested tag and + // type. + // + return true; +} + +bool +IceInternal::BasicStream::writeOptImpl(Int tag, OptionalType type) +{ + if(getWriteEncoding() == Encoding_1_0) + { + return false; // Optional members aren't supported with the 1.0 encoding. + } + + Byte v = static_cast<Byte>(type); + if(tag < 31) + { + v |= tag << 3; + write(v); + } + else + { + v |= 0x0F8; // tag = 31 + write(v); + writeSize(tag); + } + return true; +} + +bool +IceInternal::BasicStream::skipOpt(OptionalType type) +{ + int sz; + switch(type) + { + case Ice::OptionalTypeF1: + { + sz = 1; + break; + } + case Ice::OptionalTypeF2: + { + sz = 2; + break; + } + case Ice::OptionalTypeF4: + { + sz = 4; + break; + } + case Ice::OptionalTypeF8: + { + sz = 8; + break; + } + case Ice::OptionalTypeSize: + { + skipSize(); + return true; + } + case Ice::OptionalTypeVSize: + { + sz = readSize(); + break; + } + case Ice::OptionalTypeFSize: + { + read(sz); + break; + } + default: + { + return false; + } + } + skip(sz); + return true; +} + +bool +BasicStream::skipOpts() +{ + // + // Skip remaining un-read optional members. + // + OptionalType type; + do + { + if(i >= b.begin() + _currentReadEncaps->start + _currentReadEncaps->sz) + { + return false; // End of encapsulation also indicates end of optionals. + } + + Byte v; + read(v); + type = static_cast<OptionalType>(v & 0x07); // Read first 3 bits. + if(static_cast<Int>(v >> 3) == 31) + { + skipSize(); + } + } + while(skipOpt(type)); + assert(type == OptionalTypeEndMarker); + return true; +} + void -IceInternal::BasicStream::write(const ObjectPtr& v) +IceInternal::BasicStream::throwUnmarshalOutOfBoundsException(const char* file, int line) +{ + throw UnmarshalOutOfBoundsException(file, line); +} + +void +IceInternal::BasicStream::throwEncapsulationException(const char* file, int line) +{ + throw EncapsulationException(file, line); +} + +void +IceInternal::BasicStream::initReadEncaps() +{ + if(!_currentReadEncaps) // Lazy initialization. + { + _currentReadEncaps = &_preAllocatedReadEncaps; + _currentReadEncaps->sz = static_cast<Ice::Int>(b.size()); + } + + if(!_currentReadEncaps->decoder) // Lazy initialization. + { + _currentReadEncaps->decoder = new EncapsDecoder(this, _currentReadEncaps, _sliceObjects); + } +} + +void +IceInternal::BasicStream::initWriteEncaps() { if(!_currentWriteEncaps) // Lazy initialization. { @@ -1697,361 +1756,867 @@ IceInternal::BasicStream::write(const ObjectPtr& v) _currentWriteEncaps->start = b.size(); } - if(!_currentWriteEncaps->toBeMarshaledMap) // Lazy initialization. + if(_currentWriteEncaps->format == Ice::DefaultFormat) { - _currentWriteEncaps->toBeMarshaledMap = new PtrToIndexMap; - _currentWriteEncaps->marshaledMap = new PtrToIndexMap; - _currentWriteEncaps->typeIdMap = new TypeIdWriteMap; + _currentWriteEncaps->format = _instance->defaultsAndOverrides()->defaultFormat; } + if(!_currentWriteEncaps->encoder) // Lazy initialization. + { + _currentWriteEncaps->encoder = new EncapsEncoder(this, _currentWriteEncaps); + } +} + +void +IceInternal::BasicStream::EncapsEncoder::write(const ObjectPtr& v) +{ if(v) { // - // Look for this instance in the to-be-marshaled map. + // Register the object. // - PtrToIndexMap::iterator p = _currentWriteEncaps->toBeMarshaledMap->find(v); - if(p == _currentWriteEncaps->toBeMarshaledMap->end()) + Int index = registerObject(v); + + if(_encaps->encoding == Encoding_1_0) + { + // + // Object references are encoded as a negative integer in 1.0. + // + _stream->write(-index); + _usesClasses = true; + } + else if(_sliceType != NoSlice && _encaps->format == SlicedFormat) { // - // Didn't find it, try the marshaled map next. + // An object reference that appears inside a slice of an + // object or exception encoded as a positive non-zero + // index into a per-slice indirection table. + // + // We use _indirectionMap to keep track of the object + // references in the current slice; it maps the object + // reference to the position in the indirection list. Note + // that the position is offset by one (e.g., the first + // position = 1). // - PtrToIndexMap::iterator q = _currentWriteEncaps->marshaledMap->find(v); - if(q == _currentWriteEncaps->marshaledMap->end()) + IndirectionMap::iterator p = _indirectionMap.find(index); + if(p == _indirectionMap.end()) { - // - // We haven't seen this instance previously, create a - // new index, and insert it into the to-be-marshaled - // map. - // - q = _currentWriteEncaps->toBeMarshaledMap->insert( - _currentWriteEncaps->toBeMarshaledMap->end(), - pair<const ObjectPtr, Int>(v, ++_currentWriteEncaps->writeIndex)); + _indirectionTable.push_back(index); + const Int sz = static_cast<Int>(_indirectionTable.size()); // Position + 1 + _indirectionMap.insert(make_pair(index, sz)); + _stream->writeSize(sz); } - p = q; + else + { + _stream->writeSize(p->second); + } + } + else + { + _stream->writeSize(index); } + } + else + { // - // Write the index for the instance. + // Write nil reference. // - write(-(p->second)); + if(_encaps->encoding == Encoding_1_0) + { + _stream->write(0); + _usesClasses = true; + } + else + { + _stream->writeSize(0); + } } - else +} + +void +IceInternal::BasicStream::EncapsEncoder::write(const UserException& v) +{ + v.__write(_stream); + writePendingObjects(); +} + +void +IceInternal::BasicStream::EncapsEncoder::startObject(const SlicedDataPtr& data) +{ + _sliceType = ObjectSlice; + _firstSlice = true; + if(data) { - write(0); // Write null pointer. + writeSlicedData(data); } } void -IceInternal::BasicStream::read(PatchFunc patchFunc, void* patchAddr) +IceInternal::BasicStream::EncapsEncoder::endObject() { - if(!_currentReadEncaps) // Lazy initialization. + if(_encaps->encoding == Encoding_1_0) { - _currentReadEncaps = &_preAllocatedReadEncaps; + // + // Write the Object slice. + // + startSlice(Object::ice_staticId(), true); + _stream->writeSize(0); // For compatibility with the old AFM. + endSlice(); } + _sliceType = NoSlice; +} - if(!_currentReadEncaps->patchMap) // Lazy initialization. +void +IceInternal::BasicStream::EncapsEncoder::startException(const SlicedDataPtr& data) +{ + _sliceType = ExceptionSlice; + _firstSlice = true; + if(_encaps->encoding == Encoding_1_0) + { + _usesClassesPos = _stream->b.size(); + _stream->write(false); // Placeholder for usesClasses boolean + } + if(data) { - _currentReadEncaps->patchMap = new PatchMap; - _currentReadEncaps->unmarshaledMap = new IndexToPtrMap; - _currentReadEncaps->typeIdMap = new TypeIdReadMap; + writeSlicedData(data); } +} - ObjectPtr v; +void +IceInternal::BasicStream::EncapsEncoder::endException() +{ + if(_encaps->encoding == Encoding_1_0) + { + Byte* dest = &(*(_stream->b.begin() + _usesClassesPos)); + *dest = static_cast<Byte>(_usesClasses); + } + _sliceType = NoSlice; +} - Int index; - read(index); +void +IceInternal::BasicStream::EncapsEncoder::startSlice(const string& typeId, bool last) +{ + assert(_indirectionTable.empty() && _indirectionMap.empty()); + _sliceFlags = 0; + _sliceFlagsPos = _stream->b.size(); - if(patchAddr) + // + // Encode the slice size for the old encoding and if using the + // sliced format. + // + if(_encaps->encoding == Encoding_1_0 || _encaps->format == SlicedFormat) { - if(index == 0) - { - // Calling the patch function for null instances is necessary for correct functioning of Ice for - // Python and Ruby. - patchFunc(patchAddr, v); // Null Ptr. - return; - } + _sliceFlags |= FLAG_HAS_SLICE_SIZE; + } - if(index < 0) + // + // This is the last slice. + // + if(last) + { + _sliceFlags |= FLAG_IS_LAST_SLICE; + } + + // + // For object slices, encode the flag and the type ID either as a + // string or index. For exception slices, don't encode slice flags + // for the old encoding and always encode the type ID a string. + // + if(_sliceType == ObjectSlice) + { + _stream->write(Byte(0)); // Placeholder for the slice flags + + // + // Encode the type ID (only in the first slice for the compact + // encoding). + // + if(_encaps->format == SlicedFormat || _encaps->encoding == Encoding_1_0 || _firstSlice) { - PatchMap::iterator p = _currentReadEncaps->patchMap->find(-index); - if(p == _currentReadEncaps->patchMap->end()) - { - // - // We have no outstanding instances to be patched for this - // index, so make a new entry in the patch map. - // - p = _currentReadEncaps->patchMap->insert(make_pair(-index, PatchList())).first; - } // - // Append a patch entry for this instance. + // If the type ID has already been seen, write the index + // of the type ID, otherwise allocate a new type ID and + // write the string. // - PatchEntry e; - e.patchFunc = patchFunc; - e.patchAddr = patchAddr; - p->second.push_back(e); - patchPointers(-index, _currentReadEncaps->unmarshaledMap->end(), p); - return; + TypeIdWriteMap::const_iterator p = _typeIdMap.find(typeId); + if(p != _typeIdMap.end()) + { + _sliceFlags |= FLAG_HAS_TYPE_ID_INDEX; + _stream->writeSize(p->second); + } + else + { + _sliceFlags |= FLAG_HAS_TYPE_ID_STRING; + _typeIdMap.insert(make_pair(typeId, ++_typeIdIndex)); + _stream->write(typeId, false); + } } } - if(index <= 0) + else { - throw MarshalException(__FILE__, __LINE__, "Invalid class instance index"); + if(_encaps->encoding != Encoding_1_0) + { + _stream->write(Byte(0)); // Placeholder for the slice flags + } + _stream->write(typeId, false); } - string mostDerivedId; - readTypeId(mostDerivedId); - string id = mostDerivedId; - while(true) + if(_sliceFlags & FLAG_HAS_SLICE_SIZE) + { + _stream->write(Int(0)); // Placeholder for the slice length. + } + + _writeSlice = _stream->b.size(); + _firstSlice = false; +} + +void +IceInternal::BasicStream::EncapsEncoder::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(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) + { + assert(_encaps->encoding != Encoding_1_0); + _stream->write(static_cast<Byte>(OptionalTypeEndMarker)); + } + + // + // Write the slice length if necessary. + // + if(_sliceFlags & FLAG_HAS_SLICE_SIZE) { + Int sz = static_cast<Int>(_stream->b.size() - _writeSlice + sizeof(Int)); + Byte* dest = &(*(_stream->b.begin() + _writeSlice - sizeof(Int))); + _stream->write(sz, dest); + } + + // + // Only write the indirection table if it contains entries. + // + if(!_indirectionTable.empty()) + { + assert(_encaps->encoding != Encoding_1_0); + assert(_encaps->format == SlicedFormat); + _sliceFlags |= FLAG_HAS_INDIRECTION_TABLE; + // - // If we slice all the way down to Ice::Object, we throw - // because Ice::Object is abstract. + // Write the indirection table as a sequence<size> to conserve space. // - if(id == Ice::Object::ice_staticId()) + _stream->writeSizeSeq(_indirectionTable); + + _indirectionTable.clear(); + _indirectionMap.clear(); + } + + // + // Finally, update the slice flags (or the object slice has index + // type ID boolean for the 1.0 encoding) + // + if(_encaps->encoding == Encoding_1_0) + { + if(_sliceType == ObjectSlice) // No flags for 1.0 exception slices. { - throw NoObjectFactoryException(__FILE__, __LINE__, "", mostDerivedId); + Byte* dest = &(*(_stream->b.begin() + _sliceFlagsPos)); + *dest = static_cast<Byte>(_sliceFlags & FLAG_HAS_TYPE_ID_INDEX ? true : false); } + } + else + { + Byte* dest = &(*(_stream->b.begin() + _sliceFlagsPos)); + *dest = _sliceFlags; + } +} - // - // Try to find a factory registered for the specific type. - // - ObjectFactoryPtr userFactory = _instance->servantFactoryManager()->find(id); - if(userFactory) +void +IceInternal::BasicStream::EncapsEncoder::writePendingObjects() +{ + // + // With the 1.0 encoding, write pending objects if nil or non-nil + // references were written (_usesClasses = true). Otherwise, write + // pending objects only if some non-nil references were written. + // + if(_encaps->encoding == Encoding_1_0) + { + if(!_usesClasses) { - v = userFactory->create(id); + return; } - + _usesClasses = false; + } + else if(_toBeMarshaledMap.empty()) + { + return; + } + else + { // - // If that fails, invoke the default factory if one has been - // registered. + // Write end marker for encapsulation optionals before encoding + // the pending objects. // - if(!v) - { - userFactory = _instance->servantFactoryManager()->find(""); - if(userFactory) - { - v = userFactory->create(id); - } - } + _stream->write(static_cast<Byte>(OptionalTypeEndMarker)); + } + while(!_toBeMarshaledMap.empty()) + { // - // Last chance: check the table of static factories (i.e., - // automatically generated factories for concrete classes). + // 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. // - if(!v) + _marshaledMap.insert(_toBeMarshaledMap.begin(), _toBeMarshaledMap.end()); + + PtrToIndexMap savedMap; + savedMap.swap(_toBeMarshaledMap); + _stream->writeSize(static_cast<Int>(savedMap.size())); + for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p) { - ObjectFactoryPtr of = IceInternal::factoryTable->getObjectFactory(id); - if(of) + // + // Ask the instance to marshal itself. Any new class + // instances that are triggered by the classes marshaled + // are added to toBeMarshaledMap. + // + if(_encaps->encoding == Encoding_1_0) { - v = of->create(id); - assert(v); + _stream->write(p->second); + } + else + { + _stream->writeSize(p->second); } - } - if(!v) - { - if(_sliceObjects) + try { - // - // Performance sensitive, so we use lazy initialization for tracing. - // - if(_traceSlicing == -1) - { - _traceSlicing = _instance->traceLevels()->slicing; - _slicingCat = _instance->traceLevels()->slicingCat; - } - if(_traceSlicing > 0) - { - traceSlicing("class", id, _slicingCat, _instance->initializationData().logger); - } - skipSlice(); // Slice off this derived part -- we don't understand it. - readTypeId(id); // Read next id for next iteration. - continue; + p->first->ice_preMarshal(); } - else + catch(const std::exception& ex) + { + Warning out(_stream->instance()->initializationData().logger); + out << "std::exception raised by ice_preMarshal:\n" << ex; + } + catch(...) { - NoObjectFactoryException ex(__FILE__, __LINE__); - ex.type = id; - throw ex; + Warning out(_stream->instance()->initializationData().logger); + out << "unknown exception raised by ice_preMarshal"; } + + p->first->__write(_stream); } + } + _stream->writeSize(0); // Zero marker indicates end of sequence of sequences of instances. +} + +void +IceInternal::BasicStream::EncapsEncoder::writeSlicedData(const SlicedDataPtr& slicedData) +{ + assert(slicedData); + + // + // We only remarshal preserved slices if the target encoding is > 1.0 and 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(_encaps->encoding == Encoding_1_0 || _encaps->format != SlicedFormat) + { + return; + } - IndexToPtrMap::const_iterator unmarshaledPos = - _currentReadEncaps->unmarshaledMap->insert(make_pair(index, v)).first; + for(SliceInfoSeq::const_iterator p = slicedData->slices.begin(); p != slicedData->slices.end(); ++p) + { + startSlice((*p)->typeId, (*p)->isLastSlice); + + // + // Write the bytes associated with this slice. + // + _stream->writeBlob((*p)->bytes); + + if((*p)->hasOptionalMembers) + { + _sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS; + } // - // Record each object instance so that readPendingObjects can - // invoke ice_postUnmarshal after all objects have been - // unmarshaled. + // Assemble and write the indirection table. The table must have the same order + // as the list of objects. // - if(!_objectList) + for(vector<ObjectPtr>::const_iterator q = (*p)->objects.begin(); q != (*p)->objects.end(); ++q) { - _objectList = new ObjectList; + _indirectionTable.push_back(registerObject(*q)); } - _objectList->push_back(v); - v->__read(this, false); - patchPointers(index, unmarshaledPos, _currentReadEncaps->patchMap->end()); - return; + endSlice(); } +} + +Int +IceInternal::BasicStream::EncapsEncoder::registerObject(const ObjectPtr& v) +{ + assert(v); // - // We can't possibly end up here: at the very least, the type ID - // "::Ice::Object" must be recognized, or client and server were - // compiled with mismatched Slice definitions. + // Look for this instance in the to-be-marshaled map. // - throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + PtrToIndexMap::const_iterator p = _toBeMarshaledMap.find(v); + if(p != _toBeMarshaledMap.end()) + { + return p->second; + } + + // + // Didn't find it, try the marshaled map next. + // + PtrToIndexMap::const_iterator q = _marshaledMap.find(v); + if(q != _marshaledMap.end()) + { + return q->second; + } + + // + // We haven't seen this instance previously, create a new + // index, and insert it into the to-be-marshaled map. + // + _toBeMarshaledMap.insert(make_pair(v, ++_objectIdIndex)); + return _objectIdIndex; } void -IceInternal::BasicStream::write(const UserException& v) +IceInternal::BasicStream::EncapsDecoder::read(PatchFunc patchFunc, void* patchAddr) { - write(v.__usesClasses()); - v.__write(this); - if(v.__usesClasses()) + ObjectPtr v; + + Int index; + if(_encaps->encoding == Encoding_1_0) { - writePendingObjects(); + // + // Object references are encoded as a negative integer in 1.0. + // + _stream->read(index); + _usesClasses = true; + if(index > 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid object id"); + } + index = -index; + } + else + { + // + // Later versions use a size. + // + index = _stream->readSize(); + if(index < 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid object id"); + } + } + + if(index == 0) + { + // + // Calling the patch function for null instances is necessary for correct functioning of Ice for + // Python and Ruby. + // + ObjectPtr nil; + patchFunc(patchAddr, nil); + } + else if(_sliceType != NoSlice && _sliceFlags & FLAG_HAS_INDIRECTION_TABLE) + { + // + // 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. + // + IndirectPatchEntry e; + e.index = index - 1; + e.patchFunc = patchFunc; + e.patchAddr = patchAddr; + _indirectPatchList.push_back(e); + } + else + { + addPatchEntry(index, patchFunc, patchAddr); } } void -IceInternal::BasicStream::throwException() +IceInternal::BasicStream::EncapsDecoder::throwException(const UserExceptionFactoryPtr& factory) { - bool usesClasses; - read(usesClasses); + assert(_sliceType == NoSlice); + + if(_encaps->encoding == Encoding_1_0) + { + // + // 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 the exception was sliced. With encoding > 1.0, we + // don't need this, each slice indirect patch table indicates + // the presence of objects. + // + bool usesClasses; + _stream->read(usesClasses); + _usesClasses |= usesClasses; + } - string id; - read(id, false); - const string origId = id; + _sliceType = ExceptionSlice; + _skipFirstSlice = false; - for(;;) + // + // Read the first slice header. + // + startSlice(); + const string mostDerivedId = _typeId; + UserExceptionFactoryPtr exceptionFactory = factory; + while(true) { // - // Look for a factory for this ID. + // Look for a statically-generated factory for this ID. + // + if(!exceptionFactory) + { + exceptionFactory = factoryTable->getExceptionFactory(_typeId); + } + + // + // We found a factory, we get out of this loop. // - UserExceptionFactoryPtr factory = factoryTable->getExceptionFactory(id); - if(factory) + if(exceptionFactory) { // - // Got factory -- get the factory to instantiate the + // Got factory -- ask the factory to instantiate the // exception, initialize the exception members, and throw // the exception. // try { - factory->createAndThrow(); + assert(exceptionFactory); + exceptionFactory->createAndThrow(_typeId); } catch(UserException& ex) { - ex.__read(this, false); - if(usesClasses) - { - readPendingObjects(); - } - ex.ice_throw(); + ex.__read(_stream); + readPendingObjects(); + throw; + + // Never reached. } } - else + + // + // Performance sensitive, so we use lazy initialization for + // tracing. + // + if(_traceSlicing == -1) { - // - // Performance sensitive, so we use lazy initialization - // for tracing. - // - if(_traceSlicing == -1) + _traceSlicing = _stream->instance()->traceLevels()->slicing; + _slicingCat = _stream->instance()->traceLevels()->slicingCat; + } + if(_traceSlicing > 0) + { + traceSlicing("exception", _typeId, _slicingCat, _stream->instance()->initializationData().logger); + } + + // + // Slice off what we don't understand. + // + skipSlice(); + + // + // If this is the last slice, raise an exception and stop un-marshalling. + // + if(_sliceFlags & FLAG_IS_LAST_SLICE) + { + if(mostDerivedId.length() > 2 && mostDerivedId[0] == ':' && mostDerivedId[1] == ':') { - _traceSlicing = _instance->traceLevels()->slicing; - _slicingCat = _instance->traceLevels()->slicingCat; + throw UnknownUserException(__FILE__, __LINE__, mostDerivedId.substr(2)); } - if(_traceSlicing > 0) + else { - traceSlicing("exception", id, _slicingCat, _instance->initializationData().logger); + throw UnknownUserException(__FILE__, __LINE__, mostDerivedId); } + } - skipSlice(); // Slice off what we don't understand. - - try + try + { + startSlice(); + } + catch(UnmarshalOutOfBoundsException& 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. + // + if(_encaps->encoding == Encoding_1_0) { - read(id, false); // Read type id for next slice. + // Set the reason member to a more helpful message. + ex.reason = "unknown exception type `" + mostDerivedId + "'"; } - catch(UnmarshalOutOfBoundsException& ex) + throw; + } + } +} + +void +IceInternal::BasicStream::EncapsDecoder::startObject() +{ + assert(_sliceType == ObjectSlice); + _skipFirstSlice = true; +} + +SlicedDataPtr +IceInternal::BasicStream::EncapsDecoder::endObject(bool preserve) +{ + if(_encaps->encoding == Encoding_1_0) + { + // + // Read the Ice::Object slice. + // + startSlice(); + + // + // For compatibility with the old AFM. + // + Int sz = _stream->readSize(); + if(sz != 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid Object slice"); + } + + endSlice(); + } + + _sliceType = NoSlice; + SlicedDataPtr slicedData; + if(preserve) + { + slicedData = readSlicedData(); + } + _slices.clear(); + _indirectionTables.clear(); + return slicedData; +} + +void +IceInternal::BasicStream::EncapsDecoder::startException() +{ + assert(_sliceType == ExceptionSlice); + _skipFirstSlice = true; +} + +SlicedDataPtr +IceInternal::BasicStream::EncapsDecoder::endException(bool preserve) +{ + _sliceType = NoSlice; + SlicedDataPtr slicedData; + if(preserve) + { + slicedData = readSlicedData(); + } + _slices.clear(); + _indirectionTables.clear(); + return slicedData; +} + +const string& +IceInternal::BasicStream::EncapsDecoder::startSlice() +{ + // + // If first slice, don't read the header, it was already read in + // readInstance or throwException to find the factory. + // + if(_skipFirstSlice) + { + _skipFirstSlice = false; + return _typeId; + } + + // + // Read the slice flags. For the 1.0 encoding there's no flag but + // just a boolean for object slices. The boolean indicates whether + // or not the type ID is encoded as a string or as an index. + // + if(_encaps->encoding == Encoding_1_0) + { + _sliceFlags = FLAG_HAS_SLICE_SIZE; + if(_sliceType == ObjectSlice) // For exceptions, the type ID is always encoded as a string + { + bool isIndex; + _stream->read(isIndex); + _sliceFlags |= isIndex ? FLAG_HAS_TYPE_ID_INDEX : FLAG_HAS_TYPE_ID_STRING; + } + } + else + { + _stream->read(_sliceFlags); + } + + // + // 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(_sliceType == ObjectSlice) + { + if(_sliceFlags & FLAG_HAS_TYPE_ID_INDEX) + { + Int index = _stream->readSize(); + TypeIdReadMap::const_iterator k = _typeIdMap.find(index); + if(k == _typeIdMap.end()) { - // - // When read() raises this exception it means we've seen the last slice, - // so we set the reason member to a more helpful message. - // - ex.reason = "unknown exception type `" + origId + "'"; - throw; + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); } + _typeId = k->second; + } + else if(_sliceFlags & FLAG_HAS_TYPE_ID_STRING) + { + _stream->read(_typeId, false); + _typeIdMap.insert(make_pair(++_typeIdIndex, _typeId)); + } + else + { + // Only the most derived slice encodes the type ID for the + // compact format. + _typeId.clear(); } + } + else + { + _stream->read(_typeId, false); } // - // The only way out of the loop above is to find an exception for - // which the receiver has a factory. If this does not happen, - // sender and receiver disagree about the Slice definitions they - // use. In that case, the receiver will eventually fail to read - // another type ID and throw a MarshalException. + // Read the slice size if necessary. // + if(_sliceFlags & FLAG_HAS_SLICE_SIZE) + { + _stream->read(_sliceSize); + if(_sliceSize < 4) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + } + else + { + _sliceSize = 0; + } + + // + // Reset the indirect patch list for this new slice. + // + _indirectPatchList.clear(); + return _typeId; } void -IceInternal::BasicStream::writePendingObjects() +IceInternal::BasicStream::EncapsDecoder::endSlice() { - if(_currentWriteEncaps && _currentWriteEncaps->toBeMarshaledMap) + if(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) + { + _stream->skipOpts(); + } + + // + // Read the indirection table if one is present and transform the + // indirect patch list into patch entries with direct references. + // + if(_sliceFlags & FLAG_HAS_INDIRECTION_TABLE) { - while(_currentWriteEncaps->toBeMarshaledMap->size()) + // + // The table is written as a sequence<size> to conserve space. + // + IndexList indirectionTable; + _stream->readSizeSeq(indirectionTable); + + // + // 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.empty() && !_indirectPatchList.empty()) + { + throw MarshalException(__FILE__, __LINE__, "empty indirection table"); + } + else if(!indirectionTable.empty() && _indirectPatchList.empty() && !(_sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)) { - PtrToIndexMap savedMap = *_currentWriteEncaps->toBeMarshaledMap; - writeSize(static_cast<Int>(savedMap.size())); - for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p) + throw MarshalException(__FILE__, __LINE__, "no references to indirection table"); + } + + // + // Convert indirect references into direct references. + // + for(IndirectPatchList::iterator p = _indirectPatchList.begin(); p != _indirectPatchList.end(); ++p) + { + assert(p->index >= 0); + if(p->index >= static_cast<Int>(indirectionTable.size())) + { + throw MarshalException(__FILE__, __LINE__, "indirection out of range"); + } + const Int id = indirectionTable[p->index]; + if(id <= 0) { // - // Add an instance from the old to-be-marshaled map to - // the marshaled map and then ask the instance to - // marshal itself. Any new class instances that are - // triggered by the classes marshaled are added to - // toBeMarshaledMap. + // Entries in the table must be positive, just like a regular object reference. // - _currentWriteEncaps->marshaledMap->insert(*p); - writeInstance(p->first, p->second); + throw MarshalException(__FILE__, __LINE__, "invalid id in object indirection table"); } - - // - // We have marshaled all the instances for this pass, - // substract what we have marshaled from the - // toBeMarshaledMap. - // - PtrToIndexMap newMap; - set_difference(_currentWriteEncaps->toBeMarshaledMap->begin(), - _currentWriteEncaps->toBeMarshaledMap->end(), - savedMap.begin(), savedMap.end(), - insert_iterator<PtrToIndexMap>(newMap, newMap.begin())); - *_currentWriteEncaps->toBeMarshaledMap = newMap; + addPatchEntry(id, p->patchFunc, p->patchAddr); } } - writeSize(0); // Zero marker indicates end of sequence of sequences of instances. -} +} void -IceInternal::BasicStream::readPendingObjects() +IceInternal::BasicStream::EncapsDecoder::readPendingObjects() { + // + // With the 1.0 encoding, read pending objects if nil or non-nil + // references were read (_usesClasses == true). Otherwise, read + // pending objects only if some non-nil references were read. + // + if(_encaps->encoding == Encoding_1_0) + { + if(!_usesClasses) + { + return; + } + _usesClasses = false; + } + else if(_patchMap.empty()) + { + return; + } + else + { + // + // Read unread encapsulation optionals before reading the + // pending objects. + // + _stream->skipOpts(); + } + Int num; + ObjectList objectList; do { - readSize(num); + num = _stream->readSize(); for(Int k = num; k > 0; --k) { - read(0, 0); + objectList.push_back(readInstance()); } } while(num); - if(_currentReadEncaps && _currentReadEncaps->patchMap && _currentReadEncaps->patchMap->size() != 0) + if(!_patchMap.empty()) { // // If any entries remain in the patch map, the sender has sent an index for an object, but failed // to supply the object. // - throw MarshalException(__FILE__, __LINE__, "Index for class received, but no instance"); + throw MarshalException(__FILE__, __LINE__, "index for class received, but no instance"); } // @@ -2060,137 +2625,316 @@ IceInternal::BasicStream::readPendingObjects() // unmarshaled in order to ensure that any object data members // have been properly patched. // - if(_objectList) + for(ObjectList::iterator p = objectList.begin(); p != objectList.end(); ++p) { - for(ObjectList::iterator p = _objectList->begin(); p != _objectList->end(); ++p) + try { - try - { - (*p)->ice_postUnmarshal(); - } - catch(const std::exception& ex) + (*p)->ice_postUnmarshal(); + } + catch(const std::exception& ex) + { + Warning out(_stream->instance()->initializationData().logger); + out << "std::exception raised by ice_postUnmarshal:\n" << ex; + } + catch(...) + { + Warning out(_stream->instance()->initializationData().logger); + out << "unknown exception raised by ice_postUnmarshal"; + } + } +} + +ObjectPtr +IceInternal::BasicStream::EncapsDecoder::readInstance() +{ + Int index; + if(_encaps->encoding == Encoding_1_0) + { + _stream->read(index); + } + else + { + index = _stream->readSize(); + } + + ObjectPtr v; + if(index <= 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid object id"); + } + + _sliceType = ObjectSlice; + _skipFirstSlice = false; + + // + // Read the first slice header. + // + startSlice(); + const string mostDerivedId = _typeId; + ObjectFactoryManagerPtr servantFactoryManager = _stream->instance()->servantFactoryManager(); + while(true) + { + // + // For the 1.0 encoding, the type ID for the base Object class + // marks the last slice. + // + if(_typeId == Object::ice_staticId()) + { + throw NoObjectFactoryException(__FILE__, __LINE__, "", mostDerivedId); + } + + // + // Try to find a factory registered for the specific type. + // + ObjectFactoryPtr userFactory = servantFactoryManager->find(_typeId); + if(userFactory) + { + v = userFactory->create(_typeId); + } + + // + // If that fails, invoke the default factory if one has been + // registered. + // + if(!v) + { + userFactory = servantFactoryManager->find(""); + if(userFactory) { - Ice::Warning out(_instance->initializationData().logger); - out << "std::exception raised by ice_postUnmarshal:\n" << ex; + v = userFactory->create(_typeId); } - catch(...) + } + + // + // Last chance: check the table of static factories (i.e., + // automatically generated factories for concrete classes). + // + if(!v) + { + ObjectFactoryPtr of = IceInternal::factoryTable->getObjectFactory(_typeId); + if(of) { - Ice::Warning out(_instance->initializationData().logger); - out << "unknown exception raised by ice_postUnmarshal"; + v = of->create(_typeId); + assert(v); } } + + // + // We found a factory, we get out of this loop. + // + if(v) + { + break; + } + + // + // Performance sensitive, so we use lazy initialization for tracing. + // + if(_traceSlicing == -1) + { + _traceSlicing = _stream->instance()->traceLevels()->slicing; + _slicingCat = _stream->instance()->traceLevels()->slicingCat; + } + if(_traceSlicing > 0) + { + traceSlicing("class", _typeId, _slicingCat, _stream->instance()->initializationData().logger); + } + + // + // If object slicing is disabled, stop un-marshalling. + // + if(!_sliceObjects) + { + throw NoObjectFactoryException(__FILE__, __LINE__, "object slicing is disabled", _typeId); + } + + // + // Slice off what we don't understand. + // + skipSlice(); + + // + // If this is the last slice, keep the object as an opaque + // UnknownSlicedData object. + // + if(_sliceFlags & FLAG_IS_LAST_SLICE) + { + v = new UnknownSlicedObject(mostDerivedId); + break; + } + + startSlice(); // Read next Slice header for next iteration. } -} + + // + // Add the object to the map of un-marshalled objects, this must + // be done before reading the objects (for circular references). + // + _unmarshaledMap.insert(make_pair(index, v)); -void -IceInternal::BasicStream::sliceObjects(bool doSlice) -{ - _sliceObjects = doSlice; -} + // + // Read the object. + // + v->__read(_stream); -void -IceInternal::BasicStream::throwUnmarshalOutOfBoundsException(const char* file, int line) -{ - throw UnmarshalOutOfBoundsException(file, line); -} + // + // Patch all instances now that the object is un-marshalled. + // + PatchMap::iterator patchPos = _patchMap.find(index); + if(patchPos != _patchMap.end()) + { + assert(patchPos->second.size() > 0); + + // + // Patch all pointers that refer to the instance. + // + for(PatchList::iterator k = patchPos->second.begin(); k != patchPos->second.end(); ++k) + { + (*k->patchFunc)(k->patchAddr, v); + } + + // + // Clear out the patch map for that index -- there is nothing left + // to patch for that index for the time being. + // + _patchMap.erase(patchPos); + } -void -IceInternal::BasicStream::throwUnsupportedEncodingException(const char* file, int line, Byte eMajor, Byte eMinor) -{ - UnsupportedEncodingException ex(file, line); - ex.badMajor = static_cast<unsigned char>(eMajor); - ex.badMinor = static_cast<unsigned char>(eMinor); - ex.major = static_cast<unsigned char>(encodingMajor); - ex.minor = static_cast<unsigned char>(encodingMinor); - throw ex; + return v; } void -IceInternal::BasicStream::throwEncapsulationException(const char* file, int line) +IceInternal::BasicStream::EncapsDecoder::addPatchEntry(Int index, PatchFunc patchFunc, void* patchAddr) { - throw EncapsulationException(file, line); -} + assert(index > 0); -void -IceInternal::BasicStream::writeInstance(const ObjectPtr& v, Int index) -{ - write(index); - try - { - v->ice_preMarshal(); - } - catch(const std::exception& ex) + // + // Check if already un-marshalled the object. If that's the case, + // just patch the object smart pointer and we're done. + // + IndexToPtrMap::iterator p = _unmarshaledMap.find(index); + if(p != _unmarshaledMap.end()) { - Ice::Warning out(_instance->initializationData().logger); - out << "std::exception raised by ice_preMarshal:\n" << ex; + (*patchFunc)(patchAddr, p->second); + return; } - catch(...) + + // + // Add patch entry if the object isn't un-marshalled yet, the + // smart pointer will be patched when the instance is + // un-marshalled. + // + + PatchMap::iterator q = _patchMap.find(index); + if(q == _patchMap.end()) { - Ice::Warning out(_instance->initializationData().logger); - out << "unknown exception raised by ice_preMarshal"; + // + // We have no outstanding instances to be patched for this + // index, so make a new entry in the patch map. + // + q = _patchMap.insert(make_pair(index, PatchList())).first; } - v->__write(this); + + // + // Append a patch entry for this instance. + // + PatchEntry e; + e.patchFunc = patchFunc; + e.patchAddr = patchAddr; + q->second.push_back(e); } void -IceInternal::BasicStream::patchPointers(Int index, IndexToPtrMap::const_iterator unmarshaledPos, - PatchMap::iterator patchPos) +IceInternal::BasicStream::EncapsDecoder::skipSlice() { - // - // Called whenever we have unmarshaled a new instance. The index - // is the index of the instance. UnmarshaledPos denotes the - // instance just unmarshaled and patchPos denotes the patch map - // entry for the index just unmarshaled. (Exactly one of these two - // iterators must be end().) Patch any pointers in the patch map - // with the new address. - // - assert( (unmarshaledPos != _currentReadEncaps->unmarshaledMap->end() - && patchPos == _currentReadEncaps->patchMap->end()) - || (unmarshaledPos == _currentReadEncaps->unmarshaledMap->end() - && patchPos != _currentReadEncaps->patchMap->end()) - ); + Container::iterator start = _stream->i; - if(unmarshaledPos != _currentReadEncaps->unmarshaledMap->end()) + if(_sliceFlags & FLAG_HAS_SLICE_SIZE) { - // - // We have just unmarshaled an instance -- check if something - // needs patching for that instance. - // - patchPos = _currentReadEncaps->patchMap->find(index); - if(patchPos == _currentReadEncaps->patchMap->end()) - { - return; // We don't have anything to patch for the instance just unmarshaled. - } + assert(_sliceSize >= 4); + _stream->skip(_sliceSize - sizeof(Int)); } else { + throw MarshalException(__FILE__, + __LINE__, + "compact format prevents slicing (the sender should use the sliced format instead)"); + } + + if(_encaps->encoding != Encoding_1_0) + { // - // We have just unmarshaled an index -- check if we have - // unmarshaled the instance for that index yet. + // Preserve this slice. // - unmarshaledPos = _currentReadEncaps->unmarshaledMap->find(index); - if(unmarshaledPos == _currentReadEncaps->unmarshaledMap->end()) + SliceInfoPtr info = new SliceInfo; + info->typeId = _typeId; + info->hasOptionalMembers = _sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS; + info->isLastSlice = _sliceFlags & FLAG_IS_LAST_SLICE; + 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. + // + vector<Byte>(start, _stream->i - 1).swap(info->bytes); + } + else { - return; // We haven't unmarshaled the instance yet. + vector<Byte>(start, _stream->i).swap(info->bytes); + } + _slices.push_back(info); + + _indirectionTables.push_back(IndexList()); + + if(_sliceFlags & FLAG_HAS_INDIRECTION_TABLE) + { + // + // Read the indirection table, which is written as a sequence<size> to conserve space. + // + _stream->readSizeSeq(_indirectionTables.back()); } } - assert(patchPos->second.size() > 0); +} - ObjectPtr v = unmarshaledPos->second; - assert(v); +SlicedDataPtr +IceInternal::BasicStream::EncapsDecoder::readSlicedData() +{ + if(_slices.empty()) // No preserved slices. + { + return 0; + } // - // Patch all pointers that refer to the instance. + // The _indirectionTables member holds the indirection table for each slice + // in _slices. // - for(PatchList::iterator k = patchPos->second.begin(); k != patchPos->second.end(); ++k) + assert(_slices.size() == _indirectionTables.size()); + + for(SliceInfoSeq::size_type n = 0; n < _slices.size(); ++n) { - (*k->patchFunc)(k->patchAddr, v); + // + // We use the "objects" list in SliceInfo to hold references to the target + // objects. Note however that we may not have actually read these objects + // yet, so they need to be treated just like we had read the object references + // directly (i.e., we add them to the patch list). + // + // Another important note: the SlicedData object that we return here must + // not be destroyed before readPendingObjects is called, otherwise the + // patch references will refer to invalid addresses. + // + const IndexList& table = _indirectionTables[n]; + _slices[n]->objects.resize(table.size()); + IndexList::size_type j = 0; + for(IndexList::const_iterator p = table.begin(); p != table.end(); ++p) + { + const Int id = *p; + if(id <= 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid id in object indirection table"); + } + addPatchEntry(id, &patchHandle<Object>, &_slices[n]->objects[j++]); + } } - // - // Clear out the patch map for that index -- there is nothing left - // to patch for that index for the time being. - // - _currentReadEncaps->patchMap->erase(patchPos); + return new SlicedData(_slices); } - |