1
2 //
3 // Copyright (c) ZeroC, Inc. All rights reserved.
4 //
5
6 #include <CsUtil.h>
7 #include <DotNetNames.h>
8 #include <Slice/Util.h>
9 #include <IceUtil/Functional.h>
10 #include <IceUtil/StringUtil.h>
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14
15 #ifdef _WIN32
16 # include <direct.h>
17 #else
18 # include <unistd.h>
19 #endif
20
21 using namespace std;
22 using namespace Slice;
23 using namespace IceUtil;
24 using namespace IceUtilInternal;
25
26 namespace
27 {
28
29 string
lookupKwd(const string & name,int baseTypes,bool mangleCasts=false)30 lookupKwd(const string& name, int baseTypes, bool mangleCasts = false)
31 {
32 //
33 // Keyword list. *Must* be kept in alphabetical order.
34 //
35 static const string keywordList[] =
36 {
37 "abstract", "as", "async", "await", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const",
38 "continue", "decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern",
39 "false", "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface",
40 "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", "override",
41 "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short",
42 "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof",
43 "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void", "volatile", "while"
44 };
45 bool found = binary_search(&keywordList[0],
46 &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
47 name,
48 Slice::CICompare());
49 if(found)
50 {
51 return "@" + name;
52 }
53 if(mangleCasts && (name == "checkedCast" || name == "uncheckedCast"))
54 {
55 return string(DotNet::manglePrefix) + name;
56 }
57 return Slice::DotNet::mangleName(name, baseTypes);
58 }
59
60 //
61 // Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
62 //
63 StringList
splitScopedName(const string & scoped)64 splitScopedName(const string& scoped)
65 {
66 assert(scoped[0] == ':');
67 StringList ids;
68 string::size_type next = 0;
69 string::size_type pos;
70 while((pos = scoped.find("::", next)) != string::npos)
71 {
72 pos += 2;
73 if(pos != scoped.size())
74 {
75 string::size_type endpos = scoped.find("::", pos);
76 if(endpos != string::npos)
77 {
78 ids.push_back(scoped.substr(pos, endpos - pos));
79 }
80 }
81 next = pos;
82 }
83 if(next != scoped.size())
84 {
85 ids.push_back(scoped.substr(next));
86 }
87 else
88 {
89 ids.push_back("");
90 }
91
92 return ids;
93 }
94
95 }
96
97 string
getNamespacePrefix(const ContainedPtr & cont)98 Slice::CsGenerator::getNamespacePrefix(const ContainedPtr& cont)
99 {
100 //
101 // Traverse to the top-level module.
102 //
103 ModulePtr m;
104 ContainedPtr p = cont;
105 while(true)
106 {
107 if(ModulePtr::dynamicCast(p))
108 {
109 m = ModulePtr::dynamicCast(p);
110 }
111
112 ContainerPtr c = p->container();
113 p = ContainedPtr::dynamicCast(c); // This cast fails for Unit.
114 if(!p)
115 {
116 break;
117 }
118 }
119
120 assert(m);
121
122 static const string prefix = "cs:namespace:";
123
124 string q;
125 if(m->findMetaData(prefix, q))
126 {
127 q = q.substr(prefix.size());
128 }
129 return q;
130 }
131
132 string
getCustomTypeIdNamespace(const UnitPtr & ut)133 Slice::CsGenerator::getCustomTypeIdNamespace(const UnitPtr& ut)
134 {
135 DefinitionContextPtr dc = ut->findDefinitionContext(ut->topLevelFile());
136 assert(dc);
137
138 static const string typeIdNsPrefix = "cs:typeid-namespace:";
139 string result = dc->findMetaData(typeIdNsPrefix);
140 if(!result.empty())
141 {
142 result = result.substr(typeIdNsPrefix.size());
143 }
144 return result;
145 }
146
147 string
getNamespace(const ContainedPtr & cont)148 Slice::CsGenerator::getNamespace(const ContainedPtr& cont)
149 {
150 string scope = fixId(cont->scope());
151 if(scope.rfind(".") == scope.size() - 1)
152 {
153 scope = scope.substr(0, scope.size() - 1);
154 }
155 string prefix = getNamespacePrefix(cont);
156 if(!prefix.empty())
157 {
158 if(!scope.empty())
159 {
160 return prefix + "." + scope;
161 }
162 else
163 {
164 return prefix;
165 }
166 }
167
168 return scope;
169 }
170
171 string
getUnqualified(const string & type,const string & scope,bool builtin)172 Slice::CsGenerator::getUnqualified(const string& type, const string& scope, bool builtin)
173 {
174 if(type.find(".") != string::npos && type.find(scope) == 0 && type.find(".", scope.size() + 1) == string::npos)
175 {
176 return type.substr(scope.size() + 1);
177 }
178 else if(builtin)
179 {
180 return type.find(".") == string::npos ? type : "global::" + type;
181 }
182 else
183 {
184 return "global::" + type;
185 }
186 }
187
188 string
getUnqualified(const ContainedPtr & p,const string & package,const string & prefix,const string & suffix)189 Slice::CsGenerator::getUnqualified(const ContainedPtr& p, const string& package, const string& prefix,
190 const string& suffix)
191 {
192 string name = fixId(prefix + p->name() + suffix);
193 string contPkg = getNamespace(p);
194 if(contPkg == package || contPkg.empty())
195 {
196 return name;
197 }
198 else
199 {
200 return "global::" + contPkg + "." + name;
201 }
202 }
203
204 //
205 // If the passed name is a scoped name, return the identical scoped name,
206 // but with all components that are C# keywords replaced by
207 // their "@"-prefixed version; otherwise, if the passed name is
208 // not scoped, but a C# keyword, return the "@"-prefixed name;
209 // otherwise, check if the name is one of the method names of baseTypes;
210 // if so, prefix it with ice_; otherwise, return the name unchanged.
211 //
212 string
fixId(const string & name,int baseTypes,bool mangleCasts)213 Slice::CsGenerator::fixId(const string& name, int baseTypes, bool mangleCasts)
214 {
215 if(name.empty())
216 {
217 return name;
218 }
219 if(name[0] != ':')
220 {
221 return lookupKwd(name, baseTypes, mangleCasts);
222 }
223 StringList ids = splitScopedName(name);
224 StringList newIds;
225 for(StringList::const_iterator i = ids.begin(); i != ids.end(); ++i)
226 {
227 newIds.push_back(lookupKwd(*i, baseTypes));
228 }
229 stringstream result;
230 for(StringList::const_iterator j = newIds.begin(); j != newIds.end(); ++j)
231 {
232 if(j != newIds.begin())
233 {
234 result << '.';
235 }
236 result << *j;
237 }
238 return result.str();
239 }
240
241 string
fixId(const ContainedPtr & cont,int baseTypes,bool mangleCasts)242 Slice::CsGenerator::fixId(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
243 {
244 ContainerPtr container = cont->container();
245 ContainedPtr contained = ContainedPtr::dynamicCast(container);
246 if(contained && contained->hasMetaData("cs:property") &&
247 (contained->containedType() == Contained::ContainedTypeClass ||
248 contained->containedType() == Contained::ContainedTypeStruct))
249 {
250 return "_" + cont->name();
251 }
252 else
253 {
254 return fixId(cont->name(), baseTypes, mangleCasts);
255 }
256 }
257
258 string
getOptionalFormat(const TypePtr & type,const string & scope)259 Slice::CsGenerator::getOptionalFormat(const TypePtr& type, const string& scope)
260 {
261 BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
262 string prefix = getUnqualified("Ice.OptionalFormat", scope);
263 if(bp)
264 {
265 switch(bp->kind())
266 {
267 case Builtin::KindByte:
268 case Builtin::KindBool:
269 {
270 return prefix + ".F1";
271 }
272 case Builtin::KindShort:
273 {
274 return prefix + ".F2";
275 }
276 case Builtin::KindInt:
277 case Builtin::KindFloat:
278 {
279 return prefix + ".F4";
280 }
281 case Builtin::KindLong:
282 case Builtin::KindDouble:
283 {
284 return prefix + ".F8";
285 }
286 case Builtin::KindString:
287 {
288 return prefix + ".VSize";
289 }
290 case Builtin::KindObject:
291 {
292 return prefix + ".Class";
293 }
294 case Builtin::KindObjectProxy:
295 {
296 return prefix + ".FSize";
297 }
298 case Builtin::KindLocalObject:
299 {
300 assert(false);
301 break;
302 }
303 case Builtin::KindValue:
304 {
305 return prefix + ".Class";
306 }
307 }
308 }
309
310 if(EnumPtr::dynamicCast(type))
311 {
312 return prefix + ".Size";
313 }
314
315 SequencePtr seq = SequencePtr::dynamicCast(type);
316 if(seq)
317 {
318 if(seq->type()->isVariableLength())
319 {
320 return prefix + ".FSize";
321 }
322 else
323 {
324 return prefix + ".VSize";
325 }
326 }
327
328 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
329 if(d)
330 {
331 if(d->keyType()->isVariableLength() || d->valueType()->isVariableLength())
332 {
333 return prefix + ".FSize";
334 }
335 else
336 {
337 return prefix + ".VSize";
338 }
339 }
340
341 StructPtr st = StructPtr::dynamicCast(type);
342 if(st)
343 {
344 if(st->isVariableLength())
345 {
346 return prefix + ".FSize";
347 }
348 else
349 {
350 return prefix + ".VSize";
351 }
352 }
353
354 if(ProxyPtr::dynamicCast(type))
355 {
356 return prefix + ".FSize";
357 }
358
359 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
360 assert(cl);
361 return prefix + ".Class";
362 }
363
364 string
getStaticId(const TypePtr & type)365 Slice::CsGenerator::getStaticId(const TypePtr& type)
366 {
367 BuiltinPtr b = BuiltinPtr::dynamicCast(type);
368 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
369
370 assert(isClassType(type));
371
372 if(b)
373 {
374 return "Ice.Value.ice_staticId()";
375 }
376 else if(cl->isInterface())
377 {
378 ContainedPtr cont = ContainedPtr::dynamicCast(cl->container());
379 assert(cont);
380 return getUnqualified(cont) + "." + cl->name() + "Disp_.ice_staticId()";
381 }
382 else
383 {
384 return getUnqualified(cl) + ".ice_staticId()";
385 }
386 }
387
388 string
typeToString(const TypePtr & type,const string & package,bool optional,bool local,const StringList & metaData)389 Slice::CsGenerator::typeToString(const TypePtr& type, const string& package, bool optional, bool local,
390 const StringList& metaData)
391 {
392 if(!type)
393 {
394 return "void";
395 }
396
397 if(optional)
398 {
399 return getUnqualified("Ice.Optional", package) + "<" + typeToString(type, package, false, local) + ">";
400 }
401
402 static const char* builtinTable[] =
403 {
404 "byte",
405 "bool",
406 "short",
407 "int",
408 "long",
409 "float",
410 "double",
411 "string",
412 "Ice.Object",
413 "Ice.ObjectPrx",
414 "System.Object",
415 "Ice.Value"
416 };
417
418 if(local)
419 {
420 for(StringList::const_iterator i = metaData.begin(); i != metaData.end(); ++i)
421 {
422 const string clrType = "cs:type:";
423 const string meta = *i;
424 if(meta.find(clrType) == 0)
425 {
426 return meta.substr(clrType.size());
427 }
428 }
429 }
430
431 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
432 if(builtin)
433 {
434 if(!local && builtin->kind() == Builtin::KindObject)
435 {
436 return getUnqualified(builtinTable[Builtin::KindValue], package, true);
437 }
438 else
439 {
440 return getUnqualified(builtinTable[builtin->kind()], package, true);
441 }
442 }
443
444 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
445 if(cl)
446 {
447 if(cl->isInterface() && !local)
448 {
449 return getUnqualified("Ice.Value", package);
450 }
451 else
452 {
453 return getUnqualified(cl, package);
454 }
455 }
456
457 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
458 if(proxy)
459 {
460 ClassDefPtr def = proxy->_class()->definition();
461 if(def->isInterface() || def->allOperations().size() > 0)
462 {
463 return getUnqualified(proxy->_class(), package, "", "Prx");
464 }
465 else
466 {
467 return getUnqualified("Ice.ObjectPrx", package);
468 }
469 }
470
471 SequencePtr seq = SequencePtr::dynamicCast(type);
472 if(seq)
473 {
474 string prefix = "cs:generic:";
475 string meta;
476 if(seq->findMetaData(prefix, meta))
477 {
478 string customType = meta.substr(prefix.size());
479 if(customType == "List" || customType == "LinkedList" || customType == "Queue" || customType == "Stack")
480 {
481 return "global::System.Collections.Generic." + customType + "<" +
482 typeToString(seq->type(), package, optional, local) + ">";
483 }
484 else
485 {
486 return "global::" + customType + "<" + typeToString(seq->type(), package, optional, local) + ">";
487 }
488 }
489
490 prefix = "cs:serializable:";
491 if(seq->findMetaData(prefix, meta))
492 {
493 string customType = meta.substr(prefix.size());
494 return "global::" + customType;
495 }
496
497 return typeToString(seq->type(), package, optional, local) + "[]";
498 }
499
500 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
501 if(d)
502 {
503 string prefix = "cs:generic:";
504 string meta;
505 string typeName;
506 if(d->findMetaData(prefix, meta))
507 {
508 typeName = meta.substr(prefix.size());
509 }
510 else
511 {
512 typeName = "Dictionary";
513 }
514 return "global::System.Collections.Generic." + typeName + "<" +
515 typeToString(d->keyType(), package, optional, local) + ", " +
516 typeToString(d->valueType(), package, optional, local) + ">";
517 }
518
519 ContainedPtr contained = ContainedPtr::dynamicCast(type);
520 if(contained)
521 {
522 return getUnqualified(contained, package);
523 }
524
525 return "???";
526 }
527
528 string
resultStructName(const string & className,const string & opName,bool marshaledResult)529 Slice::CsGenerator::resultStructName(const string& className, const string& opName, bool marshaledResult)
530 {
531 ostringstream s;
532 s << className
533 << "_"
534 << IceUtilInternal::toUpper(opName.substr(0, 1))
535 << opName.substr(1)
536 << (marshaledResult ? "MarshaledResult" : "Result");
537 return s.str();
538 }
539
540 string
resultType(const OperationPtr & op,const string & package,bool dispatch)541 Slice::CsGenerator::resultType(const OperationPtr& op, const string& package, bool dispatch)
542 {
543 ClassDefPtr cl = ClassDefPtr::dynamicCast(op->container()); // Get the class containing the op.
544 if(dispatch && op->hasMarshaledResult())
545 {
546 return getUnqualified(cl, package, "", resultStructName("", op->name(), true));
547 }
548
549 string t;
550 ParamDeclList outParams = op->outParameters();
551 if(op->returnType() || !outParams.empty())
552 {
553 if(outParams.empty())
554 {
555 t = typeToString(op->returnType(), package, op->returnIsOptional(), cl->isLocal());
556 }
557 else if(op->returnType() || outParams.size() > 1)
558 {
559 t = getUnqualified(cl, package, "", resultStructName("", op->name()));
560 }
561 else
562 {
563 t = typeToString(outParams.front()->type(), package, outParams.front()->optional(), cl->isLocal());
564 }
565 }
566
567 return t;
568 }
569
570 string
taskResultType(const OperationPtr & op,const string & scope,bool dispatch)571 Slice::CsGenerator::taskResultType(const OperationPtr& op, const string& scope, bool dispatch)
572 {
573 string t = resultType(op, scope, dispatch);
574 if(t.empty())
575 {
576 return "global::System.Threading.Tasks.Task";
577 }
578 else
579 {
580 return "global::System.Threading.Tasks.Task<" + t + '>';
581 }
582 }
583
584 bool
isClassType(const TypePtr & type)585 Slice::CsGenerator::isClassType(const TypePtr& type)
586 {
587 if(ClassDeclPtr::dynamicCast(type))
588 {
589 return true;
590 }
591 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
592 return builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue);
593 }
594
595 bool
isValueType(const TypePtr & type)596 Slice::CsGenerator::isValueType(const TypePtr& type)
597 {
598 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
599 if(builtin)
600 {
601 switch(builtin->kind())
602 {
603 case Builtin::KindString:
604 case Builtin::KindObject:
605 case Builtin::KindObjectProxy:
606 case Builtin::KindLocalObject:
607 case Builtin::KindValue:
608 {
609 return false;
610 break;
611 }
612 default:
613 {
614 return true;
615 break;
616 }
617 }
618 }
619 StructPtr s = StructPtr::dynamicCast(type);
620 if(s)
621 {
622 if(s->hasMetaData("cs:class"))
623 {
624 return false;
625 }
626 DataMemberList dm = s->dataMembers();
627 for(DataMemberList::const_iterator i = dm.begin(); i != dm.end(); ++i)
628 {
629 if(!isValueType((*i)->type()) || (*i)->defaultValueType())
630 {
631 return false;
632 }
633 }
634 return true;
635 }
636 if(EnumPtr::dynamicCast(type))
637 {
638 return true;
639 }
640 return false;
641 }
642
643 void
writeMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & package,const string & param,bool marshal,const string & customStream)644 Slice::CsGenerator::writeMarshalUnmarshalCode(Output &out,
645 const TypePtr& type,
646 const string& package,
647 const string& param,
648 bool marshal,
649 const string& customStream)
650 {
651 string stream = customStream;
652 if(stream.empty())
653 {
654 stream = marshal ? "ostr" : "istr";
655 }
656
657 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
658 if(builtin)
659 {
660 switch(builtin->kind())
661 {
662 case Builtin::KindByte:
663 {
664 if(marshal)
665 {
666 out << nl << stream << ".writeByte(" << param << ");";
667 }
668 else
669 {
670 out << nl << param << " = " << stream << ".readByte()" << ';';
671 }
672 break;
673 }
674 case Builtin::KindBool:
675 {
676 if(marshal)
677 {
678 out << nl << stream << ".writeBool(" << param << ");";
679 }
680 else
681 {
682 out << nl << param << " = " << stream << ".readBool()" << ';';
683 }
684 break;
685 }
686 case Builtin::KindShort:
687 {
688 if(marshal)
689 {
690 out << nl << stream << ".writeShort(" << param << ");";
691 }
692 else
693 {
694 out << nl << param << " = " << stream << ".readShort()" << ';';
695 }
696 break;
697 }
698 case Builtin::KindInt:
699 {
700 if(marshal)
701 {
702 out << nl << stream << ".writeInt(" << param << ");";
703 }
704 else
705 {
706 out << nl << param << " = " << stream << ".readInt()" << ';';
707 }
708 break;
709 }
710 case Builtin::KindLong:
711 {
712 if(marshal)
713 {
714 out << nl << stream << ".writeLong(" << param << ");";
715 }
716 else
717 {
718 out << nl << param << " = " << stream << ".readLong()" << ';';
719 }
720 break;
721 }
722 case Builtin::KindFloat:
723 {
724 if(marshal)
725 {
726 out << nl << stream << ".writeFloat(" << param << ");";
727 }
728 else
729 {
730 out << nl << param << " = " << stream << ".readFloat()" << ';';
731 }
732 break;
733 }
734 case Builtin::KindDouble:
735 {
736 if(marshal)
737 {
738 out << nl << stream << ".writeDouble(" << param << ");";
739 }
740 else
741 {
742 out << nl << param << " = " << stream << ".readDouble()" << ';';
743 }
744 break;
745 }
746 case Builtin::KindString:
747 {
748 if(marshal)
749 {
750 out << nl << stream << ".writeString(" << param << ");";
751 }
752 else
753 {
754 out << nl << param << " = " << stream << ".readString()" << ';';
755 }
756 break;
757 }
758 case Builtin::KindObject:
759 case Builtin::KindValue:
760 {
761 if(marshal)
762 {
763 out << nl << stream << ".writeValue(" << param << ");";
764 }
765 else
766 {
767 out << nl << stream << ".readValue(" << param << ");";
768 }
769 break;
770 }
771 case Builtin::KindObjectProxy:
772 {
773 string typeS = typeToString(type, package);
774 if(marshal)
775 {
776 out << nl << stream << ".writeProxy(" << param << ");";
777 }
778 else
779 {
780 out << nl << param << " = " << stream << ".readProxy()" << ';';
781 }
782 break;
783 }
784 case Builtin::KindLocalObject:
785 {
786 assert(false);
787 break;
788 }
789 }
790 return;
791 }
792
793 ProxyPtr prx = ProxyPtr::dynamicCast(type);
794 if(prx)
795 {
796 ClassDefPtr def = prx->_class()->definition();
797 if(def->isInterface() || def->allOperations().size() > 0)
798 {
799 string typeS = typeToString(type, package);
800 if(marshal)
801 {
802 out << nl << typeS << "Helper.write(" << stream << ", " << param << ");";
803 }
804 else
805 {
806 out << nl << param << " = " << typeS << "Helper.read(" << stream << ");";
807 }
808 }
809 else
810 {
811 if(marshal)
812 {
813 out << nl << stream << ".writeProxy(" << param << ");";
814 }
815 else
816 {
817 out << nl << param << " = " << stream << ".readProxy()" << ';';
818 }
819 }
820 return;
821 }
822
823 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
824 if(cl)
825 {
826 if(marshal)
827 {
828 out << nl << stream << ".writeValue(" << param << ");";
829 }
830 else
831 {
832 out << nl << stream << ".readValue(" << param << ");";
833 }
834 return;
835 }
836
837 StructPtr st = StructPtr::dynamicCast(type);
838 if(st)
839 {
840 if(marshal)
841 {
842 if(!isValueType(st))
843 {
844 out << nl << typeToString(st, package) << ".ice_write(" << stream << ", " << param << ");";
845 }
846 else
847 {
848 out << nl << param << ".ice_writeMembers(" << stream << ");";
849 }
850 }
851 else
852 {
853 if(!isValueType(st))
854 {
855 out << nl << param << " = " << typeToString(type, package) << ".ice_read(" << stream << ");";
856 }
857 else
858 {
859 out << nl << param << ".ice_readMembers(" << stream << ");";
860 }
861 }
862 return;
863 }
864
865 EnumPtr en = EnumPtr::dynamicCast(type);
866 if(en)
867 {
868 if(marshal)
869 {
870 out << nl << stream << ".writeEnum((int)" << param << ", " << en->maxValue() << ");";
871 }
872 else
873 {
874 out << nl << param << " = (" << typeToString(type, package) << ')' << stream << ".readEnum(" << en->maxValue()
875 << ");";
876 }
877 return;
878 }
879
880 SequencePtr seq = SequencePtr::dynamicCast(type);
881 if(seq)
882 {
883 writeSequenceMarshalUnmarshalCode(out, seq, package, param, marshal, true, stream);
884 return;
885 }
886
887 assert(ConstructedPtr::dynamicCast(type));
888 string helperName;
889 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
890 if(d)
891 {
892 helperName = getUnqualified(d, package, "", "Helper");
893 }
894 else
895 {
896 helperName = typeToString(type, package) + "Helper";
897 }
898
899 if(marshal)
900 {
901 out << nl << helperName << ".write(" << stream << ", " << param << ");";
902 }
903 else
904 {
905 out << nl << param << " = " << helperName << ".read(" << stream << ')' << ';';
906 }
907 }
908
909 void
writeOptionalMarshalUnmarshalCode(Output & out,const TypePtr & type,const string & scope,const string & param,int tag,bool marshal,const string & customStream)910 Slice::CsGenerator::writeOptionalMarshalUnmarshalCode(Output &out,
911 const TypePtr& type,
912 const string& scope,
913 const string& param,
914 int tag,
915 bool marshal,
916 const string& customStream)
917 {
918 string stream = customStream;
919 if(stream.empty())
920 {
921 stream = marshal ? "ostr" : "istr";
922 }
923
924 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
925 if(builtin)
926 {
927 switch(builtin->kind())
928 {
929 case Builtin::KindByte:
930 {
931 if(marshal)
932 {
933 out << nl << stream << ".writeByte(" << tag << ", " << param << ");";
934 }
935 else
936 {
937 //
938 // BUGFIX: with .NET Core reading the byte optional directly in the
939 // result struct can fails unexpectly with optimized builds.
940 //
941 if(param.find(".") != string::npos)
942 {
943 out << sb;
944 out << nl << "var tmp = " << stream << ".readByte(" << tag << ");";
945 out << nl << param << " = tmp;";
946 out << eb;
947 }
948 else
949 {
950 out << nl << param << " = " << stream << ".readByte(" << tag << ");";
951 }
952 }
953 break;
954 }
955 case Builtin::KindBool:
956 {
957 if(marshal)
958 {
959 out << nl << stream << ".writeBool(" << tag << ", " << param << ");";
960 }
961 else
962 {
963 //
964 // BUGFIX: with .NET Core reading the bool optional directly in the
965 // result struct fails unexpectly with optimized builds.
966 //
967 if(param.find(".") != string::npos)
968 {
969 out << sb;
970 out << nl << "var tmp = " << stream << ".readBool(" << tag << ");";
971 out << nl << param << " = tmp;";
972 out << eb;
973 }
974 else
975 {
976 out << nl << param << " = " << stream << ".readBool(" << tag << ");";
977 }
978 }
979 break;
980 }
981 case Builtin::KindShort:
982 {
983 if(marshal)
984 {
985 out << nl << stream << ".writeShort(" << tag << ", " << param << ");";
986 }
987 else
988 {
989 out << nl << param << " = " << stream << ".readShort(" << tag << ");";
990 }
991 break;
992 }
993 case Builtin::KindInt:
994 {
995 if(marshal)
996 {
997 out << nl << stream << ".writeInt(" << tag << ", " << param << ");";
998 }
999 else
1000 {
1001 out << nl << param << " = " << stream << ".readInt(" << tag << ");";
1002 }
1003 break;
1004 }
1005 case Builtin::KindLong:
1006 {
1007 if(marshal)
1008 {
1009 out << nl << stream << ".writeLong(" << tag << ", " << param << ");";
1010 }
1011 else
1012 {
1013 out << nl << param << " = " << stream << ".readLong(" << tag << ");";
1014 }
1015 break;
1016 }
1017 case Builtin::KindFloat:
1018 {
1019 if(marshal)
1020 {
1021 out << nl << stream << ".writeFloat(" << tag << ", " << param << ");";
1022 }
1023 else
1024 {
1025 out << nl << param << " = " << stream << ".readFloat(" << tag << ");";
1026 }
1027 break;
1028 }
1029 case Builtin::KindDouble:
1030 {
1031 if(marshal)
1032 {
1033 out << nl << stream << ".writeDouble(" << tag << ", " << param << ");";
1034 }
1035 else
1036 {
1037 out << nl << param << " = " << stream << ".readDouble(" << tag << ");";
1038 }
1039 break;
1040 }
1041 case Builtin::KindString:
1042 {
1043 if(marshal)
1044 {
1045 out << nl << stream << ".writeString(" << tag << ", " << param << ");";
1046 }
1047 else
1048 {
1049 out << nl << param << " = " << stream << ".readString(" << tag << ");";
1050 }
1051 break;
1052 }
1053 case Builtin::KindObject:
1054 case Builtin::KindValue:
1055 {
1056 if(marshal)
1057 {
1058 out << nl << stream << ".writeValue(" << tag << ", " << param << ");";
1059 }
1060 else
1061 {
1062 out << nl << stream << ".readValue(" << tag << ", " << param << ");";
1063 }
1064 break;
1065 }
1066 case Builtin::KindObjectProxy:
1067 {
1068 string typeS = typeToString(type, scope);
1069 if(marshal)
1070 {
1071 out << nl << stream << ".writeProxy(" << tag << ", " << param << ");";
1072 }
1073 else
1074 {
1075 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<"
1076 << getUnqualified("Ice.ObjectPrx", scope) << ">(" << stream << ".readProxy(" << tag << "));";
1077 }
1078 break;
1079 }
1080 case Builtin::KindLocalObject:
1081 {
1082 assert(false);
1083 break;
1084 }
1085 }
1086 return;
1087 }
1088
1089 ProxyPtr prx = ProxyPtr::dynamicCast(type);
1090 if(prx)
1091 {
1092 if(marshal)
1093 {
1094 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag
1095 << ", " << getUnqualified("Ice.OptionalFormat", scope) << ".FSize))";
1096 out << sb;
1097 out << nl << "int pos = " << stream << ".startSize();";
1098 writeMarshalUnmarshalCode(out, type, scope, param + ".Value", marshal, customStream);
1099 out << nl << stream << ".endSize(pos);";
1100 out << eb;
1101 }
1102 else
1103 {
1104 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getUnqualified("Ice.OptionalFormat", scope)
1105 << ".FSize))";
1106 out << sb;
1107 out << nl << stream << ".skip(4);";
1108 string tmp = "tmpVal";
1109 string typeS = typeToString(type, scope);
1110 out << nl << typeS << ' ' << tmp << ';';
1111 writeMarshalUnmarshalCode(out, type, scope, tmp, marshal, customStream);
1112 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">(" << tmp << ");";
1113 out << eb;
1114 out << nl << "else";
1115 out << sb;
1116 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">();";
1117 out << eb;
1118 }
1119 return;
1120 }
1121
1122 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
1123 if(cl)
1124 {
1125 if(marshal)
1126 {
1127 out << nl << stream << ".writeValue(" << tag << ", " << param << ");";
1128 }
1129 else
1130 {
1131 out << nl << stream << ".readValue(" << tag << ", " << param << ");";
1132 }
1133 return;
1134 }
1135
1136 StructPtr st = StructPtr::dynamicCast(type);
1137 if(st)
1138 {
1139 if(marshal)
1140 {
1141 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
1142 << getOptionalFormat(st, scope) << "))";
1143 out << sb;
1144 if(st->isVariableLength())
1145 {
1146 out << nl << "int pos = " << stream << ".startSize();";
1147 }
1148 else
1149 {
1150 out << nl << stream << ".writeSize(" << st->minWireSize() << ");";
1151 }
1152 writeMarshalUnmarshalCode(out, type, scope, param + ".Value", marshal, customStream);
1153 if(st->isVariableLength())
1154 {
1155 out << nl << stream << ".endSize(pos);";
1156 }
1157 out << eb;
1158 }
1159 else
1160 {
1161 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(st, scope) << "))";
1162 out << sb;
1163 if(st->isVariableLength())
1164 {
1165 out << nl << stream << ".skip(4);";
1166 }
1167 else
1168 {
1169 out << nl << stream << ".skipSize();";
1170 }
1171 string typeS = typeToString(type, scope);
1172 string tmp = "tmpVal";
1173 if(isValueType(st))
1174 {
1175 out << nl << typeS << ' ' << tmp << " = new " << typeS << "();";
1176 }
1177 else
1178 {
1179 out << nl << typeS << ' ' << tmp << " = null;";
1180 }
1181 writeMarshalUnmarshalCode(out, type, scope, tmp, marshal, customStream);
1182 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">(" << tmp << ");";
1183 out << eb;
1184 out << nl << "else";
1185 out << sb;
1186 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">();";
1187 out << eb;
1188 }
1189 return;
1190 }
1191
1192 EnumPtr en = EnumPtr::dynamicCast(type);
1193 if(en)
1194 {
1195 size_t sz = en->enumerators().size();
1196 if(marshal)
1197 {
1198 out << nl << "if(" << param << ".HasValue)";
1199 out << sb;
1200 out << nl << stream << ".writeEnum(" << tag << ", (int)" << param << ".Value, " << sz << ");";
1201 out << eb;
1202 }
1203 else
1204 {
1205 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getUnqualified("Ice.OptionalFormat", scope)
1206 << ".Size))";
1207 out << sb;
1208 string typeS = typeToString(type, scope);
1209 string tmp = "tmpVal";
1210 out << nl << typeS << ' ' << tmp << ';';
1211 writeMarshalUnmarshalCode(out, type, scope, tmp, marshal, customStream);
1212 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">(" << tmp << ");";
1213 out << eb;
1214 out << nl << "else";
1215 out << sb;
1216 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">();";
1217 out << eb;
1218 }
1219 return;
1220 }
1221
1222 SequencePtr seq = SequencePtr::dynamicCast(type);
1223 if(seq)
1224 {
1225 writeOptionalSequenceMarshalUnmarshalCode(out, seq, scope, param, tag, marshal, stream);
1226 return;
1227 }
1228
1229 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
1230 assert(d);
1231 TypePtr keyType = d->keyType();
1232 TypePtr valueType = d->valueType();
1233 if(marshal)
1234 {
1235 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
1236 << getOptionalFormat(d, scope) << "))";
1237 out << sb;
1238 if(keyType->isVariableLength() || valueType->isVariableLength())
1239 {
1240 out << nl << "int pos = " << stream << ".startSize();";
1241 }
1242 else
1243 {
1244 out << nl << stream << ".writeSize(" << param << ".Value == null ? 1 : " << param << ".Value.Count * "
1245 << (keyType->minWireSize() + valueType->minWireSize()) << " + (" << param
1246 << ".Value.Count > 254 ? 5 : 1));";
1247 }
1248 writeMarshalUnmarshalCode(out, type, scope, param + ".Value", marshal, customStream);
1249 if(keyType->isVariableLength() || valueType->isVariableLength())
1250 {
1251 out << nl << stream << ".endSize(pos);";
1252 }
1253 out << eb;
1254 }
1255 else
1256 {
1257 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(d, scope) << "))";
1258 out << sb;
1259 if(keyType->isVariableLength() || valueType->isVariableLength())
1260 {
1261 out << nl << stream << ".skip(4);";
1262 }
1263 else
1264 {
1265 out << nl << stream << ".skipSize();";
1266 }
1267 string typeS = typeToString(type, scope);
1268 string tmp = "tmpVal";
1269 out << nl << typeS << ' ' << tmp << " = new " << typeS << "();";
1270 writeMarshalUnmarshalCode(out, type, scope, tmp, marshal, customStream);
1271 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">(" << tmp << ");";
1272 out << eb;
1273 out << nl << "else";
1274 out << sb;
1275 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << typeS << ">();";
1276 out << eb;
1277 }
1278 }
1279
1280 void
writeSequenceMarshalUnmarshalCode(Output & out,const SequencePtr & seq,const string & scope,const string & param,bool marshal,bool useHelper,const string & customStream)1281 Slice::CsGenerator::writeSequenceMarshalUnmarshalCode(Output& out,
1282 const SequencePtr& seq,
1283 const string& scope,
1284 const string& param,
1285 bool marshal,
1286 bool useHelper,
1287 const string& customStream)
1288 {
1289 string stream = customStream;
1290 if(stream.empty())
1291 {
1292 stream = marshal ? "ostr" : "istr";
1293 }
1294
1295 ContainedPtr cont = ContainedPtr::dynamicCast(seq->container());
1296 assert(cont);
1297 if(useHelper)
1298 {
1299 string helperName = getUnqualified(getNamespace(seq) + "." + seq->name() + "Helper", scope);
1300 if(marshal)
1301 {
1302 out << nl << helperName << ".write(" << stream << ", " << param << ");";
1303 }
1304 else
1305 {
1306 out << nl << param << " = " << helperName << ".read(" << stream << ");";
1307 }
1308 return;
1309 }
1310
1311 TypePtr type = seq->type();
1312 string typeS = typeToString(type, scope);
1313
1314 const string genericPrefix = "cs:generic:";
1315 string genericType;
1316 string addMethod = "Add";
1317 const bool isGeneric = seq->findMetaData(genericPrefix, genericType);
1318 bool isStack = false;
1319 bool isList = false;
1320 bool isLinkedList = false;
1321 bool isCustom = false;
1322 if(isGeneric)
1323 {
1324 genericType = genericType.substr(genericPrefix.size());
1325 if(genericType == "LinkedList")
1326 {
1327 addMethod = "AddLast";
1328 isLinkedList = true;
1329 }
1330 else if(genericType == "Queue")
1331 {
1332 addMethod = "Enqueue";
1333 }
1334 else if(genericType == "Stack")
1335 {
1336 addMethod = "Push";
1337 isStack = true;
1338 }
1339 else if(genericType == "List")
1340 {
1341 isList = true;
1342 }
1343 else
1344 {
1345 isCustom = true;
1346 }
1347 }
1348
1349 const bool isArray = !isGeneric;
1350 const string limitID = isArray ? "Length" : "Count";
1351
1352 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
1353 ProxyPtr proxy = ProxyPtr::dynamicCast(type);
1354 ClassDefPtr clsDef;
1355 if(proxy)
1356 {
1357 clsDef = proxy->_class()->definition();
1358 }
1359 bool isObjectProxySeq = clsDef && !clsDef->isInterface() && clsDef->allOperations().size() == 0;
1360 Builtin::Kind kind = builtin ? builtin->kind() : Builtin::KindObjectProxy;
1361
1362 if(builtin || isObjectProxySeq)
1363 {
1364 switch(kind)
1365 {
1366 case Builtin::KindValue:
1367 case Builtin::KindObject:
1368 case Builtin::KindObjectProxy:
1369 {
1370 if(marshal)
1371 {
1372 out << nl << "if(" << param << " == null)";
1373 out << sb;
1374 out << nl << stream << ".writeSize(0);";
1375 out << eb;
1376 out << nl << "else";
1377 out << sb;
1378 out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
1379 if(isGeneric && !isList)
1380 {
1381 if(isStack)
1382 {
1383 //
1384 // If the collection is a stack, write in top-to-bottom order. Stacks
1385 // cannot contain Ice.Object.
1386 //
1387 out << nl << getUnqualified("Ice.ObjectPrx", scope) << "[] " << param << "_tmp = " << param
1388 << ".ToArray();";
1389 out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
1390 out << sb;
1391 out << nl << stream << ".writeProxy(" << param << "_tmp[ix]);";
1392 out << eb;
1393 }
1394 else
1395 {
1396 out << nl << "global::System.Collections.Generic.IEnumerator<" << typeS
1397 << "> e = " << param << ".GetEnumerator();";
1398 out << nl << "while(e.MoveNext())";
1399 out << sb;
1400 string func = (kind == Builtin::KindObject ||
1401 kind == Builtin::KindValue) ? "writeValue" : "writeProxy";
1402 out << nl << stream << '.' << func << "(e.Current);";
1403 out << eb;
1404 }
1405 }
1406 else
1407 {
1408 out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
1409 out << sb;
1410 string func = (kind == Builtin::KindObject ||
1411 kind == Builtin::KindValue) ? "writeValue" : "writeProxy";
1412 out << nl << stream << '.' << func << '(' << param << "[ix]);";
1413 out << eb;
1414 }
1415 out << eb;
1416 }
1417 else
1418 {
1419 out << nl << "int " << param << "_lenx = " << stream << ".readAndCheckSeqSize("
1420 << static_cast<unsigned>(type->minWireSize()) << ");";
1421 if(!isStack)
1422 {
1423 out << nl << param << " = new ";
1424 }
1425 if((kind == Builtin::KindObject || kind == Builtin::KindValue))
1426 {
1427 string patcherName;
1428 if(isArray)
1429 {
1430 patcherName = "global::IceInternal.Patcher.arrayReadValue";
1431 out << getUnqualified("Ice.Value", scope) << "[" << param << "_lenx];";
1432 }
1433 else if(isCustom)
1434 {
1435 patcherName = "global::IceInternal.Patcher.customSeqReadValue";
1436 out << "global::" << genericType << "<" << getUnqualified("Ice.Value", scope) << ">();";
1437 }
1438 else
1439 {
1440 patcherName = "global::IceInternal.Patcher.listReadValue";
1441 out << "global::System.Collections.Generic." << genericType << "<"
1442 << getUnqualified("Ice.Value", scope) << ">(" << param << "_lenx);";
1443 }
1444 out << nl << "for(int ix = 0; ix < " << param << "_lenx; ++ix)";
1445 out << sb;
1446 out << nl << stream << ".readValue(" << patcherName << "<"
1447 << getUnqualified("Ice.Value", scope) << ">(" << param << ", ix));";
1448 }
1449 else
1450 {
1451 if(isStack)
1452 {
1453 out << nl << getUnqualified("Ice.ObjectPrx", scope) << "[] " << param << "_tmp = new "
1454 << getUnqualified("Ice.ObjectPrx", scope) << "[" << param << "_lenx];";
1455 }
1456 else if(isArray)
1457 {
1458 out << getUnqualified("Ice.ObjectPrx", scope) << "[" << param << "_lenx];";
1459 }
1460 else if(isCustom)
1461 {
1462 out << "global::" << genericType << "<" << getUnqualified("Ice.ObjectPrx", scope)
1463 << ">();";
1464 }
1465 else
1466 {
1467 out << "global::System.Collections.Generic." << genericType << "<"
1468 << getUnqualified("Ice.ObjectPrx", scope) << ">(";
1469 if(!isLinkedList)
1470 {
1471 out << param << "_lenx";
1472 }
1473 out << ");";
1474 }
1475
1476 out << nl << "for(int ix = 0; ix < " << param << "_lenx; ++ix)";
1477 out << sb;
1478 if(isArray || isStack)
1479 {
1480 string v = isArray ? param : param + "_tmp";
1481 out << nl << v << "[ix] = " << stream << ".readProxy();";
1482 }
1483 else
1484 {
1485 out << nl << getUnqualified("Ice.ObjectPrx", scope) << " val = new "
1486 << getUnqualified("Ice.ObjectPrxHelperBase", scope) << "();";
1487 out << nl << "val = " << stream << ".readProxy();";
1488 out << nl << param << "." << addMethod << "(val);";
1489 }
1490 }
1491 out << eb;
1492
1493 if(isStack)
1494 {
1495 out << nl << "global::System.Array.Reverse(" << param << "_tmp);";
1496 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">("
1497 << param << "_tmp);";
1498 }
1499 }
1500 break;
1501 }
1502 default:
1503 {
1504 string prefix = "cs:serializable:";
1505 string meta;
1506 if(seq->findMetaData(prefix, meta))
1507 {
1508 if(marshal)
1509 {
1510 out << nl << stream << ".writeSerializable(" << param << ");";
1511 }
1512 else
1513 {
1514 out << nl << param << " = (" << typeToString(seq, scope) << ")" << stream << ".readSerializable();";
1515 }
1516 break;
1517 }
1518
1519 string func = typeS;
1520 func[0] = static_cast<char>(toupper(static_cast<unsigned char>(typeS[0])));
1521 if(marshal)
1522 {
1523 if(isArray)
1524 {
1525 out << nl << stream << ".write" << func << "Seq(" << param << ");";
1526 }
1527 else if(isCustom)
1528 {
1529 out << nl << stream << ".write" << func << "Seq(" << param << " == null ? 0 : "
1530 << param << ".Count, " << param << ");";
1531 }
1532 else
1533 {
1534 assert(isGeneric);
1535 out << nl << stream << ".write" << func << "Seq(" << param << " == null ? 0 : "
1536 << param << ".Count, " << param << ");";
1537 }
1538 }
1539 else
1540 {
1541 if(isArray)
1542 {
1543 out << nl << param << " = " << stream << ".read" << func << "Seq();";
1544 }
1545 else if(isCustom)
1546 {
1547 out << sb;
1548 out << nl << param << " = new " << "global::" << genericType << "<"
1549 << typeToString(type, scope) << ">();";
1550 out << nl << "int szx = " << stream << ".readSize();";
1551 out << nl << "for(int ix = 0; ix < szx; ++ix)";
1552 out << sb;
1553 out << nl << param << ".Add(" << stream << ".read" << func << "());";
1554 out << eb;
1555 out << eb;
1556 }
1557 else
1558 {
1559 assert(isGeneric);
1560 out << nl << stream << ".read" << func << "Seq(out " << param << ");";
1561 }
1562 }
1563 break;
1564 }
1565 }
1566 return;
1567 }
1568
1569 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
1570 if(cl)
1571 {
1572 if(marshal)
1573 {
1574 out << nl << "if(" << param << " == null)";
1575 out << sb;
1576 out << nl << stream << ".writeSize(0);";
1577 out << eb;
1578 out << nl << "else";
1579 out << sb;
1580 out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
1581 if(isGeneric && !isList)
1582 {
1583 //
1584 // Stacks cannot contain class instances, so there is no need to marshal a
1585 // stack bottom-up here.
1586 //
1587 out << nl << "global::System.Collections.Generic.IEnumerator<" << typeS
1588 << "> e = " << param << ".GetEnumerator();";
1589 out << nl << "while(e.MoveNext())";
1590 out << sb;
1591 out << nl << stream << ".writeValue(e.Current);";
1592 out << eb;
1593 }
1594 else
1595 {
1596 out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
1597 out << sb;
1598 out << nl << stream << ".writeValue(" << param << "[ix]);";
1599 out << eb;
1600 }
1601 out << eb;
1602 }
1603 else
1604 {
1605 out << sb;
1606 out << nl << "int szx = " << stream << ".readAndCheckSeqSize("
1607 << static_cast<unsigned>(type->minWireSize()) << ");";
1608 out << nl << param << " = new ";
1609 string patcherName;
1610 if(isArray)
1611 {
1612 patcherName = "global::IceInternal.Patcher.arrayReadValue";
1613 out << toArrayAlloc(typeS + "[]", "szx") << ";";
1614 }
1615 else if(isCustom)
1616 {
1617 patcherName = "global::IceInternal.Patcher.customSeqReadValue";
1618 out << "global::" << genericType << "<" << typeS << ">();";
1619 }
1620 else
1621 {
1622 patcherName = "global::IceInternal.Patcher.listReadValue";
1623 out << "global::System.Collections.Generic." << genericType << "<" << typeS << ">(szx);";
1624 }
1625 out << nl << "for(int ix = 0; ix < szx; ++ix)";
1626 out << sb;
1627 string scoped = ContainedPtr::dynamicCast(type)->scoped();
1628 out << nl << stream << ".readValue(" << patcherName << '<' << typeS << ">(" << param << ", ix));";
1629 out << eb;
1630 out << eb;
1631 }
1632 return;
1633 }
1634
1635 StructPtr st = StructPtr::dynamicCast(type);
1636 if(st)
1637 {
1638 if(marshal)
1639 {
1640 out << nl << "if(" << param << " == null)";
1641 out << sb;
1642 out << nl << stream << ".writeSize(0);";
1643 out << eb;
1644 out << nl << "else";
1645 out << sb;
1646 out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
1647 if(isGeneric && !isList)
1648 {
1649 //
1650 // Stacks are marshaled top-down.
1651 //
1652 if(isStack)
1653 {
1654 out << nl << typeS << "[] " << param << "_tmp = " << param << ".ToArray();";
1655 out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
1656 }
1657 else
1658 {
1659 out << nl << "global::System.Collections.Generic.IEnumerator<" << typeS
1660 << "> e = " << param << ".GetEnumerator();";
1661 out << nl << "while(e.MoveNext())";
1662 }
1663 }
1664 else
1665 {
1666 out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
1667 }
1668 out << sb;
1669 string call;
1670 if(isGeneric && !isList && !isStack)
1671 {
1672 if(isValueType(type))
1673 {
1674 call = "e.Current";
1675 }
1676 else
1677 {
1678 call = "(e.Current == null ? new ";
1679 call += typeS + "() : e.Current)";
1680 }
1681 }
1682 else
1683 {
1684 if(isValueType(type))
1685 {
1686 call = param;
1687 if(isStack)
1688 {
1689 call += "_tmp";
1690 }
1691 }
1692 else
1693 {
1694 call = "(";
1695 call += param;
1696 if(isStack)
1697 {
1698 call += "_tmp";
1699 }
1700 call += "[ix] == null ? new " + typeS + "() : " + param;
1701 if(isStack)
1702 {
1703 call += "_tmp";
1704 }
1705 }
1706 call += "[ix]";
1707 if(!isValueType(type))
1708 {
1709 call += ")";
1710 }
1711 }
1712 call += ".";
1713 call += "ice_writeMembers";
1714 call += "(" + stream + ");";
1715 out << nl << call;
1716 out << eb;
1717 out << eb;
1718 }
1719 else
1720 {
1721 out << sb;
1722 out << nl << "int szx = " << stream << ".readAndCheckSeqSize("
1723 << static_cast<unsigned>(type->minWireSize()) << ");";
1724 if(isArray)
1725 {
1726 out << nl << param << " = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
1727 }
1728 else if(isCustom)
1729 {
1730 out << nl << param << " = new global::" << genericType << "<" << typeS << ">();";
1731 }
1732 else if(isStack)
1733 {
1734 out << nl << typeS << "[] " << param << "_tmp = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
1735 }
1736 else
1737 {
1738 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">(";
1739 if(!isLinkedList)
1740 {
1741 out << "szx";
1742 }
1743 out << ");";
1744 }
1745 out << nl << "for(int ix = 0; ix < szx; ++ix)";
1746 out << sb;
1747 if(isArray || isStack)
1748 {
1749 string v = isArray ? param : param + "_tmp";
1750 if(!isValueType(st))
1751 {
1752 out << nl << v << "[ix] = new " << typeS << "();";
1753 }
1754 out << nl << v << "[ix].ice_readMembers(" << stream << ");";
1755 }
1756 else
1757 {
1758 out << nl << typeS << " val = new " << typeS << "();";
1759 out << nl << "val.ice_readMembers(" << stream << ");";
1760 out << nl << param << "." << addMethod << "(val);";
1761 }
1762 out << eb;
1763 if(isStack)
1764 {
1765 out << nl << "global::System.Array.Reverse(" << param << "_tmp);";
1766 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">("
1767 << param << "_tmp);";
1768 }
1769 out << eb;
1770 }
1771 return;
1772 }
1773
1774 EnumPtr en = EnumPtr::dynamicCast(type);
1775 if(en)
1776 {
1777 if(marshal)
1778 {
1779 out << nl << "if(" << param << " == null)";
1780 out << sb;
1781 out << nl << stream << ".writeSize(0);";
1782 out << eb;
1783 out << nl << "else";
1784 out << sb;
1785 out << nl << stream << ".writeSize(" << param << '.'<< limitID << ");";
1786 if(isGeneric && !isList)
1787 {
1788 //
1789 // Stacks are marshaled top-down.
1790 //
1791 if(isStack)
1792 {
1793 out << nl << typeS << "[] " << param << "_tmp = " << param << ".ToArray();";
1794 out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
1795 out << sb;
1796 out << nl << stream << ".writeEnum((int)" << param << "_tmp[ix], " << en->maxValue() << ");";
1797 out << eb;
1798 }
1799 else
1800 {
1801 out << nl << "global::System.Collections.Generic.IEnumerator<" << typeS
1802 << "> e = " << param << ".GetEnumerator();";
1803 out << nl << "while(e.MoveNext())";
1804 out << sb;
1805 out << nl << stream << ".writeEnum((int)e.Current, " << en->maxValue() << ");";
1806 out << eb;
1807 }
1808 }
1809 else
1810 {
1811 out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
1812 out << sb;
1813 out << nl << stream << ".writeEnum((int)" << param << "[ix], " << en->maxValue() << ");";
1814 out << eb;
1815 }
1816 out << eb;
1817 }
1818 else
1819 {
1820 out << sb;
1821 out << nl << "int szx = " << stream << ".readAndCheckSeqSize(" <<
1822 static_cast<unsigned>(type->minWireSize()) << ");";
1823 if(isArray)
1824 {
1825 out << nl << param << " = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
1826 }
1827 else if(isCustom)
1828 {
1829 out << nl << param << " = new global::" << genericType << "<" << typeS << ">();";
1830 }
1831 else if(isStack)
1832 {
1833 out << nl << typeS << "[] " << param << "_tmp = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
1834 }
1835 else
1836 {
1837 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">(";
1838 if(!isLinkedList)
1839 {
1840 out << "szx";
1841 }
1842 out << ");";
1843 }
1844 out << nl << "for(int ix = 0; ix < szx; ++ix)";
1845 out << sb;
1846 if(isArray || isStack)
1847 {
1848 string v = isArray ? param : param + "_tmp";
1849 out << nl << v << "[ix] = (" << typeS << ')' << stream << ".readEnum(" << en->maxValue() << ");";
1850 }
1851 else
1852 {
1853 out << nl << param << "." << addMethod << "((" << typeS << ')' << stream << ".readEnum("
1854 << en->maxValue() << "));";
1855 }
1856 out << eb;
1857 if(isStack)
1858 {
1859 out << nl << "global::System.Array.Reverse(" << param << "_tmp);";
1860 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">("
1861 << param << "_tmp);";
1862 }
1863 out << eb;
1864 }
1865 return;
1866 }
1867
1868 string helperName;
1869 if(ProxyPtr::dynamicCast(type))
1870 {
1871 helperName = getUnqualified(ProxyPtr::dynamicCast(type)->_class(), scope, "", "PrxHelper");
1872 }
1873 else
1874 {
1875 helperName = getUnqualified(ContainedPtr::dynamicCast(type), scope, "", "Helper");
1876 }
1877
1878 string func;
1879 if(marshal)
1880 {
1881 func = "write";
1882 out << nl << "if(" << param << " == null)";
1883 out << sb;
1884 out << nl << stream << ".writeSize(0);";
1885 out << eb;
1886 out << nl << "else";
1887 out << sb;
1888 out << nl << stream << ".writeSize(" << param << '.' << limitID << ");";
1889 if(isGeneric && !isList)
1890 {
1891 //
1892 // Stacks are marshaled top-down.
1893 //
1894 if(isStack)
1895 {
1896 out << nl << typeS << "[] " << param << "_tmp = " << param << ".ToArray();";
1897 out << nl << "for(int ix = 0; ix < " << param << "_tmp.Length; ++ix)";
1898 out << sb;
1899 out << nl << helperName << '.' << func << '(' << stream << ", " << param << "_tmp[ix]);";
1900 out << eb;
1901 }
1902 else
1903 {
1904 out << nl << "global::System.Collections.Generic.IEnumerator<" << typeS
1905 << "> e = " << param << ".GetEnumerator();";
1906 out << nl << "while(e.MoveNext())";
1907 out << sb;
1908 out << nl << helperName << '.' << func << '(' << stream << ", e.Current);";
1909 out << eb;
1910 }
1911 }
1912 else
1913 {
1914 out << nl << "for(int ix = 0; ix < " << param << '.' << limitID << "; ++ix)";
1915 out << sb;
1916 out << nl << helperName << '.' << func << '(' << stream << ", " << param << "[ix]);";
1917 out << eb;
1918 }
1919 out << eb;
1920 }
1921 else
1922 {
1923 func = "read";
1924 out << sb;
1925 out << nl << "int szx = " << stream << ".readAndCheckSeqSize("
1926 << static_cast<unsigned>(type->minWireSize()) << ");";
1927 if(isArray)
1928 {
1929 out << nl << param << " = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
1930 }
1931 else if(isCustom)
1932 {
1933 out << nl << param << " = new global::" << genericType << "<" << typeS << ">();";
1934 }
1935 else if(isStack)
1936 {
1937 out << nl << typeS << "[] " << param << "_tmp = new " << toArrayAlloc(typeS + "[]", "szx") << ";";
1938 }
1939 else
1940 {
1941 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">();";
1942 }
1943 out << nl << "for(int ix = 0; ix < szx; ++ix)";
1944 out << sb;
1945 if(isArray || isStack)
1946 {
1947 string v = isArray ? param : param + "_tmp";
1948 out << nl << v << "[ix] = " << helperName << '.' << func << '(' << stream << ");";
1949 }
1950 else
1951 {
1952 out << nl << param << "." << addMethod << "(" << helperName << '.' << func << '(' << stream << "));";
1953 }
1954 out << eb;
1955 if(isStack)
1956 {
1957 out << nl << "global::System.Array.Reverse(" << param << "_tmp);";
1958 out << nl << param << " = new global::System.Collections.Generic." << genericType << "<" << typeS << ">("
1959 << param << "_tmp);";
1960 }
1961 out << eb;
1962 }
1963
1964 return;
1965 }
1966
1967 void
writeOptionalSequenceMarshalUnmarshalCode(Output & out,const SequencePtr & seq,const string & scope,const string & param,int tag,bool marshal,const string & customStream)1968 Slice::CsGenerator::writeOptionalSequenceMarshalUnmarshalCode(Output& out,
1969 const SequencePtr& seq,
1970 const string& scope,
1971 const string& param,
1972 int tag,
1973 bool marshal,
1974 const string& customStream)
1975 {
1976 string stream = customStream;
1977 if(stream.empty())
1978 {
1979 stream = marshal ? "ostr" : "istr";
1980 }
1981
1982 const TypePtr type = seq->type();
1983 const string typeS = typeToString(type, scope);
1984 const string seqS = typeToString(seq, scope);
1985
1986 string meta;
1987 const bool isArray = !seq->findMetaData("cs:generic:", meta);
1988 const string length = isArray ? param + ".Value.Length" : param + ".Value.Count";
1989
1990 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
1991 if(builtin)
1992 {
1993 switch(builtin->kind())
1994 {
1995 case Builtin::KindByte:
1996 case Builtin::KindBool:
1997 case Builtin::KindShort:
1998 case Builtin::KindInt:
1999 case Builtin::KindFloat:
2000 case Builtin::KindLong:
2001 case Builtin::KindDouble:
2002 case Builtin::KindString:
2003 {
2004 string func = typeS;
2005 func[0] = static_cast<char>(toupper(static_cast<unsigned char>(typeS[0])));
2006 const bool isSerializable = seq->findMetaData("cs:serializable:", meta);
2007
2008 if(marshal)
2009 {
2010 if(isSerializable)
2011 {
2012 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag
2013 << ", " << getUnqualified("Ice.OptionalFormat", scope) << ".VSize))";
2014 out << sb;
2015 out << nl << stream << ".writeSerializable(" << param << ".Value);";
2016 out << eb;
2017 }
2018 else if(isArray)
2019 {
2020 out << nl << stream << ".write" << func << "Seq(" << tag << ", " << param << ");";
2021 }
2022 else
2023 {
2024 out << nl << "if(" << param << ".HasValue)";
2025 out << sb;
2026 out << nl << stream << ".write" << func << "Seq(" << tag << ", " << param
2027 << ".Value == null ? 0 : " << param << ".Value.Count, " << param << ".Value);";
2028 out << eb;
2029 }
2030 }
2031 else
2032 {
2033 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq, scope) << "))";
2034 out << sb;
2035 if(builtin->isVariableLength())
2036 {
2037 out << nl << stream << ".skip(4);";
2038 }
2039 else if(builtin->kind() != Builtin::KindByte && builtin->kind() != Builtin::KindBool)
2040 {
2041 out << nl << stream << ".skipSize();";
2042 }
2043 string tmp = "tmpVal";
2044 out << nl << seqS << ' ' << tmp << ';';
2045 writeSequenceMarshalUnmarshalCode(out, seq, scope, tmp, marshal, true, stream);
2046 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">(" << tmp
2047 << ");";
2048 out << eb;
2049 out << nl << "else";
2050 out << sb;
2051 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">();";
2052 out << eb;
2053 }
2054 break;
2055 }
2056
2057 case Builtin::KindValue:
2058 case Builtin::KindObject:
2059 case Builtin::KindObjectProxy:
2060 {
2061 if(marshal)
2062 {
2063 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
2064 << getOptionalFormat(seq, scope) << "))";
2065 out << sb;
2066 out << nl << "int pos = " << stream << ".startSize();";
2067 writeSequenceMarshalUnmarshalCode(out, seq, scope, param + ".Value", marshal, true, stream);
2068 out << nl << stream << ".endSize(pos);";
2069 out << eb;
2070 }
2071 else
2072 {
2073 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq, scope) << "))";
2074 out << sb;
2075 out << nl << stream << ".skip(4);";
2076 string tmp = "tmpVal";
2077 out << nl << seqS << ' ' << tmp << ';';
2078 writeSequenceMarshalUnmarshalCode(out, seq, scope, tmp, marshal, true, stream);
2079 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">(" << tmp
2080 << ");";
2081 out << eb;
2082 out << nl << "else";
2083 out << sb;
2084 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">();";
2085 out << eb;
2086 }
2087 break;
2088 }
2089
2090 case Builtin::KindLocalObject:
2091 assert(false);
2092 }
2093
2094 return;
2095 }
2096
2097 StructPtr st = StructPtr::dynamicCast(type);
2098 if(st)
2099 {
2100 if(marshal)
2101 {
2102 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
2103 << getOptionalFormat(seq, scope) << "))";
2104 out << sb;
2105 if(st->isVariableLength())
2106 {
2107 out << nl << "int pos = " << stream << ".startSize();";
2108 }
2109 else if(st->minWireSize() > 1)
2110 {
2111 out << nl << stream << ".writeSize(" << param << ".Value == null ? 1 : " << length << " * "
2112 << st->minWireSize() << " + (" << length << " > 254 ? 5 : 1));";
2113 }
2114 writeSequenceMarshalUnmarshalCode(out, seq, scope, param + ".Value", marshal, true, stream);
2115 if(st->isVariableLength())
2116 {
2117 out << nl << stream << ".endSize(pos);";
2118 }
2119 out << eb;
2120 }
2121 else
2122 {
2123 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq, scope) << "))";
2124 out << sb;
2125 if(st->isVariableLength())
2126 {
2127 out << nl << stream << ".skip(4);";
2128 }
2129 else if(st->minWireSize() > 1)
2130 {
2131 out << nl << stream << ".skipSize();";
2132 }
2133 string tmp = "tmpVal";
2134 out << nl << seqS << ' ' << tmp << ';';
2135 writeSequenceMarshalUnmarshalCode(out, seq, scope, tmp, marshal, true, stream);
2136 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">(" << tmp << ");";
2137 out << eb;
2138 out << nl << "else";
2139 out << sb;
2140 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">();";
2141 out << eb;
2142 }
2143 return;
2144 }
2145
2146 //
2147 // At this point, all remaining element types have variable size.
2148 //
2149 if(marshal)
2150 {
2151 out << nl << "if(" << param << ".HasValue && " << stream << ".writeOptional(" << tag << ", "
2152 << getOptionalFormat(seq, scope) << "))";
2153 out << sb;
2154 out << nl << "int pos = " << stream << ".startSize();";
2155 writeSequenceMarshalUnmarshalCode(out, seq, scope, param + ".Value", marshal, true, stream);
2156 out << nl << stream << ".endSize(pos);";
2157 out << eb;
2158 }
2159 else
2160 {
2161 out << nl << "if(" << stream << ".readOptional(" << tag << ", " << getOptionalFormat(seq, scope) << "))";
2162 out << sb;
2163 out << nl << stream << ".skip(4);";
2164 string tmp = "tmpVal";
2165 out << nl << seqS << ' ' << tmp << ';';
2166 writeSequenceMarshalUnmarshalCode(out, seq, scope, tmp, marshal, true, stream);
2167 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">(" << tmp << ");";
2168 out << eb;
2169 out << nl << "else";
2170 out << sb;
2171 out << nl << param << " = new " << getUnqualified("Ice.Optional", scope) << "<" << seqS << ">();";
2172 out << eb;
2173 }
2174 }
2175
2176 void
writeSerializeDeserializeCode(Output & out,const TypePtr & type,const string & scope,const string & param,bool optional,int,bool serialize)2177 Slice::CsGenerator::writeSerializeDeserializeCode(Output &out,
2178 const TypePtr& type,
2179 const string& scope,
2180 const string& param,
2181 bool optional,
2182 int /*tag*/,
2183 bool serialize)
2184 {
2185 //
2186 // Could do it only when param == "info", but not as good for testing
2187 //
2188 string dataMember = "this." + param;
2189 if(optional)
2190 {
2191 const string typeName = typeToString(type, scope, true);
2192 if(serialize)
2193 {
2194 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2195 }
2196 else
2197 {
2198 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2199 << "));";
2200 }
2201 return;
2202 }
2203
2204 BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
2205 if(builtin)
2206 {
2207 switch(builtin->kind())
2208 {
2209 case Builtin::KindByte:
2210 {
2211 if(serialize)
2212 {
2213 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2214 }
2215 else
2216 {
2217 out << nl << dataMember << " = " << "info.GetByte(\"" << param << "\");";
2218 }
2219 break;
2220 }
2221 case Builtin::KindBool:
2222 {
2223 if(serialize)
2224 {
2225 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2226 }
2227 else
2228 {
2229 out << nl << dataMember << " = " << "info.GetBoolean(\"" << param << "\");";
2230 }
2231 break;
2232 }
2233 case Builtin::KindShort:
2234 {
2235 if(serialize)
2236 {
2237 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2238 }
2239 else
2240 {
2241 out << nl << dataMember << " = " << "info.GetInt16(\"" << param << "\");";
2242 }
2243 break;
2244 }
2245 case Builtin::KindInt:
2246 {
2247 if(serialize)
2248 {
2249 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2250 }
2251 else
2252 {
2253 out << nl << dataMember << " = " << "info.GetInt32(\"" << param << "\");";
2254 }
2255 break;
2256 }
2257 case Builtin::KindLong:
2258 {
2259 if(serialize)
2260 {
2261 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2262 }
2263 else
2264 {
2265 out << nl << dataMember << " = " << "info.GetInt64(\"" << param << "\");";
2266 }
2267 break;
2268 }
2269 case Builtin::KindFloat:
2270 {
2271 if(serialize)
2272 {
2273 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2274 }
2275 else
2276 {
2277 out << nl << dataMember << " = " << "info.GetSingle(\"" << param << "\");";
2278 }
2279 break;
2280 }
2281 case Builtin::KindDouble:
2282 {
2283 if(serialize)
2284 {
2285 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ");";
2286 }
2287 else
2288 {
2289 out << nl << dataMember << " = " << "info.GetDouble(\"" << param << "\");";
2290 }
2291 break;
2292 }
2293 case Builtin::KindString:
2294 {
2295 if(serialize)
2296 {
2297 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << " == null ? \"\" : "
2298 << dataMember << ");";
2299 }
2300 else
2301 {
2302 out << nl << dataMember << " = " << "info.GetString(\"" << param << "\");";
2303 }
2304 break;
2305 }
2306 case Builtin::KindValue:
2307 case Builtin::KindObject:
2308 case Builtin::KindLocalObject:
2309 {
2310 const string typeName = typeToString(type, scope, false);
2311 if(serialize)
2312 {
2313 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2314 }
2315 else
2316 {
2317 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof("
2318 << typeName << "));";
2319 }
2320 break;
2321 }
2322 case Builtin::KindObjectProxy:
2323 {
2324 if(serialize)
2325 {
2326 out << nl << "info.AddValue(\"" << param << "\", " << dataMember
2327 << ", typeof(Ice.ObjectPrxHelperBase));";
2328 }
2329 else
2330 {
2331 out << nl << dataMember << " = (Ice.ObjectPrx)info.GetValue(\"" << param
2332 << "\", typeof(Ice.ObjectPrxHelperBase));";
2333 }
2334 break;
2335 }
2336 }
2337 return;
2338 }
2339
2340 ProxyPtr prx = ProxyPtr::dynamicCast(type);
2341 if(prx)
2342 {
2343 const string typeName = typeToString(type, scope, false);
2344 if(serialize)
2345 {
2346 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "Helper));";
2347 }
2348 else
2349 {
2350 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2351 << "Helper));";
2352 }
2353 return;
2354 }
2355
2356 ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
2357 if(cl)
2358 {
2359 const string typeName = typeToString(type, scope, false);
2360 if(serialize)
2361 {
2362 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2363 }
2364 else
2365 {
2366 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2367 << "));";
2368 }
2369 return;
2370 }
2371
2372 StructPtr st = StructPtr::dynamicCast(type);
2373 if(st)
2374 {
2375 const string typeName = typeToString(type, scope, false);
2376 if(serialize)
2377 {
2378 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2379 }
2380 else
2381 {
2382 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2383 << "));";
2384 }
2385 return;
2386 }
2387
2388 EnumPtr en = EnumPtr::dynamicCast(type);
2389 if(en)
2390 {
2391 const string typeName = typeToString(type, scope, false);
2392 if(serialize)
2393 {
2394 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2395 }
2396 else
2397 {
2398 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2399 << "));";
2400 }
2401 return;
2402 }
2403
2404 SequencePtr seq = SequencePtr::dynamicCast(type);
2405 if(seq)
2406 {
2407 const string typeName = typeToString(type, scope, false);
2408 if(serialize)
2409 {
2410 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2411 }
2412 else
2413 {
2414 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2415 << "));";
2416 }
2417 return;
2418 }
2419
2420 DictionaryPtr d = DictionaryPtr::dynamicCast(type);
2421 assert(d);
2422 const string typeName = typeToString(type, scope, false);
2423 if(serialize)
2424 {
2425 out << nl << "info.AddValue(\"" << param << "\", " << dataMember << ", typeof(" << typeName << "));";
2426 }
2427 else
2428 {
2429 out << nl << dataMember << " = (" << typeName << ")info.GetValue(\"" << param << "\", typeof(" << typeName
2430 << "));";
2431 }
2432 }
2433
2434 string
toArrayAlloc(const string & decl,const string & sz)2435 Slice::CsGenerator::toArrayAlloc(const string& decl, const string& sz)
2436 {
2437 int count = 0;
2438 string::size_type pos = decl.size();
2439 while(pos > 1 && decl.substr(pos - 2, 2) == "[]")
2440 {
2441 ++count;
2442 pos -= 2;
2443 }
2444 assert(count > 0);
2445
2446 ostringstream o;
2447 o << decl.substr(0, pos) << '[' << sz << ']' << decl.substr(pos + 2);
2448 return o.str();
2449 }
2450
2451 void
validateMetaData(const UnitPtr & u)2452 Slice::CsGenerator::validateMetaData(const UnitPtr& u)
2453 {
2454 MetaDataVisitor visitor;
2455 u->visit(&visitor, true);
2456 }
2457
2458 bool
visitUnitStart(const UnitPtr & p)2459 Slice::CsGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p)
2460 {
2461 //
2462 // Validate global metadata in the top-level file and all included files.
2463 //
2464 StringList files = p->allFiles();
2465 for(StringList::iterator q = files.begin(); q != files.end(); ++q)
2466 {
2467 string file = *q;
2468 DefinitionContextPtr dc = p->findDefinitionContext(file);
2469 assert(dc);
2470 StringList globalMetaData = dc->getMetaData();
2471 StringList newGlobalMetaData;
2472 static const string csPrefix = "cs:";
2473 static const string clrPrefix = "clr:";
2474
2475 for(StringList::iterator r = globalMetaData.begin(); r != globalMetaData.end(); ++r)
2476 {
2477 string& s = *r;
2478 string oldS = s;
2479
2480 if(s.find(clrPrefix) == 0)
2481 {
2482 s.replace(0, clrPrefix.size(), csPrefix);
2483 }
2484
2485 if(s.find(csPrefix) == 0)
2486 {
2487 static const string csAttributePrefix = csPrefix + "attribute:";
2488 static const string csTypeIdNsPrefix = csPrefix + "typeid-namespace:";
2489 if(!(s.find(csTypeIdNsPrefix) == 0 && s.size() > csTypeIdNsPrefix.size()) &&
2490 !(s.find(csAttributePrefix) == 0 && s.size() > csAttributePrefix.size()))
2491 {
2492 dc->warning(InvalidMetaData, file, -1, "ignoring invalid global metadata `" + oldS + "'");
2493 continue;
2494 }
2495 }
2496 newGlobalMetaData.push_back(oldS);
2497 }
2498
2499 dc->setMetaData(newGlobalMetaData);
2500 }
2501 return true;
2502 }
2503
2504 bool
visitModuleStart(const ModulePtr & p)2505 Slice::CsGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
2506 {
2507 validate(p);
2508 return true;
2509 }
2510
2511 void
visitModuleEnd(const ModulePtr &)2512 Slice::CsGenerator::MetaDataVisitor::visitModuleEnd(const ModulePtr&)
2513 {
2514 }
2515
2516 void
visitClassDecl(const ClassDeclPtr & p)2517 Slice::CsGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
2518 {
2519 validate(p);
2520 }
2521
2522 bool
visitClassDefStart(const ClassDefPtr & p)2523 Slice::CsGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
2524 {
2525 validate(p);
2526 return true;
2527 }
2528
2529 void
visitClassDefEnd(const ClassDefPtr &)2530 Slice::CsGenerator::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
2531 {
2532 }
2533
2534 bool
visitExceptionStart(const ExceptionPtr & p)2535 Slice::CsGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
2536 {
2537 validate(p);
2538 return true;
2539 }
2540
2541 void
visitExceptionEnd(const ExceptionPtr &)2542 Slice::CsGenerator::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
2543 {
2544 }
2545
2546 bool
visitStructStart(const StructPtr & p)2547 Slice::CsGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p)
2548 {
2549 validate(p);
2550 return true;
2551 }
2552
2553 void
visitStructEnd(const StructPtr &)2554 Slice::CsGenerator::MetaDataVisitor::visitStructEnd(const StructPtr&)
2555 {
2556 }
2557
2558 void
visitOperation(const OperationPtr & p)2559 Slice::CsGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p)
2560 {
2561 validate(p);
2562
2563 ParamDeclList params = p->parameters();
2564 for(ParamDeclList::const_iterator i = params.begin(); i != params.end(); ++i)
2565 {
2566 visitParamDecl(*i);
2567 }
2568 }
2569
2570 void
visitParamDecl(const ParamDeclPtr & p)2571 Slice::CsGenerator::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p)
2572 {
2573 validate(p);
2574 }
2575
2576 void
visitDataMember(const DataMemberPtr & p)2577 Slice::CsGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p)
2578 {
2579 validate(p);
2580 }
2581
2582 void
visitSequence(const SequencePtr & p)2583 Slice::CsGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p)
2584 {
2585 validate(p);
2586 }
2587
2588 void
visitDictionary(const DictionaryPtr & p)2589 Slice::CsGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p)
2590 {
2591 validate(p);
2592 }
2593
2594 void
visitEnum(const EnumPtr & p)2595 Slice::CsGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p)
2596 {
2597 validate(p);
2598 }
2599
2600 void
visitConst(const ConstPtr & p)2601 Slice::CsGenerator::MetaDataVisitor::visitConst(const ConstPtr& p)
2602 {
2603 validate(p);
2604 }
2605
2606 void
validate(const ContainedPtr & cont)2607 Slice::CsGenerator::MetaDataVisitor::validate(const ContainedPtr& cont)
2608 {
2609 const string msg = "ignoring invalid metadata";
2610
2611 StringList localMetaData = cont->getMetaData();
2612 StringList newLocalMetaData;
2613
2614 const UnitPtr ut = cont->unit();
2615 const DefinitionContextPtr dc = ut->findDefinitionContext(cont->file());
2616 assert(dc);
2617
2618 for(StringList::iterator p = localMetaData.begin(); p != localMetaData.end(); ++p)
2619 {
2620 string& s = *p;
2621 string oldS = s;
2622
2623 const string csPrefix = "cs:";
2624 const string clrPrefix = "clr:";
2625
2626 if(s.find(clrPrefix) == 0)
2627 {
2628 s.replace(0, clrPrefix.size(), csPrefix);
2629 }
2630
2631 if(s.find(csPrefix) == 0)
2632 {
2633 SequencePtr seq = SequencePtr::dynamicCast(cont);
2634 if(seq)
2635 {
2636 static const string csGenericPrefix = csPrefix + "generic:";
2637 if(s.find(csGenericPrefix) == 0)
2638 {
2639 string type = s.substr(csGenericPrefix.size());
2640 if(type == "LinkedList" || type == "Queue" || type == "Stack")
2641 {
2642 if(!isClassType(seq->type()))
2643 {
2644 newLocalMetaData.push_back(s);
2645 continue;
2646 }
2647 }
2648 else if(!type.empty())
2649 {
2650 newLocalMetaData.push_back(s);
2651 continue; // Custom type or List<T>
2652 }
2653 }
2654 static const string csSerializablePrefix = csPrefix + "serializable:";
2655 if(s.find(csSerializablePrefix) == 0)
2656 {
2657 string meta;
2658 if(cont->findMetaData(csPrefix + "generic:", meta))
2659 {
2660 dc->warning(InvalidMetaData, cont->file(), cont->line(), msg + " `" + meta + "':\n" +
2661 "serialization can only be used with the array mapping for byte sequences");
2662 continue;
2663 }
2664 string type = s.substr(csSerializablePrefix.size());
2665 BuiltinPtr builtin = BuiltinPtr::dynamicCast(seq->type());
2666 if(!type.empty() && builtin && builtin->kind() == Builtin::KindByte)
2667 {
2668 newLocalMetaData.push_back(s);
2669 continue;
2670 }
2671 }
2672 }
2673 else if(StructPtr::dynamicCast(cont))
2674 {
2675 if(s.substr(csPrefix.size()) == "class")
2676 {
2677 newLocalMetaData.push_back(s);
2678 continue;
2679 }
2680 if(s.substr(csPrefix.size()) == "property")
2681 {
2682 newLocalMetaData.push_back(s);
2683 continue;
2684 }
2685 static const string csImplementsPrefix = csPrefix + "implements:";
2686 if(s.find(csImplementsPrefix) == 0)
2687 {
2688 newLocalMetaData.push_back(s);
2689 continue;
2690 }
2691 }
2692 else if(ClassDefPtr::dynamicCast(cont))
2693 {
2694 if(s.substr(csPrefix.size()) == "property")
2695 {
2696 newLocalMetaData.push_back(s);
2697 continue;
2698 }
2699 static const string csImplementsPrefix = csPrefix + "implements:";
2700 if(s.find(csImplementsPrefix) == 0)
2701 {
2702 newLocalMetaData.push_back(s);
2703 continue;
2704 }
2705 }
2706 else if(DictionaryPtr::dynamicCast(cont))
2707 {
2708 static const string csGenericPrefix = csPrefix + "generic:";
2709 if(s.find(csGenericPrefix) == 0)
2710 {
2711 string type = s.substr(csGenericPrefix.size());
2712 if(type == "SortedDictionary" || type == "SortedList")
2713 {
2714 newLocalMetaData.push_back(s);
2715 continue;
2716 }
2717 }
2718 }
2719 else if(DataMemberPtr::dynamicCast(cont))
2720 {
2721 DataMemberPtr dataMember = DataMemberPtr::dynamicCast(cont);
2722 StructPtr st = StructPtr::dynamicCast(dataMember->container());
2723 ExceptionPtr ex = ExceptionPtr::dynamicCast(dataMember->container());
2724 ClassDefPtr cl = ClassDefPtr::dynamicCast(dataMember->container());
2725 bool isLocal = (st && st->isLocal()) || (ex && ex->isLocal()) || (cl && cl->isLocal());
2726 static const string csTypePrefix = csPrefix + "type:";
2727 if(isLocal && s.find(csTypePrefix) == 0)
2728 {
2729 newLocalMetaData.push_back(s);
2730 continue;
2731 }
2732 }
2733 else if(ModulePtr::dynamicCast(cont))
2734 {
2735 static const string csNamespacePrefix = csPrefix + "namespace:";
2736 if(s.find(csNamespacePrefix) == 0 && s.size() > csNamespacePrefix.size())
2737 {
2738 newLocalMetaData.push_back(s);
2739 continue;
2740 }
2741 }
2742
2743 static const string csAttributePrefix = csPrefix + "attribute:";
2744 static const string csTie = csPrefix + "tie";
2745 if(s.find(csAttributePrefix) == 0 && s.size() > csAttributePrefix.size())
2746 {
2747 newLocalMetaData.push_back(s);
2748 continue;
2749 }
2750 else if(s.find(csTie) == 0 && s.size() == csTie.size())
2751 {
2752 newLocalMetaData.push_back(s);
2753 continue;
2754 }
2755
2756 dc->warning(InvalidMetaData, cont->file(), cont->line(), msg + " `" + oldS + "'");
2757 continue;
2758 }
2759 else if(s == "delegate")
2760 {
2761 ClassDefPtr cl = ClassDefPtr::dynamicCast(cont);
2762 if(cl && cl->isDelegate())
2763 {
2764 newLocalMetaData.push_back(s);
2765 continue;
2766 }
2767
2768 dc->warning(InvalidMetaData, cont->file(), cont->line(), msg + " `" + s + "'");
2769 continue;
2770 }
2771 newLocalMetaData.push_back(s);
2772 }
2773
2774 cont->setMetaData(newLocalMetaData);
2775 }
2776