OpenDDS  Snapshot(2023/04/28-20:55)
marshal_generator.cpp
Go to the documentation of this file.
1 /*
2  * Distributed under the OpenDDS License.
3  * See: http://www.opendds.org/license.html
4  */
5 
6 #include "marshal_generator.h"
7 
8 #include "dds_generator.h"
9 #include "field_info.h"
10 #include "topic_keys.h"
11 #include "be_util.h"
12 
14 #include <dds/DCPS/Definitions.h>
15 #include <dds/DCPS/Util.h>
16 #include <dds/DCPS/Serializer.h>
17 
18 #include <utl_identifier.h>
19 
20 #include <string>
21 #include <sstream>
22 #include <iostream>
23 #include <cctype>
24 #include <map>
25 
26 #define OPENDDS_IDL_STR(X) #X
27 
28 using std::string;
29 using namespace AstTypeClassification;
31 using namespace OpenDDS::DCPS;
32 
33 namespace {
34  const string RtpsNamespace = " ::OpenDDS::RTPS::", DdsNamespace = " ::DDS::";
35 
36  typedef bool (*gen_special_case)(const string& cxx);
37  typedef std::map<std::string, gen_special_case> SpecialCases;
38  SpecialCases special_struct_cases;
39  SpecialCases special_seq_cases;
40 
41  typedef bool (*gen_special_union)(const string& cxx,
42  AST_Union* u,
43  AST_Type* discriminator,
44  const std::vector<AST_UnionBranch*>& branches);
45  typedef std::map<std::string, gen_special_union> SpecialUnionCases;
46  SpecialUnionCases special_union_cases;
47 
48  bool genRtpsSpecialSequence(const string& cxx);
49  bool genPropertySpecialSequence(const string& cxx);
50  bool genRtpsSpecialStruct(const string& cxx);
51  bool genRtpsParameter(const string& cxx,
52  AST_Union* u,
53  AST_Type* discriminator,
54  const std::vector<AST_UnionBranch*>& branches);
55  bool genRtpsSubmessage(const string& cxx,
56  AST_Union* u,
57  AST_Type* discriminator,
58  const std::vector<AST_UnionBranch*>& branches);
59  bool genProperty_t(const string& cxx);
60  bool genBinaryProperty_t(const string& cxx);
61  bool genPropertyQosPolicy(const string& cxx);
62  bool genSecuritySubmessage(const string& cxx);
63 
64  void init_special_cases()
65  {
66  if (special_seq_cases.empty()) {
67  special_seq_cases["ParameterList"] = genRtpsSpecialSequence;
68  special_seq_cases["prop_seq"] = genPropertySpecialSequence;
69  }
70  if (special_struct_cases.empty()) {
71  special_struct_cases["rtps_set"] = genRtpsSpecialStruct;
72  special_struct_cases["Property_t"] = genProperty_t;
73  special_struct_cases["BinaryProperty_t"] = genBinaryProperty_t;
74  special_struct_cases["PropertyQosPolicy"] = genPropertyQosPolicy;
75  special_struct_cases["SecuritySubmessage"] = genSecuritySubmessage;
76  }
77  if (special_union_cases.empty()) {
78  special_union_cases["Parameter"] = genRtpsParameter;
79  special_union_cases["Submessage"] = genRtpsSubmessage;
80  }
81  }
82 
83  bool generate_special_sequence(
84  AST_Typedef* typedef_node, const std::string& cpp_name, bool& result)
85  {
86  std::string template_name;
87  if (!be_global->special_serialization(typedef_node, template_name)) {
88  return false;
89  }
90 
91  init_special_cases();
92  SpecialCases::iterator it = special_seq_cases.find(template_name);
93  if (it == special_seq_cases.end()) {
95  std::string("Invalid special case sequence template name \"") +
96  template_name + "\"", typedef_node);
97  result = false;
98  } else {
99  result = (it->second)(cpp_name);
100  }
101  return true;
102  }
103 
104  bool generate_special_struct(AST_Structure* node, const std::string& cpp_name, bool& result)
105  {
106  std::string template_name;
107  if (!be_global->special_serialization(node, template_name)) {
108  return false;
109  }
110 
111  init_special_cases();
112  SpecialCases::iterator it = special_struct_cases.find(template_name);
113  if (it == special_struct_cases.end()) {
115  std::string("Invalid special case struct template name \"") +
116  template_name + "\"", node);
117  result = false;
118  } else {
119  result = (it->second)(cpp_name);
120  }
121  return true;
122  }
123 
124  bool generate_special_union(const std::string& cpp_name, AST_Union* node,
125  AST_Type* disc_type, const std::vector<AST_UnionBranch*>& branches, bool& result)
126  {
127  std::string template_name;
128  if (!be_global->special_serialization(node, template_name)) {
129  return false;
130  }
131 
132  init_special_cases();
133  SpecialUnionCases::iterator it = special_union_cases.find(template_name);
134  if (it == special_union_cases.end()) {
136  std::string("Invalid special case struct template name \"") +
137  template_name + "\"", node);
138  result = false;
139  } else {
140  result = (it->second)(cpp_name, node, disc_type, branches);
141  }
142  return true;
143  }
144 
145  string streamCommon(const std::string& indent, AST_Decl* node, const string& name,
146  AST_Type* type, const string& prefix, bool wrap_nested_key_only,
147  Intro& intro, const string& stru = "");
148 
149  const std::string construct_bound_fail =
150  "strm.get_construction_status() == Serializer::BoundConstructionFailure";
151  const std::string construct_elem_fail =
152  "strm.get_construction_status() == Serializer::ElementConstructionFailure";
153 } /* namespace */
154 
155 bool marshal_generator::gen_enum(AST_Enum*, UTL_ScopedName* name,
156  const std::vector<AST_EnumVal*>& vals, const char*)
157 {
158  NamespaceGuard ng;
159  be_global->add_include("dds/DCPS/Serializer.h");
160  string cxx = scoped(name); // name as a C++ class
161  {
162  Function insertion("operator<<", "bool");
163  insertion.addArg("strm", "Serializer&");
164  insertion.addArg("enumval", "const " + cxx + "&");
165  insertion.endArgs();
166  const std::string idl_name = canonical_name(name);
167  be_global->impl_ <<
168  " if (CORBA::ULong(enumval) >= " << vals.size() << ") {\n"
169  " if (OpenDDS::DCPS::log_level >= OpenDDS::DCPS::LogLevel::Warning) {\n"
170  " ACE_ERROR((LM_WARNING, \"(%P|%t) WARNING: "
171  "%u is an invalid enumerated value for " << idl_name << "\\n\", enumval));\n"
172  " }\n"
173  " return false;\n"
174  " }\n"
175  " return strm << static_cast<CORBA::ULong>(enumval);\n";
176  }
177  {
178  Function extraction("operator>>", "bool");
179  extraction.addArg("strm", "Serializer&");
180  extraction.addArg("enumval", cxx + "&");
181  extraction.endArgs();
182  be_global->impl_ <<
183  " CORBA::ULong temp = 0;\n"
184  " if (strm >> temp) {\n"
185  " if (temp >= " << vals.size() << ") {\n"
186  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n"
187  " return false;\n"
188  " }\n"
189  " enumval = static_cast<" << cxx << ">(temp);\n"
190  " return true;\n"
191  " }\n"
192  " return false;\n";
193  }
194  return true;
195 }
196 
197 namespace {
198  string getSizeExprPrimitive(AST_Type* type,
199  const string& count_expr = "count", const string& size_expr = "size",
200  const string& encoding_expr = "encoding")
201  {
202  if (type->node_type() != AST_Decl::NT_pre_defined) {
203  return "";
204  }
205  AST_PredefinedType* pt = dynamic_cast<AST_PredefinedType*>(type);
206  const string first_args = encoding_expr + ", " + size_expr;
207  switch (pt->pt()) {
208  case AST_PredefinedType::PT_octet:
209  return "primitive_serialized_size_octet(" + first_args + ", " + count_expr + ")";
210  case AST_PredefinedType::PT_char:
211  return "primitive_serialized_size_char(" + first_args + ", " + count_expr + ")";
212  case AST_PredefinedType::PT_wchar:
213  return "primitive_serialized_size_wchar(" + first_args + ", " + count_expr + ")";
214  case AST_PredefinedType::PT_boolean:
215  return "primitive_serialized_size_boolean(" + first_args + ", " + count_expr + ")";
216 #if OPENDDS_HAS_EXPLICIT_INTS
217  case AST_PredefinedType::PT_uint8:
218  return "primitive_serialized_size_uint8(" + first_args + ", " + count_expr + ")";
219  case AST_PredefinedType::PT_int8:
220  return "primitive_serialized_size_int8(" + first_args + ", " + count_expr + ")";
221 #endif
222  default:
223  return "primitive_serialized_size(" + first_args + ", " +
224  scoped(type->name()) + "(), " + count_expr + ")";
225  }
226  }
227 
228  string getSerializerName(AST_Type* type)
229  {
230  switch (dynamic_cast<AST_PredefinedType*>(type)->pt()) {
231  case AST_PredefinedType::PT_long:
232  return "long";
233  case AST_PredefinedType::PT_ulong:
234  return "ulong";
235  case AST_PredefinedType::PT_short:
236  return "short";
237  case AST_PredefinedType::PT_ushort:
238  return "ushort";
239 #if OPENDDS_HAS_EXPLICIT_INTS
240  case AST_PredefinedType::PT_int8:
241  return "int8";
242  case AST_PredefinedType::PT_uint8:
243  return "uint8";
244 #endif
245  case AST_PredefinedType::PT_octet:
246  return "octet";
247  case AST_PredefinedType::PT_char:
248  return "char";
249  case AST_PredefinedType::PT_wchar:
250  return "wchar";
251  case AST_PredefinedType::PT_float:
252  return "float";
253  case AST_PredefinedType::PT_double:
254  return "double";
255  case AST_PredefinedType::PT_longlong:
256  return "longlong";
257  case AST_PredefinedType::PT_ulonglong:
258  return "ulonglong";
259  case AST_PredefinedType::PT_longdouble:
260  return "longdouble";
261  case AST_PredefinedType::PT_boolean:
262  return "boolean";
263  default:
264  return "";
265  }
266  }
267 
268  string nameOfSeqHeader(AST_Type* elem)
269  {
270  string ser = getSerializerName(elem);
271  if (ser.size()) {
272  ser[0] = static_cast<char>(std::toupper(ser[0]));
273  }
274  if (ser[0] == 'U' || ser[0] == 'W') {
275  ser[1] = static_cast<char>(std::toupper(ser[1]));
276  }
277  const size_t fourthLast = ser.size() - 4;
278  if (ser.size() > 7 && ser.substr(fourthLast) == "long") {
279  ser[fourthLast] = static_cast<char>(std::toupper(ser[fourthLast]));
280  }
281  if (ser == "Longdouble") return "LongDouble";
282  return ser;
283  }
284 
285  string streamAndCheck(const string& expr, size_t indent = 2)
286  {
287  string idt(indent, ' ');
288  return idt + "if (!(strm " + expr + ")) {\n" +
289  idt + " return false;\n" +
290  idt + "}\n";
291  }
292 
293  string checkAlignment(AST_Type* elem)
294  {
295  // At this point the stream must be 4-byte aligned (from the sequence
296  // length), but it might need to be 8-byte aligned for primitives > 4.
297  // (If XCDR version is < 2)
298  switch (dynamic_cast<AST_PredefinedType*>(elem)->pt()) {
299  case AST_PredefinedType::PT_longlong:
300  case AST_PredefinedType::PT_ulonglong:
301  case AST_PredefinedType::PT_double:
302  case AST_PredefinedType::PT_longdouble:
303  return " encoding.align(size, 8);\n";
304  default:
305  return "";
306  }
307  }
308 
309  bool genRtpsSpecialSequence(const string& cxx)
310  {
311  {
312  Function serialized_size("serialized_size", "void");
313  serialized_size.addArg("encoding", "const Encoding&");
314  serialized_size.addArg("size", "size_t&");
315  serialized_size.addArg("seq", "const " + cxx + "&");
316  serialized_size.endArgs();
317  be_global->impl_ <<
318  " for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
319  " if (seq[i]._d() == OpenDDS::RTPS::PID_SENTINEL) continue;\n"
320  " serialized_size(encoding, size, seq[i]);\n"
321  " align(size, 4);\n"
322  " }\n"
323  " size += 4; /* PID_SENTINEL */\n";
324  }
325  {
326  Function insertion("operator<<", "bool");
327  insertion.addArg("strm", "Serializer&");
328  insertion.addArg("seq", "const " + cxx + "&");
329  insertion.endArgs();
330  be_global->impl_ <<
331  " for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
332  " if (seq[i]._d() == OpenDDS::RTPS::PID_SENTINEL) continue;\n"
333  " if (!(strm << seq[i])) {\n"
334  " return false;\n"
335  " }\n"
336  " }\n"
337  " return (strm << OpenDDS::RTPS::PID_SENTINEL)\n"
338  " && (strm << OpenDDS::RTPS::PID_PAD);\n";
339  }
340  {
341  Function extraction("operator>>", "bool");
342  extraction.addArg("strm", "Serializer&");
343  extraction.addArg("seq", cxx + "&");
344  extraction.endArgs();
345  be_global->impl_ <<
346  " while (true) {\n"
347  " const CORBA::ULong idx = OpenDDS::DCPS::grow(seq) - 1;\n"
348  " if (!(strm >> seq[idx])) {\n"
349  " return false;\n"
350  " }\n"
351  " if (seq[idx]._d() == OpenDDS::RTPS::PID_SENTINEL) {\n"
352  " seq.length(idx);\n"
353  " return true;\n"
354  " }\n"
355  " }\n";
356  }
357  return true;
358  }
359 
360  bool genPropertySpecialSequence(const string& cxx)
361  {
362  {
363  Function serialized_size("serialized_size", "void");
364  serialized_size.addArg("encoding", "const Encoding&");
365  serialized_size.addArg("size", "size_t&");
366  serialized_size.addArg("seq", "const " + cxx + "&");
367  serialized_size.endArgs();
368  be_global->impl_ <<
369  " primitive_serialized_size_ulong(encoding, size);\n"
370  " for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
371  " serialized_size(encoding, size, seq[i]);\n"
372  " }\n";
373  }
374  {
375  Function insertion("operator<<", "bool");
376  insertion.addArg("strm", "Serializer&");
377  insertion.addArg("seq", "const " + cxx + "&");
378  insertion.endArgs();
379  be_global->impl_ <<
380  " CORBA::ULong serlen = 0;\n"
381  " for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
382  " if (seq[i].propagate) {\n"
383  " ++serlen;\n"
384  " }\n"
385  " }\n"
386  " if (!(strm << serlen)) {\n"
387  " return false;\n"
388  " }\n"
389  " for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
390  " if (!(strm << seq[i])) {\n"
391  " return false;\n"
392  " }\n"
393  " }\n"
394  " return true;\n";
395  }
396  {
397  Function extraction("operator>>", "bool");
398  extraction.addArg("strm", "Serializer&");
399  extraction.addArg("seq", cxx + "&");
400  extraction.endArgs();
401  be_global->impl_ <<
402  " CORBA::ULong length;\n"
403  " if (!(strm >> length)) {\n"
404  " return false;\n"
405  " }\n"
406  " if (length > strm.length()) {\n"
407  " return false;\n"
408  " }\n"
409  " seq.length(length);\n"
410  " for (CORBA::ULong i = 0; i < length; ++i) {\n"
411  " if (!(strm >> seq[i])) {\n"
412  " return false;\n"
413  " }\n"
414  " }\n"
415  " return true;\n";
416  }
417  return true;
418  }
419 
420  void skip_to_end_sequence(const std::string indent,
421  std::string start, std::string end, std::string seq_type_name,
422  bool use_cxx11, Classification cls, AST_Sequence* seq)
423  {
424  std::string elem_type_name = seq_type_name + "::value_type";
425 
426  if (cls & CL_STRING) {
427  if (cls & CL_WIDE) {
428  elem_type_name = use_cxx11 ? "std::wstring" : "CORBA::WString_var";
429  } else {
430  elem_type_name = use_cxx11 ? "std::string" : "CORBA::String_var";
431  }
432  }
433 
434  std::string tempvar = "tempvar";
435  be_global->impl_ <<
436  indent << "if (encoding.xcdr_version() == Encoding::XCDR_VERSION_2) {\n" <<
437  indent << " strm.skip(end_of_seq - strm.rpos());\n" <<
438  indent << "} else {\n";
439 
440  const bool classic_array_copy = !use_cxx11 && (cls & CL_ARRAY);
441 
442  if (!classic_array_copy) {
443  be_global->impl_ <<
444  indent << " " << elem_type_name << " " << tempvar << ";\n";
445  }
446 
447  std::string stream_to = tempvar;
448  if (cls & CL_STRING) {
449  if (cls & CL_BOUNDED) {
450  AST_Type* elem = resolveActualType(seq->base_type());
451  const string args = stream_to + (use_cxx11 ? ", " : ".out(), ") + bounded_arg(elem);
452  stream_to = getWrapper(args, elem, WD_INPUT);
453  }
454  } else {
455  Intro intro;
456  RefWrapper wrapper(seq->base_type(), scoped(deepest_named_type(seq->base_type())->name()),
457  classic_array_copy ? tempvar : stream_to, false);
458  wrapper.classic_array_copy_ = classic_array_copy;
459  wrapper.done(&intro);
460  stream_to = wrapper.ref();
461  intro.join(be_global->impl_, indent + " ");
462  }
463 
464  be_global->impl_ <<
465  indent << " for (CORBA::ULong j = " << start << " + 1; j < " << end << "; ++j) {\n" <<
466  indent << " strm >> " << stream_to << ";\n" <<
467  indent << " }\n" <<
468  indent << "}\n";
469  }
470 
471  void skip_to_end_array(const std::string& indent)
472  {
473  be_global->impl_ <<
474  indent << "if (encoding.xcdr_version() == Encoding::XCDR_VERSION_2) {\n" <<
475  indent << " strm.set_construction_status(Serializer::ElementConstructionFailure);\n" <<
476  indent << " strm.skip(end_of_arr - strm.rpos());\n" <<
477  indent << " return false;\n" <<
478  indent << "} else {\n" <<
479  indent << " strm.set_construction_status(Serializer::ConstructionSuccessful);\n" <<
480  indent << " discard_flag = true;\n" <<
481  indent << "}\n";
482  }
483 
484  void gen_sequence_i(
485  UTL_ScopedName* tdname, AST_Sequence* seq, bool nested_key_only, AST_Typedef* typedef_node = 0,
486  const FieldInfo* anonymous = 0)
487  {
488  be_global->add_include("dds/DCPS/Util.h");
489  be_global->add_include("dds/DCPS/Serializer.h");
490  if (anonymous) {
491  seq = dynamic_cast<AST_Sequence*>(anonymous->type_);
492  }
493  const std::string named_as = anonymous ? anonymous->scoped_type_ : scoped(tdname);
494  RefWrapper base_wrapper(seq, named_as, "seq");
495  base_wrapper.typedef_node_ = typedef_node;
496  base_wrapper.nested_key_only_ = nested_key_only;
497 
498  NamespaceGuard ng(!anonymous);
499 
500  if (!anonymous) {
501  bool special_result;
502  if (generate_special_sequence(typedef_node, base_wrapper.type_name_, special_result)) {
503  return;
504  }
505  }
506 
507  AST_Type* elem = resolveActualType(seq->base_type());
508  TryConstructFailAction try_construct = be_global->sequence_element_try_construct(seq);
509 
510  Classification elem_cls = classify(elem);
511  const bool primitive = elem_cls & CL_PRIMITIVE;
512  if (!elem->in_main_file()) {
513  if (elem->node_type() == AST_Decl::NT_pre_defined) {
514  if (be_global->language_mapping() != BE_GlobalData::LANGMAP_FACE_CXX &&
515  be_global->language_mapping() != BE_GlobalData::LANGMAP_SP_CXX) {
516  const std::string hdr = "dds/CorbaSeq/" + nameOfSeqHeader(elem) + "SeqTypeSupportImpl.h";
517  be_global->conditional_include(hdr.c_str(), BE_GlobalData::STREAM_CPP,
518  "#ifndef OPENDDS_SAFETY_PROFILE");
519  }
520  } else {
521  be_global->add_referenced(elem->file_name().c_str());
522  }
523  }
524 
525  const std::string cxx_elem =
526  anonymous ? anonymous->scoped_elem_ : scoped(deepest_named_type(seq->base_type())->name());
527  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
528 
529  RefWrapper(base_wrapper).done().generate_tag();
530 
531  {
532  Intro intro;
533  RefWrapper wrapper(base_wrapper);
534  wrapper.done(&intro);
535  const std::string value_access = wrapper.value_access();
536  const std::string get_length = wrapper.seq_get_length();
537  const std::string check_empty = wrapper.seq_check_empty();
538  Function serialized_size("serialized_size", "void");
539  serialized_size.addArg("encoding", "const Encoding&");
540  serialized_size.addArg("size", "size_t&");
541  serialized_size.addArg("seq", wrapper.wrapped_type_name());
542  serialized_size.endArgs();
543 
544  if ((elem_cls & CL_INTERFACE) == 0) {
545  marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", !primitive, false);
546 
547  intro.join(be_global->impl_, " ");
548 
549  be_global->impl_ <<
550  " primitive_serialized_size_ulong(encoding, size);\n"
551  " if (" << check_empty << ") {\n"
552  " return;\n"
553  " }\n";
554  }
555 
556  if (elem_cls & CL_ENUM) {
557  be_global->impl_ <<
558  " primitive_serialized_size_ulong(encoding, size, " + get_length + ");\n";
559  } else if (elem_cls & CL_PRIMITIVE) {
560  be_global->impl_ << checkAlignment(elem) <<
561  " " + getSizeExprPrimitive(elem, get_length) << ";\n";
562  } else if (elem_cls & CL_INTERFACE) {
563  be_global->impl_ <<
564  " // sequence of objrefs is not marshaled\n";
565  } else if (elem_cls == CL_UNKNOWN) {
566  be_global->impl_ <<
567  " // sequence of unknown/unsupported type\n";
568  } else { // String, Struct, Array, Sequence, Union
569  be_global->impl_ <<
570  " for (CORBA::ULong i = 0; i < " << get_length << "; ++i) {\n";
571  if (elem_cls & CL_STRING) {
572  be_global->impl_ <<
573  " primitive_serialized_size_ulong(encoding, size);\n";
574  const string strlen_suffix = (elem_cls & CL_WIDE)
575  ? " * char16_cdr_size;\n" : " + 1;\n";
576  if (use_cxx11) {
577  be_global->impl_ <<
578  " size += " + value_access + "[i].size()" << strlen_suffix;
579  } else {
580  be_global->impl_ <<
581  " if (" + value_access + "[i]) {\n"
582  " size += ACE_OS::strlen(" + value_access + "[i])" << strlen_suffix <<
583  " }\n";
584  }
585  } else {
586  RefWrapper elem_wrapper(elem, cxx_elem, value_access + "[i]");
587  elem_wrapper.nested_key_only_ = nested_key_only;
588  Intro intro;
589  elem_wrapper.done(&intro);
590  const std::string indent = " ";
591  intro.join(be_global->impl_, indent);
592  be_global->impl_ <<
593  indent << "serialized_size(encoding, size, " << elem_wrapper.ref() << ");\n";
594  }
595  be_global->impl_ <<
596  " }\n";
597  }
598  }
599 
600  {
601  Intro intro;
602  RefWrapper wrapper(base_wrapper);
603  wrapper.done(&intro);
604  const std::string value_access = wrapper.value_access();
605  const std::string get_length = wrapper.seq_get_length();
606  const std::string check_empty = wrapper.seq_check_empty();
607  const std::string get_buffer = wrapper.seq_get_buffer();
608  Function insertion("operator<<", "bool");
609  insertion.addArg("strm", "Serializer&");
610  insertion.addArg("seq", wrapper.wrapped_type_name());
611  insertion.endArgs();
612 
613  if ((elem_cls & CL_INTERFACE) == 0) {
614  be_global->impl_ <<
615  " const Encoding& encoding = strm.encoding();\n"
616  " ACE_UNUSED_ARG(encoding);\n";
618  " serialized_size(encoding, total_size, seq);\n"
619  " if (!strm.write_delimiter(total_size)) {\n"
620  " return false;\n"
621  " }\n", !primitive);
622 
623  intro.join(be_global->impl_, " ");
624 
625  be_global->impl_ <<
626  " const CORBA::ULong length = " << get_length << ";\n";
627  if (!seq->unbounded()) {
628  be_global->impl_ <<
629  " if (length > " << bounded_arg(seq) << ") {\n"
630  " return false;\n"
631  " }\n";
632  }
633  be_global->impl_ <<
634  streamAndCheck("<< length") <<
635  " if (length == 0) {\n"
636  " return true;\n"
637  " }\n";
638  }
639 
640  if (elem_cls & CL_PRIMITIVE) {
641  AST_PredefinedType* predef = dynamic_cast<AST_PredefinedType*>(elem);
642  if (use_cxx11 && predef->pt() == AST_PredefinedType::PT_boolean) {
643  be_global->impl_ <<
644  " for (CORBA::ULong i = 0; i < length; ++i) {\n" <<
645  streamAndCheck("<< ACE_OutputCDR::from_boolean(" + value_access + "[i])", 4) <<
646  " }\n"
647  " return true;\n";
648  } else {
649  be_global->impl_ <<
650  " return strm.write_" << getSerializerName(elem)
651  << "_array(" << get_buffer << ", length);\n";
652  }
653  } else if (elem_cls & CL_INTERFACE) {
654  be_global->impl_ <<
655  " return false; // sequence of objrefs is not marshaled\n";
656  } else if (elem_cls == CL_UNKNOWN) {
657  be_global->impl_ <<
658  " return false; // sequence of unknown/unsupported type\n";
659  } else { // Enum, String, Struct, Array, Sequence, Union
660  be_global->impl_ <<
661  " for (CORBA::ULong i = 0; i < length; ++i) {\n";
662  if ((elem_cls & (CL_STRING | CL_BOUNDED)) == (CL_STRING | CL_BOUNDED)) {
663  const string args = value_access + "[i], " + bounded_arg(elem);
664  be_global->impl_ <<
665  streamAndCheck("<< " + getWrapper(args, elem, WD_OUTPUT), 4);
666  } else {
667  RefWrapper elem_wrapper(elem, cxx_elem, value_access + "[i]");
668  elem_wrapper.nested_key_only_ = nested_key_only;
669  Intro intro;
670  elem_wrapper.done(&intro);
671  intro.join(be_global->impl_, " ");
672  be_global->impl_ << streamAndCheck("<< " + elem_wrapper.ref(), 4);
673  }
674  be_global->impl_ <<
675  " }\n"
676  " return true;\n";
677  }
678  }
679 
680  {
681  Intro intro;
682  RefWrapper wrapper(base_wrapper);
683  wrapper.is_const_ = false;
684  wrapper.done(&intro);
685  const std::string value_access = wrapper.value_access();
686  const std::string get_length = wrapper.seq_get_length();
687  const std::string check_empty = wrapper.seq_check_empty();
688  const std::string get_buffer = wrapper.seq_get_buffer();
689  Function extraction("operator>>", "bool");
690  extraction.addArg("strm", "Serializer&");
691  extraction.addArg("seq", wrapper.wrapped_type_name());
692  extraction.endArgs();
693 
694  if ((elem_cls & CL_INTERFACE) == 0) {
695  be_global->impl_ <<
696  " const Encoding& encoding = strm.encoding();\n"
697  " ACE_UNUSED_ARG(encoding);\n";
699  " if (!strm.read_delimiter(total_size)) {\n"
700  " return false;\n"
701  " }\n", !primitive);
702 
703  if (!primitive) {
704  be_global->impl_ << " const size_t end_of_seq = strm.rpos() + total_size;\n";
705  }
706  be_global->impl_ <<
707  " CORBA::ULong length;\n"
708  << streamAndCheck(">> length");
709  // The check here is to prevent very large sequences from being allocated.
710  be_global->impl_ <<
711  " if (length > strm.length()) {\n"
712  " if (DCPS_debug_level >= 8) {\n"
713  " ACE_DEBUG((LM_DEBUG, ACE_TEXT(\"(%P|%t) Invalid sequence length (%u)\\n\"), length));\n"
714  " }\n"
715  " return false;\n"
716  " }\n";
717  }
718 
719  AST_PredefinedType* predef = dynamic_cast<AST_PredefinedType*>(elem);
720  string bound;
721  if (!seq->unbounded()) {
722  bound = use_cxx11 ? bounded_arg(seq) : value_access + ".maximum()";
723  }
724  //create a variable called newlength which tells us how long we need to copy to
725  //for an unbounded sequence this is just our length
726  //for a bounded sequence this is our maximum
727  //we save the old length so we know how far we need to read until
728  if ((elem_cls & CL_INTERFACE) == 0) {
729  be_global->impl_ << " CORBA::ULong new_length = length;\n";
730  }
731 
732  if (elem_cls & CL_PRIMITIVE) {
733  // if we are a bounded primitive, we read to our max then return false
734  if (!seq->unbounded()) {
735  be_global->impl_ <<
736  " if (length > " << bound << ") {\n"
737  " new_length = " << bound << ";\n"
738  " }\n"
739  " " << wrapper.seq_resize("new_length");
740  if (use_cxx11 && predef->pt() == AST_PredefinedType::PT_boolean) {
741  be_global->impl_ <<
742  " for (CORBA::ULong i = 0; i < new_length; ++i) {\n"
743  " bool b;\n" <<
744  streamAndCheck(">> ACE_InputCDR::to_boolean(b)", 4) <<
745  " " + value_access + "[i] = b;\n"
746  " }\n";
747  } else {
748  be_global->impl_ <<
749  " strm.read_" << getSerializerName(elem) << "_array(" << get_buffer << ", new_length);\n";
750  }
751  be_global->impl_ <<
752  " if (new_length != length) {\n"
753  " size_t skip_length = 0;\n"
754  " " << getSizeExprPrimitive(elem, "(length - new_length)", "skip_length", "encoding") << ";\n"
755  " strm.set_construction_status(Serializer::BoundConstructionFailure);\n"
756  " strm.skip(skip_length);\n"
757  " return false;\n"
758  " }\n";
759  } else {
760  be_global->impl_ <<
761  " " << wrapper.seq_resize("new_length");
762  if (use_cxx11 && predef->pt() == AST_PredefinedType::PT_boolean) {
763  be_global->impl_ <<
764  " for (CORBA::ULong i = 0; i < length; ++i) {\n"
765  " bool b;\n" <<
766  streamAndCheck(">> ACE_InputCDR::to_boolean(b)", 4) <<
767  " " << value_access << "[i] = b;\n"
768  " }\n"
769  " return true;\n";
770  } else {
771  be_global->impl_ <<
772  " if (length == 0) {\n"
773  " return true;\n"
774  " }\n"
775  " return strm.read_" << getSerializerName(elem)
776  << "_array(" << get_buffer << ", length);\n";
777  }
778  }
779  } else if (elem_cls & CL_INTERFACE) {
780  be_global->impl_ <<
781  " return false; // sequence of objrefs is not marshaled\n";
782  return;
783  } else if (elem_cls == CL_UNKNOWN) {
784  be_global->impl_ <<
785  " return false; // sequence of unknown/unsupported type\n";
786  return;
787  } else { // Enum, String, Struct, Array, Sequence, Union
788  const std::string elem_access = value_access + "[i]";
789  if (!seq->unbounded()) {
790  be_global->impl_ <<
791  " if (length > " << (use_cxx11 ? bounded_arg(seq) : value_access + ".maximum()") << ") {\n"
792  " new_length = " << bound << ";\n"
793  " }\n";
794  }
795  //change the size of seq length to prepare
796  be_global->impl_ <<
797  " " << wrapper.seq_resize("new_length");
798  //read the entire length of the writer's sequence
799  be_global->impl_ <<
800  " for (CORBA::ULong i = 0; i < new_length; ++i) {\n";
801 
802  Intro intro;
803  std::string stream_to;
804  std::string classic_array_copy;
805  if (!use_cxx11 && (elem_cls & CL_ARRAY)) {
806  RefWrapper classic_array_wrapper(
807  seq->base_type(), scoped(deepest_named_type(seq->base_type())->name()), elem_access);
808  classic_array_wrapper.classic_array_copy_ = true;
809  classic_array_wrapper.done(&intro);
810  classic_array_copy = classic_array_wrapper.classic_array_copy();
811  stream_to = classic_array_wrapper.ref();
812  } else if (elem_cls & CL_STRING) {
813  if (elem_cls & CL_BOUNDED) {
814  const string args = elem_access + (use_cxx11 ? ", " : ".out(), ") + bounded_arg(elem);
815  stream_to = getWrapper(args, elem, WD_INPUT);
816  } else {
817  const string getbuffer =
818  (be_global->language_mapping() == BE_GlobalData::LANGMAP_NONE)
819  ? ".get_buffer()" : "";
820  stream_to = value_access + getbuffer + "[i]";
821  }
822  } else {
823  RefWrapper elem_wrapper(elem, cxx_elem, value_access + "[i]", false);
824  elem_wrapper.nested_key_only_ = nested_key_only;
825  elem_wrapper.done(&intro);
826  stream_to = elem_wrapper.ref();
827  }
828  const std::string indent = " ";
829  intro.join(be_global->impl_, indent);
830  be_global->impl_ <<
831  indent << " if (!(strm >> " << stream_to << ")) {\n";
832 
833  if (try_construct == tryconstructfailaction_use_default) {
834  be_global->impl_ <<
835  type_to_default(" ", elem, elem_access) <<
836  " strm.set_construction_status(Serializer::ConstructionSuccessful);\n";
837  } else if ((try_construct == tryconstructfailaction_trim) && (elem_cls & CL_BOUNDED) &&
838  (elem_cls & (CL_STRING | CL_SEQUENCE))) {
839  if (elem_cls & CL_STRING){
840  const std::string check_not_empty =
841  use_cxx11 ? "!" + elem_access + ".empty()" : elem_access + ".in()";
842  const std::string get_length =
843  use_cxx11 ? elem_access + ".length()" : "ACE_OS::strlen(" + elem_access + ".in())";
844  const string inout = use_cxx11 ? "" : ".inout()";
845  be_global->impl_ <<
846  " if (" + construct_bound_fail + " && " << check_not_empty << " && (" <<
847  bounded_arg(elem) << " < " << get_length << ")) {\n"
848  " " << elem_access << inout <<
849  (use_cxx11 ? (".resize(" + bounded_arg(elem) + ");\n") : ("[" + bounded_arg(elem) + "] = 0;\n")) <<
850  " strm.set_construction_status(Serializer::ConstructionSuccessful);\n"
851  " } else {\n"
852  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n";
853  skip_to_end_sequence(" ", "i", "length", named_as, use_cxx11, elem_cls, seq);
854  be_global->impl_ <<
855  " return false;\n"
856  " }\n";
857  } else if (elem_cls & CL_SEQUENCE) {
858  be_global->impl_ <<
859  " if (" + construct_elem_fail + ") {\n";
860  skip_to_end_sequence(" ", "i", "length", named_as, use_cxx11, elem_cls, seq);
861  be_global->impl_ <<
862  " return false;\n"
863  " }\n"
864  " strm.set_construction_status(Serializer::ConstructionSuccessful);\n";
865  }
866  } else {
867  //discard/default
868  be_global->impl_ <<
869  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n";
870  skip_to_end_sequence(" ", "i", "length", named_as, use_cxx11, elem_cls, seq);
871  be_global->impl_ <<
872  " return false;\n";
873  }
874  be_global->impl_ <<
875  " }\n";
876  if (classic_array_copy.size()) {
877  be_global->impl_ <<
878  " " << classic_array_copy << "\n";
879  }
880  be_global->impl_ << " }\n";
881  }
882  if (!primitive) {
883  be_global->impl_ <<
884  " if (new_length != length) {\n";
885  skip_to_end_sequence(" ", "new_length", "length", named_as, use_cxx11, elem_cls, seq);
886  be_global->impl_ <<
887  " strm.set_construction_status(Serializer::BoundConstructionFailure);\n"
888  " return false;\n"
889  " }\n";
890  }
891  be_global->impl_ <<
892  " return true;\n";
893  }
894  }
895 
896  void gen_sequence(UTL_ScopedName* name, AST_Typedef* typedef_node, AST_Sequence* seq)
897  {
898  gen_sequence_i(name, seq, false, typedef_node);
899  if (needs_nested_key_only(seq)) {
900  gen_sequence_i(name, seq, true, typedef_node);
901  }
902  }
903 
904  void gen_anonymous_sequence(const FieldInfo& sf)
905  {
906  gen_sequence_i(0, 0, false, 0, &sf);
907  if (needs_nested_key_only(sf.type_)) {
908  gen_sequence_i(0, 0, true, 0, &sf);
909  }
910  }
911 
912  void gen_array_i(
913  UTL_ScopedName* name, AST_Array* arr, bool nested_key_only, const FieldInfo* anonymous = 0)
914  {
915  be_global->add_include("dds/DCPS/Serializer.h");
916  if (anonymous) {
917  arr = dynamic_cast<AST_Array*>(anonymous->type_);
918  }
919  const std::string named_as = anonymous ? anonymous->scoped_type_ : scoped(name);
920  RefWrapper base_wrapper(arr, named_as, "arr");
921  base_wrapper.nested_key_only_ = nested_key_only;
922  NamespaceGuard ng(!anonymous);
923 
924  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
925 
926  AST_Type* elem = resolveActualType(arr->base_type());
927  TryConstructFailAction try_construct = be_global->array_element_try_construct(arr);
928  Classification elem_cls = classify(elem);
929  const bool primitive = elem_cls & CL_PRIMITIVE;
930  if (!elem->in_main_file()
931  && elem->node_type() != AST_Decl::NT_pre_defined) {
932  be_global->add_referenced(elem->file_name().c_str());
933  }
934  const std::string cxx_elem =
935  anonymous ? anonymous->scoped_elem_ : scoped(deepest_named_type(arr->base_type())->name());
936  const ACE_CDR::ULong n_elems = array_element_count(arr);
937 
938  RefWrapper(base_wrapper).done().generate_tag();
939 
940  if (!nested_key_only) {
941  RefWrapper wrapper(base_wrapper);
942  wrapper.is_const_ = false;
943  wrapper.done();
944  Function set_default("set_default", "void", "");
945  set_default.addArg("arr", wrapper.wrapped_type_name());
946  set_default.endArgs();
947  string indent = " ";
948  NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
949  be_global->impl_ << type_to_default(indent, elem, wrapper.value_access() + nfl.index_);
950  }
951 
952  {
953  RefWrapper wrapper(base_wrapper);
954  wrapper.done();
955  Function serialized_size("serialized_size", "void");
956  serialized_size.addArg("encoding", "const Encoding&");
957  serialized_size.addArg("size", "size_t&");
958  serialized_size.addArg("arr", wrapper.wrapped_type_name());
959  serialized_size.endArgs();
960 
961  marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", !primitive, false);
962 
963  if (elem_cls & CL_ENUM) {
964  be_global->impl_ <<
965  " primitive_serialized_size_ulong(encoding, size, " << n_elems << ");\n";
966  } else if (elem_cls & CL_PRIMITIVE) {
967  std::ostringstream n_elems_ss;
968  n_elems_ss << n_elems;
969  be_global->impl_ <<
970  " " << getSizeExprPrimitive(elem, n_elems_ss.str()) << ";\n";
971  } else { // String, Struct, Array, Sequence, Union
972  string indent = " ";
973  NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
974  if (elem_cls & CL_STRING) {
975  be_global->impl_ <<
976  indent << "primitive_serialized_size_ulong(encoding, size);\n" <<
977  indent;
978  if (use_cxx11) {
979  be_global->impl_ << "size += " << wrapper.value_access() << nfl.index_ << ".size()";
980  } else {
981  be_global->impl_ << "size += ACE_OS::strlen(" << wrapper.value_access()
982  << nfl.index_ << ".in())";
983  }
984  be_global->impl_ << ((elem_cls & CL_WIDE) ? " * char16_cdr_size;\n" : " + 1;\n");
985  } else {
986  RefWrapper elem_wrapper(elem, cxx_elem, wrapper.value_access() + nfl.index_);
987  elem_wrapper.nested_key_only_ = nested_key_only;
988  Intro intro;
989  elem_wrapper.done(&intro);
990  intro.join(be_global->impl_, indent);
991  be_global->impl_ <<
992  indent << "serialized_size(encoding, size, " << elem_wrapper.ref() << ");\n";
993  }
994  }
995  }
996 
997  {
998  RefWrapper wrapper(base_wrapper);
999  wrapper.done();
1000  Function insertion("operator<<", "bool");
1001  insertion.addArg("strm", "Serializer&");
1002  insertion.addArg("arr", wrapper.wrapped_type_name());
1003  insertion.endArgs();
1004 
1005  be_global->impl_ <<
1006  " const Encoding& encoding = strm.encoding();\n"
1007  " ACE_UNUSED_ARG(encoding);\n";
1008 
1010  "serialized_size(encoding, total_size, arr);"
1011  "if (!strm.write_delimiter(total_size)) {"
1012  " return false;"
1013  "}", !primitive);
1014  const std::string accessor = wrapper.value_access() + (use_cxx11 ? ".data()" : ".in()");
1015  if (elem_cls & CL_PRIMITIVE) {
1016  string suffix;
1017  for (unsigned int i = 1; i < arr->n_dims(); ++i)
1018  suffix += use_cxx11 ? "->data()" : "[0]";
1019  be_global->impl_ <<
1020  " return strm.write_" << getSerializerName(elem)
1021  << "_array(" << accessor << suffix << ", " << n_elems << ");\n";
1022  } else { // Enum, String, Struct, Array, Sequence, Union
1023  {
1024  string indent = " ";
1025  NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
1026  RefWrapper elem_wrapper(elem, cxx_elem, wrapper.value_access() + nfl.index_);
1027  elem_wrapper.nested_key_only_ = nested_key_only;
1028  Intro intro;
1029  elem_wrapper.done(&intro);
1030  intro.join(be_global->impl_, indent);
1031  be_global->impl_ << streamAndCheck("<< " + elem_wrapper.ref(), indent.size());
1032  }
1033  be_global->impl_ << " return true;\n";
1034  }
1035  }
1036 
1037  {
1038  RefWrapper wrapper(base_wrapper);
1039  wrapper.is_const_ = false;
1040  wrapper.done();
1041  Function extraction("operator>>", "bool");
1042  extraction.addArg("strm", "Serializer&");
1043  extraction.addArg("arr", wrapper.wrapped_type_name());
1044  extraction.endArgs();
1045 
1046  if (!primitive) {
1047  be_global->impl_ << " bool discard_flag = false;\n";
1048  }
1049  be_global->impl_ <<
1050  " const Encoding& encoding = strm.encoding();\n"
1051  " ACE_UNUSED_ARG(encoding);\n";
1053  " if (!strm.read_delimiter(total_size)) {\n"
1054  " return false;\n"
1055  " }\n", !primitive);
1056 
1057  if (!primitive && (try_construct != tryconstructfailaction_use_default)) {
1058  be_global->impl_ << " const size_t end_of_arr = strm.rpos() + total_size;\n";
1059  }
1060 
1061  const std::string accessor = wrapper.value_access() + (use_cxx11 ? ".data()" : ".out()");
1062  if (primitive) {
1063  string suffix;
1064  for (unsigned int i = 1; i < arr->n_dims(); ++i)
1065  suffix += use_cxx11 ? "->data()" : "[0]";
1066  be_global->impl_ <<
1067  " return strm.read_" << getSerializerName(elem)
1068  << "_array(" << accessor << suffix << ", " << n_elems << ");\n";
1069  } else { // Enum, String, Struct, Array, Sequence, Union
1070  {
1071  string indent = " ";
1072  NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
1073  const std::string elem_access = wrapper.value_access() + nfl.index_;
1074 
1075  Intro intro;
1076  std::string stream;
1077  std::string classic_array_copy;
1078  if (!use_cxx11 && (elem_cls & CL_ARRAY)) {
1079  RefWrapper classic_array_wrapper(
1080  arr->base_type(), scoped(deepest_named_type(arr->base_type())->name()),
1081  wrapper.value_access() + nfl.index_);
1082  classic_array_wrapper.classic_array_copy_ = true;
1083  classic_array_wrapper.done(&intro);
1084  classic_array_copy = classic_array_wrapper.classic_array_copy();
1085  stream = "(strm >> " + classic_array_wrapper.ref() + ")";
1086  } else {
1087  stream = streamCommon(
1088  indent, 0, "", arr->base_type(), ">> " + elem_access, nested_key_only, intro);
1089  }
1090  intro.join(be_global->impl_, indent);
1091  be_global->impl_ <<
1092  indent << "if (!" << stream << ") {\n";
1093 
1094  indent += " ";
1095  if (try_construct == tryconstructfailaction_use_default) {
1096  be_global->impl_ <<
1097  type_to_default(indent, elem, elem_access) <<
1098  indent << "strm.set_construction_status(Serializer::ConstructionSuccessful);\n";
1099  } else if ((try_construct == tryconstructfailaction_trim) && (elem_cls & CL_BOUNDED) &&
1100  (elem_cls & (CL_STRING | CL_SEQUENCE))) {
1101  if (elem_cls & CL_STRING) {
1102  const std::string check_not_empty =
1103  use_cxx11 ? "!" + elem_access + ".empty()" : elem_access + ".in()";
1104  const std::string get_length =
1105  use_cxx11 ? elem_access + ".length()" : "ACE_OS::strlen(" + elem_access + ".in())";
1106  const string inout = use_cxx11 ? "" : ".inout()";
1107  be_global->impl_ <<
1108  indent << "if (" << construct_bound_fail << " && " <<
1109  check_not_empty << " && (" << bounded_arg(elem) << " < " << get_length << ")) {\n" <<
1110  indent << " " << wrapper.value_access() + nfl.index_ << inout <<
1111  (use_cxx11 ? (".resize(" + bounded_arg(elem) + ")") : ("[" + bounded_arg(elem) + "] = 0")) << ";\n" <<
1112  indent << " strm.set_construction_status(Serializer::ConstructionSuccessful);\n" <<
1113  indent << "} else {\n";
1114  skip_to_end_array(indent);
1115  be_global->impl_ <<
1116  indent << "}\n";
1117  } else if (elem_cls & CL_SEQUENCE) {
1118  be_global->impl_ <<
1119  indent << "if (" + construct_elem_fail + ") {\n";
1120  skip_to_end_array(indent);
1121  be_global->impl_ <<
1122  indent << "} else {\n" <<
1123  indent << " strm.set_construction_status(Serializer::ConstructionSuccessful);\n" <<
1124  indent << "}\n";
1125  }
1126  } else {
1127  //discard/default
1128  skip_to_end_array(indent);
1129  }
1130  if (classic_array_copy.size()) {
1131  be_global->impl_ <<
1132  indent << "} else {\n" <<
1133  indent << " " << classic_array_copy << "\n";
1134  }
1135  indent.erase(0, 2);
1136  be_global->impl_ <<
1137  indent << "}\n";
1138  }
1139  be_global->impl_ <<
1140  " if (discard_flag) {\n"
1141  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n"
1142  " return false;\n"
1143  " }\n"
1144  " return true;\n";
1145  }
1146  }
1147  }
1148 
1149  void gen_array(UTL_ScopedName* name, AST_Array* arr)
1150  {
1151  gen_array_i(name, arr, false);
1152  if (needs_nested_key_only(arr)) {
1153  gen_array_i(name, arr, true);
1154  }
1155  }
1156 
1157  void gen_anonymous_array(const FieldInfo& af)
1158  {
1159  gen_array_i(0, 0, false, &af);
1160  if (needs_nested_key_only(af.type_)) {
1161  gen_array_i(0, 0, true, &af);
1162  }
1163  }
1164 
1165  // This function looks through the fields of a struct for the key
1166  // specified and returns the AST_Type associated with that key.
1167  // Because the key name can contain indexed arrays and nested
1168  // structures, things can get interesting.
1169  AST_Type* find_type_i(AST_Structure* struct_node, const string& key)
1170  {
1171  string key_base = key; // the field we are looking for here
1172  string key_rem; // the sub-field we will look for recursively
1173  bool is_array = false;
1174  size_t pos = key.find_first_of(".[");
1175  if (pos != string::npos) {
1176  key_base = key.substr(0, pos);
1177  if (key[pos] == '[') {
1178  is_array = true;
1179  size_t l_brack = key.find("]");
1180  if (l_brack == string::npos) {
1181  throw string("Missing right bracket");
1182  } else if (l_brack != key.length()) {
1183  key_rem = key.substr(l_brack+1);
1184  }
1185  } else {
1186  key_rem = key.substr(pos+1);
1187  }
1188  }
1189 
1190  const Fields fields(struct_node);
1191  const Fields::Iterator fields_end = fields.end();
1192  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
1193  AST_Field* const field = *i;
1194  if (key_base == field->local_name()->get_string()) {
1195  AST_Type* field_type = resolveActualType(field->field_type());
1196  if (!is_array && key_rem.empty()) {
1197  // The requested key field matches this one. We do not allow
1198  // arrays (must be indexed specifically) or structs (must
1199  // identify specific sub-fields).
1200  AST_Structure* sub_struct = dynamic_cast<AST_Structure*>(field_type);
1201  if (sub_struct != 0) {
1202  throw string("Structs not allowed as keys");
1203  }
1204  AST_Array* array_node = dynamic_cast<AST_Array*>(field_type);
1205  if (array_node != 0) {
1206  throw string("Arrays not allowed as keys");
1207  }
1208  return field_type;
1209  } else if (is_array) {
1210  // must be a typedef of an array
1211  AST_Array* array_node = dynamic_cast<AST_Array*>(field_type);
1212  if (array_node == 0) {
1213  throw string("Indexing for non-array type");
1214  }
1215  if (array_node->n_dims() > 1) {
1216  throw string("Only single dimension arrays allowed in keys");
1217  }
1218  if (key_rem == "") {
1219  return array_node->base_type();
1220  } else {
1221  // This must be a struct...
1222  if ((key_rem[0] != '.') || (key_rem.length() == 1)) {
1223  throw string("Unexpected characters after array index");
1224  } else {
1225  // Set up key_rem and field_type and let things fall into
1226  // the struct code below
1227  key_rem = key_rem.substr(1);
1228  field_type = array_node->base_type();
1229  }
1230  }
1231  }
1232 
1233  // nested structures
1234  AST_Structure* sub_struct = dynamic_cast<AST_Structure*>(field_type);
1235  if (sub_struct == 0) {
1236  throw string("Expected structure field for ") + key_base;
1237  }
1238 
1239  // find type of nested struct field
1240  return find_type_i(sub_struct, key_rem);
1241  }
1242  }
1243  throw string("Field not found.");
1244  }
1245 
1246  AST_Type* find_type(AST_Structure* struct_node, const string& key)
1247  {
1248  try {
1249  return find_type_i(struct_node, key);
1250  } catch (const string& error) {
1251  const std::string struct_name = scoped(struct_node->name());
1253  "Invalid key specification for " + struct_name + " (" + key + "): " + error,
1254  struct_node);
1255  }
1256  return 0;
1257  }
1258 
1259  bool is_bounded_type(AST_Type* type, Encoding::Kind encoding)
1260  {
1261  bool bounded = true;
1262  static std::vector<AST_Type*> type_stack;
1263  type = resolveActualType(type);
1264  for (size_t i = 0; i < type_stack.size(); ++i) {
1265  // If we encounter the same type recursively, then we are unbounded
1266  if (type == type_stack[i]) return false;
1267  }
1268  type_stack.push_back(type);
1269  Classification fld_cls = classify(type);
1270  if ((fld_cls & CL_STRING) && !(fld_cls & CL_BOUNDED)) {
1271  bounded = false;
1272  } else if (fld_cls & CL_STRUCTURE) {
1273  const ExtensibilityKind exten = be_global->extensibility(type);
1274  if (exten != extensibilitykind_final && encoding != Encoding::KIND_UNALIGNED_CDR) {
1275  /*
1276  * TODO(iguessthislldo): This is a workaround for not properly
1277  * implementing serialized_size_bound for XCDR. See XTYPE-83.
1278  */
1279  bounded = false;
1280  } else {
1281  const Fields fields(dynamic_cast<AST_Structure*>(type));
1282  const Fields::Iterator fields_end = fields.end();
1283  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
1284  if (!is_bounded_type((*i)->field_type(), encoding)) {
1285  bounded = false;
1286  break;
1287  }
1288  }
1289  }
1290  } else if (fld_cls & CL_SEQUENCE) {
1291  if (fld_cls & CL_BOUNDED) {
1292  AST_Sequence* seq_node = dynamic_cast<AST_Sequence*>(type);
1293  if (!is_bounded_type(seq_node->base_type(), encoding)) bounded = false;
1294  } else {
1295  bounded = false;
1296  }
1297  } else if (fld_cls & CL_ARRAY) {
1298  AST_Array* array_node = dynamic_cast<AST_Array*>(type);
1299  if (!is_bounded_type(array_node->base_type(), encoding)) bounded = false;
1300  } else if (fld_cls & CL_UNION) {
1301  const ExtensibilityKind exten = be_global->extensibility(type);
1302  if (exten != extensibilitykind_final && encoding != Encoding::KIND_UNALIGNED_CDR) {
1303  /*
1304  * TODO(iguessthislldo): This is a workaround for not properly
1305  * implementing serialized_size_bound for XCDR. See XTYPE-83.
1306  */
1307  bounded = false;
1308  } else {
1309  const Fields fields(dynamic_cast<AST_Union*>(type));
1310  const Fields::Iterator fields_end = fields.end();
1311  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
1312  if (!is_bounded_type((*i)->field_type(), encoding)) {
1313  bounded = false;
1314  break;
1315  }
1316  }
1317  }
1318  }
1319  type_stack.pop_back();
1320  return bounded;
1321  }
1322 
1323  ExtensibilityKind max_extensibility_kind(AST_Type* type)
1324  {
1326  static std::vector<AST_Type*> type_stack;
1327 
1328  type = resolveActualType(type);
1329  for (size_t i = 0; i < type_stack.size(); ++i) {
1330  // If we encounter the same type recursively, then it has already been considered
1331  if (type == type_stack[i]) return extensibilitykind_final;
1332  }
1333  type_stack.push_back(type);
1334 
1335  const Classification fld_cls = classify(type);
1336  if (fld_cls & CL_STRUCTURE || fld_cls & CL_UNION) {
1337  exten = be_global->extensibility(type);
1338  if (exten == extensibilitykind_mutable) {
1339  type_stack.pop_back();
1341  }
1342 
1343  const Fields fields(fld_cls & CL_STRUCTURE ? dynamic_cast<AST_Structure*>(type) : dynamic_cast<AST_Union*>(type));
1344  const Fields::Iterator fields_end = fields.end();
1346  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
1347  if (extensibilitykind_mutable == (this_exten = max_extensibility_kind(type))) {
1348  type_stack.pop_back();
1350  }
1351  if (exten < this_exten) {
1352  exten = this_exten;
1353  }
1354  }
1355  type_stack.pop_back();
1356  return exten;
1357  } else if (fld_cls & CL_ARRAY) {
1358  type_stack.pop_back();
1359  return max_extensibility_kind(dynamic_cast<AST_Array*>(type)->base_type());
1360  } else if (fld_cls & CL_SEQUENCE) {
1361  type_stack.pop_back();
1362  return max_extensibility_kind(dynamic_cast<AST_Sequence*>(type)->base_type());
1363  } else {
1364  type_stack.pop_back();
1365  return extensibilitykind_final;
1366  }
1367  }
1368 
1369  /**
1370  * Convert a compiler Encoding value to the string name of the corresponding
1371  * OpenDDS::DCPS::Encoding::XcdrVersion.
1372  */
1373  std::string encoding_to_xcdr_version(Encoding::Kind encoding)
1374  {
1375  switch (encoding) {
1376  case Encoding::KIND_XCDR1:
1377  return "Encoding::XCDR_VERSION_1";
1378  case Encoding::KIND_XCDR2:
1379  return "Encoding::XCDR_VERSION_2";
1380  default:
1381  return "Encoding::XCDR_VERSION_NONE";
1382  }
1383  }
1384 
1385  /**
1386  * Convert a compiler Encoding value to the string name of the corresponding
1387  * OpenDDS::DCPS::Encoding::Kind.
1388  */
1389  std::string encoding_to_encoding_kind(Encoding::Kind encoding)
1390  {
1391  switch (encoding) {
1392  case Encoding::KIND_XCDR1:
1393  return "Encoding::KIND_XCDR1";
1394  case Encoding::KIND_XCDR2:
1395  return "Encoding::KIND_XCDR2";
1396  default:
1397  return "Encoding::KIND_UNALIGNED_CDR";
1398  }
1399  }
1400 
1401  void align(Encoding::Kind encoding, size_t& value, size_t by)
1402  {
1403  const Encoding enc(encoding);
1404  enc.align(value, by);
1405  }
1406 
1407  void idl_max_serialized_size_dheader(
1408  Encoding::Kind encoding, ExtensibilityKind exten, size_t& size)
1409  {
1410  if (exten != extensibilitykind_final && encoding == Encoding::KIND_XCDR2) {
1411  align(encoding, size, 4);
1412  size += 4;
1413  }
1414  }
1415 
1416  void idl_max_serialized_size(Encoding::Kind encoding, size_t& size, AST_Type* type);
1417 
1418  // Max marshaled size of repeating 'type' 'n' times in the stream
1419  // (for an array or sequence)
1420  void idl_max_serialized_size_repeating(
1421  Encoding::Kind encoding, size_t& size, AST_Type* type, size_t n)
1422  {
1423  if (n > 0) {
1424  // 1st element may need padding relative to whatever came before
1425  idl_max_serialized_size(encoding, size, type);
1426  }
1427  if (n > 1) {
1428  // subsequent elements may need padding relative to prior element
1429  // TODO(iguessthislldo): https://github.com/OpenDDS/OpenDDS/pull/1668#discussion_r432521888
1430  const size_t prev_size = size;
1431  idl_max_serialized_size(encoding, size, type);
1432  size += (n - 2) * (size - prev_size);
1433  }
1434  }
1435 
1436  /// Should only be called on bounded types
1437  void idl_max_serialized_size(Encoding::Kind encoding, size_t& size, AST_Type* type)
1438  {
1439  type = resolveActualType(type);
1440  const ExtensibilityKind exten = be_global->extensibility(type);
1441  switch (type->node_type()) {
1442  case AST_Decl::NT_pre_defined: {
1443  AST_PredefinedType* p = dynamic_cast<AST_PredefinedType*>(type);
1444  switch (p->pt()) {
1445  case AST_PredefinedType::PT_char:
1446  case AST_PredefinedType::PT_boolean:
1447  case AST_PredefinedType::PT_octet:
1448 #if OPENDDS_HAS_EXPLICIT_INTS
1449  case AST_PredefinedType::PT_uint8:
1450  case AST_PredefinedType::PT_int8:
1451 #endif
1452  size += 1;
1453  break;
1454  case AST_PredefinedType::PT_short:
1455  case AST_PredefinedType::PT_ushort:
1456  align(encoding, size, 2);
1457  size += 2;
1458  break;
1459  case AST_PredefinedType::PT_wchar:
1460  align(encoding, size, 2);
1461  size += 2;
1462  break;
1463  case AST_PredefinedType::PT_long:
1464  case AST_PredefinedType::PT_ulong:
1465  case AST_PredefinedType::PT_float:
1466  align(encoding, size, 4);
1467  size += 4;
1468  break;
1469  case AST_PredefinedType::PT_longlong:
1470  case AST_PredefinedType::PT_ulonglong:
1471  case AST_PredefinedType::PT_double:
1472  align(encoding, size, 8);
1473  size += 8;
1474  break;
1475  case AST_PredefinedType::PT_longdouble:
1476  align(encoding, size, 16);
1477  size += 16;
1478  break;
1479  default:
1480  // Anything else shouldn't be in a DDS type or is unbounded.
1481  break;
1482  }
1483  break;
1484  }
1485  case AST_Decl::NT_enum:
1486  align(encoding, size, 4);
1487  size += 4;
1488  break;
1489  case AST_Decl::NT_string:
1490  case AST_Decl::NT_wstring: {
1491  AST_String* string_node = dynamic_cast<AST_String*>(type);
1492  align(encoding, size, 4);
1493  size += 4;
1494  const int width = (string_node->width() == 1) ? 1 : 2 /*UTF-16*/;
1495  size += width * string_node->max_size()->ev()->u.ulval;
1496  if (type->node_type() == AST_Decl::NT_string) {
1497  size += 1; // narrow string includes the null terminator
1498  }
1499  break;
1500  }
1501  case AST_Decl::NT_struct: {
1502  const Fields fields(dynamic_cast<AST_Structure*>(type));
1503  const Fields::Iterator fields_end = fields.end();
1504  idl_max_serialized_size_dheader(encoding, exten, size);
1505  // TODO(iguessthislldo) Handle Parameter List
1506  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
1507  idl_max_serialized_size(encoding, size, (*i)->field_type());
1508  }
1509  break;
1510  }
1511  case AST_Decl::NT_sequence: {
1512  AST_Sequence* seq_node = dynamic_cast<AST_Sequence*>(type);
1513  AST_Type* base_node = seq_node->base_type();
1514  idl_max_serialized_size_dheader(encoding, exten, size);
1515  size_t bound = seq_node->max_size()->ev()->u.ulval;
1516  align(encoding, size, 4);
1517  size += 4;
1518  idl_max_serialized_size_repeating(encoding, size, base_node, bound);
1519  break;
1520  }
1521  case AST_Decl::NT_array: {
1522  AST_Array* array_node = dynamic_cast<AST_Array*>(type);
1523  AST_Type* base_node = array_node->base_type();
1524  idl_max_serialized_size_dheader(encoding, exten, size);
1525  idl_max_serialized_size_repeating(
1526  encoding, size, base_node, array_element_count(array_node));
1527  break;
1528  }
1529  case AST_Decl::NT_union: {
1530  AST_Union* union_node = dynamic_cast<AST_Union*>(type);
1531  idl_max_serialized_size_dheader(encoding, exten, size);
1532  // TODO(iguessthislldo) Handle Parameter List
1533  idl_max_serialized_size(encoding, size, union_node->disc_type());
1534  size_t largest_field_size = 0;
1535  const size_t starting_size = size;
1536  const Fields fields(union_node);
1537  const Fields::Iterator fields_end = fields.end();
1538  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
1539  idl_max_serialized_size(encoding, size, (*i)->field_type());
1540  size_t field_size = size - starting_size;
1541  if (field_size > largest_field_size) {
1542  largest_field_size = field_size;
1543  }
1544  // rewind:
1545  size = starting_size;
1546  }
1547  size += largest_field_size;
1548  break;
1549  }
1550  default:
1551  // Anything else should be not here or is unbounded
1552  break;
1553  }
1554  }
1555 }
1556 
1557 bool marshal_generator::gen_typedef(AST_Typedef* node, UTL_ScopedName* name, AST_Type* base, const char*)
1558 {
1559  switch (base->node_type()) {
1560  case AST_Decl::NT_sequence:
1561  gen_sequence(name, node, dynamic_cast<AST_Sequence*>(base));
1562  break;
1563  case AST_Decl::NT_array:
1564  gen_array(name, dynamic_cast<AST_Array*>(base));
1565  break;
1566  default:
1567  return true;
1568  }
1569  return true;
1570 }
1571 
1572 namespace {
1573  // common to both fields (in structs) and branches (in unions)
1574  string findSizeCommon(const std::string& indent, AST_Decl*field, const string& name,
1575  AST_Type* type, const string& prefix, bool wrap_nested_key_only,
1576  Intro& intro, const string& = "") // same sig as streamCommon
1577  {
1578  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
1579  const bool is_union_member = prefix == "uni";
1580 
1581  AST_Type* const actual_type = resolveActualType(type);
1582  const Classification fld_cls = classify(actual_type);
1583 
1584  const string qual = prefix + '.' + insert_cxx11_accessor_parens(name, is_union_member);
1585 
1586  if (fld_cls & CL_ENUM) {
1587  return indent + "primitive_serialized_size_ulong(encoding, size);\n";
1588  } else if (fld_cls & CL_STRING) {
1589  const string suffix = is_union_member ? "" : ".in()";
1590  const string get_size = use_cxx11 ? (qual + ".size()")
1591  : ("ACE_OS::strlen(" + qual + suffix + ")");
1592  return indent + "primitive_serialized_size_ulong(encoding, size);\n" +
1593  indent + "size += " + get_size
1594  + ((fld_cls & CL_WIDE) ? " * char16_cdr_size;\n"
1595  : " + 1;\n");
1596  } else if (fld_cls & CL_PRIMITIVE) {
1597  AST_PredefinedType* const p = dynamic_cast<AST_PredefinedType*>(actual_type);
1598  if (p->pt() == AST_PredefinedType::PT_longdouble) {
1599  // special case use to ACE's NONNATIVE_LONGDOUBLE in CDR_Base.h
1600  return indent +
1601  "primitive_serialized_size(encoding, size, ACE_CDR::LongDouble());\n";
1602  }
1603  return indent + "primitive_serialized_size(encoding, size, " +
1604  getWrapper(qual, actual_type, WD_OUTPUT) + ");\n";
1605  } else if (fld_cls == CL_UNKNOWN) {
1606  return ""; // warning will be issued for the serialize functions
1607  } else { // sequence, struct, union, array
1608  RefWrapper wrapper(type, field_type_name(dynamic_cast<AST_Field*>(field), type),
1609  prefix + "." + insert_cxx11_accessor_parens(name, is_union_member));
1610  wrapper.nested_key_only_ = wrap_nested_key_only;
1611  wrapper.done(&intro);
1612  return indent + "serialized_size(encoding, size, " + wrapper.ref() + ");\n";
1613  }
1614  }
1615 
1616  string findSizeMutableUnion(const string& indent, AST_Decl* node, const string& name, AST_Type* type,
1617  const string& prefix, bool wrap_nested_key_only, Intro& intro,
1618  const string & = "") // same sig as streamCommon
1619  {
1620  return indent + "serialized_size_parameter_id(encoding, size, mutable_running_total);\n"
1621  + findSizeCommon(indent, node, name, type, prefix, wrap_nested_key_only, intro);
1622  }
1623 
1624  std::string generate_field_serialized_size(
1625  const std::string& indent, AST_Field* field, const std::string& prefix,
1626  bool wrap_nested_key_only, Intro& intro)
1627  {
1628  FieldInfo af(*field);
1629  if (af.anonymous()) {
1630  RefWrapper wrapper(af.type_, af.scoped_type_,
1631  prefix + "." + insert_cxx11_accessor_parens(af.name_));
1632  wrapper.nested_key_only_ = wrap_nested_key_only;
1633  wrapper.done(&intro);
1634  return indent + "serialized_size(encoding, size, " + wrapper.ref() + ");\n";
1635  }
1636  return findSizeCommon(
1637  indent, field, field->local_name()->get_string(), field->field_type(), prefix,
1638  wrap_nested_key_only, intro);
1639  }
1640 
1641  // common to both fields (in structs) and branches (in unions)
1642  string streamCommon(const std::string& /*indent*/, AST_Decl* field, const string& name,
1643  AST_Type* type, const string& prefix, bool wrap_nested_key_only, Intro& intro,
1644  const string& stru)
1645  {
1646  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
1647  const bool is_union_member = prefix.substr(3) == "uni";
1648 
1649  AST_Type* const actual_type = resolveActualType(type);
1650  const Classification fld_cls = classify(actual_type);
1651 
1652  string qual = prefix + '.' + insert_cxx11_accessor_parens(name, is_union_member);
1653  // if there is a stray '.' on the end, strip it off
1654  if (qual[qual.length() - 1] == '.') {
1655  qual.erase(qual.length() - 1);
1656  }
1657  const string shift = prefix.substr(0, 2),
1658  expr = qual.substr(3);
1659 
1660  WrapDirection dir = (shift == ">>") ? WD_INPUT : WD_OUTPUT;
1661  if ((fld_cls & CL_STRING) && (dir == WD_INPUT)) {
1662  if ((fld_cls & CL_BOUNDED)) {
1663  const string args = expr + (use_cxx11 ? ", " : ".out(), ") + bounded_arg(actual_type);
1664  return "(strm " + shift + ' ' + getWrapper(args, actual_type, WD_INPUT) + ')';
1665  }
1666  return "(strm " + qual + (use_cxx11 ? "" : ".out()") + ')';
1667  } else if (fld_cls & CL_PRIMITIVE) {
1668  return "(strm " + shift + ' ' + getWrapper(expr, actual_type, dir) + ')';
1669  } else if (fld_cls == CL_UNKNOWN) {
1670  if (dir == WD_INPUT) { // no need to warn twice
1671  std::cerr << "WARNING: field " << name << " can not be serialized. "
1672  "The struct or union it belongs to (" << stru <<
1673  ") can not be used in an OpenDDS topic type." << std::endl;
1674  }
1675  return "false";
1676  } else { // sequence, struct, union, array, enum, string(insertion)
1677  string fieldref = prefix, local = insert_cxx11_accessor_parens(name, is_union_member);
1678  const bool accessor = local.size() > 2 && local.substr(local.size() - 2) == "()";
1679  if (fld_cls & CL_STRING) {
1680  if (!accessor && !use_cxx11) {
1681  local += ".in()";
1682  }
1683  if ((fld_cls & CL_BOUNDED)) {
1684  const string args = (fieldref + '.' + local).substr(3) + ", " + bounded_arg(actual_type);
1685  return "(strm " + shift + ' ' + getWrapper(args, actual_type, WD_OUTPUT) + ')';
1686  }
1687  }
1688  RefWrapper wrapper(type, field_type_name(dynamic_cast<AST_Field*>(field), type),
1689  fieldref, local, dir == WD_OUTPUT);
1690  wrapper.nested_key_only_ = wrap_nested_key_only;
1691  wrapper.done(&intro);
1692  return "(strm " + shift + " " + wrapper.ref() + ")";
1693  }
1694  }
1695 
1696  std::string generate_field_stream(
1697  const std::string& indent, AST_Field* field, const std::string& prefix,
1698  bool wrap_nested_key_only, Intro& intro)
1699  {
1700  FieldInfo af(*field);
1701  if (af.anonymous()) {
1702  RefWrapper wrapper(af.type_, af.scoped_type_,
1703  prefix + "." + insert_cxx11_accessor_parens(af.name_));
1704  wrapper.nested_key_only_ = wrap_nested_key_only;
1705  wrapper.done(&intro);
1706  return "(strm " + wrapper.stream() + ")";
1707  }
1708  return streamCommon(
1709  indent, field, field->local_name()->get_string(), field->field_type(), prefix,
1710  wrap_nested_key_only, intro);
1711  }
1712 
1713  bool genBinaryProperty_t(const string& cxx)
1714  {
1715  {
1716  Function serialized_size("serialized_size", "void");
1717  serialized_size.addArg("encoding", "const Encoding&");
1718  serialized_size.addArg("size", "size_t&");
1719  serialized_size.addArg("stru", "const " + cxx + "&");
1720  serialized_size.endArgs();
1721  be_global->impl_ <<
1722  " if (stru.propagate) {\n"
1723  " primitive_serialized_size_ulong(encoding, size);\n"
1724  " size += ACE_OS::strlen(stru.name.in()) + 1;\n"
1725  " serialized_size(encoding, size, stru.value);\n"
1726  " }\n";
1727  }
1728  {
1729  Function insertion("operator<<", "bool");
1730  insertion.addArg("strm", "Serializer&");
1731  insertion.addArg("stru", "const " + cxx + "&");
1732  insertion.endArgs();
1733  be_global->impl_ <<
1734  " if (stru.propagate) {\n"
1735  " return (strm << stru.name.in()) && (strm << stru.value);\n"
1736  " }\n"
1737  " return true;\n";
1738  }
1739  {
1740  Function extraction("operator>>", "bool");
1741  extraction.addArg("strm", "Serializer&");
1742  extraction.addArg("stru", cxx + "&");
1743  extraction.endArgs();
1744  be_global->impl_ <<
1745  " stru.propagate = true;\n"
1746  " return (strm >> stru.name.out()) && (strm >> stru.value);\n";
1747  }
1748  return true;
1749  }
1750 
1751  bool genProperty_t(const string& cxx)
1752  {
1753  {
1754  Function serialized_size("serialized_size", "void");
1755  serialized_size.addArg("encoding", "const Encoding&");
1756  serialized_size.addArg("size", "size_t&");
1757  serialized_size.addArg("stru", "const " + cxx + "&");
1758  serialized_size.endArgs();
1759  be_global->impl_ <<
1760  " if (stru.propagate) {\n"
1761  " primitive_serialized_size_ulong(encoding, size);\n"
1762  " size += ACE_OS::strlen(stru.name.in()) + 1;\n"
1763  " primitive_serialized_size_ulong(encoding, size);\n"
1764  " size += ACE_OS::strlen(stru.value.in()) + 1;\n"
1765  " }\n";
1766  }
1767  {
1768  Function insertion("operator<<", "bool");
1769  insertion.addArg("strm", "Serializer&");
1770  insertion.addArg("stru", "const " + cxx + "&");
1771  insertion.endArgs();
1772  be_global->impl_ <<
1773  " if (stru.propagate) {\n"
1774  " return (strm << stru.name.in()) && (strm << stru.value.in());\n"
1775  " }\n"
1776  " return true;\n";
1777  }
1778  {
1779  Function extraction("operator>>", "bool");
1780  extraction.addArg("strm", "Serializer&");
1781  extraction.addArg("stru", cxx + "&");
1782  extraction.endArgs();
1783  be_global->impl_ <<
1784  " stru.propagate = true;\n"
1785  " return (strm >> stru.name.out()) && (strm >> stru.value.out());\n";
1786  }
1787  return true;
1788  }
1789 
1790  bool genPropertyQosPolicy(const string& cxx)
1791  {
1792  {
1793  Function serialized_size("serialized_size", "void");
1794  serialized_size.addArg("encoding", "const Encoding&");
1795  serialized_size.addArg("size", "size_t&");
1796  serialized_size.addArg("stru", "const " + cxx + "&");
1797  serialized_size.endArgs();
1798  be_global->impl_ <<
1799  " serialized_size(encoding, size, stru.value);\n"
1800  " serialized_size(encoding, size, stru.binary_value);\n";
1801  }
1802  {
1803  Function insertion("operator<<", "bool");
1804  insertion.addArg("strm", "Serializer&");
1805  insertion.addArg("stru", "const " + cxx + "&");
1806  insertion.endArgs();
1807  be_global->impl_ <<
1808  " return (strm << stru.value)\n"
1809  " && (strm << stru.binary_value);\n";
1810  }
1811  {
1812  Function extraction("operator>>", "bool");
1813  extraction.addArg("strm", "Serializer&");
1814  extraction.addArg("stru", cxx + "&");
1815  extraction.endArgs();
1816  be_global->impl_ <<
1817  " if (!(strm >> stru.value)) {\n"
1818  " return false;\n"
1819  " }\n"
1820  " if (!strm.length() || !strm.skip(0, 4) || !strm.length()) {\n"
1821  " return true; // optional member missing\n"
1822  " }\n"
1823  " return strm >> stru.binary_value;\n";
1824  }
1825  return true;
1826  }
1827 
1828  bool genSecuritySubmessage(const string& cxx)
1829  {
1830  {
1831  Function serialized_size("serialized_size", "void");
1832  serialized_size.addArg("encoding", "const Encoding&");
1833  serialized_size.addArg("size", "size_t&");
1834  serialized_size.addArg("stru", "const " + cxx + "&");
1835  serialized_size.endArgs();
1836  be_global->impl_ <<
1837  " serialized_size(encoding, size, stru.smHeader);\n"
1838  " primitive_serialized_size_octet(encoding, size, stru.content.length());\n";
1839  }
1840  {
1841  Function insertion("operator<<", "bool");
1842  insertion.addArg("strm", "Serializer&");
1843  insertion.addArg("stru", "const " + cxx + "&");
1844  insertion.endArgs();
1845  be_global->impl_ <<
1846  " return (strm << stru.smHeader)\n"
1847  " && strm.write_octet_array(stru.content.get_buffer(), "
1848  "stru.content.length());\n";
1849  }
1850  {
1851  Function extraction("operator>>", "bool");
1852  extraction.addArg("strm", "Serializer&");
1853  extraction.addArg("stru", cxx + "&");
1854  extraction.endArgs();
1855  be_global->impl_ <<
1856  " if (strm >> stru.smHeader) {\n"
1857  " stru.content.length(stru.smHeader.submessageLength);\n"
1858  " if (strm.read_octet_array(stru.content.get_buffer(),\n"
1859  " stru.smHeader.submessageLength)) {\n"
1860  " return true;\n"
1861  " }\n"
1862  " }\n"
1863  " return false;\n";
1864  }
1865  return true;
1866  }
1867 
1868  bool genRtpsSpecialStruct(const string& cxx)
1869  {
1870  {
1871  Function serialized_size("serialized_size", "void");
1872  serialized_size.addArg("encoding", "const Encoding&");
1873  serialized_size.addArg("size", "size_t&");
1874  serialized_size.addArg("stru", "const " + cxx + "&");
1875  serialized_size.endArgs();
1876  be_global->impl_ <<
1877  " size += "
1878  << ((cxx == RtpsNamespace + "SequenceNumberSet") ? "12" : "8")
1879  << " + 4 * ((stru.numBits + 31) / 32); // RTPS Custom\n";
1880  }
1881  {
1882  Function insertion("operator<<", "bool");
1883  insertion.addArg("strm", "Serializer&");
1884  insertion.addArg("stru", "const " + cxx + "&");
1885  insertion.endArgs();
1886  be_global->impl_ <<
1887  " if ((strm << stru.bitmapBase) && (strm << stru.numBits)) {\n"
1888  " const CORBA::ULong M = (stru.numBits + 31) / 32;\n"
1889  " if (stru.bitmap.length() < M) {\n"
1890  " return false;\n"
1891  " }\n"
1892  " for (CORBA::ULong i = 0; i < M; ++i) {\n"
1893  " if (!(strm << stru.bitmap[i])) {\n"
1894  " return false;\n"
1895  " }\n"
1896  " }\n"
1897  " return true;\n"
1898  " }\n"
1899  " return false;\n";
1900  }
1901  {
1902  Function extraction("operator>>", "bool");
1903  extraction.addArg("strm", "Serializer&");
1904  extraction.addArg("stru", cxx + "&");
1905  extraction.endArgs();
1906  be_global->impl_ <<
1907  " if ((strm >> stru.bitmapBase) && (strm >> stru.numBits)) {\n"
1908  " const CORBA::ULong M = (stru.numBits + 31) / 32;\n"
1909  " if (M > 8) {\n"
1910  " return false;\n"
1911  " }\n"
1912  " stru.bitmap.length(M);\n"
1913  " for (CORBA::ULong i = 0; i < M; ++i) {\n"
1914  " if (!(strm >> stru.bitmap[i])) {\n"
1915  " return false;\n"
1916  " }\n"
1917  " }\n"
1918  " return true;\n"
1919  " }\n"
1920  " return false;\n";
1921  }
1922  return true;
1923  }
1924 
1925  struct RtpsFieldCustomizer {
1926 
1927  explicit RtpsFieldCustomizer(const string& cxx)
1928  {
1929  if (cxx == RtpsNamespace + "DataSubmessage") {
1930  cst_["inlineQos"] = "stru.smHeader.flags & 2";
1931  iQosOffset_ = "16";
1932 
1933  } else if (cxx == RtpsNamespace + "DataFragSubmessage") {
1934  cst_["inlineQos"] = "stru.smHeader.flags & 2";
1935  iQosOffset_ = "28";
1936 
1937  } else if (cxx == RtpsNamespace + "InfoReplySubmessage") {
1938  cst_["multicastLocatorList"] = "stru.smHeader.flags & 2";
1939 
1940  } else if (cxx == RtpsNamespace + "InfoTimestampSubmessage") {
1941  cst_["timestamp"] = "!(stru.smHeader.flags & 2)";
1942 
1943  } else if (cxx == RtpsNamespace + "InfoReplyIp4Submessage") {
1944  cst_["multicastLocator"] = "stru.smHeader.flags & 2";
1945 
1946  } else if (cxx == RtpsNamespace + "SubmessageHeader") {
1947  intro_.insert("strm.swap_bytes(ACE_CDR_BYTE_ORDER != (stru.flags & 1));");
1948  }
1949  }
1950 
1951  string getConditional(const string& field_name) const
1952  {
1953  if (cst_.empty()) {
1954  return "";
1955  }
1956  std::map<string, string>::const_iterator it = cst_.find(field_name);
1957  if (it != cst_.end()) {
1958  return it->second;
1959  }
1960  return "";
1961  }
1962 
1963  string preFieldRead(const string& field_name) const
1964  {
1965  if (cst_.empty() || field_name != "inlineQos" || iQosOffset_.empty()) {
1966  return "";
1967  }
1968  return "strm.skip(stru.octetsToInlineQos - " + iQosOffset_ + ")\n"
1969  " && ";
1970  }
1971 
1972  std::map<string, string> cst_;
1973  string iQosOffset_;
1974  Intro intro_;
1975  };
1976 
1977  typedef void (*KeyIterationFn)(
1978  const std::string& indent,
1980  const string& key_name, AST_Type* ast_type,
1981  size_t* size,
1982  string* expr, Intro* intro);
1983 
1984  bool
1985  iterate_over_keys(
1986  const std::string& indent,
1987  Encoding::Kind encoding,
1988  AST_Structure* node,
1989  const std::string& struct_name,
1990  IDL_GlobalData::DCPS_Data_Type_Info* info,
1991  TopicKeys* keys,
1992  KeyIterationFn fn,
1993  size_t* size,
1994  string* expr, Intro* intro)
1995  {
1996  if (keys && keys->root_type() != TopicKeys::InvalidType) {
1997  const TopicKeys::Iterator finished = keys->end();
1998  for (TopicKeys::Iterator i = keys->begin(); i != finished; ++i) {
1999  string key_access = i.path();
2000  AST_Type* straight_ast_type = i.get_ast_type();
2001  AST_Type* ast_type;
2002  if (i.root_type() == TopicKeys::UnionType) {
2003  AST_Union* union_type = dynamic_cast<AST_Union*>(straight_ast_type);
2004  if (!union_type) {
2005  std::cerr << "ERROR: Invalid key iterator for: " << struct_name;
2006  return false;
2007  }
2008  ast_type = dynamic_cast<AST_Type*>(union_type->disc_type());
2009  key_access.append("._d()");
2010  } else {
2011  ast_type = straight_ast_type;
2012  }
2013  fn(indent, encoding, key_access, ast_type, size, expr, intro);
2014  }
2015  return true;
2016  }
2017 
2018  if (info) {
2019  IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
2020  for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
2021  const string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
2022  fn(indent, encoding, key_name, find_type(node, key_name), size, expr, intro);
2023  }
2024  }
2025 
2026  return true;
2027  }
2028 
2029  // Args must match KeyIterationFn.
2030  void idl_max_serialized_size_iteration(
2031  const std::string&, Encoding::Kind encoding, const string&, AST_Type* ast_type,
2032  size_t* size, string*, Intro*)
2033  {
2034  idl_max_serialized_size(encoding, *size, ast_type);
2035  }
2036 
2037  void serialized_size_iteration(
2038  const std::string& indent, Encoding::Kind, const string& key_name, AST_Type* ast_type,
2039  size_t*, string* expr, Intro* intro)
2040  {
2041  *expr += findSizeCommon(indent, 0, key_name, ast_type, "stru.value", false, *intro);
2042  }
2043 
2044  std::string fill_datareprseq(
2045  const OpenDDS::DataRepresentation& repr,
2046  const std::string& name,
2047  const std::string& indent)
2048  {
2049  std::vector<std::string> values;
2050  if (repr.xcdr1) {
2051  values.push_back("DDS::XCDR_DATA_REPRESENTATION");
2052  }
2053  if (repr.xcdr2) {
2054  values.push_back("DDS::XCDR2_DATA_REPRESENTATION");
2055  }
2056  if (repr.xml) {
2057  values.push_back("DDS::XML_DATA_REPRESENTATION");
2058  }
2059  if (repr.unaligned) {
2060  values.push_back("OpenDDS::DCPS::UNALIGNED_CDR_DATA_REPRESENTATION");
2061  }
2062 
2063  std::ostringstream ss;
2064  ss << indent << name << ".length(" << values.size() << ");\n";
2065  for (size_t i = 0; i < values.size(); ++i) {
2066  ss << indent << name << "[" << i << "] = " << values[i] << ";\n";
2067  }
2068  return ss.str();
2069  }
2070 
2071  bool is_bounded_topic_struct(AST_Type* type, Encoding::Kind encoding, bool key_only,
2072  TopicKeys& keys, IDL_GlobalData::DCPS_Data_Type_Info* info = 0)
2073  {
2074  /*
2075  * TODO(iguessthislldo): This is a workaround for not properly implementing
2076  * serialized_size_bound for XCDR. See XTYPE-83.
2077  */
2078  const ExtensibilityKind exten = be_global->extensibility(type);
2079  if (exten != extensibilitykind_final && encoding != Encoding::KIND_UNALIGNED_CDR) {
2080  return false;
2081  }
2082 
2083  bool bounded = true;
2084  if (key_only) {
2085  if (info) {
2086  IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
2087  AST_Structure* const struct_type = dynamic_cast<AST_Structure*>(type);
2088  for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
2089  const string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
2090  AST_Type* const field_type = find_type(struct_type, key_name);
2091  if (!is_bounded_type(field_type, encoding)) {
2092  bounded = false;
2093  break;
2094  }
2095  }
2096  } else {
2097  const TopicKeys::Iterator finished = keys.end();
2098  for (TopicKeys::Iterator i = keys.begin(); i != finished; ++i) {
2099  if (!is_bounded_type(i.get_ast_type(), encoding)) {
2100  bounded = false;
2101  break;
2102  }
2103  }
2104  }
2105  } else {
2106  bounded = is_bounded_type(type, encoding);
2107  }
2108  return bounded;
2109  }
2110 
2111  bool generate_marshal_traits_struct_bounds_functions(AST_Structure* node,
2112  TopicKeys& keys, IDL_GlobalData::DCPS_Data_Type_Info* info, bool key_only)
2113  {
2114  const char* function_prefix = key_only ? "key_only_" : "";
2115  AST_Type* const type_node = dynamic_cast<AST_Type*>(node);
2116  const Fields fields(node);
2117  const Fields::Iterator fields_end = fields.end();
2118  const std::string name = scoped(node->name());
2119  const ExtensibilityKind exten = be_global->extensibility(node);
2120 
2121  be_global->header_ <<
2122  " static SerializedSizeBound " << function_prefix <<
2123  "serialized_size_bound(const Encoding& encoding)\n"
2124  " {\n"
2125  " switch (encoding.kind()) {\n";
2126  for (unsigned e = 0; e <= Encoding::KIND_UNALIGNED_CDR; ++e) {
2127  const Encoding::Kind encoding = static_cast<Encoding::Kind>(e);
2128  be_global->header_ <<
2129  " case " << encoding_to_encoding_kind(encoding) << ":\n"
2130  " return SerializedSizeBound(";
2131  if (is_bounded_topic_struct(type_node, encoding, key_only, keys, info)) {
2132  size_t size = 0;
2133  if (key_only) {
2134  idl_max_serialized_size_dheader(encoding, exten, size);
2135  if (!iterate_over_keys("", encoding, node, name, info, &keys,
2136  idl_max_serialized_size_iteration, &size, 0, 0)) {
2137  return false;
2138  }
2139  } else {
2140  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
2141  idl_max_serialized_size(encoding, size, (*i)->field_type());
2142  }
2143  }
2144  be_global->header_ << size;
2145  }
2146  be_global->header_ << ");\n";
2147  }
2148  be_global->header_ <<
2149  " default:\n"
2150  " OPENDDS_ASSERT(false);\n"
2151  " return SerializedSizeBound();\n"
2152  " }\n"
2153  " }\n"
2154  "\n";
2155 
2156  return true;
2157  }
2158 
2159  bool generate_marshal_traits_struct(AST_Structure* node,
2160  TopicKeys& keys, IDL_GlobalData::DCPS_Data_Type_Info* info = 0)
2161  {
2162  return
2163  generate_marshal_traits_struct_bounds_functions(node, keys, info, false) && // All Fields
2164  generate_marshal_traits_struct_bounds_functions(node, keys, info, true); // Key Fields
2165  }
2166 
2167  bool generate_marshal_traits_union(AST_Union* node, bool has_key, ExtensibilityKind exten)
2168  {
2169  be_global->header_ <<
2170  " static SerializedSizeBound serialized_size_bound(const Encoding& encoding)\n"
2171  " {\n"
2172  " switch (encoding.kind()) {\n";
2173  for (unsigned e = 0; e <= Encoding::KIND_UNALIGNED_CDR; ++e) {
2174  const Encoding::Kind encoding = static_cast<Encoding::Kind>(e);
2175  be_global->header_ <<
2176  " case " << encoding_to_encoding_kind(encoding) << ":\n"
2177  " return SerializedSizeBound(";
2178  if (is_bounded_type(node, encoding)) {
2179  size_t size = 0;
2180  idl_max_serialized_size(encoding, size, node);
2181  be_global->header_ << size;
2182  }
2183  be_global->header_ << ");\n";
2184  }
2185  be_global->header_ <<
2186  " default:\n"
2187  " OPENDDS_ASSERT(false);\n"
2188  " return SerializedSizeBound();\n"
2189  " }\n"
2190  " }\n"
2191  "\n";
2192 
2193  be_global->header_ <<
2194  " static SerializedSizeBound key_only_serialized_size_bound(const Encoding& encoding)\n"
2195  " {\n"
2196  " switch (encoding.kind()) {\n";
2197  for (unsigned e = 0; e <= Encoding::KIND_UNALIGNED_CDR; ++e) {
2198  const Encoding::Kind encoding = static_cast<Encoding::Kind>(e);
2199  be_global->header_ <<
2200  " case " << encoding_to_encoding_kind(encoding) << ":\n"
2201  " return SerializedSizeBound(";
2202  /*
2203  * TODO(iguessthislldo): This is a workaround for not properly implementing
2204  * serialized_size_bound for Mutable. See XTYPE-83.
2205  */
2206  if (exten == extensibilitykind_final || encoding == Encoding::KIND_UNALIGNED_CDR) {
2207  size_t size = 0;
2208  if (has_key) {
2209  idl_max_serialized_size(encoding, size, node->disc_type());
2210  }
2211  be_global->header_ << size;
2212  }
2213  be_global->header_ << ");\n";
2214  }
2215  be_global->header_ <<
2216  " default:\n"
2217  " OPENDDS_ASSERT(false);\n"
2218  " return SerializedSizeBound();\n"
2219  " }\n"
2220  " }\n"
2221  "\n";
2222 
2223  return true;
2224  }
2225 
2226  bool generate_marshal_traits(
2227  AST_Decl* node, const std::string& cxx, ExtensibilityKind exten,
2228  TopicKeys& keys, IDL_GlobalData::DCPS_Data_Type_Info* info = 0)
2229  {
2230  AST_Structure* const struct_node =
2231  node->node_type() == AST_Decl::NT_struct ? dynamic_cast<AST_Structure*>(node) : 0;
2232  AST_Union* const union_node =
2233  node->node_type() == AST_Decl::NT_union ? dynamic_cast<AST_Union*>(node) : 0;
2234  if (!struct_node && !union_node) {
2235  idl_global->err()->misc_error("Can't generate MarshalTraits for this node", node);
2236  return false;
2237  }
2238 
2239  std::string octetSeqOnly;
2240  if (struct_node && struct_node->nfields() == 1) {
2241  AST_Field* const field = get_struct_field(struct_node, 0);
2242  AST_Type* const type = resolveActualType(field->field_type());
2243  const Classification fld_cls = classify(type);
2244  if (fld_cls & CL_SEQUENCE) {
2245  AST_Sequence* const seq = dynamic_cast<AST_Sequence*>(type);
2246  AST_Type* const base = resolveActualType(seq->base_type());
2247  if (classify(base) & CL_PRIMITIVE) {
2248  AST_PredefinedType* const pt = dynamic_cast<AST_PredefinedType*>(base);
2249  if (pt->pt() == AST_PredefinedType::PT_octet) {
2250  octetSeqOnly = field->local_name()->get_string();
2251  }
2252  }
2253  }
2254  }
2255 
2256  std::string export_string;
2257  if (octetSeqOnly.size()) {
2258  const ACE_CString exporter = be_global->export_macro();
2259  if (exporter != "") {
2260  export_string = string(" ") + exporter.c_str();
2261  }
2262  }
2263 
2264  be_global->add_include("dds/DCPS/TypeSupportImpl.h");
2265 
2266  be_global->header_ <<
2267  "template <>\n"
2268  "struct" << export_string << " MarshalTraits<" << cxx << "> {\n"
2269  " static void representations_allowed_by_type(DDS::DataRepresentationIdSeq& seq)\n"
2270  " {\n"
2271  << fill_datareprseq(be_global->data_representations(node), "seq", " ") <<
2272  " }\n"
2273  "\n";
2274 
2275  if (struct_node) {
2276  if (!generate_marshal_traits_struct(struct_node, keys, info)) {
2277  return false;
2278  }
2279  } else if (union_node) {
2280  if (!generate_marshal_traits_union(union_node, keys.count(), exten)) {
2281  return false;
2282  }
2283  }
2284 
2285  const char* msg_block_fn_decl_end = " { return false; }";
2286  if (octetSeqOnly.size()) {
2287  const char* get_len;
2288  const char* set_len;
2289  const char* get_buffer;
2290  const char* buffer_pre = "";
2291  if (be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11) {
2292  get_len = "size";
2293  set_len = "resize";
2294  get_buffer = "[0]";
2295  buffer_pre = "&";
2296  octetSeqOnly += "()";
2297  } else {
2298  get_len = set_len = "length";
2299  get_buffer = ".get_buffer()";
2300  }
2301 
2302  be_global->impl_ <<
2303  "bool MarshalTraits<" << cxx << ">::to_message_block(ACE_Message_Block& mb, "
2304  "const " << cxx << "& stru)\n"
2305  "{\n"
2306  " if (mb.size(stru." << octetSeqOnly << "." << get_len << "()) != 0) {\n"
2307  " return false;\n"
2308  " }\n"
2309  " return mb.copy(reinterpret_cast<const char*>(" << buffer_pre << "stru."
2310  << octetSeqOnly << get_buffer << "), stru." << octetSeqOnly << "." << get_len
2311  << "()) == 0;\n"
2312  "}\n\n"
2313  "bool MarshalTraits<" << cxx << ">::from_message_block(" << cxx << "& stru, "
2314  "const ACE_Message_Block& mb)\n"
2315  "{\n"
2316  " stru." << octetSeqOnly << "." << set_len << "(static_cast<unsigned>(mb.total_length()));\n"
2317  " ACE_CDR::Octet* dst = " << buffer_pre << "stru." << octetSeqOnly << get_buffer << ";\n"
2318  " for (const ACE_Message_Block* m = &mb; m; m = m->cont()) {\n"
2319  " std::memcpy(dst, m->rd_ptr(), m->length());\n"
2320  " dst += m->length();\n"
2321  " }\n"
2322  " return true;\n"
2323  "}\n\n";
2324 
2325  msg_block_fn_decl_end = ";";
2326  }
2327  be_global->header_ <<
2328  " static bool to_message_block(ACE_Message_Block&, const " << cxx << "&)"
2329  << msg_block_fn_decl_end << "\n"
2330  " static bool from_message_block(" << cxx << "&, const ACE_Message_Block&)"
2331  << msg_block_fn_decl_end << "\n";
2332 
2333  /*
2334  * This is used for the CDR header.
2335  * This is just for the base type, nested types can have different
2336  * extensibilities.
2337  */
2338  be_global->header_ <<
2339  " static Extensibility extensibility() { return ";
2340  switch (exten) {
2342  be_global->header_ << "FINAL";
2343  break;
2345  be_global->header_ << "APPENDABLE";
2346  break;
2348  be_global->header_ << "MUTABLE";
2349  break;
2350  default:
2351  idl_global->err()->misc_error(
2352  "Unexpected extensibility while generating MarshalTraits", node);
2353  return false;
2354  }
2355  be_global->header_ << "; }\n";
2356 
2357  /*
2358  * This is used for topic type extensibility level.
2359  */
2360  const ExtensibilityKind ek = max_extensibility_kind(dynamic_cast<AST_Type*>(node));
2361  be_global->header_ <<
2362  " static Extensibility max_extensibility_level() { return ";
2363  switch (ek) {
2365  be_global->header_ << "FINAL";
2366  break;
2368  be_global->header_ << "APPENDABLE";
2369  break;
2371  be_global->header_ << "MUTABLE";
2372  break;
2373  default:
2374  idl_global->err()->misc_error(
2375  "Unexpected extensibility level while generating MarshalTraits", node);
2376  return false;
2377  }
2378  be_global->header_ << "; }\n"
2379  "};\n";
2380 
2381  return true;
2382  }
2383 
2384  bool generate_struct_deserialization(
2385  AST_Structure* node, FieldFilter field_type)
2386  {
2387  const std::string actual_cpp_name = scoped(node->name());
2388  std::string cpp_name = actual_cpp_name;
2389  std::string const_cpp_name;
2390  switch (field_type) {
2391  case FieldFilter_All:
2392  const_cpp_name = "const" + actual_cpp_name + "&";
2393  break;
2395  cpp_name = "const NestedKeyOnly<" + actual_cpp_name + ">";
2396  const_cpp_name = "const NestedKeyOnly<const" + actual_cpp_name + ">&";
2397  break;
2398  case FieldFilter_KeyOnly:
2399  cpp_name = "const KeyOnly<" + actual_cpp_name + ">";
2400  const_cpp_name = "const KeyOnly<const" + actual_cpp_name + ">&";
2401  break;
2402  }
2403  const std::string value_access = field_type == FieldFilter_All ? "" : ".value";
2404  const bool wrap_nested_key_only = field_type != FieldFilter_All;
2405  const Fields fields(node, field_type);
2406  const Fields::Iterator fields_end = fields.end();
2407  RtpsFieldCustomizer rtpsCustom(cpp_name);
2408 
2409  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
2410 
2411  const ExtensibilityKind exten = be_global->extensibility(node);
2412  const bool not_final = exten != extensibilitykind_final;
2413  const bool is_mutable = exten == extensibilitykind_mutable;
2414  const bool is_appendable = exten == extensibilitykind_appendable;
2415 
2416  {
2417  Function extraction("operator>>", "bool");
2418  extraction.addArg("strm", "Serializer&");
2419  extraction.addArg("stru", cpp_name + "&");
2420  extraction.endArgs();
2421  Intro intro;
2422  string expr;
2423  const std::string indent = " ";
2424 
2425  be_global->impl_ <<
2426  " const Encoding& encoding = strm.encoding();\n"
2427  " ACE_UNUSED_ARG(encoding);\n";
2428  if (is_appendable) {
2429  be_global->impl_ <<
2430  " bool reached_end_of_struct = false;\n"
2431  " ACE_UNUSED_ARG(reached_end_of_struct);\n";
2432  }
2434  " if (!strm.read_delimiter(total_size)) {\n"
2435  " return false;\n"
2436  " }\n", not_final);
2437 
2438  if (not_final) {
2439  be_global->impl_ <<
2440  " const size_t end_of_struct = strm.rpos() + total_size;\n"
2441  "\n";
2442  }
2443 
2444  if (is_mutable) {
2445  be_global->impl_ <<
2446  " if (encoding.xcdr_version() != Encoding::XCDR_VERSION_NONE) {\n"
2447  " set_default(stru" << (wrap_nested_key_only ? ".value" : "") << ");\n"
2448  "\n"
2449  " unsigned member_id;\n"
2450  " size_t field_size;\n"
2451  " while (true) {\n";
2452 
2453  /*
2454  * Get the Member ID and see if we're done. In XCDR1 we use a special
2455  * member ID to stop the loop. We don't have a PID marking the end in
2456  * XCDR2 parameter lists, but we have the size, so we need to stop
2457  * after we hit the offset marked by the delimiter, but before trying
2458  * to read a non-existent member id.
2459  */
2460  be_global->impl_ <<
2461  " if (encoding.xcdr_version() == Encoding::XCDR_VERSION_2 && strm.rpos() >= end_of_struct) {\n"
2462  " return true;\n"
2463  " }\n"
2464  " bool must_understand = false;\n"
2465  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
2466  " return false;\n"
2467  " }\n"
2468  " if (encoding.xcdr_version() == Encoding::XCDR_VERSION_1 && member_id == Serializer::pid_list_end) {\n"
2469  " return true;\n"
2470  " }\n"
2471  " const size_t end_of_field = strm.rpos() + field_size;\n"
2472  " ACE_UNUSED_ARG(end_of_field);\n"
2473  "\n";
2474 
2475  std::ostringstream cases;
2476  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
2477  AST_Field* const field = *i;
2478  const OpenDDS::XTypes::MemberId id = be_global->get_id(field);
2479  string field_name =
2480  string("stru") + value_access + "." + field->local_name()->get_string();
2481  cases <<
2482  " case " << id << ": {\n"
2483  " if (!" << generate_field_stream(
2484  indent, field, ">> stru" + value_access, wrap_nested_key_only, intro) << ") {\n";
2485  AST_Type* const field_type = resolveActualType(field->field_type());
2486  Classification fld_cls = classify(field_type);
2487 
2488  if (use_cxx11) {
2489  field_name += "()";
2490  }
2491  const TryConstructFailAction try_construct = be_global->try_construct(field);
2492  if (try_construct == tryconstructfailaction_use_default) {
2493  cases <<
2494  type_to_default(" ", field_type, field_name, field->field_type()->anonymous()) <<
2495  " strm.set_construction_status(Serializer::ConstructionSuccessful);\n";
2496  if (!(fld_cls & CL_STRING)) cases << " strm.skip(end_of_field - strm.rpos());\n";
2497  } else if ((try_construct == tryconstructfailaction_trim) && (fld_cls & CL_BOUNDED) &&
2498  (fld_cls & (CL_STRING | CL_SEQUENCE))) {
2499  if ((fld_cls & CL_STRING) && (fld_cls & CL_BOUNDED)) {
2500  const std::string check_not_empty = use_cxx11 ? "!" + field_name + ".empty()" : field_name + ".in()";
2501  const std::string get_length = use_cxx11 ? field_name + ".length()" : "ACE_OS::strlen(" + field_name + ".in())";
2502  const std::string inout = use_cxx11 ? "" : ".inout()";
2503  cases <<
2504  " if (" + construct_bound_fail + " && " << check_not_empty << " && ("
2505  << bounded_arg(field_type) << " < " << get_length << ")) {\n"
2506  " " << field_name << inout;
2507  if (use_cxx11) {
2508  cases <<
2509  ".resize(" << bounded_arg(field_type) << ");\n";
2510  } else {
2511  cases <<
2512  "[" << bounded_arg(field_type) << "] = 0;\n";
2513  }
2514  cases <<
2515  " } else {\n"
2516  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n"
2517  " return false;\n"
2518  " }\n";
2519  } else if (fld_cls & CL_SEQUENCE) {
2520  cases <<
2521  " if (" + construct_elem_fail + ") {\n"
2522  " return false;\n"
2523  " }\n"
2524  " strm.set_construction_status(Serializer::ConstructionSuccessful);\n"
2525  " strm.skip(end_of_field - strm.rpos());\n";
2526  }
2527 
2528  } else { //discard/default
2529  cases <<
2530  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n";
2531  if (!(fld_cls & CL_STRING)) {
2532  cases <<
2533  " strm.skip(end_of_field - strm.rpos());\n";
2534  }
2535  cases <<
2536  " return false;\n";
2537  }
2538  cases <<
2539  " }\n"
2540  " break;\n"
2541  " }\n";
2542  }
2543  intro.join(be_global->impl_, indent);
2544  const string switch_cases = cases.str();
2545  string sw_indent = " ";
2546  if (switch_cases.empty()) {
2547  sw_indent = " ";
2548  } else {
2549  be_global->impl_ <<
2550  " switch (member_id) {\n"
2551  << switch_cases <<
2552  " default:\n";
2553  }
2554 
2555  be_global->impl_ <<
2556  sw_indent << "if (must_understand) {\n" <<
2557  sw_indent << " if (DCPS_debug_level >= 8) {\n" <<
2558  sw_indent << " ACE_DEBUG((LM_DEBUG, ACE_TEXT(\"(%P|%t) unknown must_understand field(%u) in "
2559  << cpp_name << "\\n\"), member_id));\n" <<
2560  sw_indent << " }\n" <<
2561  sw_indent << " return false;\n" <<
2562  sw_indent << "}\n" <<
2563  sw_indent << "strm.skip(field_size);\n";
2564 
2565  if (!switch_cases.empty()) {
2566  be_global->impl_ <<
2567  " break;\n"
2568  " }\n";
2569  }
2570 
2571  be_global->impl_ <<
2572  " }\n"
2573  " return false;\n"
2574  " }\n"
2575  "\n";
2576  }
2577 
2578  expr = "";
2579  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
2580  AST_Field* const field = *i;
2581  if (expr.size() && exten != extensibilitykind_appendable) {
2582  expr += "\n && ";
2583  }
2584  if (is_appendable) {
2585  expr +=
2586  " reached_end_of_struct |= (encoding.xcdr_version() == Encoding::XCDR_VERSION_2 && strm.rpos() >= end_of_struct);\n";
2587  }
2588  const string field_name = field->local_name()->get_string();
2589  const string cond = rtpsCustom.getConditional(field_name);
2590  if (!cond.empty()) {
2591  string prefix = rtpsCustom.preFieldRead(field_name);
2592  if (is_appendable) {
2593  if (!prefix.empty()) {
2594  prefix = prefix.substr(0, prefix.length() - 8);
2595  expr +=
2596  " if (!" + prefix + ") {\n"
2597  " return false;\n"
2598  " }\n";
2599  }
2600  expr += " if ((" + cond + ") && !";
2601  } else {
2602  expr += prefix + "(!(" + cond + ") || ";
2603  }
2604  } else if (is_appendable) {
2605  AST_Type* const type = field->field_type();
2606  string stru_field_name = "stru" + value_access + "." + field_name;
2607  if (use_cxx11) {
2608  stru_field_name += "()";
2609  }
2610  expr +=
2611  " if (reached_end_of_struct) {\n" +
2612  type_to_default(" ", type, stru_field_name, type->anonymous()) +
2613  " } else {\n"
2614  " if (!";
2615  }
2616  expr += generate_field_stream(
2617  indent, field, ">> stru" + value_access, wrap_nested_key_only, intro);
2618  if (is_appendable) {
2619  expr += ") {\n"
2620  " return false;\n"
2621  " }\n";
2622  if (cond.empty()) {
2623  expr +=
2624  " }\n";
2625  }
2626  } else if (!cond.empty()) {
2627  expr += ")";
2628  }
2629  }
2630  intro.join(be_global->impl_, indent);
2631  if (is_appendable) {
2632  expr +=
2633  " if (encoding.xcdr_version() == Encoding::XCDR_VERSION_2 && strm.rpos() < end_of_struct) {\n"
2634  " strm.skip(end_of_struct - strm.rpos());\n"
2635  " }\n"
2636  " return true;\n";
2637  be_global->impl_ << expr;
2638  } else if (expr.empty()) {
2639  be_global->impl_ << " return true;\n";
2640  } else {
2641  be_global->impl_ << " return " << expr << ";\n";
2642  }
2643  }
2644  return true;
2645  }
2646 
2647  bool generate_struct_serialization_functions(AST_Structure* node, FieldFilter field_type)
2648  {
2649  const std::string actual_cpp_name = scoped(node->name());
2650  std::string cpp_name = actual_cpp_name;
2651  std::string const_cpp_name;
2652  switch (field_type) {
2653  case FieldFilter_All:
2654  const_cpp_name = "const" + actual_cpp_name + "&";
2655  break;
2657  cpp_name = "const NestedKeyOnly<" + actual_cpp_name + ">";
2658  const_cpp_name = "const NestedKeyOnly<const" + actual_cpp_name + ">&";
2659  break;
2660  case FieldFilter_KeyOnly:
2661  cpp_name = "const KeyOnly<" + actual_cpp_name + ">";
2662  const_cpp_name = "const KeyOnly<const" + actual_cpp_name + ">&";
2663  break;
2664  }
2665  const std::string value_access = field_type == FieldFilter_All ? "" : ".value";
2666  const bool wrap_nested_key_only = field_type != FieldFilter_All;
2667  const Fields fields(node, field_type);
2668  const Fields::Iterator fields_end = fields.end();
2669  RtpsFieldCustomizer rtpsCustom(cpp_name);
2670 
2671  const ExtensibilityKind exten = be_global->extensibility(node);
2672  const bool not_final = exten != extensibilitykind_final;
2673  const bool is_mutable = exten == extensibilitykind_mutable;
2674 
2675  {
2676  Function serialized_size("serialized_size", "void");
2677  serialized_size.addArg("encoding", "const Encoding&");
2678  serialized_size.addArg("size", "size_t&");
2679  serialized_size.addArg("stru", const_cpp_name);
2680  serialized_size.endArgs();
2681 
2682  if (is_mutable) {
2683  /*
2684  * For parameter lists this is used to hold the total size while
2685  * size is hijacked for field sizes because of alignment resets.
2686  */
2687  be_global->impl_ <<
2688  " size_t mutable_running_total = 0;\n";
2689  }
2690 
2691  marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", not_final, false);
2692 
2693  std::string expr;
2694  Intro intro;
2695  const std::string indent = " ";
2696  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
2697  AST_Field* const field = *i;
2698  AST_Type* field_type = resolveActualType(field->field_type());
2699  if (!field_type->in_main_file() && field_type->node_type() != AST_Decl::NT_pre_defined) {
2700  be_global->add_referenced(field_type->file_name().c_str());
2701  }
2702  const string field_name = field->local_name()->get_string(),
2703  cond = rtpsCustom.getConditional(field_name);
2704  if (!cond.empty()) {
2705  expr += " if (" + cond + ") {\n ";
2706  }
2707  if (is_mutable) {
2708  expr +=
2709  " serialized_size_parameter_id(encoding, size, mutable_running_total);\n";
2710  }
2711  expr += generate_field_serialized_size(
2712  indent, field, "stru" + value_access, wrap_nested_key_only, intro);
2713  if (!cond.empty()) {
2714  expr += " }\n";
2715  }
2716  }
2717  intro.join(be_global->impl_, indent);
2718  be_global->impl_ << expr;
2719 
2720  if (is_mutable) {
2721  be_global->impl_ <<
2722  " serialized_size_list_end_parameter_id(encoding, size, mutable_running_total);\n";
2723  }
2724  }
2725 
2726  {
2727  Function insertion("operator<<", "bool");
2728  insertion.addArg("strm", "Serializer&");
2729  insertion.addArg("stru", const_cpp_name);
2730  insertion.endArgs();
2731  be_global->impl_ <<
2732  " const Encoding& encoding = strm.encoding();\n"
2733  " ACE_UNUSED_ARG(encoding);\n";
2735  " serialized_size(encoding, total_size, stru);\n"
2736  " if (!strm.write_delimiter(total_size)) {\n"
2737  " return false;\n"
2738  " }\n", not_final);
2739 
2740  // Mutable Code
2741  std::ostringstream mutable_fields;
2742  Intro intro = rtpsCustom.intro_;
2743  const std::string indent = " ";
2744  if (is_mutable) {
2745  const std::string mutable_indent = indent + " ";
2746  mutable_fields <<
2747  " if (encoding.xcdr_version() != Encoding::XCDR_VERSION_NONE) {\n"
2748  " size_t size = 0;\n"
2749  " ACE_UNUSED_ARG(size);\n";
2750  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
2751  AST_Field* const field = *i;
2752  const OpenDDS::XTypes::MemberId id = be_global->get_id(field);
2753  const bool must_understand = be_global->is_effectively_must_understand(field);
2754 
2755  mutable_fields
2756  << generate_field_serialized_size(
2757  mutable_indent, field, "stru" + value_access, wrap_nested_key_only, intro)
2758  << "\n"
2759  " if (!strm.write_parameter_id("
2760  << id << ", size" << (must_understand ? ", true" : "") << ")) {\n"
2761  " return false;\n"
2762  " }\n"
2763  " size = 0;\n"
2764  " if (!" << generate_field_stream(
2765  mutable_indent, field, "<< stru" + value_access, wrap_nested_key_only, intro)
2766  << ") {\n"
2767  " return false;\n"
2768  " }\n";
2769  }
2770  mutable_fields << "\n"
2771  " if (!strm.write_list_end_parameter_id()) {\n"
2772  " return false;\n"
2773  " }\n"
2774  " return true;\n"
2775  " }\n";
2776  }
2777 
2778  // Non-Mutable Code
2779  string expr;
2780  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
2781  AST_Field* const field = *i;
2782  if (expr.size()) expr += "\n && ";
2783  const string field_name = field->local_name()->get_string(),
2784  cond = rtpsCustom.getConditional(field_name);
2785  if (!cond.empty()) {
2786  expr += "(!(" + cond + ") || ";
2787  }
2788  expr += generate_field_stream(
2789  indent, field, "<< stru" + value_access, wrap_nested_key_only, intro);
2790  if (!cond.empty()) {
2791  expr += ")";
2792  }
2793  }
2794 
2795  intro.join(be_global->impl_, indent);
2796  if (expr.empty()) {
2797  expr = "true";
2798  }
2799  be_global->impl_ << mutable_fields.str() << " return " << expr << ";\n";
2800  }
2801 
2802  return generate_struct_deserialization(node, field_type);
2803  }
2804 
2805 } // anonymous namespace
2806 
2807 
2808 void marshal_generator::generate_dheader_code(const std::string& code, bool dheader_required, bool is_ser_func)
2809 {
2810  //DHeader appears on aggregated types that are mutable or appendable in XCDR2
2811  //DHeader also appears on ALL sequences and arrays of non-primitives
2812  if (dheader_required) {
2813  if (is_ser_func) {
2814  be_global->impl_ << " size_t total_size = 0;\n";
2815  }
2816  be_global->impl_ << " if (encoding.xcdr_version() == Encoding::XCDR_VERSION_2) {\n"
2817  << code <<
2818  " }\n";
2819  }
2820 }
2821 
2822 bool marshal_generator::gen_struct(AST_Structure* node,
2823  UTL_ScopedName* name,
2824  const std::vector<AST_Field*>& fields,
2825  AST_Type::SIZE_TYPE /* size */,
2826  const char* /* repoid */)
2827 {
2828  NamespaceGuard ng;
2829  be_global->add_include("dds/DCPS/Serializer.h");
2830  const string cxx = scoped(name); // name as a C++ class
2831  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
2832 
2833  {
2834  Function set_default("set_default", "void", "");
2835  set_default.addArg("stru", cxx + "&");
2836  set_default.endArgs();
2837  std::ostringstream contents;
2838  Intro intro;
2839  for (size_t i = 0; i < fields.size(); ++i) {
2840  AST_Field* const field = fields[i];
2841  AST_Type* const type = field->field_type();
2842  string field_name = string("stru.") + field->local_name()->get_string();
2843  if (use_cxx11) {
2844  field_name += "()";
2845  }
2846  contents << type_to_default(" ", type, field_name, type->anonymous());
2847  }
2848  intro.join(be_global->impl_, " ");
2849  be_global->impl_ << contents.str();
2850  }
2851 
2852  bool special_result;
2853  if (generate_special_struct(node, cxx, special_result)) {
2854  return special_result;
2855  }
2856 
2857  FieldInfo::EleLenSet anonymous_seq_generated;
2858  for (size_t i = 0; i < fields.size(); ++i) {
2859  if (fields[i]->field_type()->anonymous()) {
2860  FieldInfo af(*fields[i]);
2861  if (af.arr_) {
2862  gen_anonymous_array(af);
2863  } else if (af.seq_ && af.is_new(anonymous_seq_generated)) {
2864  gen_anonymous_sequence(af);
2865  }
2866  }
2867  }
2868 
2869  if (!generate_struct_serialization_functions(node, FieldFilter_All) ||
2870  !generate_struct_serialization_functions(node, FieldFilter_NestedKeyOnly)) {
2871  return false;
2872  }
2873 
2874  IDL_GlobalData::DCPS_Data_Type_Info* info = idl_global->is_dcps_type(name);
2875  const bool is_topic_type = be_global->is_topic_type(node);
2876  TopicKeys keys;
2877  if (is_topic_type) {
2878  keys = TopicKeys(node);
2879  info = 0; // Annotations Override DCPS_DATA_TYPE
2880 
2881  if (!generate_struct_serialization_functions(node, FieldFilter_KeyOnly)) {
2882  return false;
2883  }
2884  }
2885 
2886  if ((info || is_topic_type) &&
2887  !generate_marshal_traits(node, cxx, be_global->extensibility(node), keys, info)) {
2888  return false;
2889  }
2890 
2891  if (info && !is_topic_type) {
2892  {
2893  Function serialized_size("serialized_size", "void");
2894  serialized_size.addArg("encoding", "const Encoding&");
2895  serialized_size.addArg("size", "size_t&");
2896  serialized_size.addArg("stru", "const KeyOnly<const " + cxx + ">");
2897  serialized_size.endArgs();
2898 
2899  be_global->impl_ <<
2900  " switch (encoding.xcdr_version()) {\n";
2901  const char* indent = " ";
2902  for (unsigned e = 0; e <= Encoding::KIND_UNALIGNED_CDR; ++e) {
2903  string expr;
2904  Intro intro;
2905  const Encoding::Kind encoding = static_cast<Encoding::Kind>(e);
2906  if (!iterate_over_keys(indent, encoding, node, cxx, info, 0,
2907  serialized_size_iteration, 0, &expr, &intro)) {
2908  return false;
2909  }
2910  be_global->impl_ <<
2911  " case " << encoding_to_xcdr_version(encoding) << ":\n"
2912  " {\n";
2913  intro.join(be_global->impl_, indent);
2914  be_global->impl_
2915  << expr <<
2916  " break;\n"
2917  " }\n";
2918  }
2919  be_global->impl_ <<
2920  " }\n";
2921  }
2922 
2923  {
2924  Function insertion("operator<<", "bool");
2925  insertion.addArg("strm", "Serializer&");
2926  insertion.addArg("stru", "KeyOnly<const " + cxx + ">");
2927  insertion.endArgs();
2928 
2929  bool first = true;
2930  std::string expr;
2931  Intro intro;
2932  const char* indent = " ";
2933 
2934  IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
2935  for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
2936  const string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
2937  AST_Type* const field_type = find_type(node, key_name);
2938  if (first) {
2939  first = false;
2940  } else {
2941  expr += "\n && ";
2942  }
2943  expr += streamCommon(indent, 0, key_name, field_type, "<< stru.value", false, intro);
2944  }
2945 
2946  intro.join(be_global->impl_, indent);
2947  be_global->impl_ << " return " << (first ? "true" : expr) << ";\n";
2948  }
2949 
2950  {
2951  Function extraction("operator>>", "bool");
2952  extraction.addArg("strm", "Serializer&");
2953  extraction.addArg("stru", "KeyOnly<" + cxx + ">");
2954  extraction.endArgs();
2955 
2956  bool first = true;
2957  Intro intro;
2958  std::string expr;
2959  const std::string indent = " ";
2960 
2961  IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
2962  for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
2963  const string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
2964  AST_Type* const field_type = find_type(node, key_name);
2965  if (first) {
2966  first = false;
2967  } else {
2968  expr += "\n && ";
2969  }
2970  expr += streamCommon(indent, 0, key_name, field_type, ">> stru.value", false, intro);
2971  }
2972 
2973  intro.join(be_global->impl_, indent);
2974  be_global->impl_ << " return " << (first ? "true" : expr) << ";\n";
2975  }
2976  }
2977 
2978  return true;
2979 }
2980 
2981 void
2982 marshal_generator::gen_field_getValueFromSerialized(AST_Structure* node, const std::string& clazz)
2983 {
2984  //loop through meta struct
2985  //check the id for a match to our id
2986  //if we are not a match, skip to the next field
2987  //if we are a match, deserialize the field
2988  const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11;
2989  std::string expr;
2990  const ExtensibilityKind exten = be_global->extensibility(node);
2991  const bool not_final = exten != extensibilitykind_final;
2992  const bool is_mutable = exten == extensibilitykind_mutable;
2993  const std::string actual_cpp_name = scoped(node->name());
2994  std::string cpp_name = actual_cpp_name;
2995  const Fields fields(node);
2996  const Fields::Iterator fields_end = fields.end();
2997  RtpsFieldCustomizer rtpsCustom(cpp_name);
2998 
2999  be_global->impl_ <<
3000  " Value getValue(Serializer& strm, const char* field, const TypeSupportImpl* = 0) const\n"
3001  " {\n"
3002  " const Encoding& encoding = strm.encoding();\n"
3003  " ACE_UNUSED_ARG(encoding);\n";
3005  " if (!strm.read_delimiter(total_size)) {\n"
3006  " throw std::runtime_error(\"Unable to reader delimiter in getValue\");\n"
3007  " }\n", not_final);
3008  be_global->impl_ <<
3009  " std::string base_field = field;\n"
3010  " const size_t index = base_field.find('.');\n"
3011  " std::string subfield;\n"
3012  " if (index != std::string::npos) {\n"
3013  " subfield = base_field.substr(index + 1);\n"
3014  " base_field = base_field.substr(0, index);\n"
3015  " }\n";
3016 
3017  if (is_mutable) {
3018  be_global->impl_ <<
3019  " if (encoding.xcdr_version() != Encoding::XCDR_VERSION_NONE) {\n"
3020  " unsigned field_id = map_name_to_id(base_field.c_str());\n"
3021  " ACE_UNUSED_ARG(field_id);\n"
3022  " unsigned member_id;\n"
3023  " size_t field_size;\n"
3024  " const size_t end_of_struct = strm.rpos() + total_size;\n"
3025  " while (true) {\n"
3026  " if (encoding.xcdr_version() == Encoding::XCDR_VERSION_2 &&\n"
3027  " strm.rpos() >= end_of_struct) {\n"
3028  " break;\n"
3029  " }\n"
3030  " bool must_understand = false;\n"
3031  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
3032  " throw std::runtime_error(\"Field \" + OPENDDS_STRING(field) + \" Deserialization "
3033  "Error for struct " << clazz << "\");\n"
3034  " }\n"
3035  " if (encoding.xcdr_version() == Encoding::XCDR_VERSION_1 &&\n"
3036  " member_id == Serializer::pid_list_end) {\n"
3037  " throw std::runtime_error(\"Field \" + OPENDDS_STRING(field) + \" not "
3038  "valid for struct " << clazz << "\");\n"
3039  " }\n"
3040  " const size_t end_of_field = strm.rpos() + field_size;\n"
3041  " ACE_UNUSED_ARG(end_of_field);\n"
3042  "\n";
3043 
3044  std::ostringstream cases;
3045  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
3046  AST_Field* const field = *i;
3047  size_t size = 0;
3048  const OpenDDS::XTypes::MemberId id = be_global->get_id(field);
3049  std::string field_name = field->local_name()->get_string();
3050  AST_Type* const field_type = resolveActualType(field->field_type());
3051  Classification fld_cls = classify(field_type);
3052 
3053  cases << " case " << id << ": {\n";
3054  if (fld_cls & CL_SCALAR) {
3055  const std::string cxx_type = to_cxx_type(field_type, size);
3056  const std::string val = (fld_cls & CL_STRING) ? (use_cxx11 ? "val" : "val.out()")
3057  : getWrapper("val", field_type, WD_INPUT);
3058  std::string boundsCheck, transformPrefix, transformSuffix;
3059  if (fld_cls & CL_ENUM) {
3060  const std::string enumName = dds_generator::scoped_helper(field_type->name(), "_");
3061  boundsCheck = " if (val >= gen_" + enumName + "_names_size) {\n"
3062  " throw std::runtime_error(\"Enum value out of bounds\");\n"
3063  " }\n";
3064  transformPrefix = "gen_" + enumName + "_names[";
3065  transformSuffix = "]";
3066  }
3067  cases <<
3068  " if (field_id == member_id) {\n"
3069  " " << cxx_type << " val;\n" <<
3070  " if (!(strm >> " << val << ")) {\n"
3071  " throw std::runtime_error(\"Field '" << field_name << "' could not be deserialized\");\n" <<
3072  " }\n" <<
3073  boundsCheck <<
3074  " return " << transformPrefix << "val" << transformSuffix << ";\n"
3075  " } else {\n"
3076  " strm.skip(field_size);\n"
3077  " }\n"
3078  " break;\n"
3079  " }\n";
3080  } else if (fld_cls & CL_STRUCTURE) {
3081  cases <<
3082  " if (field_id == member_id) {\n"
3083  " return getMetaStruct<" << scoped(field_type->name()) << ">().getValue(strm, subfield.c_str());\n"
3084  " } else {\n"
3085  " strm.skip(field_size);\n"
3086  " }\n"
3087  " break;\n"
3088  " }\n";
3089  } else { // array, sequence, union:
3090  cases <<
3091  " strm.skip(field_size);\n"
3092  " break;\n"
3093  " }\n";
3094  }
3095  }
3096  const std::string switch_cases = cases.str();
3097  std::string sw_indent = " ";
3098  if (switch_cases.empty()) {
3099  sw_indent = " ";
3100  } else {
3101  be_global->impl_ <<
3102  " switch (member_id) {\n"
3103  << switch_cases <<
3104  " default:\n";
3105  }
3106  be_global->impl_ <<
3107  sw_indent << "if (must_understand) {\n" <<
3108  sw_indent << " if (DCPS_debug_level >= 8) {\n" <<
3109  sw_indent << " ACE_DEBUG((LM_DEBUG, ACE_TEXT(\"(%P|%t) unknown must_understand field(%u) in "
3110  << cpp_name << "\\n\"), member_id));\n" <<
3111  sw_indent << " }\n" <<
3112  sw_indent << " throw std::runtime_error(\"member id did not exist in getValue\");\n" <<
3113  sw_indent << "}\n" <<
3114  sw_indent << "strm.skip(field_size);\n";
3115  if (!switch_cases.empty()) {
3116  be_global->impl_ <<
3117  " break;\n"
3118  " }\n";
3119  }
3120  be_global->impl_ <<
3121  " }\n"
3122  " if (!field[0]) {\n" // if 'field' is the empty string...
3123  " return 0;\n" // the return value is ignored
3124  " }\n"
3125  " throw std::runtime_error(\"Did not find field in getValue\");\n"
3126  " }\n";
3127  }
3128  //The following is Appendable/Final
3129  //It is also used when Mutable but not in XCDR1 or XCDR2
3130  expr = "";
3131  for (Fields::Iterator i = fields.begin(); i != fields_end; ++i) {
3132  AST_Field* const field = *i;
3133  size_t size = 0;
3134  const std::string idl_name = canonical_name(field);
3135  AST_Type* const field_type = resolveActualType(field->field_type());
3136  Classification fld_cls = classify(field_type);
3137  if (fld_cls & CL_SCALAR) {
3138  const std::string cxx_type = to_cxx_type(field_type, size);
3139  const std::string val = (fld_cls & CL_STRING) ? (use_cxx11 ? "val" : "val.out()")
3140  : getWrapper("val", field_type, WD_INPUT);
3141  std::string boundsCheck, transformPrefix, transformSuffix;
3142  if (fld_cls & CL_ENUM) {
3143  const std::string enumName = dds_generator::scoped_helper(field_type->name(), "_");
3144  boundsCheck = " if (val >= gen_" + enumName + "_names_size) {\n"
3145  " throw std::runtime_error(\"Enum value out of bounds\");\n"
3146  " }\n";
3147  transformPrefix = "gen_" + enumName + "_names[";
3148  transformSuffix = "]";
3149  }
3150  expr +=
3151  " if (base_field == \"" + idl_name + "\") {\n"
3152  " " + cxx_type + " val;\n"
3153  " if (!(strm >> " + val + ")) {\n"
3154  " throw std::runtime_error(\"Field '" + idl_name + "' could "
3155  "not be deserialized\");\n"
3156  " }\n"
3157  + boundsCheck +
3158  " return " + transformPrefix + "val" + transformSuffix + ";\n"
3159  " } else {\n";
3160  if (fld_cls & CL_STRING) {
3161  expr +=
3162  " ACE_CDR::ULong len;\n"
3163  " if (!(strm >> len)) {\n"
3164  " throw std::runtime_error(\"String '" + idl_name +
3165  "' length could not be deserialized\");\n"
3166  " }\n"
3167  " if (!strm.skip(len)) {\n"
3168  " throw std::runtime_error(\"String '" + idl_name +
3169  "' contents could not be skipped\");\n"
3170  " }\n"
3171  " }\n";
3172  } else {
3173  expr +=
3174  " if (!strm.skip(1, " + OpenDDS::DCPS::to_dds_string(size) + " )) {\n"
3175  " throw std::runtime_error(\"Field '" + idl_name +
3176  "' could not be skipped\");\n"
3177  " }\n"
3178  " }\n";
3179  }
3180  } else if (fld_cls & CL_STRUCTURE) {
3181  expr +=
3182  " if (base_field == \"" + idl_name + "\") {\n"
3183  " return getMetaStruct<" + scoped(field_type->name()) + ">().getValue(strm, subfield.c_str());\n"
3184  " } else {\n"
3185  " if (!gen_skip_over(strm, static_cast<" + scoped(field_type->name()) + "*>(0))) {\n"
3186  " throw std::runtime_error(\"Field '" + idl_name + "' could not be skipped\");\n"
3187  " }\n"
3188  " }\n";
3189  } else { // array, sequence, union:
3190  std::string pre, post;
3191  if (!use_cxx11 && (fld_cls & CL_ARRAY)) {
3192  post = "_forany";
3193  } else if (use_cxx11 && (fld_cls & (CL_ARRAY | CL_SEQUENCE))) {
3194  pre = "IDL::DistinctType<";
3195  post = ", " + dds_generator::get_tag_name(scoped(deepest_named_type(field->field_type())->name())) + ">";
3196  }
3197  const std::string ptr = field->field_type()->anonymous() ?
3198  FieldInfo(*field).ptr_ : (pre + field_type_name(field) + post + '*');
3199  expr +=
3200  " if (!gen_skip_over(strm, static_cast<" + ptr + ">(0))) {\n"
3201  " throw std::runtime_error(\"Field \" + OPENDDS_STRING(field) + \" could not be skipped\");\n"
3202  " }\n";
3203  }
3204  }
3205  be_global->impl_ <<
3206  expr <<
3207  " if (!field[0]) {\n" // if 'field' is the empty string...
3208  " return 0;\n" // the return value is ignored
3209  " }\n"
3210  " throw std::runtime_error(\"Did not find field in getValue\");\n"
3211  " }\n\n";
3212 }
3213 
3214 namespace {
3215  bool genRtpsParameter(const string&, AST_Union* u, AST_Type* discriminator,
3216  const std::vector<AST_UnionBranch*>& branches)
3217  {
3218  const string cxx = RtpsNamespace + "Parameter";
3219  {
3220  Function serialized_size("serialized_size", "void");
3221  serialized_size.addArg("encoding", "const Encoding&");
3222  serialized_size.addArg("size", "size_t&");
3223  serialized_size.addArg("uni", "const " + cxx + "&");
3224  serialized_size.endArgs();
3225  generateSwitchForUnion(u, "uni._d()", findSizeCommon, branches,
3226  discriminator, "", "", cxx.c_str());
3227  be_global->impl_ <<
3228  " if (uni._d() == RTPS::PID_XTYPES_TYPE_INFORMATION) {\n"
3229  " // Parameter union uses OctetSeq but this is not actually a sequence\n"
3230  " size -= 4;\n"
3231  " }\n"
3232  " size += 4; // parameterId & length\n";
3233  }
3234  {
3235  Function insertion("operator<<", "bool");
3236  insertion.addArg("strm", "Serializer&");
3237  insertion.addArg("uni", "const " + cxx + "&");
3238  insertion.endArgs();
3239  be_global->impl_ <<
3240  " if (!(strm << uni._d())) {\n"
3241  " return false;\n"
3242  " }\n"
3243  " size_t size = serialized_size(strm.encoding(), uni);\n"
3244  " size -= 4; // parameterId & length\n"
3245  " const size_t post_pad = 4 - (size % 4);\n"
3246  " const size_t total = size + ((post_pad < 4) ? post_pad : 0);\n"
3247  " if (size > ACE_UINT16_MAX || !(strm << ACE_CDR::UShort(total))) {\n"
3248  " return false;\n"
3249  " }\n"
3250  " const Serializer::ScopedAlignmentContext sac(strm);\n"
3251  " if (uni._d() == RTPS::PID_XTYPES_TYPE_INFORMATION) {\n"
3252  " if (!strm.write_octet_array(uni.type_information().get_buffer(), uni.type_information().length())) {\n"
3253  " return false;\n"
3254  " }\n"
3255  " } else if (!insertParamData(strm, uni)) {\n"
3256  " return false;\n"
3257  " }\n"
3258  " if (post_pad < 4 && strm.encoding().alignment() != Encoding::ALIGN_NONE) {\n"
3259  " static const ACE_CDR::Octet padding[3] = {0};\n"
3260  " return strm.write_octet_array(padding, ACE_CDR::ULong(post_pad));\n"
3261  " }\n"
3262  " return true;\n";
3263  }
3264  {
3265  Function insertData("insertParamData", "bool");
3266  insertData.addArg("strm", "Serializer&");
3267  insertData.addArg("uni", "const " + cxx + "&");
3268  insertData.endArgs();
3269  generateSwitchForUnion(u, "uni._d()", streamCommon, branches, discriminator,
3270  "return", "<< ", cxx.c_str());
3271  }
3272  {
3273  Function extraction("operator>>", "bool");
3274  extraction.addArg("strm", "Serializer&");
3275  extraction.addArg("uni", cxx + "&");
3276  extraction.endArgs();
3277  be_global->impl_ <<
3278  " ACE_CDR::UShort disc, size;\n"
3279  " if (!(strm >> disc) || !(strm >> size)) {\n"
3280  " return false;\n"
3281  " }\n"
3282  " if (disc == OpenDDS::RTPS::PID_SENTINEL) {\n"
3283  " uni._d(OpenDDS::RTPS::PID_SENTINEL);\n"
3284  " return true;\n"
3285  " }\n"
3286  " if (size == 0) {\n"
3287  " uni._d(disc);\n"
3288  " return true;\n"
3289  " }\n"
3290  " if (size > strm.length()) {\n"
3291  " return false;\n"
3292  " }\n"
3293  " if (disc == RTPS::PID_PROPERTY_LIST) {\n"
3294  " // support special case deserialization of DDS::PropertyQosPolicy\n"
3295  " Message_Block_Ptr param(strm.trim(size));\n"
3296  " strm.skip(size);\n"
3297  " Serializer strm2(param.get(), Encoding(Encoding::KIND_XCDR1, strm.swap_bytes()));\n"
3298  " ::DDS::PropertyQosPolicy tmp;\n"
3299  " if (strm2 >> tmp) {\n"
3300  " uni.property(tmp);\n"
3301  " return true;\n"
3302  " } else {\n"
3303  " return false;\n"
3304  " }\n"
3305  " }\n"
3306  " const Serializer::ScopedAlignmentContext sac(strm, size);\n"
3307  " if (disc == RTPS::PID_XTYPES_TYPE_INFORMATION) {\n"
3308  " DDS::OctetSeq type_info(size);\n"
3309  " type_info.length(size);\n"
3310  " if (!strm.read_octet_array(type_info.get_buffer(), size)) {\n"
3311  " return false;\n"
3312  " }\n"
3313  " uni.type_information(type_info);\n"
3314  " return true;\n"
3315  " }\n"
3316  " switch (disc) {\n";
3317  generateSwitchBody(u, streamCommon, branches, discriminator,
3318  "", ">> ", cxx.c_str(), true);
3319  be_global->impl_ <<
3320  " default:\n"
3321  " {\n"
3322  " uni.unknown_data(DDS::OctetSeq(size));\n"
3323  " uni.unknown_data().length(size);\n"
3324  " if (!strm.read_octet_array(uni.unknown_data().get_buffer(), size)) {\n"
3325  " return false;\n"
3326  " }\n"
3327  " uni._d(disc);\n"
3328  " }\n"
3329  " }\n"
3330  " return true;\n";
3331  }
3332  return true;
3333  }
3334 
3335  bool genRtpsSubmessage(const string&, AST_Union* u, AST_Type* discriminator,
3336  const std::vector<AST_UnionBranch*>& branches)
3337  {
3338  const string cxx = RtpsNamespace + "Submessage";
3339  {
3340  Function serialized_size("serialized_size", "void");
3341  serialized_size.addArg("encoding", "const Encoding&");
3342  serialized_size.addArg("size", "size_t&");
3343  serialized_size.addArg("uni", "const " + cxx + "&");
3344  serialized_size.endArgs();
3345  generateSwitchForUnion(u, "uni._d()", findSizeCommon, branches,
3346  discriminator, "", "", cxx.c_str());
3347  }
3348  {
3349  Function insertion("operator<<", "bool");
3350  insertion.addArg("strm", "Serializer&");
3351  insertion.addArg("uni", "const " + cxx + "&");
3352  insertion.endArgs();
3353  generateSwitchForUnion(u, "uni._d()", streamCommon, branches,
3354  discriminator, "return", "<< ", cxx.c_str());
3355  }
3356  {
3357  Function insertion("operator>>", "bool");
3358  insertion.addArg("strm", "Serializer&");
3359  insertion.addArg("uni", cxx + "&");
3360  insertion.endArgs();
3361  be_global->impl_ << " // unused\n return false;\n";
3362  }
3363  return true;
3364  }
3365 
3366  void gen_union_key_serializers(AST_Union* node, FieldFilter kind)
3367  {
3368  const string cxx = scoped(node->name()); // name as a C++ class
3369  AST_Type* const discriminator = node->disc_type();
3370  const Classification disc_cls = classify(discriminator);
3371  const string key_only_wrap_out = getWrapper("uni.value._d()", discriminator, WD_OUTPUT);
3372  const ExtensibilityKind exten = be_global->extensibility(node);
3373  const bool not_final = exten != extensibilitykind_final;
3374  const bool nested_key_only = kind == FieldFilter_NestedKeyOnly;
3375  const string wrapper = kind == FieldFilter_KeyOnly ? "KeyOnly"
3376  : nested_key_only ? "NestedKeyOnly"
3377  : "<<error from " __FILE__ ":" OPENDDS_IDL_STR(__LINE__) ">>";
3378  const bool has_key = be_global->union_discriminator_is_key(node) || nested_key_only;
3379 
3380  {
3381  Function serialized_size("serialized_size", "void");
3382  serialized_size.addArg("encoding", "const Encoding&");
3383  serialized_size.addArg("size", "size_t&");
3384  serialized_size.addArg("uni", "const " + wrapper + "<const " + cxx + ">");
3385  serialized_size.endArgs();
3386 
3387  if (has_key) {
3388  marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", not_final, false);
3389 
3390  if (exten == extensibilitykind_mutable) {
3391  be_global->impl_ <<
3392  " size_t mutable_running_total = 0;\n"
3393  " serialized_size_parameter_id(encoding, size, mutable_running_total);\n";
3394  }
3395 
3396  if (disc_cls & CL_ENUM) {
3397  be_global->impl_ <<
3398  " primitive_serialized_size_ulong(encoding, size);\n";
3399  } else {
3400  be_global->impl_ <<
3401  " primitive_serialized_size(encoding, size, " << key_only_wrap_out << ");\n";
3402  }
3403 
3404  if (exten == extensibilitykind_mutable) {
3405  be_global->impl_ <<
3406  " serialized_size_list_end_parameter_id(encoding, size, mutable_running_total);\n";
3407  }
3408  }
3409  }
3410 
3411  {
3412  Function insertion("operator<<", "bool");
3413  insertion.addArg("strm", "Serializer&");
3414  insertion.addArg("uni", wrapper + "<const " + cxx + ">");
3415  insertion.endArgs();
3416 
3417  if (has_key) {
3418  be_global->impl_ <<
3419  " const Encoding& encoding = strm.encoding();\n"
3420  " ACE_UNUSED_ARG(encoding);\n";
3422  " serialized_size(encoding, total_size, uni);\n"
3423  " if (!strm.write_delimiter(total_size)) {\n"
3424  " return false;\n"
3425  " }\n", not_final);
3426 
3427  // EMHEADER for discriminator
3428  if (exten == extensibilitykind_mutable) {
3429  be_global->impl_ <<
3430  " size_t size = 0;\n";
3431 
3432  if (disc_cls & CL_ENUM) {
3433  be_global->impl_ <<
3434  " primitive_serialized_size_ulong(encoding, size);\n";
3435  } else {
3436  be_global->impl_ <<
3437  " primitive_serialized_size(encoding, size, " << key_only_wrap_out << ");\n";
3438  }
3439 
3440  be_global->impl_ <<
3441  " if (!strm.write_parameter_id(0, size)) {\n"
3442  " return false;\n"
3443  " }\n"
3444  " size = 0;\n";
3445  }
3446 
3447  be_global->impl_ << streamAndCheck("<< " + key_only_wrap_out);
3448  }
3449 
3450  be_global->impl_
3451  << " return true;\n";
3452  }
3453 
3454  {
3455  Function extraction("operator>>", "bool");
3456  extraction.addArg("strm", "Serializer&");
3457  extraction.addArg("uni", wrapper + "<" + cxx + ">");
3458  extraction.endArgs();
3459 
3460  if (has_key) {
3461  // DHEADER
3462  be_global->impl_ <<
3463  " const Encoding& encoding = strm.encoding();\n"
3464  " ACE_UNUSED_ARG(encoding);\n";
3466  " if (!strm.read_delimiter(total_size)) {\n"
3467  " return false;\n"
3468  " }\n", not_final);
3469 
3470  if (exten == extensibilitykind_mutable) {
3471  // EMHEADER for discriminator
3472  be_global->impl_ <<
3473  " unsigned member_id;\n"
3474  " size_t field_size;\n"
3475  " bool must_understand = false;\n"
3476  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
3477  " return false;\n"
3478  " }\n";
3479  }
3480 
3481  be_global->impl_
3482  << " " << scoped(discriminator->name()) << " disc;\n"
3483  << streamAndCheck(">> " + getWrapper("disc", discriminator, WD_INPUT))
3484  << " uni.value._d(disc);\n";
3485  }
3486 
3487  be_global->impl_
3488  << " return true;\n";
3489  }
3490  }
3491 }
3492 
3493 bool marshal_generator::gen_union(AST_Union* node, UTL_ScopedName* name,
3494  const std::vector<AST_UnionBranch*>& branches, AST_Type* discriminator,
3495  const char*)
3496 {
3497  NamespaceGuard ng;
3498  be_global->add_include("dds/DCPS/Serializer.h");
3499  string cxx = scoped(name); // name as a C++ class
3500  Classification disc_cls = classify(discriminator);
3501 
3502  FieldInfo::EleLenSet anonymous_seq_generated;
3503  for (size_t i = 0; i < branches.size(); ++i) {
3504  if (branches[i]->field_type()->anonymous()) {
3505  FieldInfo af(*branches[i]);
3506  if (af.arr_) {
3507  gen_anonymous_array(af);
3508  } else if (af.seq_ && af.is_new(anonymous_seq_generated)) {
3509  gen_anonymous_sequence(af);
3510  }
3511  }
3512  }
3513 
3514  const ExtensibilityKind exten = be_global->extensibility(node);
3515  const bool not_final = exten != extensibilitykind_final;
3516 
3517  {
3518  // Define the set_default function in the header and implementation file.
3519  const std::string varname("uni");
3520  Function set_default("set_default", "void", "");
3521  set_default.addArg(varname.c_str(), cxx + "&");
3522  set_default.endArgs();
3523 
3524  // Add a reference to the idl file, if the descriminator is user defined.
3525  AST_Type* disc_type = resolveActualType(discriminator);
3526  const Classification disc_cls = classify(disc_type);
3527  if (!disc_type->in_main_file() && disc_type->node_type() != AST_Decl::NT_pre_defined) {
3528  be_global->add_referenced(disc_type->file_name().c_str());
3529  }
3530 
3531  // Determine the default enum value
3532  ACE_CDR::ULong default_enum_val = 0;
3533  if (disc_cls & CL_ENUM) {
3534  AST_Enum* enu = dynamic_cast<AST_Enum*>(disc_type);
3535  UTL_ScopeActiveIterator i(enu, UTL_Scope::IK_decls);
3536  AST_EnumVal *item = dynamic_cast<AST_EnumVal*>(i.item());
3537  default_enum_val = item->constant_value()->ev()->u.eval;
3538  }
3539 
3540  // Search the union branches to find the default value according to
3541  // Table 9 of the XTypes spec v1.3
3542  bool found = false;
3543  for (std::vector<AST_UnionBranch*>::const_iterator itr = branches.begin(); itr < branches.end() && !found; ++itr) {
3544  AST_UnionBranch* branch = *itr;
3545  for (unsigned i = 0; i < branch->label_list_length(); ++i) {
3546  AST_UnionLabel* ul = branch->label(i);
3547  if (ul->label_kind() != AST_UnionLabel::UL_default) {
3548  AST_Expression::AST_ExprValue* ev = branch->label(i)->label_val()->ev();
3549  if ((ev->et == AST_Expression::EV_enum && ev->u.eval == default_enum_val) ||
3551  (ev->et == AST_Expression::EV_uint8 && ev->u.uint8val == 0) ||
3552  (ev->et == AST_Expression::EV_int8 && ev->u.int8val == 0) ||
3553 #endif
3554  (ev->et == AST_Expression::EV_short && ev->u.sval == 0) ||
3555  (ev->et == AST_Expression::EV_ushort && ev->u.usval == 0) ||
3556  (ev->et == AST_Expression::EV_long && ev->u.lval == 0) ||
3557  (ev->et == AST_Expression::EV_ulong && ev->u.ulval == 0) ||
3558  (ev->et == AST_Expression::EV_longlong && ev->u.llval == 0) ||
3559  (ev->et == AST_Expression::EV_ulonglong && ev->u.ullval == 0) ||
3560  (ev->et == AST_Expression::EV_float && ev->u.fval == 0) ||
3561  (ev->et == AST_Expression::EV_double && ev->u.dval == 0) ||
3562  (ev->et == AST_Expression::EV_longdouble && ev->u.sval == 0) ||
3563  (ev->et == AST_Expression::EV_char && ev->u.cval == 0) ||
3564  (ev->et == AST_Expression::EV_wchar && ev->u.wcval == 0) ||
3565  (ev->et == AST_Expression::EV_octet && ev->u.oval == 0) ||
3566  (ev->et == AST_Expression::EV_bool && ev->u.bval == 0))
3567  {
3568  gen_union_default(branch, varname);
3569  found = true;
3570  break;
3571  }
3572  }
3573  }
3574  }
3575 
3576  // If a default value was not found, just set the discriminator to the
3577  // default value.
3578  if (!found) {
3579  be_global->impl_ <<
3580  " " << scoped(discriminator->name()) << " temp;\n" <<
3581  type_to_default("", discriminator, " temp") <<
3582  " " << varname << "._d(temp);\n";
3583  }
3584  }
3585 
3586  bool special_result;
3587  if (generate_special_union(cxx, node, discriminator, branches, special_result)) {
3588  return special_result;
3589  }
3590 
3591  const string wrap_out = getWrapper("uni._d()", discriminator, WD_OUTPUT);
3592  {
3593  Function serialized_size("serialized_size", "void");
3594  serialized_size.addArg("encoding", "const Encoding&");
3595  serialized_size.addArg("size", "size_t&");
3596  serialized_size.addArg("uni", "const " + cxx + "&");
3597  serialized_size.endArgs();
3598 
3599  marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", not_final, false);
3600 
3601  if (exten == extensibilitykind_mutable) {
3602  be_global->impl_ <<
3603  " size_t mutable_running_total = 0;\n"
3604  " serialized_size_parameter_id(encoding, size, mutable_running_total);\n";
3605  }
3606 
3607  if (disc_cls & CL_ENUM) {
3608  be_global->impl_ <<
3609  " primitive_serialized_size_ulong(encoding, size);\n";
3610  } else {
3611  be_global->impl_ <<
3612  " primitive_serialized_size(encoding, size, " << wrap_out << ");\n";
3613  }
3614 
3615  generateSwitchForUnion(node, "uni._d()",
3616  exten == extensibilitykind_mutable ? findSizeMutableUnion : findSizeCommon,
3617  branches, discriminator, "", "", cxx.c_str());
3618 
3619  if (exten == extensibilitykind_mutable) {
3620  // TODO: XTypes B will need to edit this code to add the pid for the end of mutable unions.
3621  // Until this change is made, XCDR1 will NOT be functional
3622  be_global->impl_ <<
3623  " serialized_size_list_end_parameter_id(encoding, size, mutable_running_total);\n";
3624  }
3625  }
3626  {
3627  Function insertion("operator<<", "bool");
3628  insertion.addArg("strm", "Serializer&");
3629  insertion.addArg("uni", "const " + cxx + "&");
3630  insertion.endArgs();
3631 
3632  be_global->impl_ <<
3633  " const Encoding& encoding = strm.encoding();\n"
3634  " ACE_UNUSED_ARG(encoding);\n";
3636  " serialized_size(encoding, total_size, uni);\n"
3637  " if (!strm.write_delimiter(total_size)) {\n"
3638  " return false;\n"
3639  " }\n", not_final);
3640 
3641  // EMHEADER for discriminator
3642  if (exten == extensibilitykind_mutable) {
3643  be_global->impl_ <<
3644  " size_t size = 0;\n";
3645 
3646  if (disc_cls & CL_ENUM) {
3647  be_global->impl_ <<
3648  " primitive_serialized_size_ulong(encoding, size);\n";
3649  } else {
3650  be_global->impl_ <<
3651  " primitive_serialized_size(encoding, size, " << wrap_out << ");\n";
3652  }
3653 
3654  be_global->impl_ <<
3655  " if (!strm.write_parameter_id(0, size)) {\n"
3656  " return false;\n"
3657  " }\n"
3658  " size = 0;\n";
3659  }
3660 
3661  be_global->impl_ <<
3662  streamAndCheck("<< " + wrap_out);
3663  if (generateSwitchForUnion(node, "uni._d()", streamCommon, branches,
3664  discriminator, "return", "<< ", cxx.c_str(),
3665  false, true, true,
3666  exten == extensibilitykind_mutable ? findSizeCommon : 0)) {
3667  be_global->impl_ <<
3668  " return true;\n";
3669  }
3670  }
3671  {
3672  Function extraction("operator>>", "bool");
3673  extraction.addArg("strm", "Serializer&");
3674  extraction.addArg("uni", cxx + "&");
3675  extraction.endArgs();
3676 
3677  be_global->impl_ <<
3678  " const Encoding& encoding = strm.encoding();\n"
3679  " ACE_UNUSED_ARG(encoding);\n";
3681  " if (!strm.read_delimiter(total_size)) {\n"
3682  " return false;\n"
3683  " }\n", not_final);
3684 
3685  if (exten == extensibilitykind_mutable) {
3686  // EMHEADER for discriminator
3687  be_global->impl_ <<
3688  " unsigned member_id;\n"
3689  " size_t field_size;\n"
3690  " bool must_understand = false;\n"
3691  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
3692  " return false;\n"
3693  " }\n";
3694  TryConstructFailAction try_construct = be_global->union_discriminator_try_construct(node);
3695  be_global->impl_ <<
3696  " " << scoped(discriminator->name()) << " disc;\n"
3697  " if (!(strm >> disc)) {\n";
3698  if (try_construct == tryconstructfailaction_use_default) {
3699  be_global->impl_ <<
3700  " set_default(uni);\n"
3701  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
3702  " return false;\n"
3703  " }\n"
3704  " strm.skip(field_size);\n"
3705  " strm.set_construction_status(Serializer::ConstructionSuccessful);\n"
3706  " return true;\n";
3707  } else {
3708  be_global->impl_ <<
3709  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
3710  " return false;\n"
3711  " }\n"
3712  " strm.skip(field_size);\n"
3713  " strm.set_construction_status(Serializer::ElementConstructionFailure);\n"
3714  " return false;\n";
3715  }
3716  be_global->impl_ << " }\n";
3717 
3718  be_global->impl_ <<
3719  " member_id = 0;\n"
3720  " field_size = 0;\n"
3721  " must_understand = false;\n";
3722 
3723  const char prefix[] =
3724  " if (!strm.read_parameter_id(member_id, field_size, must_understand)) {\n"
3725  " return false;\n"
3726  " }\n";
3727  if (generateSwitchForUnion(node, "disc", streamCommon, branches,
3728  discriminator, prefix, ">> ", cxx.c_str())) {
3729  be_global->impl_ <<
3730  " return true;\n";
3731  }
3732  } else {
3733  be_global->impl_ <<
3734  " " << scoped(discriminator->name()) << " disc;\n" <<
3735  streamAndCheck(">> " + getWrapper("disc", discriminator, WD_INPUT));
3736  if (generateSwitchForUnion(node, "disc", streamCommon, branches,
3737  discriminator, "", ">> ", cxx.c_str())) {
3738  be_global->impl_ <<
3739  " return true;\n";
3740  }
3741  }
3742  }
3743 
3744  gen_union_key_serializers(node, FieldFilter_NestedKeyOnly);
3745  gen_union_key_serializers(node, FieldFilter_KeyOnly);
3746 
3747  TopicKeys keys(node);
3748  return generate_marshal_traits(node, cxx, exten, keys);
3749 }
3750 
3751 void marshal_generator::gen_union_default(AST_UnionBranch* branch, const std::string& varname)
3752 {
3753  AST_Type* br = resolveActualType(branch->field_type());
3754  const Classification br_cls = classify(br);
3755  const std::string tmpname = "tmp";
3756 
3757  if (br_cls & (CL_SEQUENCE | CL_ARRAY | CL_STRUCTURE | CL_UNION)) {
3758  be_global->impl_ << " " << scoped(branch->field_type()->name()) << " "
3759  << getWrapper(tmpname, branch->field_type(), WD_INPUT) << ";\n";
3760  }
3761 
3762  if (br_cls & (CL_STRUCTURE | CL_UNION)) {
3763  be_global->impl_ << type_to_default(" ", branch->field_type(), tmpname);
3764  be_global->impl_ << " " << varname << "." << branch->local_name()->get_string() << "(tmp);\n";
3765  } else {
3766  be_global->impl_ << type_to_default(" ", branch->field_type(),
3767  varname + "." + branch->local_name()->get_string(),
3768  false, true);
3769  }
3770 }
std::string bounded_arg(AST_Type *type)
std::string to_cxx_type(AST_Type *type, std::size_t &size)
bool is_new(EleLenSet &el_set) const
Definition: field_info.cpp:132
Iterator end()
Definition: topic_keys.cpp:500
Classification classify(AST_Type *type)
static std::string scoped_helper(UTL_ScopedName *sn, const char *sep, EscapeContext cxt=EscapeContext_Normal)
void join(std::ostream &os, const std::string &indent)
const char * c_str(void) const
ACE_CDR::ULong MemberId
Definition: TypeObject.h:910
const LogLevel::Value value
Definition: debug.cpp:61
const Classification CL_STRING
string type_to_default(const std::string &indent, AST_Type *type, const string &name, bool is_anonymous, bool is_union)
AST_Typedef * typedef_node_
const std::string type_name_
static void gen_field_getValueFromSerialized(AST_Structure *node, const std::string &clazz)
Iterator begin() const
WrapDirection
const Classification CL_SCALAR
bool gen_struct(AST_Structure *node, UTL_ScopedName *name, const std::vector< AST_Field *> &fields, AST_Type::SIZE_TYPE size, const char *repoid)
const Classification CL_WIDE
std::string field_type_name(AST_Field *field, AST_Type *field_type)
void set_default(Type &)
Definition: Serializer.h:944
sequence< octet > key
String to_dds_string(unsigned short to_convert)
const Classification CL_PRIMITIVE
std::string seq_get_length() const
size_t array_count(Type(&)[count])
Definition: Util.h:221
#define ACE_TEXT_ALWAYS_CHAR(STRING)
static RootType root_type(AST_Type *type)
Definition: topic_keys.cpp:15
static std::string get_tag_name(const std::string &base_name, const std::string &qualifier="")
std::string seq_get_buffer() const
Christopher Diggins *renamed files *fixing compilation errors *adding Visual C project file *removed make Max Lybbert *removed references to missing and unused as reported by Andy Elvey and Dan Kosecki *resynced with Christopher Diggins s branch as it exists in tree building code is back Christopher Diggins *resynced codebase with Chris s branch *removed tree building code
Definition: CHANGELOG.txt:8
std::string path()
Definition: topic_keys.cpp:335
bool classic_array_copy_
TryConstructFailAction
Definition: annotations.h:316
ExtensibilityKind
Definition: annotations.h:278
AST_Type * deepest_named_type(AST_Type *type)
const std::string name_
Definition: field_info.h:41
const Classification CL_BOUNDED
void serialized_size(const Encoding &encoding, size_t &size, const SequenceNumber &)
const Classification CL_ARRAY
#define OPENDDS_HAS_EXPLICIT_INTS
Definition: Definitions.h:83
std::string ptr_
Definition: field_info.h:66
void gen_union_default(AST_UnionBranch *branch, const std::string &varname)
bool generateSwitchBody(AST_Union *, CommonFn commonFn, const std::vector< AST_UnionBranch *> &branches, AST_Type *discriminator, const char *statementPrefix, const char *namePrefix="", const char *uni="", bool forceDisableDefault=false, bool parens=true, bool breaks=true, CommonFn commonFn2=0)
bool generateSwitchForUnion(AST_Union *u, const char *switchExpr, CommonFn commonFn, const std::vector< AST_UnionBranch *> &branches, AST_Type *discriminator, const char *statementPrefix, const char *namePrefix="", const char *uni="", bool forceDisableDefault=false, bool parens=true, bool breaks=true, CommonFn commonFn2=0)
returns true if a default: branch was generated (no default: label in IDL)
std::string canonical_name(UTL_ScopedName *sn)
std::string index_
bool gen_enum(AST_Enum *node, UTL_ScopedName *name, const std::vector< AST_EnumVal *> &contents, const char *repoid)
std::string wrapped_type_name() const
Iterator end() const
bool gen_union(AST_Union *node, UTL_ScopedName *name, const std::vector< AST_UnionBranch *> &branches, AST_Type *discriminator, const char *repoid)
size_t count()
Definition: topic_keys.cpp:515
const std::string scoped_type_
Definition: field_info.h:42
std::string getWrapper(const std::string &name, AST_Type *type, WrapDirection wd)
AST_Type * resolveActualType(AST_Type *element)
const Classification CL_UNKNOWN
void endArgs()
std::string classic_array_copy() const
static void generate_dheader_code(const std::string &code, bool dheader_required, bool is_ser_func=true)
std::string insert_cxx11_accessor_parens(const std::string &full_var_name_, bool is_union_member=false)
ACE_UINT32 ULong
std::string seq_check_empty() const
std::string value_access(const std::string &var_name="") const
OpenDDS_Dcps_Export void align(size_t &value, size_t by)
Align "value" by "by" if it&#39;s not already.
Definition: Serializer.inl:23
bool nested_key_only_
const char *const name
Definition: debug.cpp:60
std::string scoped(UTL_ScopedName *sn, EscapeContext ec=EscapeContext_Normal)
#define OPENDDS_IDL_STR(X)
AST_Type * type_
Definition: field_info.h:40
AST_Array * arr_
Definition: field_info.h:48
std::string seq_resize(const std::string &new_size) const
std::string stream() const
std::set< EleLen > EleLenSet
Definition: field_info.h:31
const Classification CL_STRUCTURE
Iterator begin()
Definition: topic_keys.cpp:495
void addArg(const char *name, const std::string &type)
BE_GlobalData * be_global
Definition: be_global.cpp:44
ACE_CDR::ULong array_element_count(AST_Array *arr)
void generate_tag() const
const Classification CL_INTERFACE
RefWrapper & done(Intro *intro=0)
std::string ref() const
void misc_error_and_abort(const std::string &message, AST_Decl *node=0)
Report a miscellaneous error and abort.
bool gen_typedef(AST_Typedef *node, UTL_ScopedName *name, AST_Type *base, const char *repoid)
const DCPS::Encoding encoding(DCPS::Encoding::KIND_UNALIGNED_CDR, DCPS::ENDIAN_BIG)
const Classification CL_ENUM
const Classification CL_SEQUENCE
FieldFilter
AST_Sequence * seq_
Definition: field_info.h:49
bool needs_nested_key_only(AST_Type *type)
const Classification CL_UNION
AST_Field * get_struct_field(AST_Structure *struct_node, unsigned index)
bool anonymous() const
Definition: field_info.cpp:137
void align(size_t &value, size_t by=(std::numeric_limits< size_t >::max)()) const
Align "value" to "by" and according to the stream&#39;s alignment.
Definition: Serializer.inl:118