summaryrefslogtreecommitdiff
path: root/cpp/src/slice2cs/CsUtil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/slice2cs/CsUtil.cpp')
-rw-r--r--cpp/src/slice2cs/CsUtil.cpp2637
1 files changed, 2637 insertions, 0 deletions
diff --git a/cpp/src/slice2cs/CsUtil.cpp b/cpp/src/slice2cs/CsUtil.cpp
new file mode 100644
index 00000000000..9d62ae21ed9
--- /dev/null
+++ b/cpp/src/slice2cs/CsUtil.cpp
@@ -0,0 +1,2637 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <CsUtil.h>
+#include <DotNetNames.h>
+#include <Slice/Util.h>
+#include <IceUtil/Functional.h>
+#include <IceUtil/StringUtil.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+# include <direct.h>
+#else
+# include <unistd.h>
+#endif
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+using namespace IceUtilInternal;
+
+namespace
+{
+
+string
+lookupKwd(const string& name, int baseTypes, bool mangleCasts = false)
+{
+ //
+ // Keyword list. *Must* be kept in alphabetical order.
+ //
+ static const string keywordList[] =
+ {
+ "abstract", "as", "async", "await", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const",
+ "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern",
+ "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface",
+ "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override",
+ "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short",
+ "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof",
+ "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while"
+ };
+ bool found = binary_search(&keywordList[0],
+ &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
+ name,
+ Slice::CICompare());
+ if(found)
+ {
+ return "@" + name;
+ }
+ if(mangleCasts && (name == "checkedCast" || name == "uncheckedCast"))
+ {
+ return string(DotNet::manglePrefix) + name;
+ }
+ return Slice::DotNet::mangleName(name, baseTypes);
+}
+
+//
+// Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
+//
+StringList
+splitScopedName(const string& scoped)
+{
+ assert(scoped[0] == ':');
+ StringList ids;
+ string::size_type next = 0;
+ string::size_type pos;
+ while((pos = scoped.find("::", next)) != string::npos)
+ {
+ pos += 2;
+ if(pos != scoped.size())
+ {
+ string::size_type endpos = scoped.find("::", pos);
+ if(endpos != string::npos)
+ {
+ ids.push_back(scoped.substr(pos, endpos - pos));
+ }
+ }
+ next = pos;
+ }
+ if(next != scoped.size())
+ {
+ ids.push_back(scoped.substr(next));
+ }
+ else
+ {
+ ids.push_back("");
+ }
+
+ return ids;
+}
+
+}
+
+//
+// If the passed name is a scoped name, return the identical scoped name,
+// but with all components that are C# keywords replaced by
+// their "@"-prefixed version; otherwise, if the passed name is
+// not scoped, but a C# keyword, return the "@"-prefixed name;
+// otherwise, check if the name is one of the method names of baseTypes;
+// if so, prefix it with ice_; otherwise, return the name unchanged.
+//
+string
+Slice::CsGenerator::fixId(const string& name, int baseTypes, bool mangleCasts)
+{
+ if(name.empty())
+ {
+ return name;
+ }
+ if(name[0] != ':')
+ {
+ return lookupKwd(name, baseTypes, mangleCasts);
+ }
+ StringList ids = splitScopedName(name);
+ StringList newIds;
+ for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
+ {
+ newIds.push_back(lookupKwd(*i, baseTypes));
+ }
+ stringstream result;
+ for(StringList::const_iterator j = newIds.begin(); j != newIds.end(); ++j)
+ {
+ if(j != newIds.begin())
+ {
+ result << '.';
+ }
+ result << *j;
+ }
+ return result.str();
+}
+
+string
+Slice::CsGenerator::fixId(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
+{
+ ContainerPtr container = cont->container();
+ ContainedPtr contained = ContainedPtr::dynamicCast(container);
+ if(contained && contained->hasMetaData("cs:property") &&
+ (contained->containedType() == Contained::ContainedTypeClass || contained->containedType() == Contained::ContainedTypeStruct))
+ {
+ return "_" + cont->name();
+ }
+ else
+ {
+ return fixId(cont->name(), baseTypes, mangleCasts);
+ }
+}
+
+string
+Slice::CsGenerator::getOptionalFormat(const TypePtr& type)
+{
+ BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
+ if(bp)
+ {
+ switch(bp->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindBool:
+ {
+ return "Ice.OptionalFormat.F1";
+ }
+ case Builtin::KindShort:
+ {
+ return "Ice.OptionalFormat.F2";
+ }
+ case Builtin::KindInt:
+ case Builtin::KindFloat:
+ {
+ return "Ice.OptionalFormat.F4";
+ }
+ case Builtin::KindLong:
+ case Builtin::KindDouble:
+ {
+ return "Ice.OptionalFormat.F8";
+ }
+ case Builtin::KindString:
+ {
+ return "Ice.OptionalFormat.VSize";
+ }
+ case Builtin::KindObject:
+ {
+ return "Ice.OptionalFormat.Class";
+ }
+ case Builtin::KindObjectProxy:
+ {
+ return "Ice.OptionalFormat.FSize";
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ case Builtin::KindValue:
+ {
+ return "Ice.OptionalFormat.Class";
+ }
+ }
+ }
+
+ if(EnumPtr::dynamicCast(type))
+ {
+ return "Ice.OptionalFormat.Size";
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return seq->type()->isVariableLength() ? "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize";
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ?
+ "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize";
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ return st->isVariableLength() ? "Ice.OptionalFormat.FSize" : "Ice.OptionalFormat.VSize";
+ }
+
+ if(ProxyPtr::dynamicCast(type))
+ {
+ return "Ice.OptionalFormat.FSize";
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ assert(cl);
+ return "Ice.OptionalFormat.Class";
+}
+
+string
+Slice::CsGenerator::getStaticId(const TypePtr& type)
+{
+ BuiltinPtr b = BuiltinPtr::dynamicCast(type);
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+
+ assert(isClassType(type));
+
+ if(b)
+ {
+ return "Ice.Value.ice_staticId()";
+ }
+ else if(cl->isInterface())
+ {
+ ContainedPtr cont = ContainedPtr::dynamicCast(cl->container());
+ assert(cont);
+ return fixId(cont->scoped(), DotNet::ICloneable) + "." + cl->name() + "Disp_.ice_staticId()";
+ }
+ else
+ {
+ return fixId(cl->scoped(), DotNet::ICloneable) + ".ice_staticId()";
+ }
+}
+
+string
+Slice::CsGenerator::typeToString(const TypePtr& type, bool optional, bool local)
+{
+ if(!type)
+ {
+ return "void";
+ }
+
+ if(optional)
+ {
+ return "Ice.Optional<" + typeToString(type, false, local) + ">";
+ }
+
+ static const char* localBuiltinTable[] =
+ {
+ "byte",
+ "bool",
+ "short",
+ "int",
+ "long",
+ "float",
+ "double",
+ "string",
+ "Ice.Object",
+ "Ice.ObjectPrx",
+ "_System.Object",
+ "Ice.Value"
+ };
+
+ static const char* builtinTable[] =
+ {
+ "byte",
+ "bool",
+ "short",
+ "int",
+ "long",
+ "float",
+ "double",
+ "string",
+ "Ice.Value",
+ "Ice.ObjectPrx",
+ "_System.Object",
+ "Ice.Value"
+ };
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return local ? localBuiltinTable[builtin->kind()] : builtinTable[builtin->kind()];
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ if(cl->isInterface() && !local)
+ {
+ return "Ice.Value";
+ }
+ else
+ {
+ return fixId(cl->scoped());
+ }
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ ClassDefPtr def = proxy->_class()->definition();
+ if(def->isInterface() || def->allOperations().size() > 0)
+ {
+ return fixId(proxy->_class()->scoped() + "Prx");
+ }
+ else
+ {
+ return "Ice.ObjectPrx";
+ }
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ string prefix = "cs:generic:";
+ string meta;
+ if(seq->findMetaData(prefix, meta))
+ {
+ string type = meta.substr(prefix.size());
+ if(type == "List" || type == "LinkedList" || type == "Queue" || type == "Stack")
+ {
+ return "_System.Collections.Generic." + type + "<" + typeToString(seq->type(), optional, local) + ">";
+ }
+ else
+ {
+ return "global::" + type + "<" + typeToString(seq->type(), optional, local) + ">";
+ }
+ }
+
+ prefix = "cs:serializable:";
+ if(seq->findMetaData(prefix, meta))
+ {
+ string type = meta.substr(prefix.size());
+ return "global::" + type;
+ }
+
+ return typeToString(seq->type(), optional, local) + "[]";
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ string prefix = "cs:generic:";
+ string meta;
+ string typeName;
+ if(d->findMetaData(prefix, meta))
+ {
+ typeName = meta.substr(prefix.size());
+ }
+ else
+ {
+ typeName = "Dictionary";
+ }
+ return "_System.Collections.Generic." + typeName
+ + "<" + typeToString(d->keyType(), optional, local) + ", " + typeToString(d->valueType(), optional, local) + ">";
+ }
+
+ ContainedPtr contained = ContainedPtr::dynamicCast(type);
+ if(contained)
+ {
+ return fixId(contained->scoped());
+ }
+
+ return "???";
+}
+
+string
+Slice::CsGenerator::resultStructName(const string& className, const string& opName, bool marshaledResult)
+{
+ ostringstream s;
+ s << className
+ << "_"
+ << IceUtilInternal::toUpper(opName.substr(0, 1))
+ << opName.substr(1)
+ << (marshaledResult ? "MarshaledResult" : "Result");
+ return s.str();
+}
+
+string
+Slice::CsGenerator::resultType(const OperationPtr& op, bool dispatch)
+{
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); // Get the class containing the op.
+ if(dispatch && op->hasMarshaledResult())
+ {
+ return resultStructName(cl->name(), op->name(), true);
+ }
+
+ string t;
+ ParamDeclList outParams = op->outParameters();
+ if(op->returnType() || !outParams.empty())
+ {
+ if(outParams.empty())
+ {
+ t = typeToString(op->returnType(), op->returnIsOptional(), cl->isLocal());
+ }
+ else if(op->returnType() || outParams.size() > 1)
+ {
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container());
+ t = fixId(cl->scope()) + resultStructName(cl->name(), op->name());
+ }
+ else
+ {
+ t = typeToString(outParams.front()->type(), outParams.front()->optional(), cl->isLocal());
+ }
+ }
+
+ return t;
+}
+
+string
+Slice::CsGenerator::taskResultType(const OperationPtr& op, bool dispatch)
+{
+ string t = resultType(op, dispatch);
+ if(t.empty())
+ {
+ return "_System.Threading.Tasks.Task";
+ }
+ else
+ {
+ return "_System.Threading.Tasks.Task<" + resultType(op, dispatch) + '>';
+ }
+}
+
+bool
+Slice::CsGenerator::isClassType(const TypePtr& type)
+{
+ if(ClassDeclPtr::dynamicCast(type))
+ {
+ return true;
+ }
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ return builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue);
+}
+
+bool
+Slice::CsGenerator::isValueType(const TypePtr& type)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindString:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ case Builtin::KindValue:
+ {
+ return false;
+ break;
+ }
+ default:
+ {
+ return true;
+ break;
+ }
+ }
+ }
+ StructPtr s = StructPtr::dynamicCast(type);
+ if(s)
+ {
+ if(s->hasMetaData("cs:class"))
+ {
+ return false;
+ }
+ DataMemberList dm = s->dataMembers();
+ for(DataMemberList::const_iterator i = dm.begin(); i != dm.end(); ++i)
+ {
+ if(!isValueType((*i)->type()) || (*i)->defaultValueType())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ if(EnumPtr::dynamicCast(type))
+ {
+ return true;
+ }
+ return false;
+}
+
+void
+Slice::CsGenerator::writeMarshalUnmarshalCode(Output &out,
+ const TypePtr& type,
+ const string& param,
+ bool marshal,
+ const string& customStream)
+{
+ string stream = customStream;
+ if(stream.empty())
+ {
+ stream = marshal ? "ostr" : "istr";
+ }
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeByte(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readByte()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindBool:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeBool(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readBool()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeShort(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readShort()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeInt(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readInt()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeLong(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readLong()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeFloat(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readFloat()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeDouble(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readDouble()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeString(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readString()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindValue:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeValue(" << param << ");";
+ }
+ else
+ {
+ out << nl << stream << ".readValue(" << param << ");";
+ }
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ string typeS = typeToString(type);
+ if(marshal)
+ {
+ out << nl << stream << ".writeProxy(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readProxy()" << ';';
+ }
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ ClassDefPtr def = prx->_class()->definition();
+ if(def->isInterface() || def->allOperations().size() > 0)
+ {
+ string typeS = typeToString(type);
+ if (marshal)
+ {
+ out << nl << typeS << "Helper.write(" << stream << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << typeS << "Helper.read(" << stream << ");";
+ }
+ }
+ else
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeProxy(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readProxy()" << ';';
+ }
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeValue(" << param << ");";
+ }
+ else
+ {
+ out << nl << stream << ".readValue(" << param << ");";
+ }
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ if(marshal)
+ {
+ if(!isValueType(st))
+ {
+ out << nl << typeToString(st) << ".ice_write(" << stream << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << ".ice_writeMembers(" << stream << ");";
+ }
+ }
+ else
+ {
+ if(!isValueType(st))
+ {
+ out << nl << param << " = " << typeToString(type) << ".ice_read(" << stream << ");";
+ }
+ else
+ {
+ out << nl << param << ".ice_readMembers(" << stream << ");";
+ }
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeEnum((int)" << param << ", " << en->maxValue() << ");";
+ }
+ else
+ {
+ out << nl << param << " = (" << fixId(en->scoped()) << ')' << stream << ".readEnum(" << en->maxValue()
+ << ");";
+ }
+ return;
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ writeSequenceMarshalUnmarshalCode(out, seq, param, marshal, true, stream);
+ return;
+ }
+
+ assert(ConstructedPtr::dynamicCast(type));
+ string typeS;
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ typeS = fixId(d->scope()) + d->name();
+ }
+ else
+ {
+ typeS = typeToString(type);
+ }
+ if(marshal)
+ {
+ out << nl << typeS << "Helper.write(" << stream << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << typeS << "Helper.read(" << stream << ')' << ';';
+ }
+}
+
+void
+Slice::CsGenerator::writeOptionalMarshalUnmarshalCode(Output &out,
+ const TypePtr& type,
+ const string& param,
+ int tag,
+ bool marshal,
+ const string& customStream)
+{
+ string stream = customStream;
+ if(stream.empty())
+ {
+ stream = marshal ? "ostr" : "istr";
+ }
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeByte(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readByte(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindBool:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeBool(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readBool(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeShort(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readShort(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeInt(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readInt(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeLong(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readLong(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeFloat(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readFloat(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeDouble(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readDouble(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeString(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << stream << ".readString(" << tag << ");";
+ }
+ break;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindValue:
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeValue(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << stream << ".readValue(" << tag << ", " << param << ");";
+ }
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ string typeS = typeToString(type);
+ if(marshal)
+ {
+ out << nl << stream << ".writeProxy(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = new Ice.Optional<Ice.ObjectPrx>(" << stream << ".readProxy(" << tag
+ << "));";
+ }
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag
+ << ", Ice.OptionalFormat.FSize))";
+ out << sb;
+ out << nl << "int pos = " << stream << ".startSize();";
+ writeMarshalUnmarshalCode(out, type, param + ".Value", marshal, customStream);
+ out << nl << stream << ".endSize(pos);";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", Ice.OptionalFormat.FSize))";
+ out << sb;
+ out << nl << stream << ".skip(4);";
+ string tmp = "tmpVal";
+ string typeS = typeToString(type);
+ out << nl << typeS << ' ' << tmp << ';';
+ writeMarshalUnmarshalCode(out, type, tmp, marshal, customStream);
+ out << nl << param << " = new Ice.Optional<" << typeS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << typeS << ">();";
+ out << eb;
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeValue(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << stream << ".readValue(" << tag << ", " << param << ");";
+ }
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
+ << getOptionalFormat(st) << "))";
+ out << sb;
+ if(st->isVariableLength())
+ {
+ out << nl << "int pos = " << stream << ".startSize();";
+ }
+ else
+ {
+ out << nl << stream << ".writeSize(" << st->minWireSize() << ");";
+ }
+ writeMarshalUnmarshalCode(out, type, param + ".Value", marshal, customStream);
+ if(st->isVariableLength())
+ {
+ out << nl << stream << ".endSize(pos);";
+ }
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(st) << "))";
+ out << sb;
+ if(st->isVariableLength())
+ {
+ out << nl << stream << ".skip(4);";
+ }
+ else
+ {
+ out << nl << stream << ".skipSize();";
+ }
+ string typeS = typeToString(type);
+ string tmp = "tmpVal";
+ if(isValueType(st))
+ {
+ out << nl << typeS << ' ' << tmp << " = new " << typeS << "();";
+ }
+ else
+ {
+ out << nl << typeS << ' ' << tmp << " = null;";
+ }
+ writeMarshalUnmarshalCode(out, type, tmp, marshal, customStream);
+ out << nl << param << " = new Ice.Optional<" << typeS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << typeS << ">();";
+ out << eb;
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ size_t sz = en->enumerators().size();
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue)";
+ out << sb;
+ out << nl << stream << ".writeEnum(" << tag << ", (int)" << param << ".Value, " << sz << ");";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", Ice.OptionalFormat.Size))";
+ out << sb;
+ string typeS = typeToString(type);
+ string tmp = "tmpVal";
+ out << nl << typeS << ' ' << tmp << ';';
+ writeMarshalUnmarshalCode(out, type, tmp, marshal, customStream);
+ out << nl << param << " = new Ice.Optional<" << typeS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << typeS << ">();";
+ out << eb;
+ }
+ return;
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ writeOptionalSequenceMarshalUnmarshalCode(out, seq, param, tag, marshal, stream);
+ return;
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ assert(d);
+ TypePtr keyType = d->keyType();
+ TypePtr valueType = d->valueType();
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
+ << getOptionalFormat(d) << "))";
+ out << sb;
+ if(keyType->isVariableLength() || valueType->isVariableLength())
+ {
+ out << nl << "int pos = " << stream << ".startSize();";
+ }
+ else
+ {
+ out << nl << stream << ".writeSize(" << param << ".Value == null ? 1 : " << param << ".Value.Count * "
+ << (keyType->minWireSize() + valueType->minWireSize()) << " + (" << param
+ << ".Value.Count > 254 ? 5 : 1));";
+ }
+ writeMarshalUnmarshalCode(out, type, param + ".Value", marshal, customStream);
+ if(keyType->isVariableLength() || valueType->isVariableLength())
+ {
+ out << nl << stream << ".endSize(pos);";
+ }
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(d) << "))";
+ out << sb;
+ if(keyType->isVariableLength() || valueType->isVariableLength())
+ {
+ out << nl << stream << ".skip(4);";
+ }
+ else
+ {
+ out << nl << stream << ".skipSize();";
+ }
+ string typeS = typeToString(type);
+ string tmp = "tmpVal";
+ out << nl << typeS << ' ' << tmp << " = new " << typeS << "();";
+ writeMarshalUnmarshalCode(out, type, tmp, marshal, customStream);
+ out << nl << param << " = new Ice.Optional<" << typeS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << typeS << ">();";
+ out << eb;
+ }
+}
+
+void
+Slice::CsGenerator::writeSequenceMarshalUnmarshalCode(Output& out,
+ const SequencePtr& seq,
+ const string& param,
+ bool marshal,
+ bool useHelper,
+ const string& customStream)
+{
+ string stream = customStream;
+ if(stream.empty())
+ {
+ stream = marshal ? "ostr" : "istr";
+ }
+
+ if(useHelper)
+ {
+ ContainedPtr cont = ContainedPtr::dynamicCast(seq->container());
+ assert(cont);
+ string helperName = fixId(cont->scoped(), DotNet::ICloneable) + "." + seq->name() + "Helper";
+ if(marshal)
+ {
+ out << nl << helperName << ".write(" << stream << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = " << helperName << ".read(" << stream << ");";
+ }
+ return;
+ }
+
+ TypePtr type = seq->type();
+ string typeS = typeToString(type);
+
+ const string genericPrefix = "cs:generic:";
+ string genericType;
+ string addMethod = "Add";
+ const bool isGeneric = seq->findMetaData(genericPrefix, genericType);
+ bool isStack = false;
+ bool isList = false;
+ bool isLinkedList = false;
+ bool isCustom = false;
+ if(isGeneric)
+ {
+ genericType = genericType.substr(genericPrefix.size());
+ if(genericType == "LinkedList")
+ {
+ addMethod = "AddLast";
+ isLinkedList = true;
+ }
+ else if(genericType == "Queue")
+ {
+ addMethod = "Enqueue";
+ }
+ else if(genericType == "Stack")
+ {
+ addMethod = "Push";
+ isStack = true;
+ }
+ else if(genericType == "List")
+ {
+ isList = true;
+ }
+ else
+ {
+ isCustom = true;
+ }
+ }
+
+ const bool isArray = !isGeneric;
+ const string limitID = isArray ? "Length" : "Count";
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ ClassDefPtr clsDef;
+ if(proxy)
+ {
+ clsDef = proxy->_class()->definition();
+ }
+ bool isObjectProxySeq = clsDef && !clsDef->isInterface() && clsDef->allOperations().size() == 0;
+ Builtin::Kind kind = builtin ? builtin->kind() : Builtin::KindObjectProxy;
+
+ if(builtin || isObjectProxySeq)
+ {
+ switch(kind)
+ {
+ case Builtin::KindValue:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << " == null)";
+ out << sb;
+ out << nl << stream << ".writeSize(0);";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
+ if(isGeneric && !isList)
+ {
+ if(isStack)
+ {
+ //
+ // If the collection is a stack, write in top-to-bottom order. Stacks
+ // cannot contain Ice.Object.
+ //
+ out << nl << "Ice.ObjectPrx[] " << param << "_tmp = " << param << ".ToArray();";
+ out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
+ out << sb;
+ out << nl << stream << ".writeProxy(" << param << "_tmp[ix]);";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "_System.Collections.Generic.IEnumerator<" << typeS
+ << "> e = " << param << ".GetEnumerator();";
+ out << nl << "while(e.MoveNext())";
+ out << sb;
+ string func = (kind == Builtin::KindObject ||
+ kind == Builtin::KindValue) ? "writeValue" : "writeProxy";
+ out << nl << stream << '.' << func << "(e.Current);";
+ out << eb;
+ }
+ }
+ else
+ {
+ out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
+ out << sb;
+ string func = (kind == Builtin::KindObject ||
+ kind == Builtin::KindValue) ? "writeValue" : "writeProxy";
+ out << nl << stream << '.' << func << '(' << param << "[ix]);";
+ out << eb;
+ }
+ out << eb;
+ }
+ else
+ {
+ out << nl << "int " << param << "_lenx = " << stream << ".readAndCheckSeqSize("
+ << static_cast<unsigned>(type->minWireSize()) << ");";
+ if(!isStack)
+ {
+ out << nl << param << " = new ";
+ }
+ if((kind == Builtin::KindObject || kind == Builtin::KindValue))
+ {
+ if(isArray)
+ {
+ out << "Ice.Value[" << param << "_lenx];";
+ }
+ else if(isCustom)
+ {
+ out << "global::" << genericType << "<Ice.Value>();";
+ }
+ else if(isGeneric)
+ {
+ out << "_System.Collections.Generic." << genericType << "<Ice.Value>(";
+ if(!isLinkedList)
+ {
+ out << param << "_lenx";
+ }
+ out << ");";
+ }
+ else
+ {
+ out << typeToString(seq) << "(" << param << "_lenx);";
+ }
+ out << nl << "for(int ix = 0; ix < " << param << "_lenx; ++ix)";
+ out << sb;
+ string patcherName;
+ if(isCustom)
+ {
+ patcherName = "CustomSeq";
+ }
+ else if(isList)
+ {
+ patcherName = "List";
+ }
+ else if(isArray)
+ {
+ patcherName = "Array";
+ }
+ else
+ {
+ patcherName = "Sequence";
+ }
+ out << nl << "IceInternal." << patcherName << "Patcher<Ice.Value> p = new IceInternal."
+ << patcherName << "Patcher<Ice.Value>(\"::Ice::Object\", " << param << ", ix);";
+ out << nl << stream << ".readValue(p.patch);";
+ }
+ else
+ {
+ if(isStack)
+ {
+ out << nl << "Ice.ObjectPrx[] " << param << "_tmp = new Ice.ObjectPrx[" << param << "_lenx];";
+ }
+ else if(isArray)
+ {
+ out << "Ice.ObjectPrx[" << param << "_lenx];";
+ }
+ else if(isGeneric)
+ {
+ out << "_System.Collections.Generic." << genericType << "<Ice.ObjectPrx>(";
+ if(!isLinkedList)
+ {
+ out << param << "_lenx";
+ }
+ out << ");";
+ }
+ else
+ {
+ out << typeToString(seq) << "(" << param << "_lenx);";
+ }
+
+ out << nl << "for(int ix = 0; ix < " << param << "_lenx; ++ix)";
+ out << sb;
+ if(isArray || isStack)
+ {
+ string v = isArray ? param : param + "_tmp";
+ out << nl << v << "[ix] = " << stream << ".readProxy();";
+ }
+ else
+ {
+ out << nl << "Ice.ObjectPrx val = new Ice.ObjectPrxHelperBase();";
+ out << nl << "val = " << stream << ".readProxy();";
+ out << nl << param << "." << addMethod << "(val);";
+ }
+ }
+ out << eb;
+
+ if(isStack)
+ {
+ out << nl << "_System.Array.Reverse(" << param << "_tmp);";
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">("
+ << param << "_tmp);";
+ }
+ }
+ break;
+ }
+ default:
+ {
+ string prefix = "cs:serializable:";
+ string meta;
+ if(seq->findMetaData(prefix, meta))
+ {
+ if(marshal)
+ {
+ out << nl << stream << ".writeSerializable(" << param << ");";
+ }
+ else
+ {
+ out << nl << param << " = (" << typeToString(seq) << ")" << stream << ".readSerializable();";
+ }
+ break;
+ }
+
+ string func = typeS;
+ func[0] = toupper(static_cast<unsigned char>(typeS[0]));
+ if(marshal)
+ {
+ if(isArray)
+ {
+ out << nl << stream << ".write" << func << "Seq(" << param << ");";
+ }
+ else if(isCustom)
+ {
+ out << nl << stream << ".write" << func << "Seq(" << param << " == null ? 0 : "
+ << param << ".Count, " << param << ");";
+ }
+ else
+ {
+ assert(isGeneric);
+ out << nl << stream << ".write" << func << "Seq(" << param << " == null ? 0 : "
+ << param << ".Count, " << param << ");";
+ }
+ }
+ else
+ {
+ if(isArray)
+ {
+ out << nl << param << " = " << stream << ".read" << func << "Seq();";
+ }
+ else if(isCustom)
+ {
+ out << sb;
+ out << nl << param << " = new " << "global::" << genericType << "<"
+ << typeToString(type) << ">();";
+ out << nl << "int szx = " << stream << ".readSize();";
+ out << nl << "for(int ix = 0; ix < szx; ++ix)";
+ out << sb;
+ out << nl << param << ".Add(" << stream << ".read" << func << "());";
+ out << eb;
+ out << eb;
+ }
+ else
+ {
+ assert(isGeneric);
+ out << nl << stream << ".read" << func << "Seq(out " << param << ");";
+ }
+ }
+ break;
+ }
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << " == null)";
+ out << sb;
+ out << nl << stream << ".writeSize(0);";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
+ if(isGeneric && !isList)
+ {
+ //
+ // Stacks cannot contain class instances, so there is no need to marshal a
+ // stack bottom-up here.
+ //
+ out << nl << "_System.Collections.Generic.IEnumerator<" << typeS
+ << "> e = " << param << ".GetEnumerator();";
+ out << nl << "while(e.MoveNext())";
+ out << sb;
+ out << nl << stream << ".writeValue(e.Current);";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
+ out << sb;
+ out << nl << stream << ".writeValue(" << param << "[ix]);";
+ out << eb;
+ }
+ out << eb;
+ }
+ else
+ {
+ out << sb;
+ out << nl << "int szx = " << stream << ".readAndCheckSeqSize("
+ << static_cast<unsigned>(type->minWireSize()) << ");";
+ out << nl << param << " = new ";
+ if(isArray)
+ {
+ out << toArrayAlloc(typeS + "[]", "szx");
+ }
+ else if(isCustom)
+ {
+ out << "global::" << genericType << "<" << typeS << ">()";
+ }
+ else if(isGeneric)
+ {
+ out << "_System.Collections.Generic." << genericType << "<" << typeS << ">(";
+ if(!isLinkedList)
+ {
+ out << "szx";
+ }
+ out << ")";
+ }
+ else
+ {
+ out << fixId(seq->scoped()) << "(szx)";
+ }
+ out << ';';
+ out << nl << "for(int ix = 0; ix < szx; ++ix)";
+ out << sb;
+
+ string patcherName;
+ if(isCustom)
+ {
+ patcherName = "CustomSeq";
+ }
+ else if(isList)
+ {
+ patcherName = "List";
+ }
+ else if(isArray)
+ {
+ patcherName = "Array";
+ }
+ else
+ {
+ patcherName = "Sequence";
+ }
+ string scoped = ContainedPtr::dynamicCast(type)->scoped();
+ out << nl << "IceInternal." << patcherName << "Patcher<" << typeS << "> spx = new IceInternal."
+ << patcherName << "Patcher<" << typeS << ">(\"" << scoped << "\", " << param << ", ix);";
+ out << nl << stream << ".readValue(spx.patch);";
+ out << eb;
+ out << eb;
+ }
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << " == null)";
+ out << sb;
+ out << nl << stream << ".writeSize(0);";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
+ if(isGeneric && !isList)
+ {
+ //
+ // Stacks are marshaled top-down.
+ //
+ if(isStack)
+ {
+ out << nl << typeS << "[] " << param << "_tmp = " << param << ".ToArray();";
+ out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
+ }
+ else
+ {
+ out << nl << "_System.Collections.Generic.IEnumerator<" << typeS
+ << "> e = " << param << ".GetEnumerator();";
+ out << nl << "while(e.MoveNext())";
+ }
+ }
+ else
+ {
+ out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
+ }
+ out << sb;
+ string call;
+ if(isGeneric && !isList && !isStack)
+ {
+ if(isValueType(type))
+ {
+ call = "e.Current";
+ }
+ else
+ {
+ call = "(e.Current == null ? new ";
+ call += typeS + "() : e.Current)";
+ }
+ }
+ else
+ {
+ if(isValueType(type))
+ {
+ call = param;
+ if(isStack)
+ {
+ call += "_tmp";
+ }
+ }
+ else
+ {
+ call = "(";
+ call += param;
+ if(isStack)
+ {
+ call += "_tmp";
+ }
+ call += "[ix] == null ? new " + typeS + "() : " + param;
+ if(isStack)
+ {
+ call += "_tmp";
+ }
+ }
+ call += "[ix]";
+ if(!isValueType(type))
+ {
+ call += ")";
+ }
+ }
+ call += ".";
+ call += "ice_writeMembers";
+ call += "(" + stream + ");";
+ out << nl << call;
+ out << eb;
+ out << eb;
+ }
+ else
+ {
+ out << sb;
+ out << nl << "int szx = " << stream << ".readAndCheckSeqSize("
+ << static_cast<unsigned>(type->minWireSize()) << ");";
+ if(isArray)
+ {
+ out << nl << param << " = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
+ }
+ else if(isCustom)
+ {
+ out << nl << param << " = new global::" << genericType << "<" << typeS << ">();";
+ }
+ else if(isStack)
+ {
+ out << nl << typeS << "[] " << param << "_tmp = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
+ }
+ else if(isGeneric)
+ {
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">(";
+ if(!isLinkedList)
+ {
+ out << "szx";
+ }
+ out << ");";
+ }
+ else
+ {
+ out << nl << param << " = new " << fixId(seq->scoped()) << "(szx);";
+ }
+ out << nl << "for(int ix = 0; ix < szx; ++ix)";
+ out << sb;
+ if(isArray || isStack)
+ {
+ string v = isArray ? param : param + "_tmp";
+ if(!isValueType(st))
+ {
+ out << nl << v << "[ix] = new " << typeS << "();";
+ }
+ out << nl << v << "[ix].ice_readMembers(" << stream << ");";
+ }
+ else
+ {
+ out << nl << typeS << " val = new " << typeS << "();";
+ out << nl << "val.ice_readMembers(" << stream << ");";
+ out << nl << param << "." << addMethod << "(val);";
+ }
+ out << eb;
+ if(isStack)
+ {
+ out << nl << "_System.Array.Reverse(" << param << "_tmp);";
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">("
+ << param << "_tmp);";
+ }
+ out << eb;
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << " == null)";
+ out << sb;
+ out << nl << stream << ".writeSize(0);";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << stream << ".writeSize(" << param << '.'<< limitID << ");";
+ if(isGeneric && !isList)
+ {
+ //
+ // Stacks are marshaled top-down.
+ //
+ if(isStack)
+ {
+ out << nl << typeS << "[] " << param << "_tmp = " << param << ".ToArray();";
+ out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
+ out << sb;
+ out << nl << stream << ".writeEnum((int)" << param << "_tmp[ix], " << en->maxValue() << ");";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "_System.Collections.Generic.IEnumerator<" << typeS
+ << "> e = " << param << ".GetEnumerator();";
+ out << nl << "while(e.MoveNext())";
+ out << sb;
+ out << nl << stream << ".writeEnum((int)e.Current, " << en->maxValue() << ");";
+ out << eb;
+ }
+ }
+ else
+ {
+ out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
+ out << sb;
+ out << nl << stream << ".writeEnum((int)" << param << "[ix], " << en->maxValue() << ");";
+ out << eb;
+ }
+ out << eb;
+ }
+ else
+ {
+ out << sb;
+ out << nl << "int szx = " << stream << ".readAndCheckSeqSize(" <<
+ static_cast<unsigned>(type->minWireSize()) << ");";
+ if(isArray)
+ {
+ out << nl << param << " = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
+ }
+ else if(isCustom)
+ {
+ out << nl << param << " = new global::" << genericType << "<" << typeS << ">();";
+ }
+ else if(isStack)
+ {
+ out << nl << typeS << "[] " << param << "_tmp = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
+ }
+ else if(isGeneric)
+ {
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">(";
+ if(!isLinkedList)
+ {
+ out << "szx";
+ }
+ out << ");";
+ }
+ else
+ {
+ out << nl << param << " = new " << fixId(seq->scoped()) << "(szx);";
+ }
+ out << nl << "for(int ix = 0; ix < szx; ++ix)";
+ out << sb;
+ if(isArray || isStack)
+ {
+ string v = isArray ? param : param + "_tmp";
+ out << nl << v << "[ix] = (" << typeS << ')' << stream << ".readEnum(" << en->maxValue() << ");";
+ }
+ else
+ {
+ out << nl << param << "." << addMethod << "((" << typeS << ')' << stream << ".readEnum("
+ << en->maxValue() << "));";
+ }
+ out << eb;
+ if(isStack)
+ {
+ out << nl << "_System.Array.Reverse(" << param << "_tmp);";
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">("
+ << param << "_tmp);";
+ }
+ out << eb;
+ }
+ return;
+ }
+
+ string helperName;
+ if(ProxyPtr::dynamicCast(type))
+ {
+ helperName = fixId(ProxyPtr::dynamicCast(type)->_class()->scoped() + "PrxHelper");
+ }
+ else
+ {
+ helperName = fixId(ContainedPtr::dynamicCast(type)->scoped() + "Helper");
+ }
+
+ string func;
+ if(marshal)
+ {
+ func = "write";
+ out << nl << "if(" << param << " == null)";
+ out << sb;
+ out << nl << stream << ".writeSize(0);";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
+ if(isGeneric && !isList)
+ {
+ //
+ // Stacks are marshaled top-down.
+ //
+ if(isStack)
+ {
+ out << nl << typeS << "[] " << param << "_tmp = " << param << ".ToArray();";
+ out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
+ out << sb;
+ out << nl << helperName << '.' << func << '(' << stream << ", " << param << "_tmp[ix]);";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "_System.Collections.Generic.IEnumerator<" << typeS
+ << "> e = " << param << ".GetEnumerator();";
+ out << nl << "while(e.MoveNext())";
+ out << sb;
+ out << nl << helperName << '.' << func << '(' << stream << ", e.Current);";
+ out << eb;
+ }
+ }
+ else
+ {
+ out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
+ out << sb;
+ out << nl << helperName << '.' << func << '(' << stream << ", " << param << "[ix]);";
+ out << eb;
+ }
+ out << eb;
+ }
+ else
+ {
+ func = "read";
+ out << sb;
+ out << nl << "int szx = " << stream << ".readAndCheckSeqSize("
+ << static_cast<unsigned>(type->minWireSize()) << ");";
+ if(isArray)
+ {
+ out << nl << param << " = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
+ }
+ else if(isCustom)
+ {
+ out << nl << param << " = new global::" << genericType << "<" << typeS << ">();";
+ }
+ else if(isStack)
+ {
+ out << nl << typeS << "[] " << param << "_tmp = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
+ }
+ else if(isGeneric)
+ {
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">();";
+ }
+ else
+ {
+ out << nl << param << " = new " << fixId(seq->scoped()) << "(szx);";
+ }
+ out << nl << "for(int ix = 0; ix < szx; ++ix)";
+ out << sb;
+ if(isArray || isStack)
+ {
+ string v = isArray ? param : param + "_tmp";
+ out << nl << v << "[ix] = " << helperName << '.' << func << '(' << stream << ");";
+ }
+ else
+ {
+ out << nl << param << "." << addMethod << "(" << helperName << '.' << func << '(' << stream << "));";
+ }
+ out << eb;
+ if(isStack)
+ {
+ out << nl << "_System.Array.Reverse(" << param << "_tmp);";
+ out << nl << param << " = new _System.Collections.Generic." << genericType << "<" << typeS << ">("
+ << param << "_tmp);";
+ }
+ out << eb;
+ }
+
+ return;
+}
+
+void
+Slice::CsGenerator::writeOptionalSequenceMarshalUnmarshalCode(Output& out,
+ const SequencePtr& seq,
+ const string& param,
+ int tag,
+ bool marshal,
+ const string& customStream)
+{
+ string stream = customStream;
+ if(stream.empty())
+ {
+ stream = marshal ? "ostr" : "istr";
+ }
+
+ const TypePtr type = seq->type();
+ const string typeS = typeToString(type);
+ const string seqS = typeToString(seq);
+
+ string meta;
+ const bool isArray = !seq->findMetaData("cs:generic:", meta);
+ const string length = isArray ? param + ".Value.Length" : param + ".Value.Count";
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindBool:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindFloat:
+ case Builtin::KindLong:
+ case Builtin::KindDouble:
+ case Builtin::KindString:
+ {
+ string func = typeS;
+ func[0] = toupper(static_cast<unsigned char>(typeS[0]));
+ const bool isSerializable = seq->findMetaData("cs:serializable:", meta);
+
+ if(marshal)
+ {
+ if(isSerializable)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag
+ << ", Ice.OptionalFormat.VSize))";
+ out << sb;
+ out << nl << stream << ".writeSerializable(" << param << ".Value);";
+ out << eb;
+ }
+ else if(isArray)
+ {
+ out << nl << stream << ".write" << func << "Seq(" << tag << ", " << param << ");";
+ }
+ else
+ {
+ out << nl << "if(" << param << ".HasValue)";
+ out << sb;
+ out << nl << stream << ".write" << func << "Seq(" << tag << ", " << param
+ << ".Value == null ? 0 : " << param << ".Value.Count, " << param << ".Value);";
+ out << eb;
+ }
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq) << "))";
+ out << sb;
+ if(builtin->isVariableLength())
+ {
+ out << nl << stream << ".skip(4);";
+ }
+ else if(builtin->kind() != Builtin::KindByte && builtin->kind() != Builtin::KindBool)
+ {
+ out << nl << stream << ".skipSize();";
+ }
+ string tmp = "tmpVal";
+ out << nl << seqS << ' ' << tmp << ';';
+ writeSequenceMarshalUnmarshalCode(out, seq, tmp, marshal, true, stream);
+ out << nl << param << " = new Ice.Optional<" << seqS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << seqS << ">();";
+ out << eb;
+ }
+ break;
+ }
+
+ case Builtin::KindValue:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
+ << getOptionalFormat(seq) << "))";
+ out << sb;
+ out << nl << "int pos = " << stream << ".startSize();";
+ writeSequenceMarshalUnmarshalCode(out, seq, param + ".Value", marshal, true, stream);
+ out << nl << stream << ".endSize(pos);";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq) << "))";
+ out << sb;
+ out << nl << stream << ".skip(4);";
+ string tmp = "tmpVal";
+ out << nl << seqS << ' ' << tmp << ';';
+ writeSequenceMarshalUnmarshalCode(out, seq, tmp, marshal, true, stream);
+ out << nl << param << " = new Ice.Optional<" << seqS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << seqS << ">();";
+ out << eb;
+ }
+ break;
+ }
+
+ case Builtin::KindLocalObject:
+ assert(false);
+ }
+
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
+ << getOptionalFormat(seq) << "))";
+ out << sb;
+ if(st->isVariableLength())
+ {
+ out << nl << "int pos = " << stream << ".startSize();";
+ }
+ else if(st->minWireSize() > 1)
+ {
+ out << nl << stream << ".writeSize(" << param << ".Value == null ? 1 : " << length << " * "
+ << st->minWireSize() << " + (" << length << " > 254 ? 5 : 1));";
+ }
+ writeSequenceMarshalUnmarshalCode(out, seq, param + ".Value", marshal, true, stream);
+ if(st->isVariableLength())
+ {
+ out << nl << stream << ".endSize(pos);";
+ }
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq) << "))";
+ out << sb;
+ if(st->isVariableLength())
+ {
+ out << nl << stream << ".skip(4);";
+ }
+ else if(st->minWireSize() > 1)
+ {
+ out << nl << stream << ".skipSize();";
+ }
+ string tmp = "tmpVal";
+ out << nl << seqS << ' ' << tmp << ';';
+ writeSequenceMarshalUnmarshalCode(out, seq, tmp, marshal, true, stream);
+ out << nl << param << " = new Ice.Optional<" << seqS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << seqS << ">();";
+ out << eb;
+ }
+ return;
+ }
+
+ //
+ // At this point, all remaining element types have variable size.
+ //
+ if(marshal)
+ {
+ out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
+ << getOptionalFormat(seq) << "))";
+ out << sb;
+ out << nl << "int pos = " << stream << ".startSize();";
+ writeSequenceMarshalUnmarshalCode(out, seq, param + ".Value", marshal, true, stream);
+ out << nl << stream << ".endSize(pos);";
+ out << eb;
+ }
+ else
+ {
+ out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq) << "))";
+ out << sb;
+ out << nl << stream << ".skip(4);";
+ string tmp = "tmpVal";
+ out << nl << seqS << ' ' << tmp << ';';
+ writeSequenceMarshalUnmarshalCode(out, seq, tmp, marshal, true, stream);
+ out << nl << param << " = new Ice.Optional<" << seqS << ">(" << tmp << ");";
+ out << eb;
+ out << nl << "else";
+ out << sb;
+ out << nl << param << " = new Ice.Optional<" << seqS << ">();";
+ out << eb;
+ }
+}
+
+void
+Slice::CsGenerator::writeSerializeDeserializeCode(Output &out,
+ const TypePtr& type,
+ const string& param,
+ bool optional,
+ int tag,
+ bool serialize)
+{
+ //
+ // Could do it only when param == "info", but not as good for testing
+ //
+ string dataMember = "this." + param;
+ if(optional)
+ {
+ const string typeName = typeToString(type, true);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "));";
+ }
+ return;
+ }
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetByte(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindBool:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetBoolean(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetInt16(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetInt32(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetInt64(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetSingle(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetDouble(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << " == null ? \"\" : " << dataMember
+ << ");";
+ }
+ else
+ {
+ out << nl << dataMember << " = " << "info.GetString(\"" << param << "\");";
+ }
+ break;
+ }
+ case Builtin::KindValue:
+ case Builtin::KindObject:
+ case Builtin::KindLocalObject:
+ {
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof("
+ << typeName << "));";
+ }
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember
+ << ", typeof(Ice.ObjectPrxHelperBase));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (Ice.ObjectPrx)info.GetValue(\"" << param
+ << "\", typeof(Ice.ObjectPrxHelperBase));";
+ }
+ break;
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "Helper));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "Helper));";
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "));";
+ }
+ return;
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "));";
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "));";
+ }
+ return;
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "));";
+ }
+ return;
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ assert(d);
+ const string typeName = typeToString(type, false);
+ if(serialize)
+ {
+ out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
+ }
+ else
+ {
+ out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
+ << "));";
+ }
+}
+
+string
+Slice::CsGenerator::toArrayAlloc(const string& decl, const string& sz)
+{
+ int count = 0;
+ string::size_type pos = decl.size();
+ while(pos > 1 && decl.substr(pos - 2, 2) == "[]")
+ {
+ ++count;
+ pos -= 2;
+ }
+ assert(count > 0);
+
+ ostringstream o;
+ o << decl.substr(0, pos) << '[' << sz << ']' << decl.substr(pos + 2);
+ return o.str();
+}
+
+void
+Slice::CsGenerator::validateMetaData(const UnitPtr& u)
+{
+ MetaDataVisitor visitor;
+ u->visit(&visitor, true);
+}
+
+bool
+Slice::CsGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p)
+{
+ //
+ // Validate global metadata in the top-level file and all included files.
+ //
+ StringList files = p->allFiles();
+ for(StringList::iterator q = files.begin(); q != files.end(); ++q)
+ {
+ string file = *q;
+ DefinitionContextPtr dc = p->findDefinitionContext(file);
+ assert(dc);
+ StringList globalMetaData = dc->getMetaData();
+ StringList newGlobalMetaData;
+ static const string csPrefix = "cs:";
+ static const string clrPrefix = "clr:";
+
+ for(StringList::iterator r = globalMetaData.begin(); r != globalMetaData.end(); ++r)
+ {
+ string& s = *r;
+ string oldS = s;
+
+ if(s.find(clrPrefix) == 0)
+ {
+ s.replace(0, clrPrefix.size(), csPrefix);
+ }
+
+ if(s.find(csPrefix) == 0)
+ {
+ static const string csAttributePrefix = csPrefix + "attribute:";
+ if(s.find(csAttributePrefix) != 0 || s.size() == csAttributePrefix.size())
+ {
+ dc->warning(InvalidMetaData, file, -1, "ignoring invalid global metadata `" + oldS + "'");
+ continue;
+ }
+ }
+ newGlobalMetaData.push_back(oldS);
+ }
+
+ dc->setMetaData(newGlobalMetaData);
+ }
+ return true;
+}
+
+bool
+Slice::CsGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitModuleEnd(const ModulePtr&)
+{
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
+{
+ validate(p);
+}
+
+bool
+Slice::CsGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
+{
+}
+
+bool
+Slice::CsGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
+{
+}
+
+bool
+Slice::CsGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitStructEnd(const StructPtr&)
+{
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p)
+{
+ validate(p);
+
+ ParamDeclList params = p->parameters();
+ for(ParamDeclList::const_iterator i = params.begin(); i != params.end(); ++i)
+ {
+ visitParamDecl(*i);
+ }
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::visitConst(const ConstPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::CsGenerator::MetaDataVisitor::validate(const ContainedPtr& cont)
+{
+ const string msg = "ignoring invalid metadata";
+
+ StringList localMetaData = cont->getMetaData();
+ StringList newLocalMetaData;
+
+ const UnitPtr unit = cont->unit();
+ const DefinitionContextPtr dc = unit->findDefinitionContext(cont->file());
+ assert(dc);
+
+ for(StringList::iterator p = localMetaData.begin(); p != localMetaData.end(); ++p)
+ {
+ string& s = *p;
+ string oldS = s;
+
+ const string csPrefix = "cs:";
+ const string clrPrefix = "clr:";
+
+ if(s.find(clrPrefix) == 0)
+ {
+ s.replace(0, clrPrefix.size(), csPrefix);
+ }
+
+
+ if(s.find(csPrefix) == 0)
+ {
+ SequencePtr seq = SequencePtr::dynamicCast(cont);
+ if(seq)
+ {
+ static const string csGenericPrefix = csPrefix + "generic:";
+ if(s.find(csGenericPrefix) == 0)
+ {
+ string type = s.substr(csGenericPrefix.size());
+ if(type == "LinkedList" || type == "Queue" || type == "Stack")
+ {
+ if(!isClassType(seq->type()))
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ }
+ else if(!type.empty())
+ {
+ newLocalMetaData.push_back(s);
+ continue; // Custom type or List<T>
+ }
+ }
+ static const string csSerializablePrefix = csPrefix + "serializable:";
+ if(s.find(csSerializablePrefix) == 0)
+ {
+ string meta;
+ if(cont->findMetaData(csPrefix + "generic:", meta))
+ {
+ dc->warning(InvalidMetaData, cont->file(), cont->line(), msg + " `" + meta + "':\n" +
+ "serialization can only be used with the array mapping for byte sequences");
+ continue;
+ }
+ string type = s.substr(csSerializablePrefix.size());
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type());
+ if(!type.empty() && builtin && builtin->kind() == Builtin::KindByte)
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ }
+ }
+ else if(StructPtr::dynamicCast(cont))
+ {
+ if(s.substr(csPrefix.size()) == "class")
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ if(s.substr(csPrefix.size()) == "property")
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ static const string csImplementsPrefix = csPrefix + "implements:";
+ if(s.find(csImplementsPrefix) == 0)
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ }
+ else if(ClassDefPtr::dynamicCast(cont))
+ {
+ if(s.substr(csPrefix.size()) == "property")
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ static const string csImplementsPrefix = csPrefix + "implements:";
+ if(s.find(csImplementsPrefix) == 0)
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ }
+ else if(DictionaryPtr::dynamicCast(cont))
+ {
+ static const string csGenericPrefix = csPrefix + "generic:";
+ if(s.find(csGenericPrefix) == 0)
+ {
+ string type = s.substr(csGenericPrefix.size());
+ if(type == "SortedDictionary" || type == "SortedList")
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ }
+ }
+
+ static const string csAttributePrefix = csPrefix + "attribute:";
+ static const string csTie = csPrefix + "tie";
+ if(s.find(csAttributePrefix) == 0 && s.size() > csAttributePrefix.size())
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+ else if(s.find(csTie) == 0 && s.size() == csTie.size())
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+
+ dc->warning(InvalidMetaData, cont->file(), cont->line(), msg + " `" + oldS + "'");
+ continue;
+ }
+ else if(s == "delegate")
+ {
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(cont);
+ if(cl && cl->isDelegate())
+ {
+ newLocalMetaData.push_back(s);
+ continue;
+ }
+
+ dc->warning(InvalidMetaData, cont->file(), cont->line(), msg + " `" + s + "'");
+ continue;
+ }
+ newLocalMetaData.push_back(s);
+ }
+
+ cont->setMetaData(newLocalMetaData);
+}