marshal_generator.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * Distributed under the OpenDDS License.
00005  * See: http://www.opendds.org/license.html
00006  */
00007 
00008 #include "marshal_generator.h"
00009 #include "be_extern.h"
00010 #include "utl_identifier.h"
00011 #include <string>
00012 #include <sstream>
00013 #include <iostream>
00014 #include <cctype>
00015 #include <map>
00016 
00017 using std::string;
00018 using namespace AstTypeClassification;
00019 
00020 #define LENGTH(CARRAY) (sizeof(CARRAY)/sizeof(CARRAY[0]))
00021 
00022 namespace {
00023 
00024   typedef bool (*is_special_case)(const string& cxx);
00025   typedef bool (*gen_special_case)(const string& cxx);
00026 
00027   typedef is_special_case is_special_sequence;
00028   typedef gen_special_case gen_special_sequence;
00029 
00030   typedef is_special_case is_special_struct;
00031   typedef gen_special_case gen_special_struct;
00032 
00033   typedef is_special_case is_special_union;
00034   typedef bool (*gen_special_union)(const string& cxx,
00035                                     AST_Type* discriminator,
00036                                     const std::vector<AST_UnionBranch*>& branches);
00037 
00038   struct special_sequence
00039   {
00040     is_special_sequence check;
00041     gen_special_sequence gen;
00042   };
00043 
00044   struct special_struct
00045   {
00046     is_special_struct check;
00047     gen_special_struct gen;
00048   };
00049 
00050   struct special_union
00051   {
00052     is_special_union check;
00053     gen_special_union gen;
00054   };
00055 
00056   bool isRtpsSpecialSequence(const string& cxx);
00057   bool genRtpsSpecialSequence(const string& cxx);
00058 
00059   bool isPropertySpecialSequence(const string& cxx);
00060   bool genPropertySpecialSequence(const string& cxx);
00061 
00062   bool isRtpsSpecialStruct(const string& cxx);
00063   bool genRtpsSpecialStruct(const string& cxx);
00064 
00065   bool isRtpsSpecialUnion(const string& cxx);
00066   bool genRtpsSpecialUnion(const string& cxx,
00067                            AST_Type* discriminator,
00068                            const std::vector<AST_UnionBranch*>& branches);
00069 
00070   bool isProperty_t(const string& cxx);
00071   bool genProperty_t(const string& cxx);
00072 
00073   bool isBinaryProperty_t(const string& cxx);
00074   bool genBinaryProperty_t(const string& cxx);
00075 
00076   bool isPropertyQosPolicy(const string& cxx);
00077   bool genPropertyQosPolicy(const string& cxx);
00078 
00079   bool isSecuritySubmessage(const string& cxx);
00080   bool genSecuritySubmessage(const string& cxx);
00081 
00082   const special_sequence special_sequences[] = {
00083     {
00084       isRtpsSpecialSequence,
00085       genRtpsSpecialSequence,
00086     },
00087     {
00088       isPropertySpecialSequence,
00089       genPropertySpecialSequence,
00090     },
00091   };
00092 
00093   const special_struct special_structs[] = {
00094     {
00095       isRtpsSpecialStruct,
00096       genRtpsSpecialStruct,
00097     },
00098     {
00099       isProperty_t,
00100       genProperty_t,
00101     },
00102     {
00103       isBinaryProperty_t,
00104       genBinaryProperty_t,
00105     },
00106     {
00107       isPropertyQosPolicy,
00108       genPropertyQosPolicy,
00109     },
00110     {
00111       isSecuritySubmessage,
00112       genSecuritySubmessage,
00113     },
00114   };
00115 
00116   const special_union special_unions[] = {
00117     {
00118       isRtpsSpecialUnion,
00119       genRtpsSpecialUnion,
00120     },
00121   };
00122 
00123 } /* namespace */
00124 
00125 bool marshal_generator::gen_enum(AST_Enum*, UTL_ScopedName* name,
00126   const std::vector<AST_EnumVal*>&, const char*)
00127 {
00128   NamespaceGuard ng;
00129   be_global->add_include("dds/DCPS/Serializer.h");
00130   string cxx = scoped(name); // name as a C++ class
00131   {
00132     Function insertion("operator<<", "bool");
00133     insertion.addArg("strm", "Serializer&");
00134     insertion.addArg("enumval", "const " + cxx + "&");
00135     insertion.endArgs();
00136     be_global->impl_ <<
00137       "  return strm << static_cast<CORBA::ULong>(enumval);\n";
00138   }
00139   {
00140     Function extraction("operator>>", "bool");
00141     extraction.addArg("strm", "Serializer&");
00142     extraction.addArg("enumval", cxx + "&");
00143     extraction.endArgs();
00144     be_global->impl_ <<
00145       "  CORBA::ULong temp = 0;\n"
00146       "  if (strm >> temp) {\n"
00147       "    enumval = static_cast<" << cxx << ">(temp);\n"
00148       "    return true;\n"
00149       "  }\n"
00150       "  return false;\n";
00151   }
00152   return true;
00153 }
00154 
00155 namespace {
00156 
00157   string getMaxSizeExprPrimitive(AST_Type* type)
00158   {
00159     if (type->node_type() != AST_Decl::NT_pre_defined) {
00160       return "";
00161     }
00162     AST_PredefinedType* pt = AST_PredefinedType::narrow_from_decl(type);
00163     switch (pt->pt()) {
00164     case AST_PredefinedType::PT_octet:
00165       return "max_marshaled_size_octet()";
00166     case AST_PredefinedType::PT_char:
00167       return "max_marshaled_size_char()";
00168     case AST_PredefinedType::PT_wchar:
00169       return "max_marshaled_size_wchar()";
00170     case AST_PredefinedType::PT_boolean:
00171       return "max_marshaled_size_boolean()";
00172     default:
00173       return "gen_max_marshaled_size(" + scoped(type->name()) + "())";
00174     }
00175   }
00176 
00177   string getSerializerName(AST_Type* type)
00178   {
00179     switch (AST_PredefinedType::narrow_from_decl(type)->pt()) {
00180     case AST_PredefinedType::PT_long:
00181       return "long";
00182     case AST_PredefinedType::PT_ulong:
00183       return "ulong";
00184     case AST_PredefinedType::PT_short:
00185       return "short";
00186     case AST_PredefinedType::PT_ushort:
00187       return "ushort";
00188     case AST_PredefinedType::PT_octet:
00189       return "octet";
00190     case AST_PredefinedType::PT_char:
00191       return "char";
00192     case AST_PredefinedType::PT_wchar:
00193       return "wchar";
00194     case AST_PredefinedType::PT_float:
00195       return "float";
00196     case AST_PredefinedType::PT_double:
00197       return "double";
00198     case AST_PredefinedType::PT_longlong:
00199       return "longlong";
00200     case AST_PredefinedType::PT_ulonglong:
00201       return "ulonglong";
00202     case AST_PredefinedType::PT_longdouble:
00203       return "longdouble";
00204     case AST_PredefinedType::PT_boolean:
00205       return "boolean";
00206     default:
00207       return "";
00208     }
00209   }
00210 
00211   string nameOfSeqHeader(AST_Type* elem)
00212   {
00213     string ser = getSerializerName(elem);
00214     if (ser.size()) {
00215       ser[0] = static_cast<char>(std::toupper(ser[0]));
00216     }
00217     if (ser[0] == 'U' || ser[0] == 'W') {
00218       ser[1] = static_cast<char>(std::toupper(ser[1]));
00219     }
00220     const size_t fourthLast = ser.size() - 4;
00221     if (ser.size() > 7 && ser.substr(fourthLast) == "long") {
00222       ser[fourthLast] = static_cast<char>(std::toupper(ser[fourthLast]));
00223     }
00224     if (ser == "Longdouble") return "LongDouble";
00225     return ser;
00226   }
00227 
00228   string streamAndCheck(const string& expr, size_t indent = 2)
00229   {
00230     string idt(indent, ' ');
00231     return idt + "if (!(strm " + expr + ")) {\n" +
00232       idt + "  return false;\n" +
00233       idt + "}\n";
00234   }
00235 
00236   string checkAlignment(AST_Type* elem)
00237   {
00238     // At this point the stream must be 4-byte aligned (from the sequence
00239     // length), but it might need to be 8-byte aligned for primitives > 4.
00240     switch (AST_PredefinedType::narrow_from_decl(elem)->pt()) {
00241     case AST_PredefinedType::PT_longlong:
00242     case AST_PredefinedType::PT_ulonglong:
00243     case AST_PredefinedType::PT_double:
00244     case AST_PredefinedType::PT_longdouble:
00245       return
00246         "  if ((size + padding) % 8) {\n"
00247         "    padding += 4;\n"
00248         "  }\n";
00249     default:
00250       return "";
00251     }
00252   }
00253 
00254   bool isRtpsSpecialSequence(const string& cxx)
00255   {
00256     return cxx == "OpenDDS::RTPS::ParameterList";
00257   }
00258 
00259   bool genRtpsSpecialSequence(const string& cxx)
00260   {
00261     {
00262       Function find_size("gen_find_size", "void");
00263       find_size.addArg("seq", "const " + cxx + "&");
00264       find_size.addArg("size", "size_t&");
00265       find_size.addArg("padding", "size_t&");
00266       find_size.endArgs();
00267       be_global->impl_ <<
00268         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00269         "    if (seq[i]._d() == OpenDDS::RTPS::PID_SENTINEL) continue;\n"
00270         "    size_t param_size = 0, param_padding = 0;\n"
00271         "    gen_find_size(seq[i], param_size, param_padding);\n"
00272         "    size += param_size + param_padding;\n"
00273         "    if (size % 4) {\n"
00274         "      size += 4 - (size % 4);\n"
00275         "    }\n"
00276         "  }\n"
00277         "  size += 4; /* PID_SENTINEL */\n";
00278     }
00279     {
00280       Function insertion("operator<<", "bool");
00281       insertion.addArg("strm", "Serializer&");
00282       insertion.addArg("seq", "const " + cxx + "&");
00283       insertion.endArgs();
00284       be_global->impl_ <<
00285         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00286         "    if (seq[i]._d() == OpenDDS::RTPS::PID_SENTINEL) continue;\n"
00287         "    if (!(strm << seq[i])) {\n"
00288         "      return false;\n"
00289         "    }\n"
00290         "  }\n"
00291         "  return (strm << OpenDDS::RTPS::PID_SENTINEL)\n"
00292         "    && (strm << OpenDDS::RTPS::PID_PAD);\n";
00293     }
00294     {
00295       Function extraction("operator>>", "bool");
00296       extraction.addArg("strm", "Serializer&");
00297       extraction.addArg("seq", cxx + "&");
00298       extraction.endArgs();
00299       be_global->impl_ <<
00300         "  while (true) {\n"
00301         "    const CORBA::ULong len = seq.length();\n"
00302         "    seq.length(len + 1);\n"
00303         "    if (!(strm >> seq[len])) {\n"
00304         "      return false;\n"
00305         "    }\n"
00306         "    if (seq[len]._d() == OpenDDS::RTPS::PID_SENTINEL) {\n"
00307         "      seq.length(len);\n"
00308         "      return true;\n"
00309         "    }\n"
00310         "  }\n";
00311     }
00312     return true;
00313   }
00314 
00315   bool isPropertySpecialSequence(const string& cxx)
00316   {
00317     return cxx == "DDS::PropertySeq"
00318       || cxx == "DDS::BinaryPropertySeq";
00319   }
00320 
00321   bool genPropertySpecialSequence(const string& cxx)
00322   {
00323     {
00324       Function find_size("gen_find_size", "void");
00325       find_size.addArg("seq", "const " + cxx + "&");
00326       find_size.addArg("size", "size_t&");
00327       find_size.addArg("padding", "size_t&");
00328       find_size.endArgs();
00329       be_global->impl_ <<
00330         "  find_size_ulong(size, padding);\n"
00331         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00332         "    gen_find_size(seq[i], size, padding);\n"
00333         "  }\n";
00334     }
00335     {
00336       Function insertion("operator<<", "bool");
00337       insertion.addArg("strm", "Serializer&");
00338       insertion.addArg("seq", "const " + cxx + "&");
00339       insertion.endArgs();
00340       be_global->impl_ <<
00341         "  CORBA::ULong serlen = 0;\n"
00342         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00343         "    if (seq[i].propagate) {\n"
00344         "      ++serlen;\n"
00345         "    }\n"
00346         "  }\n"
00347         "  if (!(strm << serlen)) {\n"
00348         "    return false;\n"
00349         "  }\n"
00350         "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n"
00351         "    if (!(strm << seq[i])) {\n"
00352         "      return false;\n"
00353         "    }\n"
00354         "  }\n"
00355         "  return true;\n";
00356     }
00357     {
00358       Function extraction("operator>>", "bool");
00359       extraction.addArg("strm", "Serializer&");
00360       extraction.addArg("seq", cxx + "&");
00361       extraction.endArgs();
00362       be_global->impl_ <<
00363         "  CORBA::ULong length;\n"
00364         "  if (!(strm >> length)) {\n"
00365         "    return false;\n"
00366         "  }\n"
00367         "  seq.length(length);\n"
00368         "  for (CORBA::ULong i = 0; i < length; ++i) {\n"
00369         "    if (!(strm >> seq[i])) {\n"
00370         "      return false;\n"
00371         "    }\n"
00372         "  }\n"
00373         "  return true;\n";
00374     }
00375     return true;
00376   }
00377 
00378   void gen_sequence(UTL_ScopedName* tdname, AST_Sequence* seq)
00379   {
00380     be_global->add_include("dds/DCPS/Serializer.h");
00381     NamespaceGuard ng;
00382     string cxx = scoped(tdname);
00383 
00384     for (size_t i = 0; i < LENGTH(special_sequences); ++i) {
00385       if (special_sequences[i].check(cxx)) {
00386         special_sequences[i].gen(cxx);
00387         return;
00388       }
00389     }
00390 
00391     AST_Type* elem = resolveActualType(seq->base_type());
00392     Classification elem_cls = classify(elem);
00393     if (!elem->in_main_file()) {
00394       if (elem->node_type() == AST_Decl::NT_pre_defined) {
00395         if (be_global->language_mapping() != BE_GlobalData::LANGMAP_FACE_CXX &&
00396             be_global->language_mapping() != BE_GlobalData::LANGMAP_SP_CXX) {
00397           be_global->add_include(("dds/CorbaSeq/" + nameOfSeqHeader(elem)
00398                                   + "SeqTypeSupportImpl.h").c_str(), BE_GlobalData::STREAM_CPP);
00399         }
00400       } else {
00401         be_global->add_referenced(elem->file_name().c_str());
00402       }
00403     }
00404     string cxx_elem = scoped(elem->name());
00405     {
00406       Function find_size("gen_find_size", "void");
00407       find_size.addArg("seq", "const " + cxx + "&");
00408       find_size.addArg("size", "size_t&");
00409       find_size.addArg("padding", "size_t&");
00410       find_size.endArgs();
00411       be_global->impl_ <<
00412         "  find_size_ulong(size, padding);\n"
00413         "  if (seq.length() == 0) {\n"
00414         "    return;\n"
00415         "  }\n";
00416       if (elem_cls & CL_ENUM) {
00417         be_global->impl_ <<
00418           "  size += seq.length() * max_marshaled_size_ulong();\n";
00419       } else if (elem_cls & CL_PRIMITIVE) {
00420         be_global->impl_ << checkAlignment(elem) <<
00421           "  size += seq.length() * " << getMaxSizeExprPrimitive(elem) << ";\n";
00422       } else if (elem_cls & CL_INTERFACE) {
00423         be_global->impl_ <<
00424           "  // sequence of objrefs is not marshaled\n";
00425       } else if (elem_cls == CL_UNKNOWN) {
00426         be_global->impl_ <<
00427           "  // sequence of unknown/unsupported type\n";
00428       } else { // String, Struct, Array, Sequence, Union
00429         be_global->impl_ <<
00430           "  for (CORBA::ULong i = 0; i < seq.length(); ++i) {\n";
00431         if (elem_cls & CL_STRING) {
00432           be_global->impl_ <<
00433             "    find_size_ulong(size, padding);\n"
00434             "    if (seq[i]) {\n"
00435             "      size += ACE_OS::strlen(seq[i])"
00436             << ((elem_cls & CL_WIDE)
00437                 ? " * OpenDDS::DCPS::Serializer::WCHAR_SIZE;\n"
00438                 : " + 1;\n") <<
00439             "    }\n";
00440         } else if (elem_cls & CL_ARRAY) {
00441           be_global->impl_ <<
00442             "    " << cxx_elem << "_var tmp_var = " << cxx_elem
00443             << "_dup(seq[i]);\n"
00444             "    " << cxx_elem << "_forany tmp = tmp_var.inout();\n"
00445             "    gen_find_size(tmp, size, padding);\n";
00446         } else { // Struct, Sequence, Union
00447           be_global->impl_ <<
00448             "    gen_find_size(seq[i], size, padding);\n";
00449         }
00450         be_global->impl_ <<
00451           "  }\n";
00452       }
00453     }
00454     {
00455       Function insertion("operator<<", "bool");
00456       insertion.addArg("strm", "Serializer&");
00457       insertion.addArg("seq", "const " + cxx + "&");
00458       insertion.endArgs();
00459       be_global->impl_ <<
00460         "  const CORBA::ULong length = seq.length();\n"
00461         << streamAndCheck("<< length") <<
00462         "  if (length == 0) {\n"
00463         "    return true;\n"
00464         "  }\n";
00465       if (elem_cls & CL_PRIMITIVE) {
00466         be_global->impl_ <<
00467           "  return strm.write_" << getSerializerName(elem)
00468           << "_array(seq.get_buffer(), length);\n";
00469       } else if (elem_cls & CL_INTERFACE) {
00470         be_global->impl_ <<
00471           "  return false; // sequence of objrefs is not marshaled\n";
00472       } else if (elem_cls == CL_UNKNOWN) {
00473         be_global->impl_ <<
00474           "  return false; // sequence of unknown/unsupported type\n";
00475       } else { // Enum, String, Struct, Array, Sequence, Union
00476         be_global->impl_ <<
00477           "  for (CORBA::ULong i = 0; i < length; ++i) {\n";
00478         if (elem_cls & CL_ARRAY) {
00479           const string typedefname = scoped(seq->base_type()->name());
00480           be_global->impl_ <<
00481             "    " << typedefname << "_var tmp_var = " << typedefname
00482             << "_dup(seq[i]);\n"
00483             "    " << typedefname << "_forany tmp = tmp_var.inout();\n"
00484             << streamAndCheck("<< tmp", 4);
00485         } else {
00486           be_global->impl_ << streamAndCheck("<< seq[i]", 4);
00487         }
00488         be_global->impl_ <<
00489           "  }\n"
00490           "  return true;\n";
00491       }
00492     }
00493     {
00494       Function extraction("operator>>", "bool");
00495       extraction.addArg("strm", "Serializer&");
00496       extraction.addArg("seq", cxx + "&");
00497       extraction.endArgs();
00498       be_global->impl_ <<
00499         "  CORBA::ULong length;\n"
00500         << streamAndCheck(">> length");
00501       if (!seq->unbounded()) {
00502         be_global->impl_ <<
00503           "  if (length > seq.maximum()) {\n"
00504           "    return false;\n"
00505           "  }\n";
00506       }
00507       be_global->impl_ <<
00508         "  seq.length(length);\n";
00509       if (elem_cls & CL_PRIMITIVE) {
00510         be_global->impl_ <<
00511           "  if (length == 0) {\n"
00512           "    return true;\n"
00513           "  }\n"
00514           "  return strm.read_" << getSerializerName(elem)
00515           << "_array(seq.get_buffer(), length);\n";
00516       } else if (elem_cls & CL_INTERFACE) {
00517         be_global->impl_ <<
00518           "  return false; // sequence of objrefs is not marshaled\n";
00519       } else if (elem_cls == CL_UNKNOWN) {
00520         be_global->impl_ <<
00521           "  return false; // sequence of unknown/unsupported type\n";
00522       } else { // Enum, String, Struct, Array, Sequence, Union
00523         be_global->impl_ <<
00524           "  for (CORBA::ULong i = 0; i < length; ++i) {\n";
00525         if (elem_cls & CL_ARRAY) {
00526           const string typedefname = scoped(seq->base_type()->name());
00527           be_global->impl_ <<
00528             "    " << typedefname << "_var tmp = " << typedefname
00529             << "_alloc();\n"
00530             "    " << typedefname << "_forany fa = tmp.inout();\n"
00531             << streamAndCheck(">> fa", 4) <<
00532             "    " << typedefname << "_copy(seq[i], tmp.in());\n";
00533         } else if (elem_cls & CL_STRING) {
00534           if (elem_cls & CL_BOUNDED) {
00535             AST_String* str = AST_String::narrow_from_decl(elem);
00536             std::ostringstream args;
00537             args << "seq[i].out(), " << str->max_size()->ev()->u.ulval;
00538             be_global->impl_ <<
00539               streamAndCheck(">> " + getWrapper(args.str(), elem, WD_INPUT), 4);
00540           } else { // unbounded string
00541             const string getbuffer =
00542               (be_global->language_mapping() == BE_GlobalData::LANGMAP_NONE)
00543               ? ".get_buffer()" : "";
00544             be_global->impl_ << streamAndCheck(">> seq" + getbuffer + "[i]", 4);
00545           }
00546         } else { // Enum, Struct, Sequence, Union
00547           be_global->impl_ << streamAndCheck(">> seq[i]", 4);
00548         }
00549         be_global->impl_ <<
00550           "  }\n"
00551           "  return true;\n";
00552       }
00553     }
00554   }
00555 
00556   string getAlignment(AST_Type* elem)
00557   {
00558     if (elem->node_type() == AST_Decl::NT_enum) {
00559       return "4";
00560     }
00561     switch (AST_PredefinedType::narrow_from_decl(elem)->pt()) {
00562     case AST_PredefinedType::PT_short:
00563     case AST_PredefinedType::PT_ushort:
00564       return "2";
00565     case AST_PredefinedType::PT_long:
00566     case AST_PredefinedType::PT_ulong:
00567     case AST_PredefinedType::PT_float:
00568       return "4";
00569     case AST_PredefinedType::PT_longlong:
00570     case AST_PredefinedType::PT_ulonglong:
00571     case AST_PredefinedType::PT_double:
00572     case AST_PredefinedType::PT_longdouble:
00573       return "8";
00574     default:
00575       return "";
00576     }
00577   }
00578 
00579   void gen_array(UTL_ScopedName* name, AST_Array* arr)
00580   {
00581     be_global->add_include("dds/DCPS/Serializer.h");
00582     NamespaceGuard ng;
00583     string cxx = scoped(name);
00584     AST_Type* elem = resolveActualType(arr->base_type());
00585     Classification elem_cls = classify(elem);
00586     if (!elem->in_main_file()
00587         && elem->node_type() != AST_Decl::NT_pre_defined) {
00588       be_global->add_referenced(elem->file_name().c_str());
00589     }
00590     string cxx_elem = scoped(elem->name());
00591     size_t n_elems = 1;
00592     for (size_t i = 0; i < arr->n_dims(); ++i) {
00593       n_elems *= arr->dims()[i]->ev()->u.ulval;
00594     }
00595     {
00596       Function find_size("gen_find_size", "void");
00597       find_size.addArg("arr", "const " + cxx + "_forany&");
00598       find_size.addArg("size", "size_t&");
00599       find_size.addArg("padding", "size_t&");
00600       find_size.endArgs();
00601       if (elem_cls & CL_ENUM) {
00602         be_global->impl_ <<
00603           "  find_size_ulong(size, padding);\n";
00604           if (n_elems > 1) {
00605             be_global->impl_ <<
00606               "  size += " << n_elems - 1 << " * max_marshaled_size_ulong();\n";
00607           }
00608       } else if (elem_cls & CL_PRIMITIVE) {
00609         const string align = getAlignment(elem);
00610         if (!align.empty()) {
00611           be_global->impl_ <<
00612             "  if ((size + padding) % " << align << ") {\n"
00613             "    padding += " << align << " - ((size + padding) % " << align
00614             << ");\n"
00615             "  }\n";
00616         }
00617         be_global->impl_ <<
00618           "  size += " << n_elems << " * " << getMaxSizeExprPrimitive(elem)
00619           << ";\n";
00620       } else { // String, Struct, Array, Sequence, Union
00621         string indent = "  ";
00622         NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
00623         if (elem_cls & CL_STRING) {
00624           be_global->impl_ <<
00625             indent << "find_size_ulong(size, padding);\n" <<
00626             indent << "size += ACE_OS::strlen(arr" << nfl.index_ << ".in())"
00627             << ((elem_cls & CL_WIDE)
00628                 ? " * OpenDDS::DCPS::Serializer::WCHAR_SIZE;\n"
00629                 : " + 1;\n");
00630         } else if (elem_cls & CL_ARRAY) {
00631           be_global->impl_ <<
00632             indent << cxx_elem << "_var tmp_var = " << cxx_elem
00633             << "_dup(arr" << nfl.index_ << ");\n" <<
00634             indent << cxx_elem << "_forany tmp = tmp_var.inout();\n" <<
00635             indent << "gen_find_size(tmp, size, padding);\n";
00636         } else { // Struct, Sequence, Union
00637           be_global->impl_ <<
00638             indent << "gen_find_size(arr" << nfl.index_
00639             << ", size, padding);\n";
00640         }
00641       }
00642     }
00643     {
00644       Function insertion("operator<<", "bool");
00645       insertion.addArg("strm", "Serializer&");
00646       insertion.addArg("arr", "const " + cxx + "_forany&");
00647       insertion.endArgs();
00648       if (elem_cls & CL_PRIMITIVE) {
00649         string suffix;
00650         for (unsigned int i = 1; i < arr->n_dims(); ++i)
00651           suffix += "[0]";
00652         be_global->impl_ <<
00653           "  return strm.write_" << getSerializerName(elem)
00654           << "_array(arr.in()" << suffix << ", " << n_elems << ");\n";
00655       } else { // Enum, String, Struct, Array, Sequence, Union
00656         {
00657           string indent = "  ";
00658           NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
00659           if (elem_cls & CL_ARRAY) {
00660             be_global->impl_ <<
00661               indent << cxx_elem << "_var tmp_var = " << cxx_elem
00662               << "_dup(arr" << nfl.index_ << ");\n" <<
00663               indent << cxx_elem << "_forany tmp = tmp_var.inout();\n" <<
00664               streamAndCheck("<< tmp", indent.size());
00665           } else {
00666             string suffix = (elem_cls & CL_STRING) ? ".in()" : "";
00667             be_global->impl_ <<
00668               streamAndCheck("<< arr" + nfl.index_ + suffix , indent.size());
00669           }
00670         }
00671         be_global->impl_ << "  return true;\n";
00672       }
00673     }
00674     {
00675       Function extraction("operator>>", "bool");
00676       extraction.addArg("strm", "Serializer&");
00677       extraction.addArg("arr", cxx + "_forany&");
00678       extraction.endArgs();
00679       if (elem_cls & CL_PRIMITIVE) {
00680         string suffix;
00681         for (unsigned int i = 1; i < arr->n_dims(); ++i)
00682           suffix += "[0]";
00683         be_global->impl_ <<
00684           "  return strm.read_" << getSerializerName(elem)
00685           << "_array(arr.out()" << suffix << ", " << n_elems << ");\n";
00686       } else { // Enum, String, Struct, Array, Sequence, Union
00687         {
00688           string indent = "  ";
00689           NestedForLoops nfl("CORBA::ULong", "i", arr, indent);
00690           if (elem_cls & CL_ARRAY) {
00691             const string typedefname = scoped(arr->base_type()->name());
00692             be_global->impl_ <<
00693               indent << typedefname << "_var tmp = " << typedefname
00694               << "_alloc();\n" <<
00695               indent << typedefname << "_forany fa = tmp.inout();\n"
00696               << streamAndCheck(">> fa", indent.size()) <<
00697               indent << typedefname << "_copy(arr" << nfl.index_ <<
00698               ", tmp.in());\n";
00699           } else {
00700             string suffix = (elem_cls & CL_STRING) ? ".out()" : "";
00701             be_global->impl_ <<
00702               streamAndCheck(">> arr" + nfl.index_ + suffix, indent.size());
00703           }
00704         }
00705         be_global->impl_ << "  return true;\n";
00706       }
00707     }
00708   }
00709 
00710   string getArrayForany(const char* prefix, const char* fname,
00711                         const string& cxx_fld)
00712   {
00713     string local = fname;
00714     if (local.size() > 2 && local.substr(local.size() - 2, 2) == "()") {
00715       local.erase(local.size() - 2);
00716     }
00717     return cxx_fld + "_forany " + prefix + '_' + local + "(const_cast<"
00718       + cxx_fld + "_slice*>(" + prefix + "." + fname + "));";
00719   }
00720 
00721   // This function looks through the fields of a struct for the key
00722   // specified and returns the AST_Type associated with that key.
00723   // Because the key name can contain indexed arrays and nested
00724   // structures, things can get interesting.
00725   AST_Type* find_type(const std::vector<AST_Field*>& fields, const string& key)
00726   {
00727     string key_base = key;   // the field we are looking for here
00728     string key_rem;          // the sub-field we will look for recursively
00729     bool is_array = false;
00730     size_t pos = key.find_first_of(".[");
00731     if (pos != string::npos) {
00732       key_base = key.substr(0, pos);
00733       if (key[pos] == '[') {
00734         is_array = true;
00735         size_t l_brack = key.find("]");
00736         if (l_brack == string::npos) {
00737           throw string("Missing right bracket");
00738         } else if (l_brack != key.length()) {
00739           key_rem = key.substr(l_brack+1);
00740         }
00741       } else {
00742         key_rem = key.substr(pos+1);
00743       }
00744     }
00745     for (size_t i = 0; i < fields.size(); ++i) {
00746       string field_name = fields[i]->local_name()->get_string();
00747       if (field_name == key_base) {
00748         AST_Type* field_type = fields[i]->field_type();
00749         if (!is_array && key_rem.empty()) {
00750           // The requested key field matches this one.  We do not allow
00751           // arrays (must be indexed specifically) or structs (must
00752           // identify specific sub-fields).
00753           AST_Structure* sub_struct = dynamic_cast<AST_Structure*>(field_type);
00754           if (sub_struct != 0) {
00755             throw string("Structs not allowed as keys");
00756           }
00757           AST_Typedef* typedef_node = dynamic_cast<AST_Typedef*>(field_type);
00758           if (typedef_node != 0) {
00759             AST_Array* array_node =
00760               dynamic_cast<AST_Array*>(typedef_node->base_type());
00761             if (array_node != 0) {
00762               throw string("Arrays not allowed as keys");
00763             }
00764           }
00765           return field_type;
00766         } else if (is_array) {
00767           // must be a typedef of an array
00768           AST_Typedef* typedef_node = dynamic_cast<AST_Typedef*>(field_type);
00769           if (typedef_node == 0) {
00770             throw string("Indexing for non-array type");
00771           }
00772           AST_Array* array_node =
00773             dynamic_cast<AST_Array*>(typedef_node->base_type());
00774           if (array_node == 0) {
00775             throw string("Indexing for non-array type");
00776           }
00777           if (array_node->n_dims() > 1) {
00778             throw string("Only single dimension arrays allowed in keys");
00779           }
00780           if (key_rem == "") {
00781             return array_node->base_type();
00782           } else {
00783             // This must be a struct...
00784             if ((key_rem[0] != '.') || (key_rem.length() == 1)) {
00785               throw string("Unexpected characters after array index");
00786             } else {
00787               // Set up key_rem and field_type and let things fall into
00788               // the struct code below
00789               key_rem = key_rem.substr(1);
00790               field_type = array_node->base_type();
00791             }
00792           }
00793         }
00794 
00795         // nested structures
00796         AST_Structure* sub_struct = dynamic_cast<AST_Structure*>(field_type);
00797         if (sub_struct == 0) {
00798           throw string("Expected structure field for ") + key_base;
00799         }
00800         size_t nfields = sub_struct->nfields();
00801         std::vector<AST_Field*> sub_fields;
00802         sub_fields.reserve(nfields);
00803 
00804         for (unsigned long i = 0; i < nfields; ++i) {
00805           AST_Field** f;
00806           sub_struct->field(f, i);
00807           sub_fields.push_back(*f);
00808         }
00809         // find type of nested struct field
00810         return find_type(sub_fields, key_rem);
00811       }
00812     }
00813     throw string("Field not found.");
00814   }
00815 
00816   bool is_bounded_type(AST_Type* type)
00817   {
00818     bool bounded = true;
00819     static std::vector<AST_Type*> type_stack;
00820     type = resolveActualType(type);
00821     for (unsigned int i = 0; i < type_stack.size(); i++) {
00822       // If we encounter the same type recursively, then we are unbounded
00823       if (type == type_stack[i]) return false;
00824     }
00825     type_stack.push_back(type);
00826     Classification fld_cls = classify(type);
00827     if ((fld_cls & CL_STRING) && !(fld_cls & CL_BOUNDED)) {
00828       bounded = false;
00829     } else if (fld_cls & CL_STRUCTURE) {
00830       AST_Structure* struct_node = dynamic_cast<AST_Structure*>(type);
00831       for (unsigned long i = 0; i < struct_node->nfields(); ++i) {
00832         AST_Field** f;
00833         struct_node->field(f, i);
00834         if (!is_bounded_type((*f)->field_type())) {
00835           bounded = false;
00836           break;
00837         }
00838       }
00839     } else if (fld_cls & CL_SEQUENCE) {
00840       if (fld_cls & CL_BOUNDED) {
00841         AST_Sequence* seq_node = dynamic_cast<AST_Sequence*>(type);
00842         if (!is_bounded_type(seq_node->base_type())) bounded = false;
00843       } else {
00844         bounded = false;
00845       }
00846     } else if (fld_cls & CL_ARRAY) {
00847       AST_Array* array_node = dynamic_cast<AST_Array*>(type);
00848       if (!is_bounded_type(array_node->base_type())) bounded = false;
00849     } else if (fld_cls & CL_UNION) {
00850       AST_Union* union_node = dynamic_cast<AST_Union*>(type);
00851       for (unsigned long i = 0; i < union_node->nfields(); ++i) {
00852         AST_Field** f;
00853         union_node->field(f, i);
00854         if (!is_bounded_type((*f)->field_type())) {
00855           bounded = false;
00856           break;
00857         }
00858       }
00859     }
00860     type_stack.pop_back();
00861     return bounded;
00862   }
00863 
00864   void align(size_t alignment, size_t& size, size_t& padding)
00865   {
00866     if ((size + padding) % alignment) {
00867       padding += alignment - ((size + padding) % alignment);
00868     }
00869   }
00870 
00871   void max_marshaled_size(AST_Type* type, size_t& size, size_t& padding);
00872 
00873   // Max marshaled size of repeating 'type' 'n' times in the stream
00874   // (for an array or sequence)
00875   void mms_repeating(AST_Type* type, size_t n, size_t& size, size_t& padding)
00876   {
00877     if (n > 0) {
00878       // 1st element may need padding relative to whatever came before
00879       max_marshaled_size(type, size, padding);
00880     }
00881     if (n > 1) {
00882       // subsequent elements may need padding relative to prior element
00883       size_t prev_size = size, prev_pad = padding;
00884       max_marshaled_size(type, size, padding);
00885       size += (n - 2) * (size - prev_size);
00886       padding += (n - 2) * (padding - prev_pad);
00887     }
00888   }
00889 
00890   // Should only be called on bounded types (see above function)
00891   void max_marshaled_size(AST_Type* type, size_t& size, size_t& padding)
00892   {
00893     type = resolveActualType(type);
00894     switch (type->node_type()) {
00895     case AST_Decl::NT_pre_defined: {
00896       AST_PredefinedType* p = AST_PredefinedType::narrow_from_decl(type);
00897       switch (p->pt()) {
00898       case AST_PredefinedType::PT_char:
00899       case AST_PredefinedType::PT_boolean:
00900       case AST_PredefinedType::PT_octet:
00901         size += 1;
00902         break;
00903       case AST_PredefinedType::PT_short:
00904       case AST_PredefinedType::PT_ushort:
00905         align(2, size, padding);
00906         size += 2;
00907         break;
00908       case AST_PredefinedType::PT_wchar:
00909         size += 3; // see Serializer::max_marshaled_size_wchar()
00910         break;
00911       case AST_PredefinedType::PT_long:
00912       case AST_PredefinedType::PT_ulong:
00913       case AST_PredefinedType::PT_float:
00914         align(4, size, padding);
00915         size += 4;
00916         break;
00917       case AST_PredefinedType::PT_longlong:
00918       case AST_PredefinedType::PT_ulonglong:
00919       case AST_PredefinedType::PT_double:
00920         align(8, size, padding);
00921         size += 8;
00922         break;
00923       case AST_PredefinedType::PT_longdouble:
00924         align(8, size, padding);
00925         size += 16;
00926         break;
00927       default:
00928         // Anything else shouldn't be in a DDS type or is unbounded.
00929         break;
00930       }
00931       break;
00932     }
00933     case AST_Decl::NT_enum:
00934       align(4, size, padding);
00935       size += 4;
00936       break;
00937     case AST_Decl::NT_string:
00938     case AST_Decl::NT_wstring: {
00939       AST_String* string_node = dynamic_cast<AST_String*>(type);
00940       align(4, size, padding);
00941       size += 4;
00942       const int width = (string_node->width() == 1) ? 1 : 2 /*UTF-16*/;
00943       size += width * string_node->max_size()->ev()->u.ulval;
00944       if (type->node_type() == AST_Decl::NT_string) {
00945         size += 1; // narrow string includes the null terminator
00946       }
00947       break;
00948     }
00949     case AST_Decl::NT_struct: {
00950       AST_Structure* struct_node = dynamic_cast<AST_Structure*>(type);
00951       for (unsigned long i = 0; i < struct_node->nfields(); ++i) {
00952         AST_Field** f;
00953         struct_node->field(f, i);
00954         AST_Type* field_type = (*f)->field_type();
00955         max_marshaled_size(field_type, size, padding);
00956       }
00957       break;
00958     }
00959     case AST_Decl::NT_sequence: {
00960       AST_Sequence* seq_node = dynamic_cast<AST_Sequence*>(type);
00961       AST_Type* base_node = seq_node->base_type();
00962       size_t bound = seq_node->max_size()->ev()->u.ulval;
00963       align(4, size, padding);
00964       size += 4;
00965       mms_repeating(base_node, bound, size, padding);
00966       break;
00967     }
00968     case AST_Decl::NT_array: {
00969       AST_Array* array_node = dynamic_cast<AST_Array*>(type);
00970       AST_Type* base_node = array_node->base_type();
00971       size_t array_size = 1;
00972       AST_Expression** dims = array_node->dims();
00973       for (unsigned long i = 0; i < array_node->n_dims(); i++) {
00974         array_size *= dims[i]->ev()->u.ulval;
00975       }
00976       mms_repeating(base_node, array_size, size, padding);
00977       break;
00978     }
00979     case AST_Decl::NT_union: {
00980       AST_Union* union_node = dynamic_cast<AST_Union*>(type);
00981       max_marshaled_size(union_node->disc_type(), size, padding);
00982       size_t largest_field_size = 0, largest_field_pad = 0;
00983       const size_t starting_size = size, starting_pad = padding;
00984       for (unsigned long i = 0; i < union_node->nfields(); ++i) {
00985         AST_Field** f;
00986         union_node->field(f, i);
00987         AST_Type* field_type = (*f)->field_type();
00988         max_marshaled_size(field_type, size, padding);
00989         size_t field_size = size - starting_size,
00990           field_pad = padding - starting_pad;
00991         if (field_size > largest_field_size) {
00992           largest_field_size = field_size;
00993           largest_field_pad = field_pad;
00994         }
00995         // rewind:
00996         size = starting_size;
00997         padding = starting_pad;
00998       }
00999       size += largest_field_size;
01000       padding += largest_field_pad;
01001       break;
01002     }
01003     default:
01004       // Anything else should be not here or is unbounded
01005       break;
01006     }
01007   }
01008 }
01009 
01010 bool marshal_generator::gen_typedef(AST_Typedef*, UTL_ScopedName* name, AST_Type* base,
01011   const char*)
01012 {
01013   switch (base->node_type()) {
01014   case AST_Decl::NT_sequence:
01015     gen_sequence(name, AST_Sequence::narrow_from_decl(base));
01016     break;
01017   case AST_Decl::NT_array:
01018     gen_array(name, AST_Array::narrow_from_decl(base));
01019     break;
01020   default:
01021     return true;
01022   }
01023   return true;
01024 }
01025 
01026 namespace {
01027   // common to both fields (in structs) and branches (in unions)
01028   string findSizeCommon(const string& name, AST_Type* type,
01029                         const string& prefix, string& intro,
01030                         const string& = "") // same sig as streamCommon
01031   {
01032     AST_Type* typedeff = type;
01033     type = resolveActualType(type);
01034     Classification fld_cls = classify(type);
01035     const string qual = prefix + '.' + name;
01036     const string indent = (prefix == "uni") ? "    " : "  ";
01037     if (fld_cls & CL_ENUM) {
01038       return indent + "find_size_ulong(size, padding);\n";
01039     } else if (fld_cls & CL_STRING) {
01040       const string suffix = (prefix == "uni") ? "" : ".in()";
01041       return indent + "find_size_ulong(size, padding);\n" +
01042         indent + "size += ACE_OS::strlen(" + qual + suffix + ")"
01043         + ((fld_cls & CL_WIDE) ? " * OpenDDS::DCPS::Serializer::WCHAR_SIZE;\n"
01044                                : " + 1;\n");
01045     } else if (fld_cls & CL_PRIMITIVE) {
01046       string align = getAlignment(type);
01047       if (!align.empty()) {
01048         align =
01049           indent + "if ((size + padding) % " + align + ") {\n" +
01050           indent + "  padding += " + align + " - ((size + padding) % "
01051           + align + ");\n" +
01052           indent + "}\n";
01053       }
01054       return align +
01055         indent + "size += gen_max_marshaled_size(" +
01056         getWrapper(qual, type, WD_OUTPUT) + ");\n";
01057     } else if (fld_cls == CL_UNKNOWN) {
01058       return ""; // warning will be issued for the serialize functions
01059     } else { // sequence, struct, union, array
01060       string fieldref = prefix, local = name;
01061       if (fld_cls & CL_ARRAY) {
01062         intro += "  " + getArrayForany(prefix.c_str(), name.c_str(),
01063                                        scoped(typedeff->name())) + '\n';
01064         fieldref += '_';
01065         if (local.size() > 2 && local.substr(local.size() - 2) == "()") {
01066           local.erase(local.size() - 2);
01067         }
01068       } else {
01069         fieldref += '.';
01070       }
01071       return indent +
01072         "gen_find_size(" + fieldref + local + ", size, padding);\n";
01073     }
01074   }
01075 
01076   // common to both fields (in structs) and branches (in unions)
01077   string streamCommon(const string& name, AST_Type* type,
01078                       const string& prefix, string& intro,
01079                       const string& stru = "")
01080   {
01081     AST_Type* typedeff = type;
01082     type = resolveActualType(type);
01083     Classification fld_cls = classify(type);
01084     const string qual = prefix + '.' + name, shift = prefix.substr(0, 2);
01085     WrapDirection dir = (shift == ">>") ? WD_INPUT : WD_OUTPUT;
01086     if ((fld_cls & CL_STRING) && (dir == WD_INPUT)) {
01087       return "(strm " + qual + ".out())";
01088     } else if (fld_cls & CL_PRIMITIVE) {
01089       return "(strm " + shift + ' '
01090         + getWrapper(qual.substr(3), type, dir) + ')';
01091     } else if (fld_cls == CL_UNKNOWN) {
01092       if (dir == WD_INPUT) { // no need to warn twice
01093         std::cerr << "WARNING: field " << name << " can not be serialized.  "
01094           "The struct or union it belongs to (" << stru <<
01095           ") can not be used in an OpenDDS topic type." << std::endl;
01096       }
01097       return "false";
01098     } else { // sequence, struct, union, array, enum, string(insertion)
01099       string fieldref = prefix, local = name;
01100       const bool accessor =
01101         local.size() > 2 && local.substr(local.size() - 2) == "()";
01102       if (fld_cls & CL_ARRAY) {
01103         string pre = prefix;
01104         if (shift == ">>" || shift == "<<") {
01105           pre.erase(0, 3);
01106         }
01107         if (accessor) {
01108           local.erase(local.size() - 2);
01109         }
01110         intro += "  " + getArrayForany(pre.c_str(), name.c_str(),
01111           scoped(typedeff->name())) + '\n';
01112         fieldref += '_';
01113       } else {
01114         fieldref += '.';
01115       }
01116       if ((fld_cls & CL_STRING) && !accessor) local += ".in()";
01117       return "(strm " + fieldref + local + ')';
01118     }
01119   }
01120 
01121   bool isBinaryProperty_t(const string& cxx)
01122   {
01123     return cxx == "DDS::BinaryProperty_t";
01124   }
01125 
01126   bool genBinaryProperty_t(const string& cxx)
01127   {
01128     {
01129       Function find_size("gen_find_size", "void");
01130       find_size.addArg("stru", "const " + cxx + "&");
01131       find_size.addArg("size", "size_t&");
01132       find_size.addArg("padding", "size_t&");
01133       find_size.endArgs();
01134       be_global->impl_ <<
01135         "  if (stru.propagate) {\n"
01136         "    find_size_ulong(size, padding);\n"
01137         "    size += ACE_OS::strlen(stru.name.in()) + 1;\n"
01138         "    gen_find_size(stru.value, size, padding);\n"
01139         "  }\n";
01140     }
01141     {
01142       Function insertion("operator<<", "bool");
01143       insertion.addArg("strm", "Serializer&");
01144       insertion.addArg("stru", "const " + cxx + "&");
01145       insertion.endArgs();
01146       be_global->impl_ <<
01147         "  if (stru.propagate) {\n"
01148         "    return (strm << stru.name.in()) && (strm << stru.value);\n"
01149         "  }\n"
01150         "  return true;\n";
01151     }
01152     {
01153       Function extraction("operator>>", "bool");
01154       extraction.addArg("strm", "Serializer&");
01155       extraction.addArg("stru", cxx + "&");
01156       extraction.endArgs();
01157       be_global->impl_ <<
01158         "  stru.propagate = true;\n"
01159         "  return (strm >> stru.name.out()) && (strm >> stru.value);\n";
01160     }
01161     return true;
01162   }
01163 
01164   bool isProperty_t(const string& cxx)
01165   {
01166     return cxx == "DDS::Property_t";
01167   }
01168 
01169   bool genProperty_t(const string& cxx)
01170   {
01171     {
01172       Function find_size("gen_find_size", "void");
01173       find_size.addArg("stru", "const " + cxx + "&");
01174       find_size.addArg("size", "size_t&");
01175       find_size.addArg("padding", "size_t&");
01176       find_size.endArgs();
01177       be_global->impl_ <<
01178         "  if (stru.propagate) {\n"
01179         "    find_size_ulong(size, padding);\n"
01180         "    size += ACE_OS::strlen(stru.name.in()) + 1;\n"
01181         "    find_size_ulong(size, padding);\n"
01182         "    size += ACE_OS::strlen(stru.value.in()) + 1;\n"
01183         "  }\n";
01184     }
01185     {
01186       Function insertion("operator<<", "bool");
01187       insertion.addArg("strm", "Serializer&");
01188       insertion.addArg("stru", "const " + cxx + "&");
01189       insertion.endArgs();
01190       be_global->impl_ <<
01191         "  if (stru.propagate) {\n"
01192         "    return (strm << stru.name.in()) && (strm << stru.value.in());\n"
01193         "  }\n"
01194         "  return true;\n";
01195     }
01196     {
01197       Function extraction("operator>>", "bool");
01198       extraction.addArg("strm", "Serializer&");
01199       extraction.addArg("stru", cxx + "&");
01200       extraction.endArgs();
01201       be_global->impl_ <<
01202         "  stru.propagate = true;\n"
01203         "  return (strm >> stru.name.out()) && (strm >> stru.value.out());\n";
01204     }
01205     return true;
01206   }
01207 
01208   bool isPropertyQosPolicy(const string& cxx)
01209   {
01210     return cxx == "DDS::PropertyQosPolicy";
01211   }
01212 
01213   bool genPropertyQosPolicy(const string& cxx)
01214   {
01215     {
01216       Function find_size("gen_find_size", "void");
01217       find_size.addArg("stru", "const " + cxx + "&");
01218       find_size.addArg("size", "size_t&");
01219       find_size.addArg("padding", "size_t&");
01220       find_size.endArgs();
01221       be_global->impl_ <<
01222         "  gen_find_size(stru.value, size, padding);\n"
01223         "  gen_find_size(stru.binary_value, size, padding);\n";
01224     }
01225     {
01226       Function insertion("operator<<", "bool");
01227       insertion.addArg("strm", "Serializer&");
01228       insertion.addArg("stru", "const " + cxx + "&");
01229       insertion.endArgs();
01230       be_global->impl_ <<
01231         "  return (strm << stru.value)\n"
01232         "    && (strm << stru.binary_value);\n";
01233     }
01234     {
01235       Function extraction("operator>>", "bool");
01236       extraction.addArg("strm", "Serializer&");
01237       extraction.addArg("stru", cxx + "&");
01238       extraction.endArgs();
01239       be_global->impl_ <<
01240         "  if (!(strm >> stru.value)) {\n"
01241         "    return false;\n"
01242         "  }\n"
01243         "  if (!strm.length() || !strm.skip(0, 4) || !strm.length()) {\n"
01244         "    return true; // optional member missing\n"
01245         "  }\n"
01246         "  return strm >> stru.binary_value;\n";
01247     }
01248     return true;
01249   }
01250 
01251   bool isSecuritySubmessage(const string& cxx)
01252   {
01253     return cxx == "OpenDDS::RTPS::SecuritySubmessage";
01254   }
01255 
01256   bool genSecuritySubmessage(const string& cxx)
01257   {
01258     {
01259       Function find_size("gen_find_size", "void");
01260       find_size.addArg("stru", "const " + cxx + "&");
01261       find_size.addArg("size", "size_t&");
01262       find_size.addArg("padding", "size_t&");
01263       find_size.endArgs();
01264       be_global->impl_ <<
01265         "  gen_find_size(stru.smHeader, size, padding);\n"
01266         "  size += stru.content.length() * max_marshaled_size_octet();\n";
01267     }
01268     {
01269       Function insertion("operator<<", "bool");
01270       insertion.addArg("strm", "Serializer&");
01271       insertion.addArg("stru", "const " + cxx + "&");
01272       insertion.endArgs();
01273       be_global->impl_ <<
01274         "  return (strm << stru.smHeader)\n"
01275         "    && strm.write_octet_array(stru.content.get_buffer(), "
01276         "stru.content.length());\n";
01277     }
01278     {
01279       Function extraction("operator>>", "bool");
01280       extraction.addArg("strm", "Serializer&");
01281       extraction.addArg("stru", cxx + "&");
01282       extraction.endArgs();
01283       be_global->impl_ <<
01284         "  if (strm >> stru.smHeader) {\n"
01285         "    stru.content.length(stru.smHeader.submessageLength);\n"
01286         "    if (strm.read_octet_array(stru.content.get_buffer(),\n"
01287         "                              stru.smHeader.submessageLength)) {\n"
01288         "      return true;\n"
01289         "    }\n"
01290         "  }\n"
01291         "  return false;\n";
01292     }
01293     return true;
01294   }
01295 
01296   bool isRtpsSpecialStruct(const string& cxx)
01297   {
01298     return cxx == "OpenDDS::RTPS::SequenceNumberSet"
01299       || cxx == "OpenDDS::RTPS::FragmentNumberSet";
01300   }
01301 
01302   bool genRtpsSpecialStruct(const string& cxx)
01303   {
01304     {
01305       Function find_size("gen_find_size", "void");
01306       find_size.addArg("stru", "const " + cxx + "&");
01307       find_size.addArg("size", "size_t&");
01308       find_size.addArg("padding", "size_t&");
01309       find_size.endArgs();
01310       be_global->impl_ <<
01311         "  size += "
01312         << ((cxx == "OpenDDS::RTPS::SequenceNumberSet") ? "12" : "8")
01313         << " + 4 * ((stru.numBits + 31) / 32); // RTPS Custom\n";
01314     }
01315     {
01316       Function insertion("operator<<", "bool");
01317       insertion.addArg("strm", "Serializer&");
01318       insertion.addArg("stru", "const " + cxx + "&");
01319       insertion.endArgs();
01320       be_global->impl_ <<
01321         "  if ((strm << stru.bitmapBase) && (strm << stru.numBits)) {\n"
01322         "    const CORBA::ULong M = (stru.numBits + 31) / 32;\n"
01323         "    if (stru.bitmap.length() < M) {\n"
01324         "      return false;\n"
01325         "    }\n"
01326         "    for (CORBA::ULong i = 0; i < M; ++i) {\n"
01327         "      if (!(strm << stru.bitmap[i])) {\n"
01328         "        return false;\n"
01329         "      }\n"
01330         "    }\n"
01331         "    return true;\n"
01332         "  }\n"
01333         "  return false;\n";
01334     }
01335     {
01336       Function extraction("operator>>", "bool");
01337       extraction.addArg("strm", "Serializer&");
01338       extraction.addArg("stru", cxx + "&");
01339       extraction.endArgs();
01340       be_global->impl_ <<
01341         "  if ((strm >> stru.bitmapBase) && (strm >> stru.numBits)) {\n"
01342         "    const CORBA::ULong M = (stru.numBits + 31) / 32;\n"
01343         "    if (M > 8) {\n"
01344         "      return false;\n"
01345         "    }\n"
01346         "    stru.bitmap.length(M);\n"
01347         "    for (CORBA::ULong i = 0; i < M; ++i) {\n"
01348         "      if (!(strm >> stru.bitmap[i])) {\n"
01349         "        return false;\n"
01350         "      }\n"
01351         "    }\n"
01352         "    return true;\n"
01353         "  }\n"
01354         "  return false;\n";
01355     }
01356     return true;
01357   }
01358 
01359   struct RtpsFieldCustomizer {
01360 
01361     explicit RtpsFieldCustomizer(const string& cxx)
01362     {
01363       if (cxx == "OpenDDS::RTPS::DataSubmessage") {
01364         cst_["inlineQos"] = "stru.smHeader.flags & 2";
01365         iQosOffset_ = "16";
01366 
01367       } else if (cxx == "OpenDDS::RTPS::DataFragSubmessage") {
01368         cst_["inlineQos"] = "stru.smHeader.flags & 2";
01369         iQosOffset_ = "28";
01370 
01371       } else if (cxx == "OpenDDS::RTPS::InfoReplySubmessage") {
01372         cst_["multicastLocatorList"] = "stru.smHeader.flags & 2";
01373 
01374       } else if (cxx == "OpenDDS::RTPS::InfoTimestampSubmessage") {
01375         cst_["timestamp"] = "!(stru.smHeader.flags & 2)";
01376 
01377       } else if (cxx == "OpenDDS::RTPS::InfoReplyIp4Submessage") {
01378         cst_["multicastLocator"] = "stru.smHeader.flags & 2";
01379 
01380       } else if (cxx == "OpenDDS::RTPS::SubmessageHeader") {
01381         preamble_ =
01382           "  strm.swap_bytes(ACE_CDR_BYTE_ORDER != (stru.flags & 1));\n";
01383       }
01384     }
01385 
01386     string getConditional(const string& field_name) const
01387     {
01388       if (cst_.empty()) {
01389         return "";
01390       }
01391       std::map<string, string>::const_iterator it = cst_.find(field_name);
01392       if (it != cst_.end()) {
01393         return it->second;
01394       }
01395       return "";
01396     }
01397 
01398     string preFieldRead(const string& field_name) const
01399     {
01400       if (cst_.empty() || field_name != "inlineQos" || iQosOffset_.empty()) {
01401         return "";
01402       }
01403       return "strm.skip(stru.octetsToInlineQos - " + iQosOffset_ + ")\n"
01404         "    && ";
01405     }
01406 
01407     std::map<string, string> cst_;
01408     string iQosOffset_, preamble_;
01409   };
01410 }
01411 
01412 bool marshal_generator::gen_struct(AST_Structure* /* node */,
01413                                    UTL_ScopedName* name,
01414                                    const std::vector<AST_Field*>& fields,
01415                                    AST_Type::SIZE_TYPE /* size */,
01416                                    const char* /* repoid */)
01417 {
01418   NamespaceGuard ng;
01419   be_global->add_include("dds/DCPS/Serializer.h");
01420   string cxx = scoped(name); // name as a C++ class
01421 
01422   for (size_t i = 0; i < LENGTH(special_structs); ++i) {
01423     if (special_structs[i].check(cxx)) {
01424       return special_structs[i].gen(cxx);
01425     }
01426   }
01427 
01428   RtpsFieldCustomizer rtpsCustom(cxx);
01429   {
01430     Function find_size("gen_find_size", "void");
01431     find_size.addArg("stru", "const " + cxx + "&");
01432     find_size.addArg("size", "size_t&");
01433     find_size.addArg("padding", "size_t&");
01434     find_size.endArgs();
01435     string expr, intro;
01436     for (size_t i = 0; i < fields.size(); ++i) {
01437       AST_Type* field_type = resolveActualType(fields[i]->field_type());
01438       if (!field_type->in_main_file()
01439           && field_type->node_type() != AST_Decl::NT_pre_defined) {
01440         be_global->add_referenced(field_type->file_name().c_str());
01441       }
01442       const string field_name = fields[i]->local_name()->get_string(),
01443         cond = rtpsCustom.getConditional(field_name);
01444       if (!cond.empty()) {
01445         expr += "  if (" + cond + ") {\n  ";
01446       }
01447       expr += findSizeCommon(field_name, field_type, "stru", intro);
01448       if (!cond.empty()) {
01449         expr += "  }\n";
01450       }
01451     }
01452     be_global->impl_ << intro << expr;
01453   }
01454   {
01455     Function insertion("operator<<", "bool");
01456     insertion.addArg("strm", "Serializer&");
01457     insertion.addArg("stru", "const " + cxx + "&");
01458     insertion.endArgs();
01459     string expr, intro = rtpsCustom.preamble_;
01460     for (size_t i = 0; i < fields.size(); ++i) {
01461       if (i) expr += "\n    && ";
01462       const string field_name = fields[i]->local_name()->get_string(),
01463         cond = rtpsCustom.getConditional(field_name);
01464       if (!cond.empty()) {
01465         expr += "(!(" + cond + ") || ";
01466       }
01467       expr += streamCommon(field_name, fields[i]->field_type(),
01468                            "<< stru", intro, cxx);
01469       if (!cond.empty()) {
01470         expr += ")";
01471       }
01472     }
01473     be_global->impl_ << intro << "  return " << expr << ";\n";
01474   }
01475   {
01476     Function extraction("operator>>", "bool");
01477     extraction.addArg("strm", "Serializer&");
01478     extraction.addArg("stru", cxx + "&");
01479     extraction.endArgs();
01480     string expr, intro;
01481     for (size_t i = 0; i < fields.size(); ++i) {
01482       if (i) expr += "\n    && ";
01483       const string field_name = fields[i]->local_name()->get_string(),
01484         cond = rtpsCustom.getConditional(field_name);
01485       if (!cond.empty()) {
01486         expr += rtpsCustom.preFieldRead(field_name);
01487         expr += "(!(" + cond + ") || ";
01488       }
01489       expr += streamCommon(field_name, fields[i]->field_type(),
01490                            ">> stru", intro, cxx);
01491       if (!cond.empty()) {
01492         expr += ")";
01493       }
01494     }
01495     be_global->impl_ << intro << "  return " << expr << ";\n";
01496   }
01497 
01498   IDL_GlobalData::DCPS_Data_Type_Info* info = idl_global->is_dcps_type(name);
01499   // Only generate these methods if this is a DCPS type
01500   if (info != 0) {
01501     bool is_bounded_struct = true;
01502     for (size_t i = 0; i < fields.size(); ++i) {
01503       if (!is_bounded_type(fields[i]->field_type())) {
01504         is_bounded_struct = false;
01505         break;
01506       }
01507     }
01508     {
01509       Function max_marsh("gen_max_marshaled_size", "size_t");
01510       max_marsh.addArg("stru", "const " + cxx + "&");
01511       max_marsh.addArg("align", "bool");
01512       max_marsh.endArgs();
01513       if (is_bounded_struct) {
01514         size_t size = 0, padding = 0;
01515         for (size_t i = 0; i < fields.size(); ++i) {
01516           max_marshaled_size(fields[i]->field_type(), size, padding);
01517         }
01518         if (padding) {
01519           be_global->impl_
01520             << "  return align ? " << size + padding << " : " << size << ";\n";
01521         } else {
01522           be_global->impl_
01523             << "  return " << size << ";\n";
01524         }
01525       } else { // unbounded
01526         be_global->impl_
01527           << "  return 0;\n";
01528       }
01529     }
01530 
01531     // Generate key-related marshaling code
01532     bool bounded_key = true;
01533     IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01534     for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01535       string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01536       AST_Type* field_type = 0;
01537       try {
01538         field_type = find_type(fields, key_name);
01539       } catch (const string& error) {
01540         std::cerr << "ERROR: Invalid key specification for " << cxx
01541                   << " (" << key_name << "). " << error << std::endl;
01542         return false;
01543       }
01544       if (!is_bounded_type(field_type)) {
01545         bounded_key = false;
01546         break;
01547       }
01548     }
01549 
01550     {
01551       Function max_marsh("gen_max_marshaled_size", "size_t");
01552       max_marsh.addArg("stru", "KeyOnly<const " + cxx + ">");
01553       max_marsh.addArg("align", "bool");
01554       max_marsh.endArgs();
01555 
01556       if (bounded_key) {  // Only generate a size if the key is bounded
01557         IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01558         size_t size = 0, padding = 0;
01559         for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01560           string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01561           AST_Type* field_type = 0;
01562           try {
01563             field_type = find_type(fields, key_name);
01564           } catch (const string& error) {
01565             std::cerr << "ERROR: Invalid key specification for " << cxx
01566                       << " (" << key_name << "). " << error << std::endl;
01567             return false;
01568           }
01569           max_marshaled_size(field_type, size, padding);
01570         }
01571         if (padding) {
01572           be_global->impl_
01573             << "  return align ? " << size + padding << " : " << size << ";\n";
01574         } else {
01575           be_global->impl_
01576             << "  return " << size << ";\n";
01577         }
01578       } else { // unbounded
01579         be_global->impl_
01580           << "  return 0;\n";
01581       }
01582     }
01583 
01584     {
01585       Function find_size("gen_find_size", "void");
01586       find_size.addArg("stru", "KeyOnly<const " + cxx + ">");
01587       find_size.addArg("size", "size_t&");
01588       find_size.addArg("padding", "size_t&");
01589       find_size.endArgs();
01590       string expr, intro;
01591       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01592       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01593         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01594         AST_Type* field_type = 0;
01595         try {
01596           field_type = find_type(fields, key_name);
01597         } catch (const string& error) {
01598           std::cerr << "ERROR: Invalid key specification for " << cxx
01599                     << " (" << key_name << "). " << error << std::endl;
01600           return false;
01601         }
01602         expr += findSizeCommon(key_name, field_type, "stru.t", intro);
01603       }
01604       be_global->impl_ << intro << expr;
01605     }
01606 
01607     {
01608       Function insertion("operator<<", "bool");
01609       insertion.addArg("strm", "Serializer&");
01610       insertion.addArg("stru", "KeyOnly<const " + cxx + ">");
01611       insertion.endArgs();
01612 
01613       bool first = true;
01614       string expr, intro;
01615       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01616       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01617         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01618         AST_Type* field_type = 0;
01619         try {
01620           field_type = find_type(fields, key_name);
01621         } catch (const string& error) {
01622           std::cerr << "ERROR: Invalid key specification for " << cxx
01623                     << " (" << key_name << "). " << error << std::endl;
01624           return false;
01625         }
01626         if (first) first = false;
01627         else       expr += "\n    && ";
01628         expr += streamCommon(key_name, field_type, "<< stru.t", intro);
01629       }
01630       if (first) be_global->impl_ << intro << "  return true;\n";
01631       else be_global->impl_ << intro << "  return " << expr << ";\n";
01632     }
01633 
01634     {
01635       Function extraction("operator>>", "bool");
01636       extraction.addArg("strm", "Serializer&");
01637       extraction.addArg("stru", "KeyOnly<" + cxx + ">");
01638       extraction.endArgs();
01639 
01640       bool first = true;
01641       string expr, intro;
01642       IDL_GlobalData::DCPS_Data_Type_Info_Iter iter(info->key_list_);
01643       for (ACE_TString* kp = 0; iter.next(kp) != 0; iter.advance()) {
01644         string key_name = ACE_TEXT_ALWAYS_CHAR(kp->c_str());
01645         AST_Type* field_type = 0;
01646         try {
01647           field_type = find_type(fields, key_name);
01648         } catch (const string& error) {
01649           std::cerr << "ERROR: Invalid key specification for " << cxx
01650                     << " (" << key_name << "). " << error << std::endl;
01651           return false;
01652         }
01653         if (first) first = false;
01654         else       expr += "\n    && ";
01655         expr += streamCommon(key_name, field_type, ">> stru.t", intro);
01656       }
01657       if (first) be_global->impl_ << intro << "  return true;\n";
01658       else be_global->impl_ << intro << "  return " << expr << ";\n";
01659     }
01660 
01661     be_global->header_ <<
01662       "template <>\n"
01663       "struct MarshalTraits<" << cxx << "> {\n"
01664       "  static bool gen_is_bounded_size() { return " << (is_bounded_struct ? "true" : "false") << "; }\n"
01665       "  static bool gen_is_bounded_key_size() { return " << (bounded_key ? "true" : "false") << "; }\n"
01666       "};\n";
01667   }
01668 
01669   return true;
01670 }
01671 
01672 namespace {
01673 
01674   bool isRtpsSpecialUnion(const string& cxx)
01675   {
01676     return cxx == "OpenDDS::RTPS::Parameter"
01677       || cxx == "OpenDDS::RTPS::Submessage";
01678   }
01679 
01680   bool genRtpsParameter(AST_Type* discriminator,
01681                         const std::vector<AST_UnionBranch*>& branches)
01682   {
01683     const string cxx = "OpenDDS::RTPS::Parameter";
01684     {
01685       Function find_size("gen_find_size", "void");
01686       find_size.addArg("uni", "const " + cxx + "&");
01687       find_size.addArg("size", "size_t&");
01688       find_size.addArg("padding", "size_t&");
01689       find_size.endArgs();
01690       generateSwitchForUnion("uni._d()", findSizeCommon, branches,
01691                              discriminator, "", "", cxx.c_str());
01692       be_global->impl_ <<
01693         "  size += 4; // parameterId & length\n";
01694     }
01695     {
01696       Function insertion("operator<<", "bool");
01697       insertion.addArg("outer_strm", "Serializer&");
01698       insertion.addArg("uni", "const " + cxx + "&");
01699       insertion.endArgs();
01700       be_global->impl_ <<
01701         "  if (!(outer_strm << uni._d())) {\n"
01702         "    return false;\n"
01703         "  }\n"
01704         "  size_t size = 0, pad = 0;\n"
01705         "  gen_find_size(uni, size, pad);\n"
01706         "  size -= 4; // parameterId & length\n"
01707         "  const size_t post_pad = 4 - ((size + pad) % 4);\n"
01708         "  const size_t total = size + pad + ((post_pad < 4) ? post_pad : 0);\n"
01709         "  if (size + pad > ACE_UINT16_MAX || "
01710         "!(outer_strm << ACE_CDR::UShort(total))) {\n"
01711         "    return false;\n"
01712         "  }\n"
01713         "  ACE_Message_Block param(size + pad);\n"
01714         "  Serializer strm(&param, outer_strm.swap_bytes(), "
01715         "outer_strm.alignment());\n"
01716         "  if (!insertParamData(strm, uni)) {\n"
01717         "    return false;\n"
01718         "  }\n"
01719         "  const ACE_CDR::Octet* data = reinterpret_cast<ACE_CDR::Octet*>("
01720         "param.rd_ptr());\n"
01721         "  if (!outer_strm.write_octet_array(data, ACE_CDR::ULong(param.length()))) {\n"
01722         "    return false;\n"
01723         "  }\n"
01724         "  if (post_pad < 4 && outer_strm.alignment() != "
01725         "Serializer::ALIGN_NONE) {\n"
01726         "    static const ACE_CDR::Octet padding[3] = {0};\n"
01727         "    return outer_strm.write_octet_array(padding, "
01728         "ACE_CDR::ULong(post_pad));\n"
01729         "  }\n"
01730         "  return true;\n";
01731     }
01732     {
01733       Function insertData("insertParamData", "bool");
01734       insertData.addArg("strm", "Serializer&");
01735       insertData.addArg("uni", "const " + cxx + "&");
01736       insertData.endArgs();
01737       generateSwitchForUnion("uni._d()", streamCommon, branches, discriminator,
01738                              "return", "<< ", cxx.c_str());
01739     }
01740     {
01741       Function extraction("operator>>", "bool");
01742       extraction.addArg("outer_strm", "Serializer&");
01743       extraction.addArg("uni", cxx + "&");
01744       extraction.endArgs();
01745       be_global->impl_ <<
01746         "  ACE_CDR::UShort disc, size;\n"
01747         "  if (!(outer_strm >> disc) || !(outer_strm >> size)) {\n"
01748         "    return false;\n"
01749         "  }\n"
01750         "  if (disc == OpenDDS::RTPS::PID_SENTINEL) {\n"
01751         "    uni._d(OpenDDS::RTPS::PID_SENTINEL);\n"
01752         "    return true;\n"
01753         "  }\n"
01754         "  ACE_Message_Block param(size);\n"
01755         "  ACE_CDR::Octet* data = reinterpret_cast<ACE_CDR::Octet*>("
01756         "param.wr_ptr());\n"
01757         "  if (!outer_strm.read_octet_array(data, size)) {\n"
01758         "    return false;\n"
01759         "  }\n"
01760         "  param.wr_ptr(size);\n"
01761         "  Serializer strm(&param, outer_strm.swap_bytes(), "
01762         "Serializer::ALIGN_CDR);\n"
01763         "  switch (disc) {\n";
01764       generateSwitchBody(streamCommon, branches, discriminator,
01765                          "return", ">> ", cxx.c_str(), true);
01766       be_global->impl_ <<
01767         "  default:\n"
01768         "    {\n"
01769         "      uni.unknown_data(DDS::OctetSeq(size));\n"
01770         "      uni.unknown_data().length(size);\n"
01771         "      std::memcpy(uni.unknown_data().get_buffer(), data, size);\n"
01772         "      uni._d(disc);\n"
01773         "    }\n"
01774         "  }\n"
01775         "  return true;\n";
01776     }
01777     return true;
01778   }
01779 
01780   bool genRtpsSubmessage(AST_Type* discriminator,
01781                          const std::vector<AST_UnionBranch*>& branches)
01782   {
01783     const string cxx = "OpenDDS::RTPS::Submessage";
01784     {
01785       Function find_size("gen_find_size", "void");
01786       find_size.addArg("uni", "const " + cxx + "&");
01787       find_size.addArg("size", "size_t&");
01788       find_size.addArg("padding", "size_t&");
01789       find_size.endArgs();
01790       generateSwitchForUnion("uni._d()", findSizeCommon, branches,
01791                              discriminator, "", "", cxx.c_str());
01792     }
01793     {
01794       Function insertion("operator<<", "bool");
01795       insertion.addArg("strm", "Serializer&");
01796       insertion.addArg("uni", "const " + cxx + "&");
01797       insertion.endArgs();
01798       generateSwitchForUnion("uni._d()", streamCommon, branches,
01799                              discriminator, "return", "<< ", cxx.c_str());
01800     }
01801     {
01802       Function insertion("operator>>", "bool");
01803       insertion.addArg("strm", "Serializer&");
01804       insertion.addArg("uni", cxx + "&");
01805       insertion.endArgs();
01806       be_global->impl_ << "  // unused\n  return false;\n";
01807     }
01808     return true;
01809   }
01810 
01811   bool genRtpsSpecialUnion(const string& cxx, AST_Type* discriminator,
01812                            const std::vector<AST_UnionBranch*>& branches)
01813   {
01814     if (cxx == "OpenDDS::RTPS::Parameter") {
01815       return genRtpsParameter(discriminator, branches);
01816     } else if (cxx == "OpenDDS::RTPS::Submessage") {
01817       return genRtpsSubmessage(discriminator, branches);
01818     } else {
01819       return false;
01820     }
01821   }
01822 }
01823 
01824 bool marshal_generator::gen_union(AST_Union*, UTL_ScopedName* name,
01825    const std::vector<AST_UnionBranch*>& branches, AST_Type* discriminator,
01826    const char*)
01827 {
01828   NamespaceGuard ng;
01829   be_global->add_include("dds/DCPS/Serializer.h");
01830   string cxx = scoped(name); // name as a C++ class
01831 
01832   for (size_t i = 0; i < LENGTH(special_unions); ++i) {
01833     if (special_unions[i].check(cxx)) {
01834       return special_unions[i].gen(cxx, discriminator, branches);
01835     }
01836   }
01837 
01838   const string wrap_out = getWrapper("uni._d()", discriminator, WD_OUTPUT);
01839   {
01840     Function find_size("gen_find_size", "void");
01841     find_size.addArg("uni", "const " + cxx + "&");
01842     find_size.addArg("size", "size_t&");
01843     find_size.addArg("padding", "size_t&");
01844     find_size.endArgs();
01845     const string align = getAlignment(discriminator);
01846     if (!align.empty()) {
01847       be_global->impl_ <<
01848         "  if ((size + padding) % " << align << ") {\n"
01849         "    padding += " << align << " - ((size + padding) % " << align
01850         << ");\n"
01851         "  }\n";
01852     }
01853     be_global->impl_ <<
01854       "  size += gen_max_marshaled_size(" << wrap_out << ");\n";
01855     generateSwitchForUnion("uni._d()", findSizeCommon, branches, discriminator,
01856                            "", "", cxx.c_str());
01857   }
01858   {
01859     Function insertion("operator<<", "bool");
01860     insertion.addArg("strm", "Serializer&");
01861     insertion.addArg("uni", "const " + cxx + "&");
01862     insertion.endArgs();
01863     be_global->impl_ <<
01864       streamAndCheck("<< " + wrap_out);
01865     if (generateSwitchForUnion("uni._d()", streamCommon, branches,
01866                                discriminator, "return", "<< ", cxx.c_str())) {
01867       be_global->impl_ <<
01868         "  return true;\n";
01869     }
01870   }
01871   {
01872     Function extraction("operator>>", "bool");
01873     extraction.addArg("strm", "Serializer&");
01874     extraction.addArg("uni", cxx + "&");
01875     extraction.endArgs();
01876     be_global->impl_ <<
01877       "  " << scoped(discriminator->name()) << " disc;\n" <<
01878       streamAndCheck(">> " + getWrapper("disc", discriminator, WD_INPUT));
01879     if (generateSwitchForUnion("disc", streamCommon, branches,
01880                                discriminator, "if", ">> ", cxx.c_str())) {
01881       be_global->impl_ <<
01882         "  return true;\n";
01883     }
01884   }
01885   return true;
01886 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1