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