diff options
Diffstat (limited to 'cpp/src/Ice/BasicStream.cpp')
-rw-r--r-- | cpp/src/Ice/BasicStream.cpp | 2196 |
1 files changed, 2196 insertions, 0 deletions
diff --git a/cpp/src/Ice/BasicStream.cpp b/cpp/src/Ice/BasicStream.cpp new file mode 100644 index 00000000000..d05b39443cb --- /dev/null +++ b/cpp/src/Ice/BasicStream.cpp @@ -0,0 +1,2196 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 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/BasicStream.h> +#include <Ice/Instance.h> +#include <Ice/Object.h> +#include <Ice/Proxy.h> +#include <Ice/ProxyFactory.h> +#include <Ice/ObjectFactory.h> +#include <Ice/ObjectFactoryManager.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/StringConverter.h> +#include <IceUtil/Unicode.h> +#include <iterator> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +namespace +{ + +class StreamUTF8BufferI : public Ice::UTF8Buffer +{ +public: + + StreamUTF8BufferI(BasicStream& stream) : + _stream(stream) + { + } + + Ice::Byte* + getMoreBytes(size_t howMany, Ice::Byte* firstUnused) + { + assert(howMany > 0); + + if(firstUnused != 0) + { + // + // Return unused bytes + // + _stream.b.resize(firstUnused - _stream.b.begin()); + } + + // + // Index of first unused byte + // + Buffer::Container::size_type pos = _stream.b.size(); + + // + // Since resize may reallocate the buffer, when firstUnused != 0, the + // return value can be != firstUnused + // + _stream.resize(pos + howMany); + + return &_stream.b[pos]; + } + +private: + + BasicStream& _stream; +}; + +} + +IceInternal::BasicStream::BasicStream(Instance* instance, bool unlimited) : + IceInternal::Buffer(instance->messageSizeMax()), + _instance(instance), + _closure(0), + _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) +{ +} + +void +IceInternal::BasicStream::clear() +{ + while(_currentReadEncaps && _currentReadEncaps != &_preAllocatedReadEncaps) + { + ReadEncaps* oldEncaps = _currentReadEncaps; + _currentReadEncaps = _currentReadEncaps->previous; + delete oldEncaps; + } + + while(_currentWriteEncaps && _currentWriteEncaps != &_preAllocatedWriteEncaps) + { + WriteEncaps* oldEncaps = _currentWriteEncaps; + _currentWriteEncaps = _currentWriteEncaps->previous; + delete oldEncaps; + } + + _startSeq = -1; + + delete _objectList; + _objectList = 0; + _sliceObjects = true; +} + +void* +IceInternal::BasicStream::closure() const +{ + return _closure; +} + +void* +IceInternal::BasicStream::closure(void* p) +{ + void* prev = _closure; + _closure = p; + return prev; +} + +void +IceInternal::BasicStream::swap(BasicStream& other) +{ + assert(_instance == other._instance); + + swapBuffer(other); + + std::swap(_closure, other._closure); + + // + // Swap is never called for BasicStreams that have more than one + // encaps. + // + 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; + } + } + + 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) +{ + std::swap(start, other.start); + + 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); + + std::swap(previous, other.previous); +} + +void +IceInternal::BasicStream::ReadEncaps::swap(ReadEncaps& other) +{ + 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); + + std::swap(previous, other.previous); +} + +void +IceInternal::BasicStream::endWriteEncapsChecked() +{ + if(!_currentWriteEncaps) + { + throw EncapsulationException(__FILE__, __LINE__, "not in an encapsulation"); + } + endWriteEncaps(); +} + +void +IceInternal::BasicStream::endReadEncapsChecked() +{ + if(!_currentReadEncaps) + { + throw EncapsulationException(__FILE__, __LINE__, "not in an encapsulation"); + } + endReadEncaps(); +} + +Int +IceInternal::BasicStream::getReadEncapsSize() +{ + assert(_currentReadEncaps); + return _currentReadEncaps->sz - static_cast<Int>(sizeof(Int)) - 2; +} + +void +IceInternal::BasicStream::skipEncaps() +{ + Int sz; + read(sz); + if(sz < 6) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + if(i - sizeof(Int) + sz > b.end()) + { + 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(); +} + +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) +{ + readSize(sz); + + if(sz == 0) + { + return; + } + + // + // 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__); + } +} + +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)); + } +} + +void +IceInternal::BasicStream::writeBlob(const vector<Byte>& v) +{ + if(!v.empty()) + { + Container::size_type pos = b.size(); + resize(pos + v.size()); + memcpy(&b[pos], &v[0], v.size()); + } +} + +void +IceInternal::BasicStream::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 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) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz); + memcpy(&b[pos], begin, sz); + } +} + +void +IceInternal::BasicStream::read(Byte& b, int end) +{ + read(b); + if(b >= end) + { + throw MarshalException(__FILE__, __LINE__, "enumerator out of range"); + } +} + +void +IceInternal::BasicStream::read(pair<const Byte*, const Byte*>& v) +{ + Int sz; + readAndCheckSeqSize(1, sz); + if(sz > 0) + { + v.first = i; + v.second = i + sz; + i += sz; + } + else + { + v.first = v.second = i; + } +} + +void +IceInternal::BasicStream::write(const vector<bool>& v) +{ + Int sz = static_cast<Int>(v.size()); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz); + copy(v.begin(), v.end(), b.begin() + pos); + } +} + +namespace +{ + +template<size_t boolSize> +struct BasicStreamWriteBoolHelper +{ + static void write(const bool* begin, BasicStream::Container::size_type pos, BasicStream::Container& b, Int sz) + { + for(int idx = 0; idx < sz; ++idx) + { + b[pos + idx] = static_cast<Ice::Byte>(*(begin + idx)); + } + } +}; + +template<> +struct BasicStreamWriteBoolHelper<1> +{ + static void write(const bool* begin, BasicStream::Container::size_type pos, BasicStream::Container& b, Int sz) + { + memcpy(&b[pos], begin, sz); + } +}; + +} + +void +IceInternal::BasicStream::write(const bool* begin, const bool* end) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz); + BasicStreamWriteBoolHelper<sizeof(bool)>::write(begin, pos, b, sz); + } +} + +void +IceInternal::BasicStream::read(vector<bool>& v) +{ + Int sz; + readAndCheckSeqSize(1, sz); + if(sz > 0) + { + v.resize(sz); + copy(i, i + sz, v.begin()); + i += sz; + } + else + { + v.clear(); + } +} + +namespace +{ + +template<size_t boolSize> +struct BasicStreamReadBoolHelper +{ + static bool* read(pair<const bool*, const bool*>& v, Int sz, BasicStream::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 BasicStreamReadBoolHelper<1> +{ + static bool* read(pair<const bool*, const bool*>& v, Int sz, BasicStream::Container::iterator& i) + { + v.first = reinterpret_cast<bool*>(i); + v.second = reinterpret_cast<bool*>(i) + sz; + return 0; + } +}; + +} + +bool* +IceInternal::BasicStream::read(pair<const bool*, const bool*>& v) +{ + bool* result = 0; + Int sz; + readAndCheckSeqSize(1, sz); + if(sz > 0) + { + result = BasicStreamReadBoolHelper<sizeof(bool)>::read(v, sz, i); + i += sz; + } + else + { + v.first = v.second = reinterpret_cast<bool*>(i); + } + return result; +} + +void +IceInternal::BasicStream::write(Short v) +{ + Container::size_type pos = b.size(); + resize(pos + sizeof(Short)); + Byte* dest = &b[pos]; +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(&v) + sizeof(Short) - 1; + *dest++ = *src--; + *dest = *src; +#else + const Byte* src = reinterpret_cast<const Byte*>(&v); + *dest++ = *src++; + *dest = *src; +#endif +} + +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); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz * sizeof(Short)); +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(begin) + sizeof(Short) - 1; + Byte* dest = &(*(b.begin() + pos)); + for(int j = 0 ; j < sz ; ++j) + { + *dest++ = *src--; + *dest++ = *src--; + src += 2 * sizeof(Short); + } +#else + memcpy(&b[pos], reinterpret_cast<const Byte*>(begin), sz * sizeof(Short)); +#endif + } +} + +void +IceInternal::BasicStream::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 +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); + 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(); + } +} + +Short* +IceInternal::BasicStream::read(pair<const Short*, const Short*>& v) +{ + Short* result = 0; + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Short)), sz); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) + v.first = reinterpret_cast<Short*>(i); + i += sz * static_cast<int>(sizeof(Short)); + v.second = reinterpret_cast<Short*>(i); +#else + result = new Short[sz]; + v.first = result; + v.second = result + 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 + { + v.first = v.second = 0; + } + return result; +} + +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); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz * sizeof(Int)); +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(begin) + sizeof(Int) - 1; + Byte* dest = &(*(b.begin() + pos)); + for(int j = 0 ; j < sz ; ++j) + { + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + src += 2 * sizeof(Int); + } +#else + memcpy(&b[pos], reinterpret_cast<const Byte*>(begin), sz * sizeof(Int)); +#endif + } +} + +void +IceInternal::BasicStream::read(vector<Int>& v) +{ + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Int)), sz); + 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(); + } +} + +Int* +IceInternal::BasicStream::read(pair<const Int*, const Int*>& v) +{ + Int* result = 0; + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Int)), sz); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) + v.first = reinterpret_cast<Int*>(i); + i += sz * static_cast<int>(sizeof(Int)); + v.second = reinterpret_cast<Int*>(i); +#else + result = new Int[sz]; + v.first = result; + v.second = result + 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 + { + v.first = v.second = 0; + } + return result; +} + +void +IceInternal::BasicStream::write(Long v) +{ + Container::size_type pos = b.size(); + resize(pos + sizeof(Long)); + Byte* dest = &b[pos]; +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(&v) + sizeof(Long) - 1; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest = *src; +#else + const Byte* src = reinterpret_cast<const Byte*>(&v); + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest = *src; +#endif +} + +void +IceInternal::BasicStream::write(const Long* begin, const Long* end) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz * sizeof(Long)); +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(begin) + sizeof(Long) - 1; + Byte* dest = &(*(b.begin() + pos)); + for(int j = 0 ; j < sz ; ++j) + { + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + src += 2 * sizeof(Long); + } +#else + memcpy(&b[pos], reinterpret_cast<const Byte*>(begin), sz * sizeof(Long)); +#endif + } +} + +void +IceInternal::BasicStream::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 +IceInternal::BasicStream::read(vector<Long>& v) +{ + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Long)), sz); + 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(); + } +} + +Long* +IceInternal::BasicStream::read(pair<const Long*, const Long*>& v) +{ + Long* result = 0; + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Long)), sz); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) + v.first = reinterpret_cast<Long*>(i); + i += sz * static_cast<int>(sizeof(Long)); + v.second = reinterpret_cast<Long*>(i); +#else + result = new Long[sz]; + v.first = result; + v.second = result + 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 + { + v.first = v.second = 0; + } + return result; +} + +void +IceInternal::BasicStream::write(Float v) +{ + Container::size_type pos = b.size(); + resize(pos + sizeof(Float)); + Byte* dest = &b[pos]; +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(&v) + sizeof(Float) - 1; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest = *src; +#else + const Byte* src = reinterpret_cast<const Byte*>(&v); + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + *dest = *src; +#endif +} + +void +IceInternal::BasicStream::write(const Float* begin, const Float* end) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz * sizeof(Float)); +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(begin) + sizeof(Float) - 1; + Byte* dest = &(*(b.begin() + pos)); + for(int j = 0 ; j < sz ; ++j) + { + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + src += 2 * sizeof(Float); + } +#else + memcpy(&b[pos], reinterpret_cast<const Byte*>(begin), sz * sizeof(Float)); +#endif + } +} + +void +IceInternal::BasicStream::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 +IceInternal::BasicStream::read(vector<Float>& v) +{ + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Float)), sz); + 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(); + } +} + +Float* +IceInternal::BasicStream::read(pair<const Float*, const Float*>& v) +{ + Float* result = 0; + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Float)), sz); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) + v.first = reinterpret_cast<Float*>(i); + i += sz * static_cast<int>(sizeof(Float)); + v.second = reinterpret_cast<Float*>(i); +#else + result = new Float[sz]; + v.first = result; + v.second = result + 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 + { + v.first = v.second = 0; + } + return result; +} + +void +IceInternal::BasicStream::write(Double v) +{ + Container::size_type pos = b.size(); + resize(pos + sizeof(Double)); + Byte* dest = &b[pos]; +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(&v) + sizeof(Double) - 1; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest = *src; +#else + const Byte* src = reinterpret_cast<const Byte*>(&v); +# if defined(__arm__) && defined(__linux) + 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 +IceInternal::BasicStream::write(const Double* begin, const Double* end) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + Container::size_type pos = b.size(); + resize(pos + sz * sizeof(Double)); +#ifdef ICE_BIG_ENDIAN + const Byte* src = reinterpret_cast<const Byte*>(begin) + sizeof(Double) - 1; + Byte* dest = &(*(b.begin() + pos)); + for(int j = 0 ; j < sz ; ++j) + { + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + *dest++ = *src--; + src += 2 * sizeof(Double); + } +#elif defined(__arm__) && defined(__linux) + const Byte* src = reinterpret_cast<const Byte*>(begin); + Byte* dest = &(*(b.begin() + pos)); + 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 + memcpy(&b[pos], reinterpret_cast<const Byte*>(begin), sz * sizeof(Double)); +#endif + } +} + +void +IceInternal::BasicStream::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(__arm__) && defined(__linux) + 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 +IceInternal::BasicStream::read(vector<Double>& v) +{ + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Double)), sz); + 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(__arm__) && defined(__linux) + 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(); + } +} + +Double* +IceInternal::BasicStream::read(pair<const Double*, const Double*>& v) +{ + Double* result = 0; + Int sz; + readAndCheckSeqSize(static_cast<int>(sizeof(Double)), sz); + if(sz > 0) + { +#if defined(__i386) || defined(_M_IX86) + v.first = reinterpret_cast<Double*>(i); + i += sz * static_cast<int>(sizeof(Double)); + v.second = reinterpret_cast<Double*>(i); +#else + result = new Double[sz]; + v.first = result; + v.second = result + 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(__arm__) && defined(__linux) + 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 + { + v.first = v.second = 0; + } + return result; +} + +// +// NOTE: This member function is intentionally omitted in order to +// cause a link error if it is used. This is for efficiency reasons: +// writing a const char * requires a traversal of the string to get +// the string length first, which takes O(n) time, whereas getting the +// string length from a std::string takes constant time. +// +/* +void +IceInternal::BasicStream::write(const char*) +{ +} +*/ + +void +IceInternal::BasicStream::writeConverted(const string& v) +{ + // + // What is the size of the resulting UTF-8 encoded string? + // Impossible to tell, so we guess. If we don't guess correctly, + // we'll have to fix the mistake afterwards + // + + Int guessedSize = static_cast<Int>(v.size()); + writeSize(guessedSize); // writeSize() only writes the size; it does not reserve any buffer space. + + size_t firstIndex = b.size(); + StreamUTF8BufferI buffer(*this); + + Byte* lastByte = _stringConverter->toUTF8(v.data(), v.data() + v.size(), buffer); + if(lastByte != b.end()) + { + b.resize(lastByte - b.begin()); + } + size_t lastIndex = b.size(); + + Int actualSize = static_cast<Int>(lastIndex - firstIndex); + + // + // Check against the guess + // + if(guessedSize != actualSize) + { + if(guessedSize <= 254 && actualSize > 254) + { + // + // Move the UTF-8 sequence 4 bytes further + // Use memmove instead of memcpy since the source and destination typically overlap. + // + resize(b.size() + 4); + memmove(b.begin() + firstIndex + 4, b.begin() + firstIndex, actualSize); + } + else if(guessedSize > 254 && actualSize <= 254) + { + // + // Move the UTF-8 sequence 4 bytes back + // + memmove(b.begin() + firstIndex - 4, b.begin() + firstIndex, actualSize); + resize(b.size() - 4); + } + + if(guessedSize <= 254) + { + rewriteSize(actualSize, b.begin() + firstIndex - 1); + } + else + { + rewriteSize(actualSize, b.begin() + firstIndex - 1 - 4); + } + } +} + +void +IceInternal::BasicStream::write(const string* begin, const string* end, bool convert) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + for(int i = 0; i < sz; ++i) + { + write(begin[i], convert); + } + } +} + +void +IceInternal::BasicStream::readConverted(string& v, int sz) +{ + _stringConverter->fromUTF8(i, i + sz, v); +} + +void +IceInternal::BasicStream::read(vector<string>& v, bool convert) +{ + Int sz; + readAndCheckSeqSize(1, sz); + if(sz > 0) + { + v.resize(sz); + for(int j = 0; j < sz; ++j) + { + read(v[j], convert); + } + } + else + { + v.clear(); + } +} + +void +IceInternal::BasicStream::write(const wstring& v) +{ + if(v.empty()) + { + writeSize(0); + return; + } + + // + // What is the size of the resulting UTF-8 encoded string? + // Impossible to tell, so we guess. If we don't guess correctly, + // we'll have to fix the mistake afterwards + // + + Int guessedSize = static_cast<Int>(v.size()); + writeSize(guessedSize); // writeSize() only writes the size; it does not reserve any buffer space. + + size_t firstIndex = b.size(); + StreamUTF8BufferI buffer(*this); + + Byte* lastByte = _wstringConverter->toUTF8(v.data(), v.data() + v.size(), buffer); + if(lastByte != b.end()) + { + b.resize(lastByte - b.begin()); + } + size_t lastIndex = b.size(); + + Int actualSize = static_cast<Int>(lastIndex - firstIndex); + + // + // Check against the guess + // + if(guessedSize != actualSize) + { + if(guessedSize <= 254 && actualSize > 254) + { + // + // Move the UTF-8 sequence 4 bytes further + // Use memmove instead of memcpy since the source and destination typically overlap. + // + resize(b.size() + 4); + memmove(b.begin() + firstIndex + 4, b.begin() + firstIndex, actualSize); + } + else if(guessedSize > 254 && actualSize <= 254) + { + // + // Move the UTF-8 sequence 4 bytes back + // + memmove(b.begin() + firstIndex - 4, b.begin() + firstIndex, actualSize); + resize(b.size() - 4); + } + + if(guessedSize <= 254) + { + rewriteSize(actualSize, b.begin() + firstIndex - 1); + } + else + { + rewriteSize(actualSize, b.begin() + firstIndex - 1 - 4); + } + } +} + +void +IceInternal::BasicStream::write(const wstring* begin, const wstring* end) +{ + Int sz = static_cast<Int>(end - begin); + writeSize(sz); + if(sz > 0) + { + for(int i = 0; i < sz; ++i) + { + write(begin[i]); + } + } +} + +void +IceInternal::BasicStream::read(wstring& v) +{ + Ice::Int sz; + readSize(sz); + if(sz > 0) + { + if(b.end() - i < sz) + { + throwUnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + + _wstringConverter->fromUTF8(i, i + sz, v); + i += sz; + } + else + { + v.clear(); + } +} + +void +IceInternal::BasicStream::read(vector<wstring>& v) +{ + Int sz; + readAndCheckSeqSize(1, sz); + if(sz > 0) + { + v.resize(sz); + for(int j = 0; j < sz; ++j) + { + read(v[j]); + } + } + else + { + v.clear(); + } +} + +void +IceInternal::BasicStream::write(const ObjectPrx& v) +{ + _instance->proxyFactory()->proxyToStream(v, this); +} + +void +IceInternal::BasicStream::read(ObjectPrx& v) +{ + v = _instance->proxyFactory()->streamToProxy(this); +} + +void +IceInternal::BasicStream::write(const ObjectPtr& v) +{ + if(!_currentWriteEncaps) // Lazy initialization. + { + _currentWriteEncaps = &_preAllocatedWriteEncaps; + _currentWriteEncaps->start = b.size(); + } + + if(!_currentWriteEncaps->toBeMarshaledMap) // Lazy initialization. + { + _currentWriteEncaps->toBeMarshaledMap = new PtrToIndexMap; + _currentWriteEncaps->marshaledMap = new PtrToIndexMap; + _currentWriteEncaps->typeIdMap = new TypeIdWriteMap; + } + + if(v) + { + // + // Look for this instance in the to-be-marshaled map. + // + PtrToIndexMap::iterator p = _currentWriteEncaps->toBeMarshaledMap->find(v); + if(p == _currentWriteEncaps->toBeMarshaledMap->end()) + { + // + // Didn't find it, try the marshaled map next. + // + PtrToIndexMap::iterator q = _currentWriteEncaps->marshaledMap->find(v); + if(q == _currentWriteEncaps->marshaledMap->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)); + } + p = q; + } + // + // Write the index for the instance. + // + write(-(p->second)); + } + else + { + write(0); // Write null pointer. + } +} + +void +IceInternal::BasicStream::read(PatchFunc patchFunc, void* patchAddr) +{ + if(!_currentReadEncaps) // Lazy initialization. + { + _currentReadEncaps = &_preAllocatedReadEncaps; + } + + if(!_currentReadEncaps->patchMap) // Lazy initialization. + { + _currentReadEncaps->patchMap = new PatchMap; + _currentReadEncaps->unmarshaledMap = new IndexToPtrMap; + _currentReadEncaps->typeIdMap = new TypeIdReadMap; + } + + ObjectPtr v; + + Int index; + read(index); + + if(patchAddr) + { + 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; + } + + if(index < 0) + { + 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. + // + PatchEntry e; + e.patchFunc = patchFunc; + e.patchAddr = patchAddr; + p->second.push_back(e); + patchPointers(-index, _currentReadEncaps->unmarshaledMap->end(), p); + return; + } + } + if(index <= 0) + { + throw MarshalException(__FILE__, __LINE__, "Invalid class instance index"); + } + + string mostDerivedId; + readTypeId(mostDerivedId); + string id = mostDerivedId; + while(true) + { + // + // If we slice all the way down to Ice::Object, we throw + // because Ice::Object is abstract. + // + if(id == Ice::Object::ice_staticId()) + { + throw NoObjectFactoryException(__FILE__, __LINE__, "", mostDerivedId); + } + + // + // Try to find a factory registered for the specific type. + // + ObjectFactoryPtr userFactory = _instance->servantFactoryManager()->find(id); + if(userFactory) + { + v = userFactory->create(id); + } + + // + // If that fails, invoke the default factory if one has been + // registered. + // + if(!v) + { + userFactory = _instance->servantFactoryManager()->find(""); + if(userFactory) + { + v = userFactory->create(id); + } + } + + // + // Last chance: check the table of static factories (i.e., + // automatically generated factories for concrete classes). + // + if(!v) + { + ObjectFactoryPtr of = IceInternal::factoryTable->getObjectFactory(id); + if(of) + { + v = of->create(id); + assert(v); + } + } + + if(!v) + { + if(_sliceObjects) + { + // + // 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; + } + else + { + NoObjectFactoryException ex(__FILE__, __LINE__); + ex.type = id; + throw ex; + } + } + + IndexToPtrMap::const_iterator unmarshaledPos = + _currentReadEncaps->unmarshaledMap->insert(make_pair(index, v)).first; + + // + // Record each object instance so that readPendingObjects can + // invoke ice_postUnmarshal after all objects have been + // unmarshaled. + // + if(!_objectList) + { + _objectList = new ObjectList; + } + _objectList->push_back(v); + + v->__read(this, false); + patchPointers(index, unmarshaledPos, _currentReadEncaps->patchMap->end()); + return; + } + + // + // 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. + // + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); +} + +void +IceInternal::BasicStream::write(const UserException& v) +{ + write(v.__usesClasses()); + v.__write(this); + if(v.__usesClasses()) + { + writePendingObjects(); + } +} + +void +IceInternal::BasicStream::throwException() +{ + bool usesClasses; + read(usesClasses); + + string id; + read(id, false); + const string origId = id; + + for(;;) + { + // + // Look for a factory for this ID. + // + UserExceptionFactoryPtr factory = factoryTable->getExceptionFactory(id); + if(factory) + { + // + // Got factory -- get the factory to instantiate the + // exception, initialize the exception members, and throw + // the exception. + // + try + { + factory->createAndThrow(); + } + catch(UserException& ex) + { + ex.__read(this, false); + if(usesClasses) + { + readPendingObjects(); + } + ex.ice_throw(); + } + } + else + { + // + // Performance sensitive, so we use lazy initialization + // for tracing. + // + if(_traceSlicing == -1) + { + _traceSlicing = _instance->traceLevels()->slicing; + _slicingCat = _instance->traceLevels()->slicingCat; + } + if(_traceSlicing > 0) + { + traceSlicing("exception", id, _slicingCat, _instance->initializationData().logger); + } + + skipSlice(); // Slice off what we don't understand. + + try + { + read(id, false); // Read type id for next slice. + } + catch(UnmarshalOutOfBoundsException& ex) + { + // + // 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; + } + } + } + + // + // 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. + // +} + +void +IceInternal::BasicStream::writePendingObjects() +{ + if(_currentWriteEncaps && _currentWriteEncaps->toBeMarshaledMap) + { + while(_currentWriteEncaps->toBeMarshaledMap->size()) + { + PtrToIndexMap savedMap = *_currentWriteEncaps->toBeMarshaledMap; + writeSize(static_cast<Int>(savedMap.size())); + for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p) + { + // + // 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. + // + _currentWriteEncaps->marshaledMap->insert(*p); + writeInstance(p->first, p->second); + } + + // + // 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; + } + } + writeSize(0); // Zero marker indicates end of sequence of sequences of instances. +} + +void +IceInternal::BasicStream::readPendingObjects() +{ + Int num; + do + { + readSize(num); + for(Int k = num; k > 0; --k) + { + read(0, 0); + } + } + while(num); + + if(_currentReadEncaps && _currentReadEncaps->patchMap && _currentReadEncaps->patchMap->size() != 0) + { + // + // If any entries remain in the patch map, the sender has sent an index for an object, but failed + // to supply the object. + // + throw MarshalException(__FILE__, __LINE__, "Index for class received, but no instance"); + } + + // + // 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. + // + if(_objectList) + { + for(ObjectList::iterator p = _objectList->begin(); p != _objectList->end(); ++p) + { + try + { + (*p)->ice_postUnmarshal(); + } + catch(const std::exception& ex) + { + Ice::Warning out(_instance->initializationData().logger); + out << "std::exception raised by ice_postUnmarshal:\n" << ex; + } + catch(...) + { + Ice::Warning out(_instance->initializationData().logger); + out << "unknown exception raised by ice_postUnmarshal"; + } + } + } +} + +void +IceInternal::BasicStream::sliceObjects(bool doSlice) +{ + _sliceObjects = doSlice; +} + +void +IceInternal::BasicStream::throwUnmarshalOutOfBoundsException(const char* file, int line) +{ + throw UnmarshalOutOfBoundsException(file, line); +} + +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; +} + +void +IceInternal::BasicStream::throwEncapsulationException(const char* file, int line) +{ + throw EncapsulationException(file, line); +} + +void +IceInternal::BasicStream::writeInstance(const ObjectPtr& v, Int index) +{ + write(index); + try + { + v->ice_preMarshal(); + } + catch(const std::exception& ex) + { + Ice::Warning out(_instance->initializationData().logger); + out << "std::exception raised by ice_preMarshal:\n" << ex; + } + catch(...) + { + Ice::Warning out(_instance->initializationData().logger); + out << "unknown exception raised by ice_preMarshal"; + } + v->__write(this); +} + +void +IceInternal::BasicStream::patchPointers(Int index, IndexToPtrMap::const_iterator unmarshaledPos, + PatchMap::iterator patchPos) +{ + // + // 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()) + ); + + if(unmarshaledPos != _currentReadEncaps->unmarshaledMap->end()) + { + // + // 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. + } + } + else + { + // + // We have just unmarshaled an index -- check if we have + // unmarshaled the instance for that index yet. + // + unmarshaledPos = _currentReadEncaps->unmarshaledMap->find(index); + if(unmarshaledPos == _currentReadEncaps->unmarshaledMap->end()) + { + return; // We haven't unmarshaled the instance yet. + } + } + assert(patchPos->second.size() > 0); + + ObjectPtr v = unmarshaledPos->second; + assert(v); + + // + // 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. + // + _currentReadEncaps->patchMap->erase(patchPos); +} + |