summaryrefslogtreecommitdiff
path: root/cpp/src/Ice/OutputStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Ice/OutputStream.cpp')
-rw-r--r--cpp/src/Ice/OutputStream.cpp1375
1 files changed, 1375 insertions, 0 deletions
diff --git a/cpp/src/Ice/OutputStream.cpp b/cpp/src/Ice/OutputStream.cpp
new file mode 100644
index 00000000000..1f784ad3675
--- /dev/null
+++ b/cpp/src/Ice/OutputStream.cpp
@@ -0,0 +1,1375 @@
+// **********************************************************************
+//
+// 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/OutputStream.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/LocalException.h>
+#include <Ice/Protocol.h>
+#include <Ice/TraceUtil.h>
+#include <Ice/LoggerUtil.h>
+#include <Ice/SlicedData.h>
+#include <IceUtil/StringConverter.h>
+#include <iterator>
+
+using namespace std;
+using namespace Ice;
+using namespace IceInternal;
+
+namespace
+{
+
+class StreamUTF8BufferI : public IceUtil::UTF8Buffer
+{
+public:
+
+ StreamUTF8BufferI(OutputStream& stream) :
+ _stream(stream)
+ {
+ }
+
+ Ice::Byte* getMoreBytes(size_t howMany, Ice::Byte* firstUnused)
+ {
+ assert(howMany > 0);
+
+ if(firstUnused != 0)
+ {
+ //
+ // Return unused bytes
+ //
+ _stream.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:
+
+ OutputStream& _stream;
+};
+
+}
+
+Ice::OutputStream::OutputStream() :
+ _instance(0),
+ _closure(0),
+ _encoding(currentEncoding),
+ _format(CompactFormat),
+ _currentEncaps(0)
+{
+ //
+ // Initialize the encoding member of our pre-allocated encapsulation, in case
+ // this stream is used without an explicit encapsulation.
+ //
+ _preAllocatedEncaps.encoding = _encoding;
+}
+
+Ice::OutputStream::OutputStream(const CommunicatorPtr& communicator) :
+ _closure(0),
+ _currentEncaps(0)
+{
+ initialize(communicator);
+}
+
+Ice::OutputStream::OutputStream(const CommunicatorPtr& communicator, const EncodingVersion& encoding) :
+ _closure(0),
+ _currentEncaps(0)
+{
+ initialize(communicator, encoding);
+}
+
+Ice::OutputStream::OutputStream(Instance* instance, const EncodingVersion& encoding) :
+ _closure(0),
+ _currentEncaps(0)
+{
+ initialize(instance, encoding);
+}
+
+void
+Ice::OutputStream::initialize(const CommunicatorPtr& communicator)
+{
+ assert(communicator);
+ InstancePtr instance = getInstance(communicator);
+ initialize(instance.get(), instance->defaultsAndOverrides()->defaultEncoding);
+}
+
+void
+Ice::OutputStream::initialize(const CommunicatorPtr& communicator, const EncodingVersion& encoding)
+{
+ assert(communicator);
+ InstancePtr instance = getInstance(communicator);
+ initialize(instance.get(), encoding);
+}
+
+void
+Ice::OutputStream::initialize(Instance* instance, const EncodingVersion& encoding)
+{
+ assert(instance);
+
+ _instance = instance;
+ _encoding = encoding;
+
+ _stringConverter = _instance->getStringConverter();
+ _wstringConverter = _instance->getWstringConverter();
+
+ _format = _instance->defaultsAndOverrides()->defaultFormat;
+
+ //
+ // Initialize the encoding member of our pre-allocated encapsulation, in case
+ // this stream is used without an explicit encapsulation.
+ //
+ _preAllocatedEncaps.encoding = encoding;
+}
+
+void
+Ice::OutputStream::clear()
+{
+ while(_currentEncaps && _currentEncaps != &_preAllocatedEncaps)
+ {
+ Encaps* oldEncaps = _currentEncaps;
+ _currentEncaps = _currentEncaps->previous;
+ delete oldEncaps;
+ }
+}
+
+void
+Ice::OutputStream::setStringConverters(const IceUtil::StringConverterPtr& sc, const IceUtil::WstringConverterPtr& wsc)
+{
+ _stringConverter = sc;
+ _wstringConverter = wsc;
+}
+
+void
+Ice::OutputStream::setFormat(FormatType fmt)
+{
+ _format = fmt;
+}
+
+void*
+Ice::OutputStream::getClosure() const
+{
+ return _closure;
+}
+
+void*
+Ice::OutputStream::setClosure(void* p)
+{
+ void* prev = _closure;
+ _closure = p;
+ return prev;
+}
+
+void
+Ice::OutputStream::swap(OutputStream& other)
+{
+ assert(_instance == other._instance);
+
+ swapBuffer(other);
+
+ std::swap(_closure, other._closure);
+
+ //
+ // Swap is never called for streams that have encapsulations being written. However,
+ // encapsulations might still be set in case marshalling failed. We just
+ // reset the encapsulations if there are still some set.
+ //
+ resetEncapsulation();
+ other.resetEncapsulation();
+}
+
+void
+Ice::OutputStream::resetEncapsulation()
+{
+ while(_currentEncaps && _currentEncaps != &_preAllocatedEncaps)
+ {
+ Encaps* oldEncaps = _currentEncaps;
+ _currentEncaps = _currentEncaps->previous;
+ delete oldEncaps;
+ }
+
+ _preAllocatedEncaps.reset();
+}
+
+void
+Ice::OutputStream::startEncapsulation()
+{
+ //
+ // If no encoding version is specified, use the current write
+ // encapsulation encoding version if there's a current write
+ // encapsulation, otherwise, use the stream encoding version.
+ //
+
+ if(_currentEncaps)
+ {
+ startEncapsulation(_currentEncaps->encoding, _currentEncaps->format);
+ }
+ else
+ {
+ startEncapsulation(_encoding, Ice::DefaultFormat);
+ }
+}
+
+void
+Ice::OutputStream::writePendingObjects()
+{
+ if(_currentEncaps && _currentEncaps->encoder)
+ {
+ _currentEncaps->encoder->writePendingObjects();
+ }
+ else if(getEncoding() == Ice::Encoding_1_0)
+ {
+ //
+ // If using the 1.0 encoding and no objects were written, we
+ // still write an empty sequence for pending objects if
+ // requested (i.e.: if this is called).
+ //
+ // This is required by the 1.0 encoding, even if no objects
+ // are written we do marshal an empty sequence if marshaled
+ // data types use classes.
+ //
+ writeSize(0);
+ }
+}
+
+void
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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 WriteBoolHelper
+{
+ static void write(const bool* begin, OutputStream::Container::size_type pos, OutputStream::Container& b, Int sz)
+ {
+ for(int idx = 0; idx < sz; ++idx)
+ {
+ b[pos + idx] = static_cast<Byte>(*(begin + idx));
+ }
+ }
+};
+
+template<>
+struct WriteBoolHelper<1>
+{
+ static void write(const bool* begin, OutputStream::Container::size_type pos, OutputStream::Container& b, Int sz)
+ {
+ memcpy(&b[pos], begin, sz);
+ }
+};
+
+}
+
+void
+Ice::OutputStream::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);
+ WriteBoolHelper<sizeof(bool)>::write(begin, pos, b, sz);
+ }
+}
+
+void
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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
+Ice::OutputStream::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(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::OutputStream::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(ICE_LITTLEBYTE_BIGWORD)
+ 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
+ }
+}
+
+//
+// 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
+Ice::OutputStream::write(const char*)
+{
+}
+*/
+
+void
+Ice::OutputStream::writeConverted(const char* vdata, size_t vsize)
+{
+ if(!_stringConverter)
+ {
+ throw MarshalException(__FILE__, __LINE__, "no string converter provided");
+ }
+
+ //
+ // 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
+ //
+ try
+ {
+ Int guessedSize = static_cast<Int>(vsize);
+ 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(vdata, vdata + vsize, buffer);
+ if(lastByte != b.end())
+ {
+ 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);
+ }
+ }
+ }
+ catch(const IceUtil::IllegalConversionException& ex)
+ {
+ throw StringConversionException(__FILE__, __LINE__, ex.reason());
+ }
+}
+
+void
+Ice::OutputStream::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
+Ice::OutputStream::write(const wstring& v)
+{
+ if(v.empty())
+ {
+ writeSize(0);
+ return;
+ }
+
+ if(!_wstringConverter)
+ {
+ throw MarshalException(__FILE__, __LINE__, "no wstring converter provided");
+ }
+
+ //
+ // 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
+ //
+ try
+ {
+ 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())
+ {
+ 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);
+ }
+ }
+ }
+ catch(const IceUtil::IllegalConversionException& ex)
+ {
+ throw StringConversionException(__FILE__, __LINE__, ex.reason());
+ }
+}
+
+void
+Ice::OutputStream::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
+#ifdef ICE_CPP11_MAPPING
+Ice::OutputStream::writeProxy(const shared_ptr<ObjectPrx>& v)
+#else
+Ice::OutputStream::write(const ObjectPrx& v)
+#endif
+{
+ if(v)
+ {
+ v->__write(*this);
+ }
+ else
+ {
+ Identity ident;
+ write(ident);
+ }
+}
+
+void
+Ice::OutputStream::writeEnum(Int v, Int maxValue)
+{
+ if(getEncoding() == Encoding_1_0)
+ {
+ if(maxValue < 127)
+ {
+ write(static_cast<Byte>(v));
+ }
+ else if(maxValue < 32767)
+ {
+ write(static_cast<Short>(v));
+ }
+ else
+ {
+ write(v);
+ }
+ }
+ else
+ {
+ writeSize(v);
+ }
+}
+
+void
+Ice::OutputStream::writeException(const UserException& e)
+{
+ initEncaps();
+ _currentEncaps->encoder->write(e);
+}
+
+bool
+Ice::OutputStream::writeOptImpl(Int tag, OptionalFormat type)
+{
+ if(getEncoding() == Encoding_1_0)
+ {
+ return false; // Optional members aren't supported with the 1.0 encoding.
+ }
+
+ Byte v = static_cast<Byte>(type);
+ if(tag < 30)
+ {
+ v |= static_cast<Byte>(tag << 3);
+ write(v);
+ }
+ else
+ {
+ v |= 0xF0; // tag = 30
+ write(v);
+ writeSize(tag);
+ }
+ return true;
+}
+
+void
+Ice::OutputStream::finished(vector<Byte>& bytes)
+{
+ vector<Byte>(b.begin(), b.end()).swap(bytes);
+}
+
+pair<const Byte*, const Byte*>
+Ice::OutputStream::finished()
+{
+ if(b.empty())
+ {
+ return pair<const Byte*, const Byte*>(reinterpret_cast<Ice::Byte*>(0), reinterpret_cast<Ice::Byte*>(0));
+ }
+ else
+ {
+ return pair<const Byte*, const Byte*>(&b[0], &b[0] + b.size());
+ }
+}
+
+void
+Ice::OutputStream::throwEncapsulationException(const char* file, int line)
+{
+ throw EncapsulationException(file, line);
+}
+
+void
+Ice::OutputStream::initEncaps()
+{
+ if(!_currentEncaps) // Lazy initialization.
+ {
+ _currentEncaps = &_preAllocatedEncaps;
+ _currentEncaps->start = b.size();
+ }
+
+ if(_currentEncaps->format == Ice::DefaultFormat)
+ {
+ _currentEncaps->format = _format;
+ }
+
+ if(!_currentEncaps->encoder) // Lazy initialization.
+ {
+ if(_currentEncaps->encoding == Encoding_1_0)
+ {
+ _currentEncaps->encoder = new EncapsEncoder10(this, _currentEncaps);
+ }
+ else
+ {
+ _currentEncaps->encoder = new EncapsEncoder11(this, _currentEncaps);
+ }
+ }
+}
+
+Int
+Ice::OutputStream::EncapsEncoder::registerTypeId(const string& typeId)
+{
+ TypeIdMap::const_iterator p = _typeIdMap.find(typeId);
+ if(p != _typeIdMap.end())
+ {
+ return p->second;
+ }
+ else
+ {
+ _typeIdMap.insert(make_pair(typeId, ++_typeIdIndex));
+ return -1;
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::write(const ValuePtr& v)
+{
+ //
+ // Object references are encoded as a negative integer in 1.0.
+ //
+ if(v)
+ {
+ _stream->write(-registerObject(v));
+ }
+ else
+ {
+ _stream->write(0);
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::write(const UserException& v)
+{
+ //
+ // User exception with the 1.0 encoding start with a boolean
+ // flag that indicates whether or not the exception uses
+ // classes.
+ //
+ // This allows reading the pending objects even if some part of
+ // the exception was sliced.
+ //
+ bool usesClasses = v.__usesClasses();
+ _stream->write(usesClasses);
+ v.__write(_stream);
+ if(usesClasses)
+ {
+ writePendingObjects();
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::startInstance(SliceType sliceType, const SlicedDataPtr&)
+{
+ _sliceType = sliceType;
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::endInstance()
+{
+ if(_sliceType == ObjectSlice)
+ {
+ //
+ // Write the Object slice.
+ //
+ startSlice(Object::ice_staticId(), -1, true);
+ _stream->writeSize(0); // For compatibility with the old AFM.
+ endSlice();
+ }
+ _sliceType = NoSlice;
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::startSlice(const string& typeId, int, bool /*last*/)
+{
+ //
+ // For object slices, encode a boolean to indicate how the type ID
+ // is encoded and the type ID either as a string or index. For
+ // exception slices, always encode the type ID as a string.
+ //
+ if(_sliceType == ObjectSlice)
+ {
+ Int index = registerTypeId(typeId);
+ if(index < 0)
+ {
+ _stream->write(false);
+ _stream->write(typeId, false);
+ }
+ else
+ {
+ _stream->write(true);
+ _stream->writeSize(index);
+ }
+ }
+ else
+ {
+ _stream->write(typeId, false);
+ }
+
+ _stream->write(Int(0)); // Placeholder for the slice length.
+
+ _writeSlice = _stream->b.size();
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::endSlice()
+{
+ //
+ // Write the slice length.
+ //
+ Int sz = static_cast<Int>(_stream->b.size() - _writeSlice + sizeof(Int));
+ Byte* dest = &(*(_stream->b.begin() + _writeSlice - sizeof(Int)));
+ _stream->write(sz, dest);
+}
+
+void
+Ice::OutputStream::EncapsEncoder10::writePendingObjects()
+{
+ while(!_toBeMarshaledMap.empty())
+ {
+ //
+ // Consider the to be marshalled objects as marshalled now,
+ // this is necessary to avoid adding again the "to be
+ // marshalled objects" into _toBeMarshaledMap while writing
+ // objects.
+ //
+ _marshaledMap.insert(_toBeMarshaledMap.begin(), _toBeMarshaledMap.end());
+
+ PtrToIndexMap savedMap;
+ savedMap.swap(_toBeMarshaledMap);
+ _stream->writeSize(static_cast<Int>(savedMap.size()));
+ for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p)
+ {
+ //
+ // Ask the instance to marshal itself. Any new class
+ // instances that are triggered by the classes marshaled
+ // are added to toBeMarshaledMap.
+ //
+ _stream->write(p->second);
+
+ try
+ {
+ p->first->ice_preMarshal();
+ }
+ catch(const std::exception& ex)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "std::exception raised by ice_preMarshal:\n" << ex;
+ }
+ catch(...)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "unknown exception raised by ice_preMarshal";
+ }
+
+ p->first->__write(_stream);
+ }
+ }
+ _stream->writeSize(0); // Zero marker indicates end of sequence of sequences of instances.
+}
+
+Int
+Ice::OutputStream::EncapsEncoder10::registerObject(const ValuePtr& v)
+{
+ assert(v);
+
+ //
+ // Look for this instance in the to-be-marshaled map.
+ //
+ PtrToIndexMap::const_iterator p = _toBeMarshaledMap.find(v);
+ if(p != _toBeMarshaledMap.end())
+ {
+ return p->second;
+ }
+
+ //
+ // Didn't find it, try the marshaled map next.
+ //
+ PtrToIndexMap::const_iterator q = _marshaledMap.find(v);
+ if(q != _marshaledMap.end())
+ {
+ return q->second;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new
+ // index, and insert it into the to-be-marshaled map.
+ //
+ _toBeMarshaledMap.insert(make_pair(v, ++_objectIdIndex));
+ return _objectIdIndex;
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::write(const ValuePtr& v)
+{
+ if(!v)
+ {
+ _stream->writeSize(0); // Nil reference.
+ }
+ else if(_current && _encaps->format == SlicedFormat)
+ {
+ //
+ // If writting an object within a slice and using the sliced
+ // format, write an index from the object indirection
+ // table. The indirect object table is encoded at the end of
+ // each slice and is always read (even if the Slice is
+ // unknown).
+ //
+ PtrToIndexMap::const_iterator p = _current->indirectionMap.find(v);
+ if(p == _current->indirectionMap.end())
+ {
+ _current->indirectionTable.push_back(v);
+ Int idx = static_cast<Int>(_current->indirectionTable.size()); // Position + 1 (0 is reserved for nil)
+ _current->indirectionMap.insert(make_pair(v, idx));
+ _stream->writeSize(idx);
+ }
+ else
+ {
+ _stream->writeSize(p->second);
+ }
+ }
+ else
+ {
+ writeInstance(v); // Write the instance or a reference if already marshaled.
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::write(const UserException& v)
+{
+ v.__write(_stream);
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::startInstance(SliceType sliceType, const SlicedDataPtr& data)
+{
+ if(!_current)
+ {
+ _current = &_preAllocatedInstanceData;
+ }
+ else
+ {
+ _current = _current->next ? _current->next : new InstanceData(_current);
+ }
+ _current->sliceType = sliceType;
+ _current->firstSlice = true;
+
+ if(data)
+ {
+ writeSlicedData(data);
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::endInstance()
+{
+ _current = _current->previous;
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::startSlice(const string& typeId, int compactId, bool last)
+{
+ assert(_current->indirectionTable.empty() && _current->indirectionMap.empty());
+
+ _current->sliceFlagsPos = _stream->b.size();
+
+ _current->sliceFlags = 0;
+ if(_encaps->format == SlicedFormat)
+ {
+ _current->sliceFlags |= FLAG_HAS_SLICE_SIZE; // Encode the slice size if using the sliced format.
+ }
+ if(last)
+ {
+ _current->sliceFlags |= FLAG_IS_LAST_SLICE; // This is the last slice.
+ }
+
+ _stream->write(Byte(0)); // Placeholder for the slice flags
+
+ //
+ // For object slices, encode the flag and the type ID either as a
+ // string or index. For exception slices, always encode the type
+ // ID a string.
+ //
+ if(_current->sliceType == ObjectSlice)
+ {
+ //
+ // Encode the type ID (only in the first slice for the compact
+ // encoding).
+ //
+ if(_encaps->format == SlicedFormat || _current->firstSlice)
+ {
+ if(compactId >= 0)
+ {
+ _current->sliceFlags |= FLAG_HAS_TYPE_ID_COMPACT;
+ _stream->writeSize(compactId);
+ }
+ else
+ {
+ Int index = registerTypeId(typeId);
+ if(index < 0)
+ {
+ _current->sliceFlags |= FLAG_HAS_TYPE_ID_STRING;
+ _stream->write(typeId, false);
+ }
+ else
+ {
+ _current->sliceFlags |= FLAG_HAS_TYPE_ID_INDEX;
+ _stream->writeSize(index);
+ }
+ }
+ }
+ }
+ else
+ {
+ _stream->write(typeId, false);
+ }
+
+ if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE)
+ {
+ _stream->write(Int(0)); // Placeholder for the slice length.
+ }
+
+ _current->writeSlice = _stream->b.size();
+ _current->firstSlice = false;
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::endSlice()
+{
+ //
+ // Write the optional member end marker if some optional members
+ // were encoded. Note that the optional members are encoded before
+ // the indirection table and are included in the slice size.
+ //
+ if(_current->sliceFlags & FLAG_HAS_OPTIONAL_MEMBERS)
+ {
+ _stream->write(OPTIONAL_END_MARKER);
+ }
+
+ //
+ // Write the slice length if necessary.
+ //
+ if(_current->sliceFlags & FLAG_HAS_SLICE_SIZE)
+ {
+ Int sz = static_cast<Int>(_stream->b.size() - _current->writeSlice + sizeof(Int));
+ Byte* dest = &(*(_stream->b.begin() + _current->writeSlice - sizeof(Int)));
+ _stream->write(sz, dest);
+ }
+
+ //
+ // Only write the indirection table if it contains entries.
+ //
+ if(!_current->indirectionTable.empty())
+ {
+ assert(_encaps->format == SlicedFormat);
+ _current->sliceFlags |= FLAG_HAS_INDIRECTION_TABLE;
+
+ //
+ // Write the indirection object table.
+ //
+ _stream->writeSize(static_cast<Int>(_current->indirectionTable.size()));
+ ObjectList::const_iterator p;
+ for(p = _current->indirectionTable.begin(); p != _current->indirectionTable.end(); ++p)
+ {
+ writeInstance(*p);
+ }
+ _current->indirectionTable.clear();
+ _current->indirectionMap.clear();
+ }
+
+ //
+ // Finally, update the slice flags.
+ //
+ Byte* dest = &(*(_stream->b.begin() + _current->sliceFlagsPos));
+ *dest = _current->sliceFlags;
+}
+
+bool
+Ice::OutputStream::EncapsEncoder11::writeOpt(Ice::Int tag, Ice::OptionalFormat format)
+{
+ if(!_current)
+ {
+ return _stream->writeOptImpl(tag, format);
+ }
+ else
+ {
+ if(_stream->writeOptImpl(tag, format))
+ {
+ _current->sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::writeSlicedData(const SlicedDataPtr& slicedData)
+{
+ assert(slicedData);
+
+ //
+ // We only remarshal preserved slices if we are using the sliced
+ // format. Otherwise, we ignore the preserved slices, which
+ // essentially "slices" the object into the most-derived type
+ // known by the sender.
+ //
+ if(_encaps->format != SlicedFormat)
+ {
+ return;
+ }
+
+ for(SliceInfoSeq::const_iterator p = slicedData->slices.begin(); p != slicedData->slices.end(); ++p)
+ {
+ startSlice((*p)->typeId, (*p)->compactId, (*p)->isLastSlice);
+
+ //
+ // Write the bytes associated with this slice.
+ //
+ _stream->writeBlob((*p)->bytes);
+
+ if((*p)->hasOptionalMembers)
+ {
+ _current->sliceFlags |= FLAG_HAS_OPTIONAL_MEMBERS;
+ }
+
+ //
+ // Make sure to also re-write the object indirection table.
+ //
+ _current->indirectionTable = (*p)->objects;
+
+ endSlice();
+ }
+}
+
+void
+Ice::OutputStream::EncapsEncoder11::writeInstance(const ValuePtr& v)
+{
+ assert(v);
+
+ //
+ // If the instance was already marshaled, just write it's ID.
+ //
+ PtrToIndexMap::const_iterator q = _marshaledMap.find(v);
+ if(q != _marshaledMap.end())
+ {
+ _stream->writeSize(q->second);
+ return;
+ }
+
+ //
+ // We haven't seen this instance previously, create a new ID,
+ // insert it into the marshaled map, and write the instance.
+ //
+ _marshaledMap.insert(make_pair(v, ++_objectIdIndex));
+
+ try
+ {
+ v->ice_preMarshal();
+ }
+ catch(const std::exception& ex)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "std::exception raised by ice_preMarshal:\n" << ex;
+ }
+ catch(...)
+ {
+ Warning out(_stream->instance()->initializationData().logger);
+ out << "unknown exception raised by ice_preMarshal";
+ }
+
+ _stream->writeSize(1); // Object instance marker.
+ v->__write(_stream);
+}