summaryrefslogtreecommitdiff
path: root/cpp/src/Transform/Data.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2003-10-21 22:25:48 +0000
committerMark Spruiell <mes@zeroc.com>2003-10-21 22:25:48 +0000
commit623184c101c904eb0d456d325d3ced4d4475d3ae (patch)
tree56a4d02eeb1f966ad1f17405a9c6b2fe84e804e0 /cpp/src/Transform/Data.cpp
parentFreeze Index Windows port (diff)
downloadice-623184c101c904eb0d456d325d3ced4d4475d3ae.tar.bz2
ice-623184c101c904eb0d456d325d3ced4d4475d3ae.tar.xz
ice-623184c101c904eb0d456d325d3ced4d4475d3ae.zip
initial check-in
Diffstat (limited to 'cpp/src/Transform/Data.cpp')
-rw-r--r--cpp/src/Transform/Data.cpp3458
1 files changed, 3458 insertions, 0 deletions
diff --git a/cpp/src/Transform/Data.cpp b/cpp/src/Transform/Data.cpp
new file mode 100644
index 00000000000..0b62d6f0b5f
--- /dev/null
+++ b/cpp/src/Transform/Data.cpp
@@ -0,0 +1,3458 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Data.h>
+#include <Transform/TransformUtil.h>
+#include <IceUtil/InputUtil.h>
+
+using namespace std;
+using namespace IceUtil;
+
+namespace Transform
+{
+
+//
+// ObjectWriter
+//
+class ObjectWriter : public Ice::Object
+{
+public:
+
+ ObjectWriter(const ObjectDataPtr&);
+
+ virtual void __write(IceInternal::BasicStream*, bool) const;
+ virtual void __read(IceInternal::BasicStream*, bool = true);
+
+private:
+
+ ObjectDataPtr _value;
+};
+
+//
+// ObjectReader
+//
+class ObjectReader : public Ice::Object
+{
+public:
+
+ ObjectReader(const DataFactoryPtr&, const Slice::TypePtr&);
+
+ virtual void __write(IceInternal::BasicStream*) const;
+ virtual void __read(IceInternal::BasicStream*, bool = true);
+
+ ObjectDataPtr getValue() const;
+
+private:
+
+ DataFactoryPtr _factory;
+ Slice::TypePtr _type;
+ ObjectDataPtr _value;
+};
+typedef IceUtil::Handle<ObjectReader> ObjectReaderPtr;
+
+} // End of namespace Transform
+
+//
+// ObjectWriter
+//
+Transform::ObjectWriter::ObjectWriter(const ObjectDataPtr& value) :
+ _value(value)
+{
+}
+
+void
+Transform::ObjectWriter::__write(IceInternal::BasicStream* os, bool) const
+{
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(_value->_type);
+ Slice::ClassDefPtr type;
+ if(decl)
+ {
+ type = decl->definition();
+ }
+ while(type)
+ {
+ os->writeTypeId(type->scoped());
+ os->startWriteSlice();
+ Slice::DataMemberList members = type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = _value->_members.find((*p)->name());
+ assert(q != _value->_members.end());
+ q->second->marshal(*os);
+ }
+ os->endWriteSlice();
+
+ Slice::ClassList bases = type->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ type = bases.front();
+ }
+ else
+ {
+ type = 0;
+ }
+ }
+
+ //
+ // Ice::Object slice
+ //
+ os->writeTypeId(Ice::Object::ice_staticId());
+ os->startWriteSlice();
+ _value->_facetMap->marshal(*os);
+ os->endWriteSlice();
+}
+
+void
+Transform::ObjectWriter::__read(IceInternal::BasicStream*, bool)
+{
+ assert(false);
+}
+
+//
+// ObjectReader
+//
+Transform::ObjectReader::ObjectReader(const DataFactoryPtr& factory, const Slice::TypePtr& type) :
+ _factory(factory), _type(type)
+{
+}
+
+void
+Transform::ObjectReader::__write(IceInternal::BasicStream*) const
+{
+ assert(false);
+}
+
+void
+Transform::ObjectReader::__read(IceInternal::BasicStream* is, bool rid)
+{
+ const_cast<ObjectDataPtr&>(_value) = new ObjectData(_factory, _type, true);
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(_type);
+ Slice::ClassDefPtr type;
+ if(decl)
+ {
+ type = decl->definition();
+ }
+ while(type)
+ {
+ if(rid)
+ {
+ string id;
+ is->readTypeId(id);
+ assert(id == type->scoped());
+ }
+
+ is->startReadSlice();
+ Slice::DataMemberList members = type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::iterator q = _value->_members.find((*p)->name());
+ assert(q != _value->_members.end());
+ q->second->unmarshal(*is);
+ }
+ is->endReadSlice();
+
+ Slice::ClassList bases = type->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ type = bases.front();
+ }
+ else
+ {
+ type = 0;
+ }
+
+ rid = true;
+ }
+
+ //
+ // Ice::Object slice
+ //
+ if(rid)
+ {
+ string id;
+ is->readTypeId(id);
+ assert(id == Ice::Object::ice_staticId());
+ }
+ is->startReadSlice();
+ _value->_facetMap->unmarshal(*is);
+ is->endReadSlice();
+}
+
+Transform::ObjectDataPtr
+Transform::ObjectReader::getValue() const
+{
+ return _value;
+}
+
+//
+// DataInterceptor
+//
+Transform::DataInterceptor::~DataInterceptor()
+{
+}
+
+//
+// DataInitializer
+//
+Transform::DataInitializer::~DataInitializer()
+{
+}
+
+//
+// DataFactory
+//
+Transform::DataFactory::DataFactory(const Ice::CommunicatorPtr& communicator, const Slice::UnitPtr& unit,
+ const ErrorReporterPtr& errorReporter) :
+ _communicator(communicator), _unit(unit), _errorReporter(errorReporter), _initializersEnabled(true)
+{
+}
+
+Transform::DataPtr
+Transform::DataFactory::create(const Slice::TypePtr& type, bool readOnly)
+{
+ DataPtr data = createImpl(type, readOnly);
+ if(_initializersEnabled && !readOnly)
+ {
+ string name = typeName(type);
+ InitMap::iterator p = _initializers.find(name);
+ if(p != _initializers.end())
+ {
+ p->second->initialize(this, data, _communicator);
+ }
+ }
+ return data;
+}
+
+Transform::DataPtr
+Transform::DataFactory::createBoolean(bool b, bool readOnly)
+{
+ return new BooleanData(getBuiltin(Slice::Builtin::KindBool), _errorReporter, readOnly, b);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createInteger(Ice::Long i, bool readOnly)
+{
+ return new IntegerData(getBuiltin(Slice::Builtin::KindLong), _errorReporter, readOnly, i);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createDouble(double d, bool readOnly)
+{
+ return new DoubleData(getBuiltin(Slice::Builtin::KindDouble), _errorReporter, readOnly, d);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createString(const string& s, bool readOnly)
+{
+ return new StringData(this, getBuiltin(Slice::Builtin::KindString), _errorReporter, readOnly, s);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createNil(bool readOnly)
+{
+ return new ObjectRef(this, getBuiltin(Slice::Builtin::KindObject), readOnly);
+}
+
+Slice::BuiltinPtr
+Transform::DataFactory::getBuiltin(Slice::Builtin::Kind kind) const
+{
+ return _unit->builtin(kind);
+}
+
+void
+Transform::DataFactory::addInitializer(const string& type, const DataInitializerPtr& init)
+{
+ _initializers.insert(InitMap::value_type(type, init));
+}
+
+void
+Transform::DataFactory::enableInitializers()
+{
+ _initializersEnabled = true;
+}
+
+void
+Transform::DataFactory::disableInitializers()
+{
+ _initializersEnabled = false;
+}
+
+Transform::ErrorReporterPtr
+Transform::DataFactory::getErrorReporter() const
+{
+ return _errorReporter;
+}
+
+Transform::DataPtr
+Transform::DataFactory::createImpl(const Slice::TypePtr& type, bool readOnly)
+{
+ Slice::BuiltinPtr builtin = Slice::BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Slice::Builtin::KindBool:
+ return new BooleanData(builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ return new IntegerData(builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ return new DoubleData(builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindString:
+ return new StringData(this, builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindObject:
+ return new ObjectRef(this, builtin, readOnly);
+
+ case Slice::Builtin::KindObjectProxy:
+ return new ProxyData(builtin, _communicator, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ return 0;
+ }
+ }
+
+ Slice::SequencePtr seq = Slice::SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return new SequenceData(this, seq, _errorReporter, readOnly);
+ }
+
+ Slice::ProxyPtr proxy = Slice::ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ return new ProxyData(proxy, _communicator, _errorReporter, readOnly);
+ }
+
+ Slice::StructPtr st = Slice::StructPtr::dynamicCast(type);
+ if(st)
+ {
+ return new StructData(this, st, _errorReporter, readOnly);
+ }
+
+ Slice::EnumPtr en = Slice::EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ return new EnumData(en, _errorReporter, readOnly);
+ }
+
+ Slice::DictionaryPtr dict = Slice::DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ return new DictionaryData(this, dict, _errorReporter, readOnly);
+ }
+
+ Slice::ClassDeclPtr cl = Slice::ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ Slice::ClassDefPtr def = cl->definition();
+ if(!def)
+ {
+ _errorReporter->error("class " + cl->scoped() + " declared but not defined");
+ }
+ return new ObjectRef(this, cl, readOnly);
+ }
+
+ return 0;
+}
+
+//
+// Data
+//
+Transform::Data::Data(const ErrorReporterPtr& errorReporter, bool readOnly) :
+ _errorReporter(errorReporter), _readOnly(readOnly)
+{
+}
+
+Transform::Data::~Data()
+{
+}
+
+bool
+Transform::Data::readOnly() const
+{
+ return _readOnly;
+}
+
+void
+Transform::Data::print(ostream& os) const
+{
+ ObjectDataHistory history;
+ IceUtil::Output out(os);
+ printI(out, history);
+}
+
+bool
+Transform::Data::isCompatible(const Slice::TypePtr& dest, const Slice::TypePtr& src)
+{
+ Slice::BuiltinPtr b1 = Slice::BuiltinPtr::dynamicCast(dest);
+ if(b1)
+ {
+ Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src);
+ switch(b1->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ {
+ if(b2)
+ {
+ switch(b2->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindString:
+ {
+ return true;
+ }
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ {
+ return false;
+ }
+ }
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindBool:
+ {
+ if(b2 && (b2->kind() == Slice::Builtin::KindBool || b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ {
+ if(b2)
+ {
+ switch(b2->kind())
+ {
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ {
+ return true;
+ }
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ {
+ return false;
+ }
+ }
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindString:
+ {
+ if(b2)
+ {
+ switch(b2->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObjectProxy:
+ {
+ return true;
+ }
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindLocalObject:
+ {
+ return false;
+ }
+ }
+
+ return false;
+ }
+ else if(Slice::EnumPtr::dynamicCast(src))
+ {
+ return true;
+ }
+ else if(Slice::ProxyPtr::dynamicCast(src))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindObject:
+ {
+ //
+ // Allow transformation from Object to class. Validation has to
+ // be done during transformation, when the actual type of
+ // an instance can be compared for compatibility with the
+ // new type.
+ //
+ Slice::ClassDeclPtr cl = Slice::ClassDeclPtr::dynamicCast(src);
+ if(cl || (b2 && b2->kind() == Slice::Builtin::KindObject))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindObjectProxy:
+ {
+ Slice::ProxyPtr p = Slice::ProxyPtr::dynamicCast(src);
+ if(p || (b2 && b2->kind() == Slice::Builtin::KindObjectProxy) ||
+ (b2 && b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindLocalObject:
+ {
+ assert(false);
+ return false;
+ }
+ }
+
+ assert(false);
+ }
+
+ Slice::ClassDeclPtr cl1 = Slice::ClassDeclPtr::dynamicCast(dest);
+ if(cl1)
+ {
+ Slice::ClassDeclPtr cl2 = Slice::ClassDeclPtr::dynamicCast(src);
+ if(cl2 && checkClasses(cl1, cl2))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ Slice::StructPtr s1 = Slice::StructPtr::dynamicCast(dest);
+ if(s1)
+ {
+ Slice::StructPtr s2 = Slice::StructPtr::dynamicCast(src);
+ if(s2 && s1->scoped() == s2->scoped())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ Slice::ProxyPtr p1 = Slice::ProxyPtr::dynamicCast(dest);
+ if(p1)
+ {
+ Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src);
+ if(b2 && (b2->kind() == Slice::Builtin::KindObjectProxy || b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ Slice::ProxyPtr p2 = Slice::ProxyPtr::dynamicCast(src);
+ if(p2 && checkClasses(p1->_class(), p2->_class()))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ Slice::DictionaryPtr d1 = Slice::DictionaryPtr::dynamicCast(dest);
+ if(d1)
+ {
+ Slice::DictionaryPtr d2 = Slice::DictionaryPtr::dynamicCast(src);
+ if(d2)
+ {
+ return isCompatible(d1->keyType(), d2->keyType()) && isCompatible(d1->valueType(), d2->valueType());
+ }
+
+ return false;
+ }
+
+ Slice::SequencePtr seq1 = Slice::SequencePtr::dynamicCast(dest);
+ if(seq1)
+ {
+ Slice::SequencePtr seq2 = Slice::SequencePtr::dynamicCast(src);
+ if(seq2)
+ {
+ return isCompatible(seq1->type(), seq2->type());
+ }
+
+ return false;
+ }
+
+ Slice::EnumPtr e1 = Slice::EnumPtr::dynamicCast(dest);
+ if(e1)
+ {
+ Slice::EnumPtr e2 = Slice::EnumPtr::dynamicCast(src);
+ Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src);
+ if((e2 && e1->scoped() == e2->scoped()) || (b2 && b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ assert(false);
+ return false;
+}
+
+bool
+Transform::Data::checkClasses(const Slice::ClassDeclPtr& dest, const Slice::ClassDeclPtr& src)
+{
+ string s1 = dest->scoped();
+ string s2 = src->scoped();
+ if(s1 == s2)
+ {
+ return true;
+ }
+ else
+ {
+ Slice::ClassDefPtr def = src->definition();
+ if(!def)
+ {
+ _errorReporter->error("class " + s2 + " declared but not defined");
+ }
+ Slice::ClassList bases = def->allBases();
+ for(Slice::ClassList::iterator p = bases.begin(); p != bases.end(); ++p)
+ {
+ if((*p)->scoped() == s1)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//
+// PrimitiveData
+//
+Transform::PrimitiveData::PrimitiveData(const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly)
+{
+}
+
+Transform::DataPtr
+Transform::PrimitiveData::getMember(const string&) const
+{
+ return 0;
+}
+
+Transform::DataPtr
+Transform::PrimitiveData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of primitive value");
+ return 0;
+}
+
+void
+Transform::PrimitiveData::registerObjects(ObjectDataMap&) const
+{
+}
+
+void
+Transform::PrimitiveData::destroy()
+{
+}
+
+//
+// BooleanData
+//
+Transform::BooleanData::BooleanData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(false)
+{
+}
+
+Transform::BooleanData::BooleanData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly, bool value) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(value)
+{
+}
+
+bool
+Transform::BooleanData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::BooleanData::operator!=(const Data& rhs) const
+{
+ const BooleanData* b = dynamic_cast<const BooleanData*>(&rhs);
+ if(!b)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != b->_value;
+}
+
+bool
+Transform::BooleanData::operator<(const Data& rhs) const
+{
+ const BooleanData* b = dynamic_cast<const BooleanData*>(&rhs);
+ if(!b)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < b->_value;
+}
+
+void
+Transform::BooleanData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ BooleanDataPtr b = BooleanDataPtr::dynamicCast(data);
+ if(b)
+ {
+ _value = b->booleanValue();
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::BooleanData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ StringDataPtr s = StringDataPtr::dynamicCast(value);
+ if(convert && s)
+ {
+ string v = s->stringValue();
+ if(v == "true")
+ {
+ _value = true;
+ }
+ else if(v == "false")
+ {
+ _value = false;
+ }
+ else
+ {
+ _errorReporter->conversionError(v, _type);
+ }
+ }
+ else
+ {
+ _value = value->booleanValue(convert);
+ }
+}
+
+Transform::DataPtr
+Transform::BooleanData::clone() const
+{
+ return new BooleanData(_type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::BooleanData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::BooleanData::marshal(IceInternal::BasicStream& os) const
+{
+ os.write(_value);
+}
+
+void
+Transform::BooleanData::unmarshal(IceInternal::BasicStream& is)
+{
+ is.read(_value);
+}
+
+bool
+Transform::BooleanData::booleanValue(bool) const
+{
+ return _value;
+}
+
+Ice::Long
+Transform::BooleanData::integerValue(bool) const
+{
+ _errorReporter->error("boolean cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::BooleanData::doubleValue(bool) const
+{
+ _errorReporter->error("boolean cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::BooleanData::stringValue(bool convert) const
+{
+ if(convert)
+ {
+ return toString();
+ }
+ else
+ {
+ return string();
+ }
+}
+
+string
+Transform::BooleanData::toString() const
+{
+ return (_value ? "true" : "false");
+}
+
+void
+Transform::BooleanData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "bool(" << toString() << ")";
+}
+
+//
+// IntegerData
+//
+Transform::IntegerData::IntegerData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(0)
+{
+}
+
+Transform::IntegerData::IntegerData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly, Ice::Long value) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(value)
+{
+}
+
+bool
+Transform::IntegerData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::IntegerData::operator!=(const Data& rhs) const
+{
+ const IntegerData* i = dynamic_cast<const IntegerData*>(&rhs);
+ if(!i)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != i->_value;
+}
+
+bool
+Transform::IntegerData::operator<(const Data& rhs) const
+{
+ const IntegerData* i = dynamic_cast<const IntegerData*>(&rhs);
+ if(!i)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < i->_value;
+}
+
+void
+Transform::IntegerData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ Ice::Long value;
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(i)
+ {
+ value = i->_value;
+ }
+ else if(s)
+ {
+ string str = s->stringValue();
+ string::size_type pos;
+ if(!IceUtil::stringToInt64(str, value, pos))
+ {
+ _errorReporter->conversionError(str, _type);
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+
+ if(rangeCheck(value))
+ {
+ _value = value;
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::IntegerData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ _value = value->integerValue(convert);
+}
+
+Transform::DataPtr
+Transform::IntegerData::clone() const
+{
+ return new IntegerData(_type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::IntegerData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::IntegerData::marshal(IceInternal::BasicStream& os) const
+{
+ rangeCheck(_value);
+
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindByte:
+ {
+ os.write(static_cast<Ice::Byte>(_value));
+ break;
+ }
+ case Slice::Builtin::KindShort:
+ {
+ os.write(static_cast<Ice::Short>(_value));
+ break;
+ }
+ case Slice::Builtin::KindInt:
+ {
+ os.write(static_cast<Ice::Int>(_value));
+ break;
+ }
+ case Slice::Builtin::KindLong:
+ {
+ os.write(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+void
+Transform::IntegerData::unmarshal(IceInternal::BasicStream& is)
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindByte:
+ {
+ Ice::Byte val;
+ is.read(val);
+ _value = val & 0xff;
+ break;
+ }
+ case Slice::Builtin::KindShort:
+ {
+ Ice::Short val;
+ is.read(val);
+ _value = val;
+ break;
+ }
+ case Slice::Builtin::KindInt:
+ {
+ Ice::Int val;
+ is.read(val);
+ _value = val;
+ break;
+ }
+ case Slice::Builtin::KindLong:
+ {
+ is.read(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+bool
+Transform::IntegerData::booleanValue(bool) const
+{
+ _errorReporter->error("integer cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::IntegerData::integerValue(bool) const
+{
+ return _value;
+}
+
+double
+Transform::IntegerData::doubleValue(bool convert) const
+{
+ if(convert)
+ {
+ return _value;
+ }
+ else
+ {
+ _errorReporter->error("integer cannot be converted to double");
+ return 0;
+ }
+}
+
+string
+Transform::IntegerData::stringValue(bool convert) const
+{
+ if(convert)
+ {
+ return toString();
+ }
+ else
+ {
+ _errorReporter->error("integer cannot be converted to string");
+ return string();
+ }
+}
+
+string
+Transform::IntegerData::toString() const
+{
+ return toString(_value);
+}
+
+bool
+Transform::IntegerData::rangeCheck(Ice::Long value) const
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindByte:
+ {
+ if(value < 0 || value > 255)
+ {
+ _errorReporter->rangeError(toString(value), _type);
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindShort:
+ {
+ if(value < SHRT_MIN || value > SHRT_MAX)
+ {
+ _errorReporter->rangeError(toString(value), _type);
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindInt:
+ {
+ if(value < INT_MIN || value > INT_MAX)
+ {
+ _errorReporter->rangeError(toString(value), _type);
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindLong:
+ {
+ return true;
+ }
+
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+
+ return false;
+}
+
+string
+Transform::IntegerData::toString(Ice::Long value)
+{
+ char buf[64];
+#ifdef WIN32
+ sprintf(buf, "%I64d", value);
+#else
+ sprintf(buf, "%lld", value);
+#endif
+ return string(buf);
+}
+
+void
+Transform::IntegerData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "integer(" << toString() << ")";
+}
+
+//
+// DoubleData
+//
+Transform::DoubleData::DoubleData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(0)
+{
+}
+
+Transform::DoubleData::DoubleData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly, double value) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(value)
+{
+}
+
+bool
+Transform::DoubleData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::DoubleData::operator!=(const Data& rhs) const
+{
+ const DoubleData* d = dynamic_cast<const DoubleData*>(&rhs);
+ if(!d)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != d->_value;
+}
+
+bool
+Transform::DoubleData::operator<(const Data& rhs) const
+{
+ const DoubleData* d = dynamic_cast<const DoubleData*>(&rhs);
+ if(!d)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < d->_value;
+}
+
+void
+Transform::DoubleData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ DoubleDataPtr d = DoubleDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(d)
+ {
+ _value = d->doubleValue();
+ }
+ else if(s)
+ {
+ string str = s->stringValue();
+ const char* start = str.c_str();
+ char* end;
+ double v = strtod(start, &end);
+ if(errno == ERANGE)
+ {
+ _errorReporter->rangeError(str, _type);
+ }
+ else
+ {
+ while(*end)
+ {
+ if(!isspace(*end))
+ {
+ _errorReporter->conversionError(str, _type);
+ break;
+ }
+ end++;
+ }
+ if(!*end)
+ {
+ _value = v;
+ }
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::DoubleData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ _value = value->doubleValue(convert);
+}
+
+Transform::DataPtr
+Transform::DoubleData::clone() const
+{
+ return new DoubleData(_type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::DoubleData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::DoubleData::marshal(IceInternal::BasicStream& os) const
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindFloat:
+ {
+ os.write(static_cast<Ice::Float>(_value));
+ break;
+ }
+ case Slice::Builtin::KindDouble:
+ {
+ os.write(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+void
+Transform::DoubleData::unmarshal(IceInternal::BasicStream& is)
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindFloat:
+ {
+ Ice::Float val;
+ is.read(val);
+ _value = val;
+ break;
+ }
+ case Slice::Builtin::KindDouble:
+ {
+ is.read(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+bool
+Transform::DoubleData::booleanValue(bool) const
+{
+ _errorReporter->error("double cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::DoubleData::integerValue(bool convert) const
+{
+ if(convert)
+ {
+ return static_cast<Ice::Long>(_value);
+ }
+ else
+ {
+ _errorReporter->error("double cannot be converted to integer");
+ return 0;
+ }
+}
+
+double
+Transform::DoubleData::doubleValue(bool) const
+{
+ return _value;
+}
+
+string
+Transform::DoubleData::stringValue(bool convert) const
+{
+ if(convert)
+ {
+ return toString();
+ }
+ else
+ {
+ _errorReporter->error("double cannot be converted to string");
+ return string();
+ }
+}
+
+string
+Transform::DoubleData::toString() const
+{
+ char buff[64];
+ sprintf(buff, "%g", _value);
+ return string(buff);
+}
+
+void
+Transform::DoubleData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "double(" << toString() << ")";
+}
+
+//
+// StringData
+//
+Transform::StringData::StringData(const DataFactoryPtr& factory, const Slice::BuiltinPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ setValue("");
+}
+
+Transform::StringData::StringData(const DataFactoryPtr& factory, const Slice::BuiltinPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const string& value) :
+ PrimitiveData(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ setValue(value);
+}
+
+Transform::DataPtr
+Transform::StringData::getMember(const string& member) const
+{
+ if(member == "length")
+ {
+ return _length;
+ }
+
+ return 0;
+}
+
+bool
+Transform::StringData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::StringData::operator!=(const Data& rhs) const
+{
+ const StringData* s = dynamic_cast<const StringData*>(&rhs);
+ if(!s)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != s->_value;
+}
+
+bool
+Transform::StringData::operator<(const Data& rhs) const
+{
+ const StringData* s = dynamic_cast<const StringData*>(&rhs);
+ if(!s)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < s->_value;
+}
+
+void
+Transform::StringData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ BooleanDataPtr b = BooleanDataPtr::dynamicCast(data);
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(data);
+ DoubleDataPtr d = DoubleDataPtr::dynamicCast(data);
+ EnumDataPtr e = EnumDataPtr::dynamicCast(data);
+ ProxyDataPtr p = ProxyDataPtr::dynamicCast(data);
+ if(s || b || i || d || e || p)
+ {
+ setValue(data->toString());
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::StringData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ setValue(value->stringValue(convert));
+}
+
+Transform::DataPtr
+Transform::StringData::clone() const
+{
+ return new StringData(_factory, _type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::StringData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::StringData::marshal(IceInternal::BasicStream& os) const
+{
+ os.write(_value);
+}
+
+void
+Transform::StringData::unmarshal(IceInternal::BasicStream& is)
+{
+ string s;
+ is.read(s);
+ setValue(s);
+}
+
+bool
+Transform::StringData::booleanValue(bool) const
+{
+ _errorReporter->error("string cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::StringData::integerValue(bool) const
+{
+ _errorReporter->error("string cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::StringData::doubleValue(bool) const
+{
+ _errorReporter->error("string cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::StringData::stringValue(bool) const
+{
+ return _value;
+}
+
+string
+Transform::StringData::toString() const
+{
+ return _value;
+}
+
+void
+Transform::StringData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "'" << toString() << "'";
+}
+
+void
+Transform::StringData::setValue(const string& value)
+{
+ _value = value;
+ _length = _factory->createInteger(static_cast<Ice::Long>(_value.size()), true);
+}
+
+//
+// ProxyData
+//
+Transform::ProxyData::ProxyData(const Slice::TypePtr& type, const Ice::CommunicatorPtr& communicator,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _type(type), _communicator(communicator)
+{
+}
+
+Transform::ProxyData::ProxyData(const Slice::TypePtr& type, const Ice::CommunicatorPtr& communicator,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const Ice::ObjectPrx& value) :
+ Data(errorReporter, readOnly), _type(type), _communicator(communicator), _value(value)
+{
+}
+
+Transform::DataPtr
+Transform::ProxyData::getMember(const string& member) const
+{
+ // TODO: Support members (id, facet, etc.)?
+#if 0
+ if(member == "length")
+ {
+ return new IntegerData(_value.length());
+ }
+#endif
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::ProxyData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of proxy value");
+ return 0;
+}
+
+bool
+Transform::ProxyData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::ProxyData::operator!=(const Data& rhs) const
+{
+ const ProxyData* p = dynamic_cast<const ProxyData*>(&rhs);
+ if(!p)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != p->_value;
+}
+
+bool
+Transform::ProxyData::operator<(const Data& rhs) const
+{
+ const ProxyData* p = dynamic_cast<const ProxyData*>(&rhs);
+ if(!p)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < p->_value;
+}
+
+void
+Transform::ProxyData::registerObjects(ObjectDataMap&) const
+{
+}
+
+void
+Transform::ProxyData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::ProxyData::set(const DataPtr& value, DataInterceptor&, bool)
+{
+ transformI(value);
+}
+
+Transform::DataPtr
+Transform::ProxyData::clone() const
+{
+ return new ProxyData(_type, _communicator, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::ProxyData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::ProxyData::destroy()
+{
+}
+
+void
+Transform::ProxyData::marshal(IceInternal::BasicStream& os) const
+{
+ os.write(_value);
+}
+
+void
+Transform::ProxyData::unmarshal(IceInternal::BasicStream& is)
+{
+ is.read(_value);
+}
+
+bool
+Transform::ProxyData::booleanValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::ProxyData::integerValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::ProxyData::doubleValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::ProxyData::stringValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to string");
+ return string();
+}
+
+string
+Transform::ProxyData::toString() const
+{
+ if(_value && _str.empty())
+ {
+ const_cast<string&>(_str) = _communicator->proxyToString(_value);
+ }
+ return _str;
+}
+
+Ice::ObjectPrx
+Transform::ProxyData::getValue() const
+{
+ return _value;
+}
+
+void
+Transform::ProxyData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << typeName(_type) << "*(" << toString() << ")";
+}
+
+void
+Transform::ProxyData::transformI(const DataPtr& data)
+{
+ ProxyDataPtr p = ProxyDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(p)
+ {
+ _value = p->getValue();
+ _str.clear();
+ }
+ else if(s)
+ {
+ setValue(s->stringValue());
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+void
+Transform::ProxyData::setValue(const string& str)
+{
+ try
+ {
+ _value = _communicator->stringToProxy(str);
+ _str = str;
+ }
+ catch(const Ice::LocalException&)
+ {
+ _errorReporter->conversionError(str, _type);
+ }
+}
+
+//
+// StructData
+//
+Transform::StructData::StructData(const DataFactoryPtr& factory, const Slice::StructPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _type(type)
+{
+ Slice::DataMemberList members = type->dataMembers();
+ for(Slice::DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ DataPtr value = factory->create((*q)->type(), _readOnly);
+ assert(value);
+ _members[(*q)->name()] = value;
+ }
+}
+
+Transform::StructData::StructData(const Slice::StructPtr& type, const ErrorReporterPtr& errorReporter, bool readOnly,
+ const DataMemberMap& members) :
+ Data(errorReporter, readOnly), _type(type)
+{
+ for(DataMemberMap::const_iterator p = members.begin(); p != members.end(); ++p)
+ {
+ _members[p->first] = p->second->clone();
+ }
+}
+
+Transform::DataPtr
+Transform::StructData::getMember(const string& member) const
+{
+ DataMemberMap::const_iterator p = _members.find(member);
+ if(p != _members.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::StructData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of struct value");
+ return 0;
+}
+
+bool
+Transform::StructData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::StructData::operator!=(const Data& rhs) const
+{
+ const StructData* s = dynamic_cast<const StructData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ assert(_members.size() == s->_members.size());
+
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = s->_members.find(p->first);
+ assert(q != s->_members.end());
+
+ if(p->second != q->second)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+Transform::StructData::operator<(const Data& rhs) const
+{
+ const StructData* s = dynamic_cast<const StructData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ assert(_members.size() == s->_members.size());
+
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = s->_members.find(p->first);
+ assert(q != s->_members.end());
+
+ if(p->second < q->second)
+ {
+ return true;
+ }
+ else if(q->second < p->second)
+ {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+void
+Transform::StructData::registerObjects(ObjectDataMap& map) const
+{
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ p->second->registerObjects(map);
+ }
+}
+
+void
+Transform::StructData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::StructData::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::StructData::clone() const
+{
+ return new StructData(_type, _errorReporter, _readOnly, _members);
+}
+
+Slice::TypePtr
+Transform::StructData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::StructData::destroy()
+{
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ p->second->destroy();
+ }
+}
+
+void
+Transform::StructData::marshal(IceInternal::BasicStream& os) const
+{
+ Slice::DataMemberList members = _type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = _members.find((*p)->name());
+ assert(q != _members.end());
+ q->second->marshal(os);
+ }
+}
+
+void
+Transform::StructData::unmarshal(IceInternal::BasicStream& is)
+{
+ Slice::DataMemberList members = _type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = _members.find((*p)->name());
+ assert(q != _members.end());
+ q->second->unmarshal(is);
+ }
+}
+
+bool
+Transform::StructData::booleanValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::StructData::integerValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::StructData::doubleValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::StructData::stringValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::StructData::toString() const
+{
+ return stringValue();
+}
+
+Transform::DataMemberMap
+Transform::StructData::getMembers() const
+{
+ return _members;
+}
+
+void
+Transform::StructData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "struct " << typeName(_type);
+ out << sb;
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ out << nl;
+ out << p->first << " = ";
+ p->second->printI(out, history);
+ }
+ out << eb;
+}
+
+void
+Transform::StructData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ StructDataPtr s = StructDataPtr::dynamicCast(data);
+ if(s && _type->scoped() == s->_type->scoped())
+ {
+ //
+ // Invoke transform() on members with the same name.
+ //
+ for(DataMemberMap::iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::iterator q = s->_members.find(p->first);
+ if(q != s->_members.end())
+ {
+ p->second->transform(q->second, interceptor);
+ }
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+//
+// SequenceData
+//
+Transform::SequenceData::SequenceData(const DataFactoryPtr& factory, const Slice::SequencePtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ _length = _factory->createInteger(0, true);
+}
+
+Transform::SequenceData::SequenceData(const DataFactoryPtr& factory, const Slice::SequencePtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const DataList& elements) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ for(DataList::const_iterator p = elements.begin(); p != elements.end(); ++p)
+ {
+ _elements.push_back((*p)->clone());
+ }
+ _length = _factory->createInteger(static_cast<Ice::Long>(_elements.size()), true);
+}
+
+Transform::DataPtr
+Transform::SequenceData::getMember(const string& member) const
+{
+ if(member == "length")
+ {
+ return _length;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::SequenceData::getElement(const DataPtr& element) const
+{
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(element);
+ if(!i)
+ {
+ _errorReporter->error("invalid sequence index type " + typeName(element->getType()));
+ }
+
+ Ice::Long iv = i->integerValue();
+ if(iv < 0 || iv >= _elements.size())
+ {
+ _errorReporter->error("sequence index " + i->toString() + " out of range");
+ }
+
+ return _elements[static_cast<DataList::size_type>(iv)];
+}
+
+bool
+Transform::SequenceData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::SequenceData::operator!=(const Data& rhs) const
+{
+ const SequenceData* s = dynamic_cast<const SequenceData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _elements != s->_elements;
+}
+
+bool
+Transform::SequenceData::operator<(const Data& rhs) const
+{
+ const SequenceData* s = dynamic_cast<const SequenceData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _elements < s->_elements;
+}
+
+void
+Transform::SequenceData::registerObjects(ObjectDataMap& map) const
+{
+ if(_type->type()->usesClasses())
+ {
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p)
+ {
+ (*p)->registerObjects(map);
+ }
+ }
+}
+
+void
+Transform::SequenceData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::SequenceData::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::SequenceData::clone() const
+{
+ return new SequenceData(_factory, _type, _errorReporter, _readOnly, _elements);
+}
+
+Slice::TypePtr
+Transform::SequenceData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::SequenceData::destroy()
+{
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p)
+ {
+ (*p)->destroy();
+ }
+}
+
+void
+Transform::SequenceData::marshal(IceInternal::BasicStream& os) const
+{
+ os.writeSize(_elements.size());
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p)
+ {
+ (*p)->marshal(os);
+ }
+}
+
+void
+Transform::SequenceData::unmarshal(IceInternal::BasicStream& is)
+{
+ Slice::TypePtr type = _type->type();
+ Ice::Int sz;
+ is.readSize(sz);
+ _elements.reserve(sz);
+ for(Ice::Int i = 0; i < sz; ++i)
+ {
+ DataPtr v = _factory->create(type, _readOnly);
+ v->unmarshal(is);
+ _elements.push_back(v);
+ }
+ _length = _factory->createInteger(sz, true);
+}
+
+bool
+Transform::SequenceData::booleanValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::SequenceData::integerValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::SequenceData::doubleValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::SequenceData::stringValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::SequenceData::toString() const
+{
+ return stringValue();
+}
+
+Transform::DataList
+Transform::SequenceData::getElements() const
+{
+ return _elements;
+}
+
+void
+Transform::SequenceData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "sequence " << typeName(_type) << " (size = " << _elements.size() << ")";
+ out << sb;
+ Ice::Int i = 0;
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p, ++i)
+ {
+ out << nl << "[" << i << "] = ";
+ (*p)->printI(out, history);
+ }
+ out << eb;
+}
+
+void
+Transform::SequenceData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ SequenceDataPtr s = SequenceDataPtr::dynamicCast(data);
+ if(s && isCompatible(_type, s->_type))
+ {
+ DataList elements;
+ for(DataList::const_iterator p = s->_elements.begin(); p != s->_elements.end(); ++p)
+ {
+ DataPtr element = _factory->create(_type->type(), _readOnly);
+ //
+ // We add the element regardless of whether transform() succeeds in order to
+ // preserve the original sequence size and order.
+ //
+ element->transform((*p), interceptor);
+ elements.push_back(element);
+ }
+ _elements = elements;
+ _length = _factory->createInteger(static_cast<Ice::Long>(_elements.size()), true);
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+//
+// EnumData
+//
+Transform::EnumData::EnumData(const Slice::EnumPtr& type, const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _type(type), _value(0)
+{
+ _count = static_cast<long>(type->getEnumerators().size());
+}
+
+Transform::EnumData::EnumData(const Slice::EnumPtr& type, const ErrorReporterPtr& errorReporter, bool readOnly,
+ Ice::Int value) :
+ Data(errorReporter, readOnly), _type(type), _value(value)
+{
+ _count = static_cast<long>(type->getEnumerators().size());
+}
+
+Transform::DataPtr
+Transform::EnumData::getMember(const string&) const
+{
+ return 0;
+}
+
+Transform::DataPtr
+Transform::EnumData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of enum value");
+ return 0;
+}
+
+bool
+Transform::EnumData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::EnumData::operator!=(const Data& rhs) const
+{
+ const EnumData* e = dynamic_cast<const EnumData*>(&rhs);
+ if(!e || _type->scoped() != e->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != e->_value;
+}
+
+bool
+Transform::EnumData::operator<(const Data& rhs) const
+{
+ const EnumData* e = dynamic_cast<const EnumData*>(&rhs);
+ if(!e || _type->scoped() != e->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < e->_value;
+}
+
+void
+Transform::EnumData::registerObjects(ObjectDataMap& map) const
+{
+}
+
+void
+Transform::EnumData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::EnumData::set(const DataPtr& value, DataInterceptor& interceptor, bool convert)
+{
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(value);
+ if(i && convert)
+ {
+ Ice::Long v = i->integerValue();
+ if(v < 0 || v > _count)
+ {
+ _errorReporter->rangeError(i->toString(), _type);
+ }
+ else
+ {
+ _value = v;
+ _name.clear();
+ }
+ }
+ else if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::EnumData::clone() const
+{
+ return new EnumData(_type, _errorReporter, _value);
+}
+
+Slice::TypePtr
+Transform::EnumData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::EnumData::destroy()
+{
+}
+
+void
+Transform::EnumData::marshal(IceInternal::BasicStream& os) const
+{
+ if(_count <= 127)
+ {
+ os.write(static_cast<Ice::Byte>(_value));
+ }
+ else if(_count <= 32767)
+ {
+ os.write(static_cast<Ice::Short>(_value));
+ }
+ else
+ {
+ os.write(_value);
+ }
+}
+
+void
+Transform::EnumData::unmarshal(IceInternal::BasicStream& is)
+{
+ if(_count <= 127)
+ {
+ Ice::Byte val;
+ is.read(val);
+ _value = val & 0xff;
+ }
+ else if(_count <= 32767)
+ {
+ Ice::Short val;
+ is.read(val);
+ _value = val;
+ }
+ else
+ {
+ is.read(_value);
+ }
+}
+
+bool
+Transform::EnumData::booleanValue(bool) const
+{
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::EnumData::integerValue(bool convert) const
+{
+ if(convert)
+ {
+ return _value;
+ }
+ else
+ {
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+ }
+}
+
+double
+Transform::EnumData::doubleValue(bool) const
+{
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::EnumData::stringValue(bool) const
+{
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::EnumData::toString() const
+{
+ if(_name.empty())
+ {
+ Slice::EnumeratorList l = _type->getEnumerators();
+ Slice::EnumeratorList::const_iterator p = l.begin();
+ Ice::Int i = _value;
+ while(i > 0)
+ {
+ ++p;
+ assert(p != l.end());
+ --i;
+ }
+ const_cast<string&>(_name) = (*p)->name();
+ }
+ return _name;
+}
+
+Ice::Int
+Transform::EnumData::getValue() const
+{
+ return _value;
+}
+
+bool
+Transform::EnumData::setValue(Ice::Int v)
+{
+ if(v >= 0 && v < _count)
+ {
+ _value = v;
+ _name.clear();
+ return true;
+ }
+ return false;
+}
+
+bool
+Transform::EnumData::setValueAsString(const string& v)
+{
+ Slice::EnumeratorList l = _type->getEnumerators();
+ Slice::EnumeratorList::const_iterator p;
+ Ice::Int i = 0;
+ for(p = l.begin(); p != l.end(); ++p, ++i)
+ {
+ if((*p)->name() == v)
+ {
+ _value = i;
+ _name = v;
+ break;
+ }
+ }
+ return p != l.end();
+}
+
+void
+Transform::EnumData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << typeName(_type) << "(" << toString() << ")";
+}
+
+void
+Transform::EnumData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ EnumDataPtr e = EnumDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(e && _type->scoped() == e->_type->scoped())
+ {
+ //
+ // Get the enumerator's name and attempt to find it in our type.
+ //
+ string name = e->toString();
+ if(!setValueAsString(name))
+ {
+ _errorReporter->conversionError(name, _type);
+ }
+ }
+ else if(s)
+ {
+ string v = s->stringValue();
+ if(!setValueAsString(v))
+ {
+ _errorReporter->conversionError(v, _type);
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+//
+// DictionaryData
+//
+Transform::DictionaryData::DictionaryData(const DataFactoryPtr& factory, const Slice::DictionaryPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ _length = _factory->createInteger(0, true);
+}
+
+Transform::DictionaryData::DictionaryData(const DataFactoryPtr& factory, const Slice::DictionaryPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const DataMap& map) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ for(DataMap::const_iterator p = map.begin(); p != map.end(); ++p)
+ {
+ _map.insert(DataMap::value_type(p->first->clone(), p->second->clone()));
+ }
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+}
+
+Transform::DataPtr
+Transform::DictionaryData::getMember(const string& member) const
+{
+ if(member == "length")
+ {
+ return _length;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::DictionaryData::getElement(const DataPtr& element) const
+{
+ // TODO: Validate element's type
+
+ DataMap::const_iterator p = _map.find(element);
+ if(p != _map.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+bool
+Transform::DictionaryData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::DictionaryData::operator!=(const Data& rhs) const
+{
+ const DictionaryData* d = dynamic_cast<const DictionaryData*>(&rhs);
+ if(!d || _type->scoped() != d->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _map != d->_map;
+}
+
+bool
+Transform::DictionaryData::operator<(const Data& rhs) const
+{
+ const DictionaryData* d = dynamic_cast<const DictionaryData*>(&rhs);
+ if(!d || _type->scoped() != d->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _map < d->_map;
+}
+
+void
+Transform::DictionaryData::registerObjects(ObjectDataMap& map) const
+{
+ if(_type->valueType()->usesClasses())
+ {
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ p->second->registerObjects(map);
+ }
+ }
+}
+
+void
+Transform::DictionaryData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::DictionaryData::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::DictionaryData::clone() const
+{
+ return new DictionaryData(_factory, _type, _errorReporter, _readOnly, _map);
+}
+
+Slice::TypePtr
+Transform::DictionaryData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::DictionaryData::destroy()
+{
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ p->first->destroy();
+ p->second->destroy();
+ }
+}
+
+void
+Transform::DictionaryData::marshal(IceInternal::BasicStream& os) const
+{
+ os.writeSize(_map.size());
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ p->first->marshal(os);
+ p->second->marshal(os);
+ }
+}
+
+void
+Transform::DictionaryData::unmarshal(IceInternal::BasicStream& is)
+{
+ Slice::TypePtr keyType = _type->keyType();
+ Slice::TypePtr valueType = _type->valueType();
+
+ Ice::Int sz;
+ is.readSize(sz);
+
+ for(Ice::Int i = 0; i < sz; ++i)
+ {
+ DataPtr key = _factory->create(keyType, _readOnly);
+ key->unmarshal(is);
+
+ DataPtr value = _factory->create(valueType, _readOnly);
+ value->unmarshal(is);
+
+ _map.insert(DataMap::value_type(key, value));
+ }
+
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+}
+
+bool
+Transform::DictionaryData::booleanValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::DictionaryData::integerValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::DictionaryData::doubleValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::DictionaryData::stringValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::DictionaryData::toString() const
+{
+ return stringValue();
+}
+
+void
+Transform::DictionaryData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "dictionary " << typeName(_type) << " (size = " << _map.size() << ")";
+ out << sb;
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ out << nl;
+ p->first->printI(out, history);
+ out << " => ";
+ p->second->printI(out, history);
+ }
+ out << eb;
+}
+
+void
+Transform::DictionaryData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ DictionaryDataPtr d = DictionaryDataPtr::dynamicCast(data);
+ if(d && isCompatible(_type, d->_type))
+ {
+ DataMap map;
+ for(DataMap::const_iterator p = d->_map.begin(); p != d->_map.end(); ++p)
+ {
+ DataPtr key = _factory->create(_type->keyType(), _readOnly);
+ DataPtr value = _factory->create(_type->valueType(), _readOnly);
+ key->transform(p->first, interceptor);
+ value->transform(p->second, interceptor);
+ DataMap::const_iterator q = map.find(key);
+ if(q != map.end())
+ {
+ ostringstream ostr;
+ ostr << "duplicate dictionary key (";
+ key->print(ostr);
+ ostr << ")";
+ _errorReporter->warning(ostr.str());
+ }
+ else
+ {
+ map.insert(DataMap::value_type(key, value));
+ }
+ }
+ _map = map;
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+Transform::DataMap
+Transform::DictionaryData::getElements() const
+{
+ return _map;
+}
+
+void
+Transform::DictionaryData::put(const DataPtr& key, const DataPtr& value, DataInterceptor& interceptor, bool convert)
+{
+ assert(!readOnly());
+
+ if(!isCompatible(_type->keyType(), key->getType()))
+ {
+ _errorReporter->typeMismatchError(_type->keyType(), key->getType(), true);
+ }
+ if(!isCompatible(_type->valueType(), value->getType()))
+ {
+ _errorReporter->typeMismatchError(_type->valueType(), value->getType(), true);
+ }
+
+ DataPtr newKey = _factory->create(_type->keyType(), false);
+ newKey->set(key, interceptor, convert);
+ DataPtr newValue = _factory->create(_type->valueType(), false);
+ newValue->set(value, interceptor, convert);
+
+ DataMap::iterator p = _map.find(newKey);
+ if(p != _map.end())
+ {
+ p->first->destroy();
+ p->second->destroy();
+ }
+
+ _map.insert(DataMap::value_type(newKey, newValue));
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+}
+
+void
+Transform::DictionaryData::remove(const DataPtr& key)
+{
+ DataMap::iterator p = _map.find(key);
+ if(p != _map.end())
+ {
+ p->first->destroy();
+ p->second->destroy();
+ _map.erase(p);
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+ }
+}
+
+//
+// ObjectData
+//
+Transform::ObjectData::ObjectData(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly) :
+ Data(factory->getErrorReporter(), readOnly), _type(type), _refCount(0)
+{
+ //
+ // Create a Data object for the facet map. We add this to the _members map so that
+ // the `ice_facets' member is handled like all other members.
+ //
+ Slice::TypeList l = _type->unit()->lookupType("::_FacetMap", false);
+ assert(!l.empty());
+ _facetMap = factory->create(l.front(), readOnly);
+ _members["ice_facets"] = _facetMap;
+
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(type);
+ if(decl)
+ {
+ Slice::ClassDefPtr def = decl->definition();
+ assert(def);
+ Slice::DataMemberList members = def->allDataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ _members[(*p)->name()] = factory->create((*p)->type(), _readOnly);
+ }
+ _id = factory->createString(decl->scoped(), true);
+ }
+ else
+ {
+ _id = factory->createString("::Ice::Object", true);
+ }
+}
+
+Transform::DataPtr
+Transform::ObjectData::getMember(const string& member) const
+{
+ if(member == "ice_id")
+ {
+ return _id;
+ }
+
+ DataMemberMap::const_iterator p = _members.find(member);
+ if(p != _members.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::ObjectData::getElement(const DataPtr& element) const
+{
+ _errorReporter->error("element requested of object value");
+ return 0;
+}
+
+bool
+Transform::ObjectData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::ObjectData::operator!=(const Data& rhs) const
+{
+ _errorReporter->error("object comparison not supported");
+ return false;
+}
+
+bool
+Transform::ObjectData::operator<(const Data& rhs) const
+{
+ _errorReporter->error("object comparison not supported");
+ return false;
+}
+
+void
+Transform::ObjectData::registerObjects(ObjectDataMap& map) const
+{
+ ObjectDataMap::iterator p = map.find(this);
+ if(p == map.end())
+ {
+ map.insert(ObjectDataMap::value_type(this, 0));
+ for(DataMemberMap::const_iterator q = _members.begin(); q != _members.end(); ++q)
+ {
+ q->second->registerObjects(map);
+ }
+ }
+}
+
+void
+Transform::ObjectData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ ObjectDataPtr o = ObjectDataPtr::dynamicCast(data);
+ if(o)
+ {
+ assert(isCompatible(_type, o->_type));
+
+ //
+ // The source object must be present in the object map (we currently don't support
+ // transforming two ObjectData instances from the same Slice unit - this transform
+ // would be handled by-reference at the ObjectRef level). We must update the object
+ // map before transforming members in order to handle cycles.
+ //
+ ObjectDataMap& objectMap = interceptor.getObjectMap();
+ ObjectDataMap::iterator p = objectMap.find(o.get());
+ assert(p != objectMap.end());
+ assert(p->second == 0);
+ objectMap.erase(p);
+ objectMap.insert(ObjectDataMap::value_type(o.get(), this));
+
+ try
+ {
+ //
+ // Invoke transform() on members with the same name.
+ //
+ for(DataMemberMap::iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::iterator q = o->_members.find(p->first);
+ if(q != o->_members.end())
+ {
+ p->second->transform(q->second, interceptor);
+ }
+ }
+ }
+ catch(...)
+ {
+ objectMap.insert(ObjectDataMap::value_type(o.get(), 0));
+ throw;
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+void
+Transform::ObjectData::set(const DataPtr&, DataInterceptor&, bool)
+{
+ assert(false);
+}
+
+Transform::DataPtr
+Transform::ObjectData::clone() const
+{
+ assert(false);
+ return 0;
+}
+
+Slice::TypePtr
+Transform::ObjectData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::ObjectData::destroy()
+{
+ assert(false);
+}
+
+void
+Transform::ObjectData::marshal(IceInternal::BasicStream& os) const
+{
+ if(!_marshaler)
+ {
+ const_cast<Ice::ObjectPtr&>(_marshaler) = new ObjectWriter(const_cast<ObjectData*>(this));
+ }
+ os.write(_marshaler);
+}
+
+void
+Transform::ObjectData::unmarshal(IceInternal::BasicStream& is)
+{
+ //
+ // Unmarshaling is done by ObjectReader.
+ //
+ assert(false);
+}
+
+bool
+Transform::ObjectData::booleanValue(bool) const
+{
+ assert(false);
+ return 0;
+}
+
+Ice::Long
+Transform::ObjectData::integerValue(bool) const
+{
+ assert(false);
+ return 0;
+}
+
+double
+Transform::ObjectData::doubleValue(bool) const
+{
+ assert(false);
+ return 0;
+}
+
+string
+Transform::ObjectData::stringValue(bool) const
+{
+ assert(false);
+ return string();
+}
+
+string
+Transform::ObjectData::toString() const
+{
+ assert(false);
+ return string();
+}
+
+void
+Transform::ObjectData::incRef()
+{
+ _refCount++;
+}
+
+void
+Transform::ObjectData::decRef()
+{
+ assert(_refCount > 0);
+ _refCount--;
+ if(_refCount == 0)
+ {
+ destroyI();
+ }
+}
+
+void
+Transform::ObjectData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "class " << typeName(_type);
+ ObjectDataHistory::iterator p = history.find(this);
+ if(p != history.end())
+ {
+ out << " (cycle)";
+ }
+ else
+ {
+ history.insert(ObjectDataHistory::value_type(this, true));
+ out << sb;
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ out << nl << p->first << " = ";
+ p->second->printI(out, history);
+ }
+ out << eb;
+ }
+}
+
+void
+Transform::ObjectData::destroyI()
+{
+ DataMemberMap members = _members;
+
+ _members.clear();
+ _marshaler = 0;
+
+ for(DataMemberMap::const_iterator p = members.begin(); p != members.end(); ++p)
+ {
+ p->second->destroy();
+ }
+}
+
+//
+// ObjectRef
+//
+Transform::ObjectRef::ObjectRef(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly) :
+ Data(factory->getErrorReporter(), readOnly), _factory(factory), _type(type)
+{
+}
+
+Transform::ObjectRef::ObjectRef(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly,
+ const ObjectDataPtr& value) :
+ Data(factory->getErrorReporter(), readOnly), _factory(factory), _type(type), _value(value)
+{
+ _value->incRef();
+}
+
+Transform::DataPtr
+Transform::ObjectRef::getMember(const string& member) const
+{
+ if(!_value)
+ {
+ _errorReporter->error("member `" + member + "' requested of nil object");
+ }
+
+ return _value->getMember(member);
+}
+
+Transform::DataPtr
+Transform::ObjectRef::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of object value");
+ return 0;
+}
+
+bool
+Transform::ObjectRef::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::ObjectRef::operator!=(const Data& rhs) const
+{
+ const ObjectRef* r = dynamic_cast<const ObjectRef*>(&rhs);
+ if(!r)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ }
+
+ if(!_value || !r->_value)
+ {
+ return !_value && r->_value;
+ }
+
+ //
+ // Reference comparison.
+ //
+ return _value.get() != r->_value.get();
+}
+
+bool
+Transform::ObjectRef::operator<(const Data& rhs) const
+{
+ _errorReporter->error("object comparison not supported");
+ return false;
+}
+
+void
+Transform::ObjectRef::registerObjects(ObjectDataMap& map) const
+{
+ if(_value)
+ {
+ _value->registerObjects(map);
+ }
+}
+
+void
+Transform::ObjectRef::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::ObjectRef::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ transformI(value, interceptor);
+}
+
+Transform::DataPtr
+Transform::ObjectRef::clone() const
+{
+ return new ObjectRef(_factory, _type, _value);
+}
+
+Slice::TypePtr
+Transform::ObjectRef::getType() const
+{
+ return _type;
+}
+
+void
+Transform::ObjectRef::destroy()
+{
+ if(_value)
+ {
+ _value->decRef();
+ _value = 0;
+ }
+}
+
+void
+Transform::ObjectRef::marshal(IceInternal::BasicStream& os) const
+{
+ if(!_value)
+ {
+ os.write(Ice::ObjectPtr());
+ return;
+ }
+
+ _value->marshal(os);
+}
+
+static void
+patchObject(void* addr, Ice::ObjectPtr& v)
+{
+ if(v)
+ {
+ Transform::ObjectRef* ref = static_cast<Transform::ObjectRef*>(addr);
+ assert(ref);
+
+ Transform::ObjectReaderPtr reader = Transform::ObjectReaderPtr::dynamicCast(v);
+ assert(reader);
+
+ ref->setValue(reader->getValue());
+ }
+}
+
+void
+Transform::ObjectRef::unmarshal(IceInternal::BasicStream& is)
+{
+ is.read(patchObject, this);
+}
+
+bool
+Transform::ObjectRef::booleanValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::ObjectRef::integerValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::ObjectRef::doubleValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::ObjectRef::stringValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::ObjectRef::toString() const
+{
+ return stringValue();
+}
+
+void
+Transform::ObjectRef::instantiate()
+{
+ ObjectDataPtr data = new ObjectData(_factory, _type, _readOnly);
+ setValue(data);
+}
+
+void
+Transform::ObjectRef::setValue(const ObjectDataPtr& value)
+{
+ // TODO: Type check?
+ ObjectDataPtr oldValue = _value;
+ _value = value;
+ if(_value)
+ {
+ _value->incRef();
+ }
+ if(oldValue)
+ {
+ oldValue->decRef();
+ }
+}
+
+void
+Transform::ObjectRef::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ if(!_value)
+ {
+ out << typeName(_type) << "(nil)";
+ }
+ else
+ {
+ ostringstream ostr;
+ _value->printI(out, history);
+ }
+}
+
+void
+Transform::ObjectRef::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ ObjectRefPtr o = ObjectRefPtr::dynamicCast(data);
+ if(!o)
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+
+ if(!o->_value)
+ {
+ //
+ // Allow a nil value from type Object.
+ //
+ if(Slice::BuiltinPtr::dynamicCast(o->_type) || isCompatible(_type, o->_type))
+ {
+ setValue(0);
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, o->_type, false);
+ }
+ }
+ else
+ {
+ Slice::TypePtr otype = o->_value->getType();
+ if(isCompatible(_type, otype))
+ {
+ //
+ // If the types are in the same Slice unit, then we can simply
+ // copy the reference. Otherwise, we check the object map to
+ // see if an equivalent object has already been created, and
+ // if not, then we have to create one.
+ //
+ if(_type->unit().get() == otype->unit().get())
+ {
+ setValue(o->_value);
+ }
+ else
+ {
+ ObjectDataMap& objectMap = interceptor.getObjectMap();
+ ObjectDataMap::iterator p = objectMap.find(o->_value.get());
+ if(p != objectMap.end() && p->second)
+ {
+ setValue(p->second);
+ }
+ else
+ {
+ string name = typeName(otype);
+ Slice::TypeList l = _type->unit()->lookupType(name, false);
+ if(l.empty())
+ {
+ // TODO: Slice object? Or missing type exception?
+ _errorReporter->warning("type `" + name + "' not found");
+ }
+ else
+ {
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(l.front());
+ if(decl)
+ {
+ Slice::ClassDefPtr def = decl->definition();
+ if(!def)
+ {
+ _errorReporter->error("no definition for " + name);
+ }
+ }
+ ObjectDataPtr data = new ObjectData(_factory, l.front(), _readOnly);
+ data->transform(o->_value, interceptor);
+ setValue(data);
+ }
+ }
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, otype, false);
+ }
+ }
+}
+
+//
+// ObjectFactory
+//
+Transform::ObjectFactory::ObjectFactory(const DataFactoryPtr& factory, const Slice::UnitPtr& unit) :
+ _factory(factory), _unit(unit)
+{
+}
+
+Ice::ObjectPtr
+Transform::ObjectFactory::create(const string& id)
+{
+ Ice::ObjectPtr result;
+
+ if(id == Ice::Object::ice_staticId())
+ {
+ result = new ObjectReader(_factory, _unit->builtin(Slice::Builtin::KindObject));
+ }
+ else
+ {
+ Slice::TypeList l = _unit->lookupTypeNoBuiltin(id);
+ if(!l.empty())
+ {
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(l.front());
+ if(!decl)
+ {
+ _factory->getErrorReporter()->error("Slice definition for `" + id + "' is not a class");
+ }
+ Slice::ClassDefPtr def = decl->definition();
+ if(!def)
+ {
+ _factory->getErrorReporter()->error("no class definition for `" + id + "'");
+ }
+ result = new ObjectReader(_factory, decl);
+ }
+ }
+
+ return result;
+}
+
+void
+Transform::ObjectFactory::destroy()
+{
+}