diff options
author | Mark Spruiell <mes@zeroc.com> | 2016-01-19 16:46:11 -0800 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2016-01-19 16:46:11 -0800 |
commit | d5dd7c866e9e1dc59dc7e127eb39f641530bf823 (patch) | |
tree | 61771e4f322a7138b643d5325a6d10acea30fb84 /cpp/src/Ice/InputStream.cpp | |
parent | Deprecate ice_name and add ice_id (diff) | |
download | ice-d5dd7c866e9e1dc59dc7e127eb39f641530bf823.tar.bz2 ice-d5dd7c866e9e1dc59dc7e127eb39f641530bf823.tar.xz ice-d5dd7c866e9e1dc59dc7e127eb39f641530bf823.zip |
ICE-6861 - removing public stream API
Diffstat (limited to 'cpp/src/Ice/InputStream.cpp')
-rw-r--r-- | cpp/src/Ice/InputStream.cpp | 2482 |
1 files changed, 2482 insertions, 0 deletions
diff --git a/cpp/src/Ice/InputStream.cpp b/cpp/src/Ice/InputStream.cpp new file mode 100644 index 00000000000..535d26a5d96 --- /dev/null +++ b/cpp/src/Ice/InputStream.cpp @@ -0,0 +1,2482 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2015 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. +// +// ********************************************************************** + +#include <IceUtil/DisableWarnings.h> +#include <Ice/InputStream.h> +#include <Ice/DefaultsAndOverrides.h> +#include <Ice/Instance.h> +#include <Ice/Object.h> +#include <Ice/Proxy.h> +#include <Ice/ProxyFactory.h> +#include <Ice/ValueFactory.h> +#include <Ice/UserExceptionFactory.h> +#include <Ice/LocalException.h> +#include <Ice/Protocol.h> +#include <Ice/FactoryTableInit.h> +#include <Ice/TraceUtil.h> +#include <Ice/TraceLevels.h> +#include <Ice/LoggerUtil.h> +#include <Ice/SlicedData.h> +#include <IceUtil/StringConverter.h> +#include <iterator> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +Ice::InputStream::InputStream() +{ + initialize(currentEncoding); +} + +Ice::InputStream::InputStream(const vector<Byte>& v) : + Buffer(v) +{ + initialize(currentEncoding); +} + +Ice::InputStream::InputStream(const pair<const Byte*, const Byte*>& p) : + Buffer(p.first, p.second) +{ + initialize(currentEncoding); +} + +Ice::InputStream::InputStream(Buffer& buf, bool adopt) : + Buffer(buf, adopt) +{ + initialize(currentEncoding); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator) +{ + initialize(communicator); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, const vector<Byte>& v) : + Buffer(v) +{ + initialize(communicator); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, const pair<const Byte*, const Byte*>& p) : + Buffer(p.first, p.second) +{ + initialize(communicator); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, Buffer& buf, bool adopt) : + Buffer(buf, adopt) +{ + initialize(communicator); +} + +Ice::InputStream::InputStream(const EncodingVersion& encoding) +{ + initialize(encoding); +} + +Ice::InputStream::InputStream(const EncodingVersion& encoding, const vector<Byte>& v) : + Buffer(v) +{ + initialize(encoding); +} + +Ice::InputStream::InputStream(const EncodingVersion& encoding, const pair<const Byte*, const Byte*>& p) : + Buffer(p.first, p.second) +{ + initialize(encoding); +} + +Ice::InputStream::InputStream(const EncodingVersion& encoding, Buffer& buf, bool adopt) : + Buffer(buf, adopt) +{ + initialize(encoding); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, const EncodingVersion& encoding) +{ + initialize(communicator, encoding); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, const EncodingVersion& encoding, + const vector<Byte>& v) : + Buffer(v) +{ + initialize(communicator, encoding); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, const EncodingVersion& encoding, + const pair<const Byte*, const Byte*>& p) : + Buffer(p.first, p.second) +{ + initialize(communicator, encoding); +} + +Ice::InputStream::InputStream(const CommunicatorPtr& communicator, const EncodingVersion& encoding, + Buffer& buf, bool adopt) : + Buffer(buf, adopt) +{ + initialize(communicator, encoding); +} + +Ice::InputStream::InputStream(Instance* instance, const EncodingVersion& encoding) +{ + initialize(instance, encoding); +} + +Ice::InputStream::InputStream(Instance* instance, const EncodingVersion& encoding, Buffer& buf, bool adopt) : + Buffer(buf, adopt) +{ + initialize(instance, encoding); +} + +void +Ice::InputStream::initialize(const CommunicatorPtr& communicator) +{ + Instance* instance = getInstance(communicator).get(); + initialize(instance, instance->defaultsAndOverrides()->defaultEncoding); +} + +void +Ice::InputStream::initialize(const CommunicatorPtr& communicator, const EncodingVersion& encoding) +{ + initialize(getInstance(communicator).get(), encoding); +} + +void +Ice::InputStream::initialize(Instance* instance, const EncodingVersion& encoding) +{ + initialize(encoding); + + _instance = instance; + + _stringConverter = _instance->getStringConverter(); + _wstringConverter = _instance->getWstringConverter(); + +#ifndef ICE_CPP11_MAPPING + _collectObjects = _instance->collectObjects(); +#endif + _traceSlicing = _instance->traceLevels()->slicing > 0; +} + +void +Ice::InputStream::initialize(const EncodingVersion& encoding) +{ + _instance = 0; + _encoding = encoding; + _currentEncaps = 0; +#ifndef ICE_CPP11_MAPPING + _collectObjects = false; +#endif + _traceSlicing = false; + _closure = 0; + _sliceObjects = true; + _startSeq = -1; + _minSeqSize = 0; + + // + // Initialize the encoding members of our pre-allocated encapsulation, in case + // this stream is used without an explicit encapsulation. + // + _preAllocatedEncaps.encoding = encoding; +} + +void +Ice::InputStream::clear() +{ + while(_currentEncaps && _currentEncaps != &_preAllocatedEncaps) + { + Encaps* oldEncaps = _currentEncaps; + _currentEncaps = _currentEncaps->previous; + delete oldEncaps; + } + + _startSeq = -1; + _sliceObjects = true; +} + +void +Ice::InputStream::setStringConverters(const IceUtil::StringConverterPtr& sc, const IceUtil::WstringConverterPtr& wsc) +{ + _stringConverter = sc; + _wstringConverter = wsc; +} + +void +Ice::InputStream::setValueFactoryManager(const ValueFactoryManagerPtr& vfm) +{ + _valueFactoryManager = vfm; +} + +void +Ice::InputStream::setLogger(const LoggerPtr& logger) +{ + _logger = logger; +} + +void +#ifdef ICE_CPP11_MAPPING +Ice::InputStream::setCompactIdResolver(std::function<std::string (int)> r) +#else +Ice::InputStream::setCompactIdResolver(const CompactIdResolverPtr& r) +#endif +{ + _compactIdResolver = r; +} + +#ifndef ICE_CPP11_MAPPING +void +Ice::InputStream::setCollectObjects(bool b) +{ + _collectObjects = b; +} +#endif + +void +Ice::InputStream::setSliceObjects(bool b) +{ + _sliceObjects = b; +} + +void +Ice::InputStream::setTraceSlicing(bool b) +{ + _traceSlicing = b; +} + +void* +Ice::InputStream::getClosure() const +{ + return _closure; +} + +void* +Ice::InputStream::setClosure(void* p) +{ + void* prev = _closure; + _closure = p; + return prev; +} + +void +Ice::InputStream::swap(InputStream& other) +{ + assert(_instance == other._instance); + + swapBuffer(other); + + std::swap(_encoding, other._encoding); + +#ifndef ICE_CPP11_MAPPING + std::swap(_collectObjects, other._collectObjects); +#endif + + std::swap(_traceSlicing, other._traceSlicing); + + std::swap(_closure, other._closure); + + std::swap(_sliceObjects, other._sliceObjects); + + // + // Swap is never called for streams that have encapsulations being read. However, + // encapsulations might still be set in case unmarshaling failed. We just + // reset the encapsulations if there are still some set. + // + resetEncapsulation(); + other.resetEncapsulation(); + + std::swap(_startSeq, other._startSeq); + std::swap(_minSeqSize, other._minSeqSize); + + std::swap(_stringConverter, other._stringConverter); + std::swap(_wstringConverter, other._wstringConverter); + std::swap(_valueFactoryManager, other._valueFactoryManager); + std::swap(_logger, other._logger); + std::swap(_compactIdResolver, other._compactIdResolver); +} + +void +Ice::InputStream::resetEncapsulation() +{ + while(_currentEncaps && _currentEncaps != &_preAllocatedEncaps) + { + Encaps* oldEncaps = _currentEncaps; + _currentEncaps = _currentEncaps->previous; + delete oldEncaps; + } + + _preAllocatedEncaps.reset(); +} + +Int +Ice::InputStream::getEncapsSize() +{ + assert(_currentEncaps); + return _currentEncaps->sz - static_cast<Int>(sizeof(Int)) - 2; +} + +EncodingVersion +Ice::InputStream::skipEncapsulation() +{ + Int sz; + read(sz); + if(sz < 6) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + if(i - sizeof(Int) + sz > b.end()) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + EncodingVersion encoding; + read(encoding.major); + read(encoding.minor); + i += sz - sizeof(Int) - 2; + return encoding; +} + +void +Ice::InputStream::readPendingObjects() +{ + if(_currentEncaps && _currentEncaps->decoder) + { + _currentEncaps->decoder->readPendingObjects(); + } + else if(getEncoding() == 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. + // + skipSize(); + } +} + +Int +Ice::InputStream::readAndCheckSeqSize(int minSize) +{ + Int sz = 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(_startSeq == -1 || i > (b.begin() + _startSeq + _minSeqSize)) + { + _startSeq = static_cast<int>(i - b.begin()); + _minSeqSize = sz * minSize; + } + else + { + _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(_startSeq + _minSeqSize > static_cast<int>(b.size())) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + + return sz; +} + +void +Ice::InputStream::readBlob(vector<Byte>& v, Int sz) +{ + if(sz > 0) + { + if(b.end() - i < sz) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + vector<Byte>(i, i + sz).swap(v); + i += sz; + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(std::vector<Ice::Byte>& v) +{ + std::pair<const Ice::Byte*, const Ice::Byte*> p; + read(p); + if(p.first != p.second) + { + v.resize(static_cast<Ice::Int>(p.second - p.first)); + copy(p.first, p.second, v.begin()); + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(pair<const Byte*, const Byte*>& v) +{ + Int sz = readAndCheckSeqSize(1); + if(sz > 0) + { + v.first = i; + v.second = i + sz; + i += sz; + } + else + { + v.first = v.second = i; + } +} + +void +Ice::InputStream::read(vector<bool>& v) +{ + Int sz = readAndCheckSeqSize(1); + if(sz > 0) + { + v.resize(sz); + copy(i, i + sz, v.begin()); + i += sz; + } + else + { + v.clear(); + } +} + +namespace +{ + +template<size_t boolSize> +struct ReadBoolHelper +{ + static bool* read(pair<const bool*, const bool*>& v, Int sz, InputStream::Container::iterator& i) + { + bool* array = new bool[sz]; + for(int idx = 0; idx < sz; ++idx) + { + array[idx] = static_cast<bool>(*(i + idx)); + } + v.first = array; + v.second = array + sz; + return array; + } +}; + +template<> +struct ReadBoolHelper<1> +{ + static bool* read(pair<const bool*, const bool*>& v, Int sz, InputStream::Container::iterator& i) + { + v.first = reinterpret_cast<bool*>(i); + v.second = reinterpret_cast<bool*>(i) + sz; + return 0; + } +}; + +} + +void +Ice::InputStream::read(pair<const bool*, const bool*>& v, IceUtil::ScopedArray<bool>& result) +{ + Int sz = readAndCheckSeqSize(1); + if(sz > 0) + { + result.reset(ReadBoolHelper<sizeof(bool)>::read(v, sz, i)); + i += sz; + } + else + { + result.reset(); + v.first = v.second = reinterpret_cast<bool*>(i); + } +} + +void +Ice::InputStream::read(Short& v) +{ + if(b.end() - i < static_cast<int>(sizeof(Short))) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + const Byte* src = &(*i); + i += sizeof(Short); +#ifdef ICE_BIG_ENDIAN + Byte* dest = reinterpret_cast<Byte*>(&v) + sizeof(Short) - 1; + *dest-- = *src++; + *dest = *src; +#else + Byte* dest = reinterpret_cast<Byte*>(&v); + *dest++ = *src++; + *dest = *src; +#endif +} + +void +Ice::InputStream::read(vector<Short>& v) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Short))); + if(sz > 0) + { + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Short)); + v.resize(sz); +#ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&v[0]) + sizeof(Short) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Short); + } +#else + copy(begin, i, reinterpret_cast<Byte*>(&v[0])); +#endif + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(pair<const Short*, const Short*>& v, IceUtil::ScopedArray<Short>& result) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Short))); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64) || defined(_M_X64) + v.first = reinterpret_cast<Short*>(i); + i += sz * static_cast<int>(sizeof(Short)); + v.second = reinterpret_cast<Short*>(i); +#else + result.reset(new Short[sz]); + v.first = result.get(); + v.second = result.get() + sz; + + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Short)); +# ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&result[0]) + sizeof(Short) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Short); + } +# else + copy(begin, i, reinterpret_cast<Byte*>(&result[0])); +# endif +#endif + } + else + { + result.reset(); + v.first = v.second = 0; + } +} + +void +Ice::InputStream::read(vector<Int>& v) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Int))); + if(sz > 0) + { + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Int)); + v.resize(sz); +#ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&v[0]) + sizeof(Int) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Int); + } +#else + copy(begin, i, reinterpret_cast<Byte*>(&v[0])); +#endif + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(pair<const Int*, const Int*>& v, ::IceUtil::ScopedArray<Int>& result) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Int))); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64) || defined(_M_X64) + v.first = reinterpret_cast<Int*>(i); + i += sz * static_cast<int>(sizeof(Int)); + v.second = reinterpret_cast<Int*>(i); +#else + result.reset(new Int[sz]); + v.first = result.get(); + v.second = result.get() + sz; + + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Int)); +# ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&result[0]) + sizeof(Int) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Int); + } +# else + copy(begin, i, reinterpret_cast<Byte*>(&result[0])); +# endif +#endif + } + else + { + result.reset(); + v.first = v.second = 0; + } +} + +void +Ice::InputStream::read(Long& v) +{ + if(b.end() - i < static_cast<int>(sizeof(Long))) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + const Byte* src = &(*i); + i += sizeof(Long); +#ifdef ICE_BIG_ENDIAN + Byte* dest = reinterpret_cast<Byte*>(&v) + sizeof(Long) - 1; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest = *src; +#else + Byte* dest = reinterpret_cast<Byte*>(&v); + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest = *src; +#endif +} + +void +Ice::InputStream::read(vector<Long>& v) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Long))); + if(sz > 0) + { + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Long)); + v.resize(sz); +#ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&v[0]) + sizeof(Long) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Long); + } +#else + copy(begin, i, reinterpret_cast<Byte*>(&v[0])); +#endif + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(pair<const Long*, const Long*>& v, IceUtil::ScopedArray<Long>& result) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Long))); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64) || defined(_M_X64) + v.first = reinterpret_cast<Long*>(i); + i += sz * static_cast<int>(sizeof(Long)); + v.second = reinterpret_cast<Long*>(i); +#else + result.reset(new Long[sz]); + v.first = result.get(); + v.second = result.get() + sz; + + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Long)); +# ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&result[0]) + sizeof(Long) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Long); + } +# else + copy(begin, i, reinterpret_cast<Byte*>(&result[0])); +# endif +#endif + } + else + { + result.reset(); + v.first = v.second = 0; + } +} + +void +Ice::InputStream::read(Float& v) +{ + if(b.end() - i < static_cast<int>(sizeof(Float))) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + const Byte* src = &(*i); + i += sizeof(Float); +#ifdef ICE_BIG_ENDIAN + Byte* dest = reinterpret_cast<Byte*>(&v) + sizeof(Float) - 1; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest = *src; +#else + Byte* dest = reinterpret_cast<Byte*>(&v); + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest = *src; +#endif +} + +void +Ice::InputStream::read(vector<Float>& v) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Float))); + if(sz > 0) + { + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Float)); + v.resize(sz); +#ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&v[0]) + sizeof(Float) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Float); + } +#else + copy(begin, i, reinterpret_cast<Byte*>(&v[0])); +#endif + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(pair<const Float*, const Float*>& v, IceUtil::ScopedArray<Float>& result) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Float))); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64) || defined(_M_X64) + v.first = reinterpret_cast<Float*>(i); + i += sz * static_cast<int>(sizeof(Float)); + v.second = reinterpret_cast<Float*>(i); +#else + result.reset(new Float[sz]); + v.first = result.get(); + v.second = result.get() + sz; + + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Float)); +# ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&result[0]) + sizeof(Float) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Float); + } +# else + copy(begin, i, reinterpret_cast<Byte*>(&result[0])); +# endif +#endif + } + else + { + result.reset(); + v.first = v.second = 0; + } +} + +void +Ice::InputStream::read(Double& v) +{ + if(b.end() - i < static_cast<int>(sizeof(Double))) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + const Byte* src = &(*i); + i += sizeof(Double); +#ifdef ICE_BIG_ENDIAN + Byte* dest = reinterpret_cast<Byte*>(&v) + sizeof(Double) - 1; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest = *src; +#else + Byte* dest = reinterpret_cast<Byte*>(&v); +# if defined(ICE_LITTLEBYTE_BIGWORD) + dest[4] = *src++; + dest[5] = *src++; + dest[6] = *src++; + dest[7] = *src++; + dest[0] = *src++; + dest[1] = *src++; + dest[2] = *src++; + dest[3] = *src; +# else + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest = *src; +# endif +#endif +} + +void +Ice::InputStream::read(vector<Double>& v) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Double))); + if(sz > 0) + { + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Double)); + v.resize(sz); +#ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&v[0]) + sizeof(Double) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Double); + } +#elif defined(ICE_LITTLEBYTE_BIGWORD) + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&v[0]); + for(int j = 0 ; j < sz ; ++j) + { + dest[4] = *src++; + dest[5] = *src++; + dest[6] = *src++; + dest[7] = *src++; + dest[0] = *src++; + dest[1] = *src++; + dest[2] = *src++; + dest[3] = *src++; + dest += sizeof(Double); + } +#else + copy(begin, i, reinterpret_cast<Byte*>(&v[0])); +#endif + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(pair<const Double*, const Double*>& v, IceUtil::ScopedArray<Double>& result) +{ + Int sz = readAndCheckSeqSize(static_cast<int>(sizeof(Double))); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64) || defined(_M_X64) + v.first = reinterpret_cast<Double*>(i); + i += sz * static_cast<int>(sizeof(Double)); + v.second = reinterpret_cast<Double*>(i); +#else + result.reset(new Double[sz]); + v.first = result.get(); + v.second = result.get() + sz; + + Container::iterator begin = i; + i += sz * static_cast<int>(sizeof(Double)); +# ifdef ICE_BIG_ENDIAN + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&result[0]) + sizeof(Double) - 1; + for(int j = 0 ; j < sz ; ++j) + { + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + *dest-- = *src++; + dest += 2 * sizeof(Double); + } +# elif defined(ICE_LITTLEBYTE_BIGWORD) + const Byte* src = &(*begin); + Byte* dest = reinterpret_cast<Byte*>(&result[0]); + for(int j = 0 ; j < sz ; ++j) + { + dest[4] = *src++; + dest[5] = *src++; + dest[6] = *src++; + dest[7] = *src++; + dest[0] = *src++; + dest[1] = *src++; + dest[2] = *src++; + dest[3] = *src++; + dest += sizeof(Double); + } + +# else + copy(begin, i, reinterpret_cast<Byte*>(&result[0])); +# endif +#endif + } + else + { + result.reset(); + v.first = v.second = 0; + } +} + +void +Ice::InputStream::readConverted(string& v, int sz) +{ + if(!_stringConverter) + { + throw MarshalException(__FILE__, __LINE__, "no string converter provided"); + } + + try + { + _stringConverter->fromUTF8(i, i + sz, v); + } + catch(const IceUtil::IllegalConversionException& ex) + { + throw StringConversionException(__FILE__, __LINE__, ex.reason()); + } +} + +void +Ice::InputStream::read(vector<string>& v, bool convert) +{ + Int sz = readAndCheckSeqSize(1); + if(sz > 0) + { + v.resize(sz); + for(int j = 0; j < sz; ++j) + { + read(v[j], convert); + } + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(wstring& v) +{ + if(!_wstringConverter) + { + throw MarshalException(__FILE__, __LINE__, "no wstring converter provided"); + } + + Int sz = readSize(); + if(sz > 0) + { + if(b.end() - i < sz) + { + throwUnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + + try + { + _wstringConverter->fromUTF8(i, i + sz, v); + i += sz; + } + catch(const IceUtil::IllegalConversionException& ex) + { + throw StringConversionException(__FILE__, __LINE__, ex.reason()); + } + } + else + { + v.clear(); + } +} + +void +Ice::InputStream::read(vector<wstring>& v) +{ + Int sz = readAndCheckSeqSize(1); + if(sz > 0) + { + v.resize(sz); + for(int j = 0; j < sz; ++j) + { + read(v[j]); + } + } + else + { + v.clear(); + } +} + +#ifdef ICE_CPP11_MAPPING +shared_ptr<ObjectPrx> +Ice::InputStream::readProxy() +{ + if(!_instance) + { + throw MarshalException(__FILE__, __LINE__, "cannot unmarshal a proxy without a communicator"); + } + + return _instance->proxyFactory()->streamToProxy(this); +} +#else +void +Ice::InputStream::read(ObjectPrx& v) +{ + if(!_instance) + { + throw MarshalException(__FILE__, __LINE__, "cannot unmarshal a proxy without a communicator"); + } + + v = _instance->proxyFactory()->streamToProxy(this); +} +#endif + +Int +Ice::InputStream::readEnum(Int maxValue) +{ + if(getEncoding() == Encoding_1_0) + { + if(maxValue < 127) + { + Byte value; + read(value); + return value; + } + else if(maxValue < 32767) + { + Short value; + read(value); + return value; + } + else + { + Int value; + read(value); + return value; + } + } + else + { + return readSize(); + } +} + +void +Ice::InputStream::throwException(const UserExceptionFactoryPtr& factory) +{ + initEncaps(); + _currentEncaps->decoder->throwException(factory); +} + +bool +Ice::InputStream::readOptImpl(Int readTag, OptionalFormat expectedFormat) +{ + if(getEncoding() == Encoding_1_0) + { + return false; // Optional members aren't supported with the 1.0 encoding. + } + + while(true) + { + if(i >= b.begin() + _currentEncaps->start + _currentEncaps->sz) + { + return false; // End of encapsulation also indicates end of optionals. + } + + Byte v; + read(v); + if(v == OPTIONAL_END_MARKER) + { + --i; // Rewind + return false; + } + + OptionalFormat format = static_cast<OptionalFormat>(v & 0x07); // First 3 bits. + Int tag = static_cast<Int>(v >> 3); + if(tag == 30) + { + tag = readSize(); + } + + if(tag > readTag) + { + i -= tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind + return false; // No optional data members with the requested tag. + } + else if(tag < readTag) + { + skipOpt(format); // Skip optional data members + } + else + { + if(format != expectedFormat) + { + ostringstream os; + os << "invalid optional data member `" << tag << "': unexpected format"; + throw MarshalException(__FILE__, __LINE__, os.str()); + } + return true; + } + } + return true; // Keep the compiler happy. +} + +void +Ice::InputStream::skipOpt(OptionalFormat type) +{ + switch(type) + { + case Ice::OptionalFormatF1: + { + skip(1); + break; + } + case Ice::OptionalFormatF2: + { + skip(2); + break; + } + case Ice::OptionalFormatF4: + { + skip(4); + break; + } + case Ice::OptionalFormatF8: + { + skip(8); + break; + } + case Ice::OptionalFormatSize: + { + skipSize(); + break; + } + case Ice::OptionalFormatVSize: + { + skip(readSize()); + break; + } + case Ice::OptionalFormatFSize: + { + Int sz; + read(sz); + skip(sz); + break; + } + case Ice::OptionalFormatClass: + { + read(0, 0); + break; + } + } +} + +void +Ice::InputStream::skipOpts() +{ + // + // Skip remaining un-read optional members. + // + while(true) + { + if(i >= b.begin() + _currentEncaps->start + _currentEncaps->sz) + { + return; // End of encapsulation also indicates end of optionals. + } + + Byte v; + read(v); + if(v == OPTIONAL_END_MARKER) + { + return; + } + + OptionalFormat format = static_cast<OptionalFormat>(v & 0x07); // Read first 3 bits. + if(static_cast<Int>(v >> 3) == 30) + { + skipSize(); + } + skipOpt(format); + } +} + +void +Ice::InputStream::throwUnmarshalOutOfBoundsException(const char* file, int line) +{ + throw UnmarshalOutOfBoundsException(file, line); +} + +void +Ice::InputStream::throwEncapsulationException(const char* file, int line) +{ + throw EncapsulationException(file, line); +} + +string +Ice::InputStream::resolveCompactId(int id) const +{ + string type; + +#ifdef ICE_CPP11_MAPPING + function<string (int)> resolver = compactIdResolver(); +#else + CompactIdResolverPtr resolver = compactIdResolver(); +#endif + + if(resolver) + { + try + { +#ifdef ICE_CPP11_MAPPING + type = resolver(id); +#else + type = resolver->resolve(id); +#endif + } + catch(const LocalException&) + { + throw; + } + catch(const std::exception& ex) + { + ostringstream ostr; + ostr << "exception in CompactIdResolver for ID " << id; + string msg = ostr.str(); + string what = ex.what(); + if(!what.empty()) + { + msg += ":\n" + what; + } + throw MarshalException(__FILE__, __LINE__, msg); + } + catch(...) + { + ostringstream ostr; + ostr << "unknown exception in CompactIdResolver for ID " << id; + throw MarshalException(__FILE__, __LINE__, ostr.str()); + } + } + + return type; +} + +void +Ice::InputStream::postUnmarshal(const ValuePtr& v) const +{ + try + { +#ifndef ICE_CPP11_MAPPING + if(_collectObjects) + { + v->ice_collectable(true); + } +#endif + v->ice_postUnmarshal(); + } + catch(const std::exception& ex) + { + if(logger()) + { + Warning out(logger()); + out << "std::exception raised by ice_postUnmarshal:\n" << ex; + } + } + catch(...) + { + if(logger()) + { + Warning out(logger()); + out << "unknown exception raised by ice_postUnmarshal"; + } + } +} + +void +Ice::InputStream::traceSkipSlice(const string& typeId, SliceType sliceType) const +{ + if(_traceSlicing && logger()) + { + traceSlicing(sliceType == ExceptionSlice ? "exception" : "object", typeId, "Slicing", logger()); + } +} + +ValueFactoryManagerPtr +Ice::InputStream::valueFactoryManager() const +{ + if(_valueFactoryManager) + { + return _valueFactoryManager; + } + else if(_instance) + { + return _instance->initializationData().valueFactoryManager; + } + + return 0; +} + +LoggerPtr +Ice::InputStream::logger() const +{ + if(_logger) + { + return _logger; + } + else if(_instance) + { + return _instance->initializationData().logger; + } + + return 0; +} + +#ifdef ICE_CPP11_MAPPING +function<string (int)> +Ice::InputStream::compactIdResolver() const +{ + if(_compactIdResolver) + { + return _compactIdResolver; + } + else if(_instance) + { + return _instance->initializationData().compactIdResolver; + } + + return nullptr; +} +#else +CompactIdResolverPtr +Ice::InputStream::compactIdResolver() const +{ + if(_compactIdResolver) + { + return _compactIdResolver; + } + else if(_instance) + { + return _instance->initializationData().compactIdResolver; + } + + return 0; +} +#endif + +void +Ice::InputStream::initEncaps() +{ + if(!_currentEncaps) // Lazy initialization. + { + _currentEncaps = &_preAllocatedEncaps; + _currentEncaps->sz = static_cast<Ice::Int>(b.size()); + } + + if(!_currentEncaps->decoder) // Lazy initialization. + { + ValueFactoryManagerPtr vfm = valueFactoryManager(); + if(_currentEncaps->encoding == Encoding_1_0) + { + _currentEncaps->decoder = new EncapsDecoder10(this, _currentEncaps, _sliceObjects, vfm); + } + else + { + _currentEncaps->decoder = new EncapsDecoder11(this, _currentEncaps, _sliceObjects, vfm); + } + } +} + +string +Ice::InputStream::EncapsDecoder::readTypeId(bool isIndex) +{ + if(isIndex) + { + Int index = _stream->readSize(); + TypeIdMap::const_iterator k = _typeIdMap.find(index); + if(k == _typeIdMap.end()) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + return k->second; + } + else + { + string typeId; + _stream->read(typeId, false); + _typeIdMap.insert(make_pair(++_typeIdIndex, typeId)); + return typeId; + } +} + +Ice::ValuePtr +Ice::InputStream::EncapsDecoder::newInstance(const string& typeId) +{ + Ice::ValuePtr v; + + // + // Try to find a factory registered for the specific type. + // +#ifdef ICE_CPP11_MAPPING + function<ValuePtr (const string&)> userFactory; + if(_valueFactoryManager) + { + userFactory = _valueFactoryManager->find(typeId); + if(userFactory) + { + v = userFactory(typeId); + } + } +#else + ValueFactoryPtr userFactory; + if(_valueFactoryManager) + { + userFactory = _valueFactoryManager->find(typeId); + if(userFactory) + { + v = userFactory->create(typeId); + } + } +#endif + // + // If that fails, invoke the default factory if one has been registered. + // + if(!v && _valueFactoryManager) + { + userFactory = _valueFactoryManager->find(""); + if(userFactory) + { +#ifdef ICE_CPP11_MAPPING + v = userFactory(typeId); +#else + v = userFactory->create(typeId); +#endif + } + } + + // + // Last chance: check the table of static factories (i.e., + // automatically generated factories for concrete classes). + // + if(!v) + { +#ifdef ICE_CPP11_MAPPING + function<ValuePtr (const string&)> of = IceInternal::factoryTable->getValueFactory(typeId); + if(of) + { + v = of(typeId); + assert(v); + } +#else + ValueFactoryPtr of = IceInternal::factoryTable->getValueFactory(typeId); + if(of) + { + v = of->create(typeId); + assert(v); + } +#endif + } + return v; +} + +void +Ice::InputStream::EncapsDecoder::addPatchEntry(Int index, PatchFunc patchFunc, void* patchAddr) +{ + 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. + // + IndexToPtrMap::iterator p = _unmarshaledMap.find(index); + if(p != _unmarshaledMap.end()) + { + (*patchFunc)(patchAddr, p->second); + return; + } + + // + // 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()) + { + // + // 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; + } + + // + // Append a patch entry for this instance. + // + PatchEntry e; + e.patchFunc = patchFunc; + e.patchAddr = patchAddr; + q->second.push_back(e); +} + +void +Ice::InputStream::EncapsDecoder::unmarshal(Int index, const Ice::ValuePtr& v) +{ + // + // 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)); + + // + // Read the object. + // + v->__read(_stream); + + // + // 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); + } + + if(_objectList.empty() && _patchMap.empty()) + { + _stream->postUnmarshal(v); + } + else + { + _objectList.push_back(v); + + if(_patchMap.empty()) + { + // + // 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(ObjectList::iterator p = _objectList.begin(); p != _objectList.end(); ++p) + { + _stream->postUnmarshal(*p); + } + _objectList.clear(); + } + } +} + +void +Ice::InputStream::EncapsDecoder10::read(PatchFunc patchFunc, void* patchAddr) +{ + assert(patchFunc && patchAddr); + + // + // Object references are encoded as a negative integer in 1.0. + // + Int index; + _stream->read(index); + if(index > 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid object id"); + } + index = -index; + + if(index == 0) + { + // + // Calling the patch function for null instances is necessary for correct functioning of Ice for + // Python and Ruby. + // + ValuePtr nil; + patchFunc(patchAddr, nil); + } + else + { + addPatchEntry(index, patchFunc, patchAddr); + } +} + +void +Ice::InputStream::EncapsDecoder10::throwException(const UserExceptionFactoryPtr& factory) +{ + assert(_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. + // + bool usesClasses; + _stream->read(usesClasses); + + _sliceType = ExceptionSlice; + _skipFirstSlice = false; + + // + // Read the first slice header. + // + startSlice(); + const string mostDerivedId = _typeId; + UserExceptionFactoryPtr exceptionFactory = factory; + while(true) + { + // + // 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. + // + if(exceptionFactory) + { + // + // Got factory -- ask the factory to instantiate the + // exception, initialize the exception members, and throw + // the exception. + // + try + { + exceptionFactory->createAndThrow(_typeId); + } + catch(UserException& ex) + { + ex.__read(_stream); + if(usesClasses) + { + readPendingObjects(); + } + throw; + + // Never reached. + } + } + + // + // Slice off what we don't understand. + // + skipSlice(); + 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. + // + // Set the reason member to a more helpful message. + // + ex.reason = "unknown exception type `" + mostDerivedId + "'"; + throw; + } + } +} + +void +#ifndef NDEBUG +Ice::InputStream::EncapsDecoder10::startInstance(SliceType sliceType) +#else +Ice::InputStream::EncapsDecoder10::startInstance(SliceType) +#endif +{ + assert(_sliceType == sliceType); + _skipFirstSlice = true; +} + +SlicedDataPtr +Ice::InputStream::EncapsDecoder10::endInstance(bool) +{ + // + // Read the Ice::Object slice. + // + if(_sliceType == ObjectSlice) + { + startSlice(); + Int sz = _stream->readSize(); // For compatibility with the old AFM. + if(sz != 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid Object slice"); + } + endSlice(); + } + _sliceType = NoSlice; + return 0; +} + +const std::string& +Ice::InputStream::EncapsDecoder10::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; + } + + // + // 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(_sliceType == ObjectSlice) + { + bool isIndex; + _stream->read(isIndex); + _typeId = readTypeId(isIndex); + } + else + { + _stream->read(_typeId, false); + } + + _stream->read(_sliceSize); + if(_sliceSize < 4) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + return _typeId; +} + +void +Ice::InputStream::EncapsDecoder10::endSlice() +{ +} + +void +Ice::InputStream::EncapsDecoder10::skipSlice() +{ + _stream->traceSkipSlice(_typeId, _sliceType); + assert(_sliceSize >= 4); + _stream->skip(_sliceSize - sizeof(Int)); +} + +void +Ice::InputStream::EncapsDecoder10::readPendingObjects() +{ + Int num; + do + { + num = _stream->readSize(); + for(Int k = num; k > 0; --k) + { + readInstance(); + } + } + while(num); + + 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"); + } +} + +void +Ice::InputStream::EncapsDecoder10::readInstance() +{ + Int index; + _stream->read(index); + + if(index <= 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid object id"); + } + + _sliceType = ObjectSlice; + _skipFirstSlice = false; + + // + // Read the first slice header. + // + startSlice(); + const string mostDerivedId = _typeId; + ValuePtr v; + 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 NoValueFactoryException(__FILE__, __LINE__, "", mostDerivedId); + } + + v = newInstance(_typeId); + + // + // We found a factory, we get out of this loop. + // + if(v) + { + break; + } + + // + // If object slicing is disabled, stop un-marshalling. + // + if(!_sliceObjects) + { + throw NoValueFactoryException(__FILE__, __LINE__, "no value factory found and object slicing is disabled", + _typeId); + } + + // + // Slice off what we don't understand. + // + skipSlice(); + startSlice(); // Read next Slice header for next iteration. + } + + // + // Un-marshal the object and add-it to the map of un-marshaled objects. + // + unmarshal(index, v); +} + +void +Ice::InputStream::EncapsDecoder11::read(PatchFunc patchFunc, void* patchAddr) +{ + Int index = _stream->readSize(); + if(index < 0) + { + throw MarshalException(__FILE__, __LINE__, "invalid object id"); + } + else if(index == 0) + { + // + // Calling the patch function for null instances is necessary for correct functioning of Ice for + // Python and Ruby. + // + if(patchFunc) + { + ValuePtr nil; + patchFunc(patchAddr, nil); + } + } + else if(_current && _current->sliceFlags & FLAG_HAS_INDIRECTION_TABLE) + { + // + // 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(patchFunc) + { + IndirectPatchEntry e; + e.index = index - 1; + e.patchFunc = patchFunc; + e.patchAddr = patchAddr; + _current->indirectPatchList.push_back(e); + } + } + else + { + readInstance(index, patchFunc, patchAddr); + } +} + +void +Ice::InputStream::EncapsDecoder11::throwException(const UserExceptionFactoryPtr& factory) +{ + assert(!_current); + + push(ExceptionSlice); + + // + // Read the first slice header. + // + startSlice(); + const string mostDerivedId = _current->typeId; + UserExceptionFactoryPtr exceptionFactory = factory; + while(true) + { + // + // Look for a statically-generated factory for this ID. + // + if(!exceptionFactory) + { + exceptionFactory = factoryTable->getExceptionFactory(_current->typeId); + } + + // + // We found a factory, we get out of this loop. + // + if(exceptionFactory) + { + // + // Got factory -- ask the factory to instantiate the + // exception, initialize the exception members, and throw + // the exception. + // + try + { + exceptionFactory->createAndThrow(_current->typeId); + } + catch(UserException& ex) + { + ex.__read(_stream); + throw; + + // Never reached. + } + } + + // + // Slice off what we don't understand. + // + skipSlice(); + + // + // If this is the last slice, raise an exception and stop un-marshalling. + // + if(_current->sliceFlags & FLAG_IS_LAST_SLICE) + { + if(mostDerivedId.length() > 2 && mostDerivedId[0] == ':' && mostDerivedId[1] == ':') + { + throw UnknownUserException(__FILE__, __LINE__, mostDerivedId.substr(2)); + } + else + { + throw UnknownUserException(__FILE__, __LINE__, mostDerivedId); + } + } + + startSlice(); + } +} + +void +#ifndef NDEBUG +Ice::InputStream::EncapsDecoder11::startInstance(SliceType sliceType) +#else +Ice::InputStream::EncapsDecoder11::startInstance(SliceType) +#endif +{ + assert(_current->sliceType == sliceType); + _current->skipFirstSlice = true; +} + +SlicedDataPtr +Ice::InputStream::EncapsDecoder11::endInstance(bool preserve) +{ + SlicedDataPtr slicedData; + if(preserve) + { + slicedData = readSlicedData(); + } + _current->slices.clear(); + _current->indirectionTables.clear(); + _current = _current->previous; + return slicedData; +} + +const std::string& +Ice::InputStream::EncapsDecoder11::startSlice() +{ + // + // If first slice, don't read the header, it was already read in + // readInstance or throwException to find the factory. + // + if(_current->skipFirstSlice) + { + _current->skipFirstSlice = false; + return _current->typeId; + } + + _stream->read(_current->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(_current->sliceType == ObjectSlice) + { + if((_current->sliceFlags & FLAG_HAS_TYPE_ID_COMPACT) == FLAG_HAS_TYPE_ID_COMPACT) // Must be checked first! + { + _current->typeId.clear(); + _current->compactId = _stream->readSize(); + } + else if(_current->sliceFlags & (FLAG_HAS_TYPE_ID_STRING | FLAG_HAS_TYPE_ID_INDEX)) + { + _current->typeId = readTypeId(_current->sliceFlags & FLAG_HAS_TYPE_ID_INDEX); + _current->compactId = -1; + } + else + { + // Only the most derived slice encodes the type ID for the compact format. + _current->typeId.clear(); + _current->compactId = -1; + } + } + else + { + _stream->read(_current->typeId, false); + } + + // + // Read the slice size if necessary. + // + if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE) + { + _stream->read(_current->sliceSize); + if(_current->sliceSize < 4) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + } + else + { + _current->sliceSize = 0; + } + + return _current->typeId; +} + +void +Ice::InputStream::EncapsDecoder11::endSlice() +{ + if(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) + { + _stream->skipOpts(); + } + + // + // Read the indirect object table if one is present. + // + if(_current->sliceFlags & FLAG_HAS_INDIRECTION_TABLE) + { + IndexList indirectionTable(_stream->readAndCheckSeqSize(1)); + for(IndexList::iterator p = indirectionTable.begin(); p != indirectionTable.end(); ++p) + { + *p = readInstance(_stream->readSize(), 0, 0); + } + + // + // 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()) + { + throw MarshalException(__FILE__, __LINE__, "empty indirection table"); + } + if(_current->indirectPatchList.empty() && !(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)) + { + throw MarshalException(__FILE__, __LINE__, "no references to indirection table"); + } + + // + // Convert indirect references into direct references. + // + IndirectPatchList::iterator p; + for(p = _current->indirectPatchList.begin(); p != _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); + } + _current->indirectPatchList.clear(); + } +} + +void +Ice::InputStream::EncapsDecoder11::skipSlice() +{ + _stream->traceSkipSlice(_current->typeId, _current->sliceType); + + Container::iterator start = _stream->i; + + if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE) + { + assert(_current->sliceSize >= 4); + _stream->skip(_current->sliceSize - sizeof(Int)); + } + else + { + if(_current->sliceType == ObjectSlice) + { + throw NoValueFactoryException(__FILE__, __LINE__, + "no value factory found and compact format prevents " + "slicing (the sender should use the sliced format instead)", + _current->typeId); + } + else + { + if(_current->typeId.length() > 2 && _current->typeId[0] == ':' && _current->typeId[1] == ':') + { + throw UnknownUserException(__FILE__, __LINE__, _current->typeId.substr(2)); + } + else + { + throw UnknownUserException(__FILE__, __LINE__, _current->typeId); + } + } + } + + // + // Preserve this slice. + // + SliceInfoPtr info = ICE_MAKE_SHARED(SliceInfo); + info->typeId = _current->typeId; + info->compactId = _current->compactId; + info->hasOptionalMembers = _current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS; + info->isLastSlice = _current->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 + { + vector<Byte>(start, _stream->i).swap(info->bytes); + } + + _current->indirectionTables.push_back(IndexList()); + + // + // 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(_current->sliceFlags & FLAG_HAS_INDIRECTION_TABLE) + { + IndexList& table = _current->indirectionTables.back(); + table.resize(_stream->readAndCheckSeqSize(1)); + for(IndexList::iterator p = table.begin(); p != table.end(); ++p) + { + *p = readInstance(_stream->readSize(), 0, 0); + } + } + + _current->slices.push_back(info); +} + +bool +Ice::InputStream::EncapsDecoder11::readOpt(Ice::Int readTag, Ice::OptionalFormat expectedFormat) +{ + if(!_current) + { + return _stream->readOptImpl(readTag, expectedFormat); + } + else if(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS) + { + return _stream->readOptImpl(readTag, expectedFormat); + } + return false; +} + +Int +Ice::InputStream::EncapsDecoder11::readInstance(Int index, PatchFunc patchFunc, void* patchAddr) +{ + assert(index > 0); + + if(index > 1) + { + if(patchFunc) + { + addPatchEntry(index, patchFunc, patchAddr); + } + return index; + } + + push(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 = ++_objectIdIndex; + + // + // Read the first slice header. + // + startSlice(); + const string mostDerivedId = _current->typeId; + Ice::ValuePtr v; + while(true) + { + if(_current->compactId >= 0) + { + // + // Translate a compact (numeric) type ID into a string type ID. + // + _current->typeId = _stream->resolveCompactId(_current->compactId); + if(_current->typeId.empty()) + { + _current->typeId = IceInternal::factoryTable->getTypeId(_current->compactId); + } + } + + if(!_current->typeId.empty()) + { + v = newInstance(_current->typeId); + + // + // We found a factory, we get out of this loop. + // + if(v) + { + break; + } + } + + // + // If object slicing is disabled, stop un-marshalling. + // + if(!_sliceObjects) + { + throw NoValueFactoryException(__FILE__, __LINE__, "no value factory found and object slicing is disabled", + _current->typeId); + } + + // + // Slice off what we don't understand. + // + skipSlice(); + + // + // If this is the last slice, keep the object as an opaque UnknownSlicedObject. + // + if(_current->sliceFlags & FLAG_IS_LAST_SLICE) + { + // + // Provide a factory with an opportunity to supply the object. + // We pass the "::Ice::Object" ID to indicate that this is the + // last chance to preserve the object. + // + v = newInstance(Object::ice_staticId()); + if(!v) + { + v = ICE_MAKE_SHARED(UnknownSlicedObject, mostDerivedId); + } + + break; + } + + startSlice(); // Read next Slice header for next iteration. + } + + // + // Un-marshal the object + // + unmarshal(index, v); + + if(!_current && !_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"); + } + + if(patchFunc) + { + patchFunc(patchAddr, v); + } + return index; +} + +SlicedDataPtr +Ice::InputStream::EncapsDecoder11::readSlicedData() +{ + if(_current->slices.empty()) // No preserved slices. + { + return 0; + } + + // + // The indirectionTables member holds the indirection table for + // each slice in slices. + // + assert(_current->slices.size() == _current->indirectionTables.size()); + for(SliceInfoSeq::size_type n = 0; n < _current->slices.size(); ++n) + { + // + // 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. + // + const IndexList& table = _current->indirectionTables[n]; + vector<ValuePtr>& objects = _current->slices[n]->objects; + objects.resize(table.size()); + IndexList::size_type j = 0; + for(IndexList::const_iterator p = table.begin(); p != table.end(); ++p) + { +#ifdef ICE_CPP11_MAPPING + addPatchEntry(*p, &patchHandle<Value>, &objects[j++]); +#else + addPatchEntry(*p, &patchHandle<Object>, &objects[j++]); +#endif + } + } + return ICE_MAKE_SHARED(SlicedData, _current->slices); +} |