xref: /aosp_15_r20/external/openscreen/tools/cddl/codegen.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "tools/cddl/codegen.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <cinttypes>
8*3f982cf4SFabien Sanglard #include <iostream>
9*3f982cf4SFabien Sanglard #include <limits>
10*3f982cf4SFabien Sanglard #include <memory>
11*3f982cf4SFabien Sanglard #include <set>
12*3f982cf4SFabien Sanglard #include <sstream>
13*3f982cf4SFabien Sanglard #include <string>
14*3f982cf4SFabien Sanglard #include <utility>
15*3f982cf4SFabien Sanglard #include <vector>
16*3f982cf4SFabien Sanglard 
17*3f982cf4SFabien Sanglard #include "absl/algorithm/container.h"
18*3f982cf4SFabien Sanglard #include "absl/types/optional.h"
19*3f982cf4SFabien Sanglard 
20*3f982cf4SFabien Sanglard // Convert '-' to '_' to use a CDDL identifier as a C identifier.
ToUnderscoreId(const std::string & x)21*3f982cf4SFabien Sanglard std::string ToUnderscoreId(const std::string& x) {
22*3f982cf4SFabien Sanglard   std::string result(x);
23*3f982cf4SFabien Sanglard   for (auto& c : result) {
24*3f982cf4SFabien Sanglard     if (c == '-')
25*3f982cf4SFabien Sanglard       c = '_';
26*3f982cf4SFabien Sanglard   }
27*3f982cf4SFabien Sanglard   return result;
28*3f982cf4SFabien Sanglard }
29*3f982cf4SFabien Sanglard 
30*3f982cf4SFabien Sanglard // Convert a CDDL identifier to camel case for use as a C typename.  E.g.
31*3f982cf4SFabien Sanglard // presentation-connection-message to PresentationConnectionMessage.
ToCamelCase(const std::string & x)32*3f982cf4SFabien Sanglard std::string ToCamelCase(const std::string& x) {
33*3f982cf4SFabien Sanglard   std::string result(x);
34*3f982cf4SFabien Sanglard   result[0] = toupper(result[0]);
35*3f982cf4SFabien Sanglard   size_t new_size = 1;
36*3f982cf4SFabien Sanglard   size_t result_size = result.size();
37*3f982cf4SFabien Sanglard   for (size_t i = 1; i < result_size; ++i, ++new_size) {
38*3f982cf4SFabien Sanglard     if (result[i] == '-') {
39*3f982cf4SFabien Sanglard       ++i;
40*3f982cf4SFabien Sanglard       if (i < result_size)
41*3f982cf4SFabien Sanglard         result[new_size] = toupper(result[i]);
42*3f982cf4SFabien Sanglard     } else {
43*3f982cf4SFabien Sanglard       result[new_size] = result[i];
44*3f982cf4SFabien Sanglard     }
45*3f982cf4SFabien Sanglard   }
46*3f982cf4SFabien Sanglard   result.resize(new_size);
47*3f982cf4SFabien Sanglard   return result;
48*3f982cf4SFabien Sanglard }
49*3f982cf4SFabien Sanglard 
50*3f982cf4SFabien Sanglard // Returns a string which represents the C++ type of |cpp_type|.  Returns an
51*3f982cf4SFabien Sanglard // empty string if there is no valid representation for |cpp_type| (e.g. a
52*3f982cf4SFabien Sanglard // vector with an invalid element type).
CppTypeToString(const CppType & cpp_type)53*3f982cf4SFabien Sanglard std::string CppTypeToString(const CppType& cpp_type) {
54*3f982cf4SFabien Sanglard   switch (cpp_type.which) {
55*3f982cf4SFabien Sanglard     case CppType::Which::kUint64:
56*3f982cf4SFabien Sanglard       return "uint64_t";
57*3f982cf4SFabien Sanglard     case CppType::Which::kString:
58*3f982cf4SFabien Sanglard       return "std::string";
59*3f982cf4SFabien Sanglard     case CppType::Which::kBytes: {
60*3f982cf4SFabien Sanglard       if (cpp_type.bytes_type.fixed_size) {
61*3f982cf4SFabien Sanglard         std::string size_string =
62*3f982cf4SFabien Sanglard             std::to_string(cpp_type.bytes_type.fixed_size.value());
63*3f982cf4SFabien Sanglard         return "std::array<uint8_t, " + size_string + ">";
64*3f982cf4SFabien Sanglard       } else {
65*3f982cf4SFabien Sanglard         return "std::vector<uint8_t>";
66*3f982cf4SFabien Sanglard       }
67*3f982cf4SFabien Sanglard     }
68*3f982cf4SFabien Sanglard     case CppType::Which::kVector: {
69*3f982cf4SFabien Sanglard       std::string element_string =
70*3f982cf4SFabien Sanglard           CppTypeToString(*cpp_type.vector_type.element_type);
71*3f982cf4SFabien Sanglard       if (element_string.empty())
72*3f982cf4SFabien Sanglard         return std::string();
73*3f982cf4SFabien Sanglard       return "std::vector<" + element_string + ">";
74*3f982cf4SFabien Sanglard     }
75*3f982cf4SFabien Sanglard     case CppType::Which::kEnum:
76*3f982cf4SFabien Sanglard       return ToCamelCase(cpp_type.name);
77*3f982cf4SFabien Sanglard     case CppType::Which::kStruct:
78*3f982cf4SFabien Sanglard       return ToCamelCase(cpp_type.name);
79*3f982cf4SFabien Sanglard     case CppType::Which::kTaggedType:
80*3f982cf4SFabien Sanglard       return CppTypeToString(*cpp_type.tagged_type.real_type);
81*3f982cf4SFabien Sanglard     default:
82*3f982cf4SFabien Sanglard       return std::string();
83*3f982cf4SFabien Sanglard   }
84*3f982cf4SFabien Sanglard }
85*3f982cf4SFabien Sanglard 
WriteEnumEqualityOperatorSwitchCases(int fd,const CppType & parent,std::string child_name,std::string parent_name)86*3f982cf4SFabien Sanglard bool WriteEnumEqualityOperatorSwitchCases(int fd,
87*3f982cf4SFabien Sanglard                                           const CppType& parent,
88*3f982cf4SFabien Sanglard                                           std::string child_name,
89*3f982cf4SFabien Sanglard                                           std::string parent_name) {
90*3f982cf4SFabien Sanglard   for (const auto& x : parent.enum_type.members) {
91*3f982cf4SFabien Sanglard     std::string enum_value = "k" + ToCamelCase(x.first);
92*3f982cf4SFabien Sanglard     dprintf(fd, "    case %s::%s: return parent == %s::%s;\n",
93*3f982cf4SFabien Sanglard             child_name.c_str(), enum_value.c_str(), parent_name.c_str(),
94*3f982cf4SFabien Sanglard             enum_value.c_str());
95*3f982cf4SFabien Sanglard   }
96*3f982cf4SFabien Sanglard 
97*3f982cf4SFabien Sanglard   return absl::c_all_of(parent.enum_type.sub_members,
98*3f982cf4SFabien Sanglard                         [&fd, &child_name, &parent_name](CppType* new_parent) {
99*3f982cf4SFabien Sanglard                           return WriteEnumEqualityOperatorSwitchCases(
100*3f982cf4SFabien Sanglard                               fd, *new_parent, child_name, parent_name);
101*3f982cf4SFabien Sanglard                         });
102*3f982cf4SFabien Sanglard }
103*3f982cf4SFabien Sanglard 
104*3f982cf4SFabien Sanglard // Write the equality operators for comparing an enum and its parent types.
WriteEnumEqualityOperator(int fd,const CppType & type,const CppType & parent)105*3f982cf4SFabien Sanglard bool WriteEnumEqualityOperator(int fd,
106*3f982cf4SFabien Sanglard                                const CppType& type,
107*3f982cf4SFabien Sanglard                                const CppType& parent) {
108*3f982cf4SFabien Sanglard   std::string name = ToCamelCase(type.name);
109*3f982cf4SFabien Sanglard   std::string parent_name = ToCamelCase(parent.name);
110*3f982cf4SFabien Sanglard 
111*3f982cf4SFabien Sanglard   // Define type == parentType.
112*3f982cf4SFabien Sanglard   dprintf(fd, "inline bool operator==(const %s& child, const %s& parent) {\n",
113*3f982cf4SFabien Sanglard           name.c_str(), parent_name.c_str());
114*3f982cf4SFabien Sanglard   dprintf(fd, "  switch (child) {\n");
115*3f982cf4SFabien Sanglard   if (!WriteEnumEqualityOperatorSwitchCases(fd, parent, name, parent_name)) {
116*3f982cf4SFabien Sanglard     return false;
117*3f982cf4SFabien Sanglard   }
118*3f982cf4SFabien Sanglard   dprintf(fd, "    default: return false;\n");
119*3f982cf4SFabien Sanglard   dprintf(fd, "  }\n}\n");
120*3f982cf4SFabien Sanglard 
121*3f982cf4SFabien Sanglard   // Define parentType == type.
122*3f982cf4SFabien Sanglard   dprintf(fd, "inline bool operator==(const %s& parent, const %s& child) {\n",
123*3f982cf4SFabien Sanglard           parent_name.c_str(), name.c_str());
124*3f982cf4SFabien Sanglard   dprintf(fd, "  return child == parent;\n}\n");
125*3f982cf4SFabien Sanglard 
126*3f982cf4SFabien Sanglard   // Define type != parentType.
127*3f982cf4SFabien Sanglard   dprintf(fd, "inline bool operator!=(const %s& child, const %s& parent) {\n",
128*3f982cf4SFabien Sanglard           name.c_str(), parent_name.c_str());
129*3f982cf4SFabien Sanglard   dprintf(fd, "  return !(child == parent);\n}\n");
130*3f982cf4SFabien Sanglard 
131*3f982cf4SFabien Sanglard   // Define parentType != type.
132*3f982cf4SFabien Sanglard   dprintf(fd, "inline bool operator!=(const %s& parent, const %s& child) {\n",
133*3f982cf4SFabien Sanglard           parent_name.c_str(), name.c_str());
134*3f982cf4SFabien Sanglard   dprintf(fd, "  return !(parent == child);\n}\n");
135*3f982cf4SFabien Sanglard 
136*3f982cf4SFabien Sanglard   return true;
137*3f982cf4SFabien Sanglard }
138*3f982cf4SFabien Sanglard 
WriteEnumStreamOperatorSwitchCases(int fd,const CppType & type,std::string name)139*3f982cf4SFabien Sanglard bool WriteEnumStreamOperatorSwitchCases(int fd,
140*3f982cf4SFabien Sanglard                                         const CppType& type,
141*3f982cf4SFabien Sanglard                                         std::string name) {
142*3f982cf4SFabien Sanglard   for (const auto& x : type.enum_type.members) {
143*3f982cf4SFabien Sanglard     std::string enum_value = "k" + ToCamelCase(x.first);
144*3f982cf4SFabien Sanglard     dprintf(fd, "    case %s::%s: os << \"%s\"; break;\n", name.c_str(),
145*3f982cf4SFabien Sanglard             enum_value.c_str(), enum_value.c_str());
146*3f982cf4SFabien Sanglard   }
147*3f982cf4SFabien Sanglard 
148*3f982cf4SFabien Sanglard   return absl::c_all_of(
149*3f982cf4SFabien Sanglard       type.enum_type.sub_members, [&fd, &name](CppType* parent) {
150*3f982cf4SFabien Sanglard         return WriteEnumStreamOperatorSwitchCases(fd, *parent, name);
151*3f982cf4SFabien Sanglard       });
152*3f982cf4SFabien Sanglard }
153*3f982cf4SFabien Sanglard 
WriteEnumOperators(int fd,const CppType & type)154*3f982cf4SFabien Sanglard bool WriteEnumOperators(int fd, const CppType& type) {
155*3f982cf4SFabien Sanglard   // Write << operator.
156*3f982cf4SFabien Sanglard   std::string name = ToCamelCase(type.name);
157*3f982cf4SFabien Sanglard   dprintf(
158*3f982cf4SFabien Sanglard       fd,
159*3f982cf4SFabien Sanglard       "inline std::ostream& operator<<(std::ostream& os, const %s& val) {\n",
160*3f982cf4SFabien Sanglard       name.c_str());
161*3f982cf4SFabien Sanglard   dprintf(fd, "  switch (val) {\n");
162*3f982cf4SFabien Sanglard   if (!WriteEnumStreamOperatorSwitchCases(fd, type, name)) {
163*3f982cf4SFabien Sanglard     return false;
164*3f982cf4SFabien Sanglard   }
165*3f982cf4SFabien Sanglard   dprintf(fd,
166*3f982cf4SFabien Sanglard           "    default: os << \"Unknown Value: \" << static_cast<int>(val);"
167*3f982cf4SFabien Sanglard           "\n      break;\n    }\n  return os;\n}\n");
168*3f982cf4SFabien Sanglard 
169*3f982cf4SFabien Sanglard   // Write equality operators.
170*3f982cf4SFabien Sanglard   return absl::c_all_of(type.enum_type.sub_members,
171*3f982cf4SFabien Sanglard                         [&fd, &type](CppType* parent) {
172*3f982cf4SFabien Sanglard                           return WriteEnumEqualityOperator(fd, type, *parent);
173*3f982cf4SFabien Sanglard                         });
174*3f982cf4SFabien Sanglard }
175*3f982cf4SFabien Sanglard 
176*3f982cf4SFabien Sanglard // Writes the equality operator for a specific Discriminated Union.
WriteDiscriminatedUnionEqualityOperator(int fd,const CppType & type,const std::string & name_prefix="")177*3f982cf4SFabien Sanglard bool WriteDiscriminatedUnionEqualityOperator(
178*3f982cf4SFabien Sanglard     int fd,
179*3f982cf4SFabien Sanglard     const CppType& type,
180*3f982cf4SFabien Sanglard     const std::string& name_prefix = "") {
181*3f982cf4SFabien Sanglard   const std::string name = name_prefix + ToCamelCase(type.name);
182*3f982cf4SFabien Sanglard   dprintf(fd, "\nbool %s::operator==(const %s& other) const {\n", name.c_str(),
183*3f982cf4SFabien Sanglard           name.c_str());
184*3f982cf4SFabien Sanglard   dprintf(fd, "  return this->which == other.which");
185*3f982cf4SFabien Sanglard   for (auto* union_member : type.discriminated_union.members) {
186*3f982cf4SFabien Sanglard     dprintf(fd, " &&\n         ");
187*3f982cf4SFabien Sanglard     switch (union_member->which) {
188*3f982cf4SFabien Sanglard       case CppType::Which::kUint64:
189*3f982cf4SFabien Sanglard         dprintf(fd,
190*3f982cf4SFabien Sanglard                 "(this->which != Which::kUint64 || this->uint == other.uint)");
191*3f982cf4SFabien Sanglard         break;
192*3f982cf4SFabien Sanglard       case CppType::Which::kString:
193*3f982cf4SFabien Sanglard         dprintf(fd,
194*3f982cf4SFabien Sanglard                 "(this->which != Which::kString || this->str == other.str)");
195*3f982cf4SFabien Sanglard         break;
196*3f982cf4SFabien Sanglard       case CppType::Which::kBytes:
197*3f982cf4SFabien Sanglard         dprintf(fd,
198*3f982cf4SFabien Sanglard                 "(this->which != Which::kBytes || this->bytes == other.bytes)");
199*3f982cf4SFabien Sanglard         break;
200*3f982cf4SFabien Sanglard       default:
201*3f982cf4SFabien Sanglard         return false;
202*3f982cf4SFabien Sanglard     }
203*3f982cf4SFabien Sanglard   }
204*3f982cf4SFabien Sanglard   dprintf(fd, ";\n}\n");
205*3f982cf4SFabien Sanglard   dprintf(fd, "bool %s::operator!=(const %s& other) const {\n", name.c_str(),
206*3f982cf4SFabien Sanglard           name.c_str());
207*3f982cf4SFabien Sanglard   dprintf(fd, "  return !(*this == other);\n}\n");
208*3f982cf4SFabien Sanglard   return true;
209*3f982cf4SFabien Sanglard }
210*3f982cf4SFabien Sanglard 
211*3f982cf4SFabien Sanglard // Writes the equality operator for a specific C++ struct.
WriteStructEqualityOperator(int fd,const CppType & type,const std::string & name_prefix="")212*3f982cf4SFabien Sanglard bool WriteStructEqualityOperator(int fd,
213*3f982cf4SFabien Sanglard                                  const CppType& type,
214*3f982cf4SFabien Sanglard                                  const std::string& name_prefix = "") {
215*3f982cf4SFabien Sanglard   const std::string name = name_prefix + ToCamelCase(type.name);
216*3f982cf4SFabien Sanglard   dprintf(fd, "\nbool %s::operator==(const %s& other) const {\n", name.c_str(),
217*3f982cf4SFabien Sanglard           name.c_str());
218*3f982cf4SFabien Sanglard   for (size_t i = 0; i < type.struct_type.members.size(); i++) {
219*3f982cf4SFabien Sanglard     if (i == 0) {
220*3f982cf4SFabien Sanglard       dprintf(fd, "  return ");
221*3f982cf4SFabien Sanglard     } else {
222*3f982cf4SFabien Sanglard       dprintf(fd, " &&\n         ");
223*3f982cf4SFabien Sanglard     }
224*3f982cf4SFabien Sanglard     auto name = ToUnderscoreId(type.struct_type.members[i].name);
225*3f982cf4SFabien Sanglard     dprintf(fd, "this->%s == other.%s", name.c_str(), name.c_str());
226*3f982cf4SFabien Sanglard   }
227*3f982cf4SFabien Sanglard   dprintf(fd, ";\n}");
228*3f982cf4SFabien Sanglard   dprintf(fd, "\nbool %s::operator!=(const %s& other) const {\n", name.c_str(),
229*3f982cf4SFabien Sanglard           name.c_str());
230*3f982cf4SFabien Sanglard   dprintf(fd, "  return !(*this == other);\n}\n");
231*3f982cf4SFabien Sanglard   std::string new_prefix = name_prefix + ToCamelCase(type.name) + "::";
232*3f982cf4SFabien Sanglard   for (const auto& x : type.struct_type.members) {
233*3f982cf4SFabien Sanglard     // NOTE: Don't need to call recursively on struct members, since all structs
234*3f982cf4SFabien Sanglard     // are handled in the calling method.
235*3f982cf4SFabien Sanglard     if (x.type->which == CppType::Which::kDiscriminatedUnion) {
236*3f982cf4SFabien Sanglard       if (!WriteDiscriminatedUnionEqualityOperator(fd, *x.type, new_prefix)) {
237*3f982cf4SFabien Sanglard         return false;
238*3f982cf4SFabien Sanglard       }
239*3f982cf4SFabien Sanglard     }
240*3f982cf4SFabien Sanglard   }
241*3f982cf4SFabien Sanglard   return true;
242*3f982cf4SFabien Sanglard }
243*3f982cf4SFabien Sanglard 
244*3f982cf4SFabien Sanglard // Write the C++ struct member definitions of every type in |members| to the
245*3f982cf4SFabien Sanglard // file descriptor |fd|.
WriteStructMembers(int fd,const std::string & name,const std::vector<CppType::Struct::CppMember> & members)246*3f982cf4SFabien Sanglard bool WriteStructMembers(
247*3f982cf4SFabien Sanglard     int fd,
248*3f982cf4SFabien Sanglard     const std::string& name,
249*3f982cf4SFabien Sanglard     const std::vector<CppType::Struct::CppMember>& members) {
250*3f982cf4SFabien Sanglard   for (const auto& x : members) {
251*3f982cf4SFabien Sanglard     std::string type_string;
252*3f982cf4SFabien Sanglard     switch (x.type->which) {
253*3f982cf4SFabien Sanglard       case CppType::Which::kStruct: {
254*3f982cf4SFabien Sanglard         if (x.type->struct_type.key_type ==
255*3f982cf4SFabien Sanglard             CppType::Struct::KeyType::kPlainGroup) {
256*3f982cf4SFabien Sanglard           if (!WriteStructMembers(fd, x.type->name,
257*3f982cf4SFabien Sanglard                                   x.type->struct_type.members))
258*3f982cf4SFabien Sanglard             return false;
259*3f982cf4SFabien Sanglard           continue;
260*3f982cf4SFabien Sanglard         } else {
261*3f982cf4SFabien Sanglard           type_string = ToCamelCase(x.name);
262*3f982cf4SFabien Sanglard         }
263*3f982cf4SFabien Sanglard       } break;
264*3f982cf4SFabien Sanglard       case CppType::Which::kOptional: {
265*3f982cf4SFabien Sanglard         // TODO(btolsch): Make this optional<T> when one lands.
266*3f982cf4SFabien Sanglard         dprintf(fd, "  bool has_%s;\n", ToUnderscoreId(x.name).c_str());
267*3f982cf4SFabien Sanglard         type_string = CppTypeToString(*x.type->optional_type);
268*3f982cf4SFabien Sanglard       } break;
269*3f982cf4SFabien Sanglard       case CppType::Which::kDiscriminatedUnion: {
270*3f982cf4SFabien Sanglard         std::string cid = ToUnderscoreId(x.name);
271*3f982cf4SFabien Sanglard         type_string = ToCamelCase(x.name);
272*3f982cf4SFabien Sanglard         dprintf(fd, "  struct %s {\n", type_string.c_str());
273*3f982cf4SFabien Sanglard         dprintf(fd, "    %s();\n    ~%s();\n\n", type_string.c_str(),
274*3f982cf4SFabien Sanglard                 type_string.c_str());
275*3f982cf4SFabien Sanglard 
276*3f982cf4SFabien Sanglard         dprintf(fd, "  bool operator==(const %s& other) const;\n",
277*3f982cf4SFabien Sanglard                 type_string.c_str());
278*3f982cf4SFabien Sanglard         dprintf(fd, "  bool operator!=(const %s& other) const;\n\n",
279*3f982cf4SFabien Sanglard                 type_string.c_str());
280*3f982cf4SFabien Sanglard         dprintf(fd, "  enum class Which {\n");
281*3f982cf4SFabien Sanglard         for (auto* union_member : x.type->discriminated_union.members) {
282*3f982cf4SFabien Sanglard           switch (union_member->which) {
283*3f982cf4SFabien Sanglard             case CppType::Which::kUint64:
284*3f982cf4SFabien Sanglard               dprintf(fd, "    kUint64,\n");
285*3f982cf4SFabien Sanglard               break;
286*3f982cf4SFabien Sanglard             case CppType::Which::kString:
287*3f982cf4SFabien Sanglard               dprintf(fd, "    kString,\n");
288*3f982cf4SFabien Sanglard               break;
289*3f982cf4SFabien Sanglard             case CppType::Which::kBytes:
290*3f982cf4SFabien Sanglard               dprintf(fd, "    kBytes,\n");
291*3f982cf4SFabien Sanglard               break;
292*3f982cf4SFabien Sanglard             default:
293*3f982cf4SFabien Sanglard               return false;
294*3f982cf4SFabien Sanglard           }
295*3f982cf4SFabien Sanglard         }
296*3f982cf4SFabien Sanglard         dprintf(fd, "    kUninitialized,\n");
297*3f982cf4SFabien Sanglard         dprintf(fd, "  } which;\n");
298*3f982cf4SFabien Sanglard         dprintf(fd, "  union {\n");
299*3f982cf4SFabien Sanglard         for (auto* union_member : x.type->discriminated_union.members) {
300*3f982cf4SFabien Sanglard           switch (union_member->which) {
301*3f982cf4SFabien Sanglard             case CppType::Which::kUint64:
302*3f982cf4SFabien Sanglard               dprintf(fd, "    uint64_t uint;\n");
303*3f982cf4SFabien Sanglard               break;
304*3f982cf4SFabien Sanglard             case CppType::Which::kString:
305*3f982cf4SFabien Sanglard               dprintf(fd, "    std::string str;\n");
306*3f982cf4SFabien Sanglard               break;
307*3f982cf4SFabien Sanglard             case CppType::Which::kBytes:
308*3f982cf4SFabien Sanglard               dprintf(fd, "    std::vector<uint8_t> bytes;\n");
309*3f982cf4SFabien Sanglard               break;
310*3f982cf4SFabien Sanglard             default:
311*3f982cf4SFabien Sanglard               return false;
312*3f982cf4SFabien Sanglard           }
313*3f982cf4SFabien Sanglard         }
314*3f982cf4SFabien Sanglard         // NOTE: This member allows the union to be easily constructed in an
315*3f982cf4SFabien Sanglard         // effectively uninitialized state.  Its value should never be used.
316*3f982cf4SFabien Sanglard         dprintf(fd, "    bool placeholder_;\n");
317*3f982cf4SFabien Sanglard         dprintf(fd, "  };\n");
318*3f982cf4SFabien Sanglard         dprintf(fd, "  };\n");
319*3f982cf4SFabien Sanglard       } break;
320*3f982cf4SFabien Sanglard       default:
321*3f982cf4SFabien Sanglard         type_string = CppTypeToString(*x.type);
322*3f982cf4SFabien Sanglard         break;
323*3f982cf4SFabien Sanglard     }
324*3f982cf4SFabien Sanglard     if (type_string.empty())
325*3f982cf4SFabien Sanglard       return false;
326*3f982cf4SFabien Sanglard     dprintf(fd, "  %s %s;\n", type_string.c_str(),
327*3f982cf4SFabien Sanglard             ToUnderscoreId(x.name).c_str());
328*3f982cf4SFabien Sanglard   }
329*3f982cf4SFabien Sanglard   return true;
330*3f982cf4SFabien Sanglard }
331*3f982cf4SFabien Sanglard 
WriteEnumMembers(int fd,const CppType & type)332*3f982cf4SFabien Sanglard void WriteEnumMembers(int fd, const CppType& type) {
333*3f982cf4SFabien Sanglard   for (const auto& x : type.enum_type.members) {
334*3f982cf4SFabien Sanglard     dprintf(fd, "  k%s = %" PRIu64 "ull,\n", ToCamelCase(x.first).c_str(),
335*3f982cf4SFabien Sanglard             x.second);
336*3f982cf4SFabien Sanglard   }
337*3f982cf4SFabien Sanglard   for (const auto* x : type.enum_type.sub_members) {
338*3f982cf4SFabien Sanglard     WriteEnumMembers(fd, *x);
339*3f982cf4SFabien Sanglard   }
340*3f982cf4SFabien Sanglard }
341*3f982cf4SFabien Sanglard 
342*3f982cf4SFabien Sanglard // Writes a C++ type definition for |type| to the file descriptor |fd|.  This
343*3f982cf4SFabien Sanglard // only generates a definition for enums and structs.
WriteTypeDefinition(int fd,const CppType & type)344*3f982cf4SFabien Sanglard bool WriteTypeDefinition(int fd, const CppType& type) {
345*3f982cf4SFabien Sanglard   std::string name = ToCamelCase(type.name);
346*3f982cf4SFabien Sanglard   switch (type.which) {
347*3f982cf4SFabien Sanglard     case CppType::Which::kEnum: {
348*3f982cf4SFabien Sanglard       dprintf(fd, "\nenum class %s : uint64_t {\n", name.c_str());
349*3f982cf4SFabien Sanglard       WriteEnumMembers(fd, type);
350*3f982cf4SFabien Sanglard       dprintf(fd, "};\n");
351*3f982cf4SFabien Sanglard       if (!WriteEnumOperators(fd, type))
352*3f982cf4SFabien Sanglard         return false;
353*3f982cf4SFabien Sanglard     } break;
354*3f982cf4SFabien Sanglard     case CppType::Which::kStruct: {
355*3f982cf4SFabien Sanglard       dprintf(fd, "\nstruct %s {\n", name.c_str());
356*3f982cf4SFabien Sanglard       if (type.type_key != absl::nullopt) {
357*3f982cf4SFabien Sanglard         dprintf(fd, "  // type key: %" PRIu64 "\n", type.type_key.value());
358*3f982cf4SFabien Sanglard       }
359*3f982cf4SFabien Sanglard       dprintf(fd, "  bool operator==(const %s& other) const;\n", name.c_str());
360*3f982cf4SFabien Sanglard       dprintf(fd, "  bool operator!=(const %s& other) const;\n\n",
361*3f982cf4SFabien Sanglard               name.c_str());
362*3f982cf4SFabien Sanglard       if (!WriteStructMembers(fd, type.name, type.struct_type.members))
363*3f982cf4SFabien Sanglard         return false;
364*3f982cf4SFabien Sanglard       dprintf(fd, "};\n");
365*3f982cf4SFabien Sanglard     } break;
366*3f982cf4SFabien Sanglard     default:
367*3f982cf4SFabien Sanglard       break;
368*3f982cf4SFabien Sanglard   }
369*3f982cf4SFabien Sanglard   return true;
370*3f982cf4SFabien Sanglard }
371*3f982cf4SFabien Sanglard 
372*3f982cf4SFabien Sanglard // Ensures that any dependencies within |cpp_type| are written to the file
373*3f982cf4SFabien Sanglard // descriptor |fd| before writing |cpp_type| to the file descriptor |fd|.  This
374*3f982cf4SFabien Sanglard // is done by walking the tree of types defined by |cpp_type| (e.g. all the
375*3f982cf4SFabien Sanglard // members for a struct).  |defs| contains the names of types that have already
376*3f982cf4SFabien Sanglard // been written.  If a type hasn't been written and needs to be, its name will
377*3f982cf4SFabien Sanglard // also be added to |defs|.
EnsureDependentTypeDefinitionsWritten(int fd,const CppType & cpp_type,std::set<std::string> * defs)378*3f982cf4SFabien Sanglard bool EnsureDependentTypeDefinitionsWritten(int fd,
379*3f982cf4SFabien Sanglard                                            const CppType& cpp_type,
380*3f982cf4SFabien Sanglard                                            std::set<std::string>* defs) {
381*3f982cf4SFabien Sanglard   switch (cpp_type.which) {
382*3f982cf4SFabien Sanglard     case CppType::Which::kVector: {
383*3f982cf4SFabien Sanglard       return EnsureDependentTypeDefinitionsWritten(
384*3f982cf4SFabien Sanglard           fd, *cpp_type.vector_type.element_type, defs);
385*3f982cf4SFabien Sanglard     }
386*3f982cf4SFabien Sanglard     case CppType::Which::kEnum: {
387*3f982cf4SFabien Sanglard       if (defs->find(cpp_type.name) != defs->end())
388*3f982cf4SFabien Sanglard         return true;
389*3f982cf4SFabien Sanglard       for (const auto* x : cpp_type.enum_type.sub_members)
390*3f982cf4SFabien Sanglard         if (!EnsureDependentTypeDefinitionsWritten(fd, *x, defs))
391*3f982cf4SFabien Sanglard           return false;
392*3f982cf4SFabien Sanglard       defs->emplace(cpp_type.name);
393*3f982cf4SFabien Sanglard       WriteTypeDefinition(fd, cpp_type);
394*3f982cf4SFabien Sanglard     } break;
395*3f982cf4SFabien Sanglard     case CppType::Which::kStruct: {
396*3f982cf4SFabien Sanglard       if (cpp_type.struct_type.key_type !=
397*3f982cf4SFabien Sanglard           CppType::Struct::KeyType::kPlainGroup) {
398*3f982cf4SFabien Sanglard         if (defs->find(cpp_type.name) != defs->end())
399*3f982cf4SFabien Sanglard           return true;
400*3f982cf4SFabien Sanglard         for (const auto& x : cpp_type.struct_type.members)
401*3f982cf4SFabien Sanglard           if (!EnsureDependentTypeDefinitionsWritten(fd, *x.type, defs))
402*3f982cf4SFabien Sanglard             return false;
403*3f982cf4SFabien Sanglard         defs->emplace(cpp_type.name);
404*3f982cf4SFabien Sanglard         WriteTypeDefinition(fd, cpp_type);
405*3f982cf4SFabien Sanglard       }
406*3f982cf4SFabien Sanglard     } break;
407*3f982cf4SFabien Sanglard     case CppType::Which::kOptional: {
408*3f982cf4SFabien Sanglard       return EnsureDependentTypeDefinitionsWritten(fd, *cpp_type.optional_type,
409*3f982cf4SFabien Sanglard                                                    defs);
410*3f982cf4SFabien Sanglard     }
411*3f982cf4SFabien Sanglard     case CppType::Which::kDiscriminatedUnion: {
412*3f982cf4SFabien Sanglard       for (const auto* x : cpp_type.discriminated_union.members)
413*3f982cf4SFabien Sanglard         if (!EnsureDependentTypeDefinitionsWritten(fd, *x, defs))
414*3f982cf4SFabien Sanglard           return false;
415*3f982cf4SFabien Sanglard     } break;
416*3f982cf4SFabien Sanglard     case CppType::Which::kTaggedType: {
417*3f982cf4SFabien Sanglard       if (!EnsureDependentTypeDefinitionsWritten(
418*3f982cf4SFabien Sanglard               fd, *cpp_type.tagged_type.real_type, defs)) {
419*3f982cf4SFabien Sanglard         return false;
420*3f982cf4SFabien Sanglard       }
421*3f982cf4SFabien Sanglard     } break;
422*3f982cf4SFabien Sanglard     default:
423*3f982cf4SFabien Sanglard       break;
424*3f982cf4SFabien Sanglard   }
425*3f982cf4SFabien Sanglard   return true;
426*3f982cf4SFabien Sanglard }
427*3f982cf4SFabien Sanglard 
428*3f982cf4SFabien Sanglard // Writes the type definition for every C++ type in |table|.  This function
429*3f982cf4SFabien Sanglard // makes sure to write them in such an order that all type dependencies are
430*3f982cf4SFabien Sanglard // written before they are need so the resulting text in the file descriptor
431*3f982cf4SFabien Sanglard // |fd| will compile without modification.  For example, the following would be
432*3f982cf4SFabien Sanglard // bad output:
433*3f982cf4SFabien Sanglard //
434*3f982cf4SFabien Sanglard // struct Foo {
435*3f982cf4SFabien Sanglard //   Bar bar;
436*3f982cf4SFabien Sanglard //   int x;
437*3f982cf4SFabien Sanglard // };
438*3f982cf4SFabien Sanglard //
439*3f982cf4SFabien Sanglard // struct Bar {
440*3f982cf4SFabien Sanglard //   int alpha;
441*3f982cf4SFabien Sanglard // };
442*3f982cf4SFabien Sanglard //
443*3f982cf4SFabien Sanglard // This function ensures that Bar would be written sometime before Foo.
WriteTypeDefinitions(int fd,CppSymbolTable * table)444*3f982cf4SFabien Sanglard bool WriteTypeDefinitions(int fd, CppSymbolTable* table) {
445*3f982cf4SFabien Sanglard   std::set<std::string> defs;
446*3f982cf4SFabien Sanglard   for (const std::unique_ptr<CppType>& real_type : table->cpp_types) {
447*3f982cf4SFabien Sanglard     if (real_type->which != CppType::Which::kStruct ||
448*3f982cf4SFabien Sanglard         real_type->struct_type.key_type ==
449*3f982cf4SFabien Sanglard             CppType::Struct::KeyType::kPlainGroup) {
450*3f982cf4SFabien Sanglard       continue;
451*3f982cf4SFabien Sanglard     }
452*3f982cf4SFabien Sanglard     if (!EnsureDependentTypeDefinitionsWritten(fd, *real_type, &defs))
453*3f982cf4SFabien Sanglard       return false;
454*3f982cf4SFabien Sanglard   }
455*3f982cf4SFabien Sanglard 
456*3f982cf4SFabien Sanglard   dprintf(fd, "\nenum class Type : uint64_t {\n");
457*3f982cf4SFabien Sanglard   dprintf(fd, "    kUnknown = 0ull,\n");
458*3f982cf4SFabien Sanglard   for (CppType* type : table->TypesWithId()) {
459*3f982cf4SFabien Sanglard     dprintf(fd, "    k%s = %" PRIu64 "ull,\n", ToCamelCase(type->name).c_str(),
460*3f982cf4SFabien Sanglard             type->type_key.value());
461*3f982cf4SFabien Sanglard   }
462*3f982cf4SFabien Sanglard   dprintf(fd, "};\n");
463*3f982cf4SFabien Sanglard   return true;
464*3f982cf4SFabien Sanglard }
465*3f982cf4SFabien Sanglard 
466*3f982cf4SFabien Sanglard // Writes a parser that takes in a uint64_t and outputs the corresponding Type
467*3f982cf4SFabien Sanglard // if one matches up, or Type::kUnknown if none does.
468*3f982cf4SFabien Sanglard // NOTE: In future, this could be changes to use a Trie, which would allow for
469*3f982cf4SFabien Sanglard // manufacturers to more easily add their own type ids to ours.
WriteTypeParserDefinition(int fd,CppSymbolTable * table)470*3f982cf4SFabien Sanglard bool WriteTypeParserDefinition(int fd, CppSymbolTable* table) {
471*3f982cf4SFabien Sanglard   dprintf(fd, "\n//static\n");
472*3f982cf4SFabien Sanglard   dprintf(fd, "Type TypeEnumValidator::SafeCast(uint64_t type_id) {\n");
473*3f982cf4SFabien Sanglard   dprintf(fd, "  switch (type_id) {\n");
474*3f982cf4SFabien Sanglard   for (CppType* type : table->TypesWithId()) {
475*3f982cf4SFabien Sanglard     dprintf(fd, "    case uint64_t{%" PRIu64 "}: return Type::k%s;\n",
476*3f982cf4SFabien Sanglard             type->type_key.value(), ToCamelCase(type->name).c_str());
477*3f982cf4SFabien Sanglard   }
478*3f982cf4SFabien Sanglard   dprintf(fd, "    default: return Type::kUnknown;\n");
479*3f982cf4SFabien Sanglard   dprintf(fd, "  }\n}\n");
480*3f982cf4SFabien Sanglard   return true;
481*3f982cf4SFabien Sanglard }
482*3f982cf4SFabien Sanglard 
483*3f982cf4SFabien Sanglard // Writes the function prototypes for the encode and decode functions for each
484*3f982cf4SFabien Sanglard // type in |table| to the file descriptor |fd|.
WriteFunctionDeclarations(int fd,CppSymbolTable * table)485*3f982cf4SFabien Sanglard bool WriteFunctionDeclarations(int fd, CppSymbolTable* table) {
486*3f982cf4SFabien Sanglard   for (CppType* real_type : table->TypesWithId()) {
487*3f982cf4SFabien Sanglard     const auto& name = real_type->name;
488*3f982cf4SFabien Sanglard     if (real_type->which != CppType::Which::kStruct ||
489*3f982cf4SFabien Sanglard         real_type->struct_type.key_type ==
490*3f982cf4SFabien Sanglard             CppType::Struct::KeyType::kPlainGroup) {
491*3f982cf4SFabien Sanglard       return false;
492*3f982cf4SFabien Sanglard     }
493*3f982cf4SFabien Sanglard     std::string cpp_name = ToCamelCase(name);
494*3f982cf4SFabien Sanglard     dprintf(fd, "\nbool Encode%s(\n", cpp_name.c_str());
495*3f982cf4SFabien Sanglard     dprintf(fd, "    const %s& data,\n", cpp_name.c_str());
496*3f982cf4SFabien Sanglard     dprintf(fd, "    CborEncodeBuffer* buffer);\n");
497*3f982cf4SFabien Sanglard     dprintf(fd, "ssize_t Encode%s(\n", cpp_name.c_str());
498*3f982cf4SFabien Sanglard     dprintf(fd, "    const %s& data,\n", cpp_name.c_str());
499*3f982cf4SFabien Sanglard     dprintf(fd, "    uint8_t* buffer,\n    size_t length);\n");
500*3f982cf4SFabien Sanglard     dprintf(fd, "ssize_t Decode%s(\n", cpp_name.c_str());
501*3f982cf4SFabien Sanglard     dprintf(fd, "    const uint8_t* buffer,\n    size_t length,\n");
502*3f982cf4SFabien Sanglard     dprintf(fd, "    %s* data);\n", cpp_name.c_str());
503*3f982cf4SFabien Sanglard   }
504*3f982cf4SFabien Sanglard   return true;
505*3f982cf4SFabien Sanglard }
506*3f982cf4SFabien Sanglard 
507*3f982cf4SFabien Sanglard bool WriteMapEncoder(int fd,
508*3f982cf4SFabien Sanglard                      const std::string& name,
509*3f982cf4SFabien Sanglard                      const std::vector<CppType::Struct::CppMember>& members,
510*3f982cf4SFabien Sanglard                      const std::string& nested_type_scope,
511*3f982cf4SFabien Sanglard                      int encoder_depth = 1);
512*3f982cf4SFabien Sanglard bool WriteArrayEncoder(int fd,
513*3f982cf4SFabien Sanglard                        const std::string& name,
514*3f982cf4SFabien Sanglard                        const std::vector<CppType::Struct::CppMember>& members,
515*3f982cf4SFabien Sanglard                        const std::string& nested_type_scope,
516*3f982cf4SFabien Sanglard                        int encoder_depth = 1);
517*3f982cf4SFabien Sanglard 
518*3f982cf4SFabien Sanglard // Writes the encoding function for the C++ type |cpp_type| to the file
519*3f982cf4SFabien Sanglard // descriptor |fd|.  |name| is the C++ variable name that needs to be encoded.
520*3f982cf4SFabien Sanglard // |nested_type_scope| is the closest C++ scope name (i.e. struct name), which
521*3f982cf4SFabien Sanglard // may be used to access local enum constants.  |encoder_depth| is used to
522*3f982cf4SFabien Sanglard // independently name independent cbor encoders that need to be created.
WriteEncoder(int fd,const std::string & name,const CppType & cpp_type,const std::string & nested_type_scope,int encoder_depth)523*3f982cf4SFabien Sanglard bool WriteEncoder(int fd,
524*3f982cf4SFabien Sanglard                   const std::string& name,
525*3f982cf4SFabien Sanglard                   const CppType& cpp_type,
526*3f982cf4SFabien Sanglard                   const std::string& nested_type_scope,
527*3f982cf4SFabien Sanglard                   int encoder_depth) {
528*3f982cf4SFabien Sanglard   switch (cpp_type.which) {
529*3f982cf4SFabien Sanglard     case CppType::Which::kStruct:
530*3f982cf4SFabien Sanglard       if (cpp_type.struct_type.key_type == CppType::Struct::KeyType::kMap) {
531*3f982cf4SFabien Sanglard         if (!WriteMapEncoder(fd, name, cpp_type.struct_type.members,
532*3f982cf4SFabien Sanglard                              cpp_type.name, encoder_depth + 1)) {
533*3f982cf4SFabien Sanglard           return false;
534*3f982cf4SFabien Sanglard         }
535*3f982cf4SFabien Sanglard         return true;
536*3f982cf4SFabien Sanglard       } else if (cpp_type.struct_type.key_type ==
537*3f982cf4SFabien Sanglard                  CppType::Struct::KeyType::kArray) {
538*3f982cf4SFabien Sanglard         if (!WriteArrayEncoder(fd, name, cpp_type.struct_type.members,
539*3f982cf4SFabien Sanglard                                cpp_type.name, encoder_depth + 1)) {
540*3f982cf4SFabien Sanglard           return false;
541*3f982cf4SFabien Sanglard         }
542*3f982cf4SFabien Sanglard         return true;
543*3f982cf4SFabien Sanglard       } else {
544*3f982cf4SFabien Sanglard         for (const auto& x : cpp_type.struct_type.members) {
545*3f982cf4SFabien Sanglard           if (x.integer_key.has_value()) {
546*3f982cf4SFabien Sanglard             dprintf(fd,
547*3f982cf4SFabien Sanglard                     "  CBOR_RETURN_ON_ERROR(cbor_encode_uint("
548*3f982cf4SFabien Sanglard                     "&encoder%d, %" PRIu64 ");\n",
549*3f982cf4SFabien Sanglard                     encoder_depth, x.integer_key.value());
550*3f982cf4SFabien Sanglard           } else {
551*3f982cf4SFabien Sanglard             dprintf(fd,
552*3f982cf4SFabien Sanglard                     "  CBOR_RETURN_ON_ERROR(cbor_encode_text_string("
553*3f982cf4SFabien Sanglard                     "&encoder%d, \"%s\", sizeof(\"%s\") - 1));\n",
554*3f982cf4SFabien Sanglard                     encoder_depth, x.name.c_str(), x.name.c_str());
555*3f982cf4SFabien Sanglard           }
556*3f982cf4SFabien Sanglard           if (!WriteEncoder(fd, name + "." + ToUnderscoreId(x.name), *x.type,
557*3f982cf4SFabien Sanglard                             nested_type_scope, encoder_depth)) {
558*3f982cf4SFabien Sanglard             return false;
559*3f982cf4SFabien Sanglard           }
560*3f982cf4SFabien Sanglard         }
561*3f982cf4SFabien Sanglard         return true;
562*3f982cf4SFabien Sanglard       }
563*3f982cf4SFabien Sanglard     case CppType::Which::kUint64:
564*3f982cf4SFabien Sanglard       dprintf(fd, "  CBOR_RETURN_ON_ERROR(cbor_encode_uint(&encoder%d, %s));\n",
565*3f982cf4SFabien Sanglard               encoder_depth, ToUnderscoreId(name).c_str());
566*3f982cf4SFabien Sanglard       return true;
567*3f982cf4SFabien Sanglard     case CppType::Which::kString: {
568*3f982cf4SFabien Sanglard       std::string cid = ToUnderscoreId(name);
569*3f982cf4SFabien Sanglard       dprintf(fd, "  if (!IsValidUtf8(%s)) {\n", cid.c_str());
570*3f982cf4SFabien Sanglard       dprintf(fd, "    return -CborErrorInvalidUtf8TextString;\n");
571*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
572*3f982cf4SFabien Sanglard       dprintf(fd,
573*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_encode_text_string(&encoder%d, "
574*3f982cf4SFabien Sanglard               "%s.c_str(), %s.size()));\n",
575*3f982cf4SFabien Sanglard               encoder_depth, cid.c_str(), cid.c_str());
576*3f982cf4SFabien Sanglard       return true;
577*3f982cf4SFabien Sanglard     }
578*3f982cf4SFabien Sanglard     case CppType::Which::kBytes: {
579*3f982cf4SFabien Sanglard       std::string cid = ToUnderscoreId(name);
580*3f982cf4SFabien Sanglard       dprintf(fd,
581*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_encode_byte_string(&encoder%d, "
582*3f982cf4SFabien Sanglard               "%s.data(), "
583*3f982cf4SFabien Sanglard               "%s.size()));\n",
584*3f982cf4SFabien Sanglard               encoder_depth, cid.c_str(), cid.c_str());
585*3f982cf4SFabien Sanglard       return true;
586*3f982cf4SFabien Sanglard     }
587*3f982cf4SFabien Sanglard     case CppType::Which::kVector: {
588*3f982cf4SFabien Sanglard       std::string cid = ToUnderscoreId(name);
589*3f982cf4SFabien Sanglard       dprintf(fd, "  {\n");
590*3f982cf4SFabien Sanglard       if (cpp_type.vector_type.min_length !=
591*3f982cf4SFabien Sanglard           CppType::Vector::kMinLengthUnbounded) {
592*3f982cf4SFabien Sanglard         dprintf(fd, "  if (%s.size() < %d) {\n", cid.c_str(),
593*3f982cf4SFabien Sanglard                 cpp_type.vector_type.min_length);
594*3f982cf4SFabien Sanglard         dprintf(fd, "    return -CborErrorTooFewItems;\n");
595*3f982cf4SFabien Sanglard         dprintf(fd, "  }\n");
596*3f982cf4SFabien Sanglard       }
597*3f982cf4SFabien Sanglard       if (cpp_type.vector_type.max_length !=
598*3f982cf4SFabien Sanglard           CppType::Vector::kMaxLengthUnbounded) {
599*3f982cf4SFabien Sanglard         dprintf(fd, "  if (%s.size() > %d) {\n", cid.c_str(),
600*3f982cf4SFabien Sanglard                 cpp_type.vector_type.max_length);
601*3f982cf4SFabien Sanglard         dprintf(fd, "    return -CborErrorTooManyItems;\n");
602*3f982cf4SFabien Sanglard         dprintf(fd, "  }\n");
603*3f982cf4SFabien Sanglard       }
604*3f982cf4SFabien Sanglard       dprintf(fd, "  CborEncoder encoder%d;\n", encoder_depth + 1);
605*3f982cf4SFabien Sanglard       dprintf(fd,
606*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_encoder_create_array(&encoder%d, "
607*3f982cf4SFabien Sanglard               "&encoder%d, %s.size()));\n",
608*3f982cf4SFabien Sanglard               encoder_depth, encoder_depth + 1, cid.c_str());
609*3f982cf4SFabien Sanglard       dprintf(fd, "  for (const auto& x : %s) {\n", cid.c_str());
610*3f982cf4SFabien Sanglard       if (!WriteEncoder(fd, "x", *cpp_type.vector_type.element_type,
611*3f982cf4SFabien Sanglard                         nested_type_scope, encoder_depth + 1)) {
612*3f982cf4SFabien Sanglard         return false;
613*3f982cf4SFabien Sanglard       }
614*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
615*3f982cf4SFabien Sanglard       dprintf(fd,
616*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_encoder_close_container(&encoder%d, "
617*3f982cf4SFabien Sanglard               "&encoder%d));\n",
618*3f982cf4SFabien Sanglard               encoder_depth, encoder_depth + 1);
619*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
620*3f982cf4SFabien Sanglard       return true;
621*3f982cf4SFabien Sanglard     }
622*3f982cf4SFabien Sanglard     case CppType::Which::kEnum: {
623*3f982cf4SFabien Sanglard       dprintf(fd,
624*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_encode_uint(&encoder%d, "
625*3f982cf4SFabien Sanglard               "static_cast<uint64_t>(%s)));\n",
626*3f982cf4SFabien Sanglard               encoder_depth, ToUnderscoreId(name).c_str());
627*3f982cf4SFabien Sanglard       return true;
628*3f982cf4SFabien Sanglard     }
629*3f982cf4SFabien Sanglard     case CppType::Which::kDiscriminatedUnion: {
630*3f982cf4SFabien Sanglard       for (const auto* union_member : cpp_type.discriminated_union.members) {
631*3f982cf4SFabien Sanglard         switch (union_member->which) {
632*3f982cf4SFabien Sanglard           case CppType::Which::kUint64:
633*3f982cf4SFabien Sanglard             dprintf(fd, "  case %s::%s::Which::kUint64:\n",
634*3f982cf4SFabien Sanglard                     ToCamelCase(nested_type_scope).c_str(),
635*3f982cf4SFabien Sanglard                     ToCamelCase(cpp_type.name).c_str());
636*3f982cf4SFabien Sanglard             if (!WriteEncoder(fd, ToUnderscoreId(name + ".uint"), *union_member,
637*3f982cf4SFabien Sanglard                               nested_type_scope, encoder_depth)) {
638*3f982cf4SFabien Sanglard               return false;
639*3f982cf4SFabien Sanglard             }
640*3f982cf4SFabien Sanglard             dprintf(fd, "    break;\n");
641*3f982cf4SFabien Sanglard             break;
642*3f982cf4SFabien Sanglard           case CppType::Which::kString:
643*3f982cf4SFabien Sanglard             dprintf(fd, "  case %s::%s::Which::kString:\n",
644*3f982cf4SFabien Sanglard                     ToCamelCase(nested_type_scope).c_str(),
645*3f982cf4SFabien Sanglard                     ToCamelCase(cpp_type.name).c_str());
646*3f982cf4SFabien Sanglard             if (!WriteEncoder(fd, ToUnderscoreId(name + ".str"), *union_member,
647*3f982cf4SFabien Sanglard                               nested_type_scope, encoder_depth)) {
648*3f982cf4SFabien Sanglard               return false;
649*3f982cf4SFabien Sanglard             }
650*3f982cf4SFabien Sanglard             dprintf(fd, "    break;\n");
651*3f982cf4SFabien Sanglard             break;
652*3f982cf4SFabien Sanglard           case CppType::Which::kBytes:
653*3f982cf4SFabien Sanglard             dprintf(fd, "  case %s::%s::Which::kBytes:\n",
654*3f982cf4SFabien Sanglard                     ToCamelCase(nested_type_scope).c_str(),
655*3f982cf4SFabien Sanglard                     ToCamelCase(cpp_type.name).c_str());
656*3f982cf4SFabien Sanglard             if (!WriteEncoder(fd, ToUnderscoreId(name + ".bytes"),
657*3f982cf4SFabien Sanglard                               *union_member, nested_type_scope,
658*3f982cf4SFabien Sanglard                               encoder_depth)) {
659*3f982cf4SFabien Sanglard               return false;
660*3f982cf4SFabien Sanglard             }
661*3f982cf4SFabien Sanglard             dprintf(fd, "    break;\n");
662*3f982cf4SFabien Sanglard             break;
663*3f982cf4SFabien Sanglard           default:
664*3f982cf4SFabien Sanglard             return false;
665*3f982cf4SFabien Sanglard         }
666*3f982cf4SFabien Sanglard       }
667*3f982cf4SFabien Sanglard       dprintf(fd, "  case %s::%s::Which::kUninitialized:\n",
668*3f982cf4SFabien Sanglard               ToCamelCase(nested_type_scope).c_str(),
669*3f982cf4SFabien Sanglard               ToCamelCase(cpp_type.name).c_str());
670*3f982cf4SFabien Sanglard       dprintf(fd, "    return -CborUnknownError;\n");
671*3f982cf4SFabien Sanglard       return true;
672*3f982cf4SFabien Sanglard     }
673*3f982cf4SFabien Sanglard     case CppType::Which::kTaggedType: {
674*3f982cf4SFabien Sanglard       dprintf(fd,
675*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_encode_tag(&encoder%d, %" PRIu64
676*3f982cf4SFabien Sanglard               "ull));\n",
677*3f982cf4SFabien Sanglard               encoder_depth, cpp_type.tagged_type.tag);
678*3f982cf4SFabien Sanglard       if (!WriteEncoder(fd, name, *cpp_type.tagged_type.real_type,
679*3f982cf4SFabien Sanglard                         nested_type_scope, encoder_depth)) {
680*3f982cf4SFabien Sanglard         return false;
681*3f982cf4SFabien Sanglard       }
682*3f982cf4SFabien Sanglard       return true;
683*3f982cf4SFabien Sanglard     }
684*3f982cf4SFabien Sanglard     default:
685*3f982cf4SFabien Sanglard       break;
686*3f982cf4SFabien Sanglard   }
687*3f982cf4SFabien Sanglard   return false;
688*3f982cf4SFabien Sanglard }
689*3f982cf4SFabien Sanglard 
690*3f982cf4SFabien Sanglard struct MemberCountResult {
691*3f982cf4SFabien Sanglard   int num_required;
692*3f982cf4SFabien Sanglard   int num_optional;
693*3f982cf4SFabien Sanglard };
694*3f982cf4SFabien Sanglard 
CountMemberTypes(int fd,const std::string & name_id,const std::vector<CppType::Struct::CppMember> & members)695*3f982cf4SFabien Sanglard MemberCountResult CountMemberTypes(
696*3f982cf4SFabien Sanglard     int fd,
697*3f982cf4SFabien Sanglard     const std::string& name_id,
698*3f982cf4SFabien Sanglard     const std::vector<CppType::Struct::CppMember>& members) {
699*3f982cf4SFabien Sanglard   int num_required = 0;
700*3f982cf4SFabien Sanglard   int num_optional = 0;
701*3f982cf4SFabien Sanglard   for (const auto& x : members) {
702*3f982cf4SFabien Sanglard     if (x.type->which == CppType::Which::kOptional) {
703*3f982cf4SFabien Sanglard       std::string x_id = ToUnderscoreId(x.name);
704*3f982cf4SFabien Sanglard       if (num_optional == 0) {
705*3f982cf4SFabien Sanglard         dprintf(fd, "  int num_optionals_present = %s.has_%s;\n",
706*3f982cf4SFabien Sanglard                 name_id.c_str(), x_id.c_str());
707*3f982cf4SFabien Sanglard       } else {
708*3f982cf4SFabien Sanglard         dprintf(fd, "  num_optionals_present += %s.has_%s;\n", name_id.c_str(),
709*3f982cf4SFabien Sanglard                 x_id.c_str());
710*3f982cf4SFabien Sanglard       }
711*3f982cf4SFabien Sanglard       ++num_optional;
712*3f982cf4SFabien Sanglard     } else {
713*3f982cf4SFabien Sanglard       ++num_required;
714*3f982cf4SFabien Sanglard     }
715*3f982cf4SFabien Sanglard   }
716*3f982cf4SFabien Sanglard   return MemberCountResult{num_required, num_optional};
717*3f982cf4SFabien Sanglard }
718*3f982cf4SFabien Sanglard 
719*3f982cf4SFabien Sanglard // Writes the encoding function for a CBOR map with the C++ type members in
720*3f982cf4SFabien Sanglard // |members| to the file descriptor |fd|.  |name| is the C++ variable name that
721*3f982cf4SFabien Sanglard // needs to be encoded.  |nested_type_scope| is the closest C++ scope name (i.e.
722*3f982cf4SFabien Sanglard // struct name), which may be used to access local enum constants.
723*3f982cf4SFabien Sanglard // |encoder_depth| is used to independently name independent cbor encoders that
724*3f982cf4SFabien Sanglard // need to be created.
WriteMapEncoder(int fd,const std::string & name,const std::vector<CppType::Struct::CppMember> & members,const std::string & nested_type_scope,int encoder_depth)725*3f982cf4SFabien Sanglard bool WriteMapEncoder(int fd,
726*3f982cf4SFabien Sanglard                      const std::string& name,
727*3f982cf4SFabien Sanglard                      const std::vector<CppType::Struct::CppMember>& members,
728*3f982cf4SFabien Sanglard                      const std::string& nested_type_scope,
729*3f982cf4SFabien Sanglard                      int encoder_depth) {
730*3f982cf4SFabien Sanglard   std::string name_id = ToUnderscoreId(name);
731*3f982cf4SFabien Sanglard   dprintf(fd, "  CborEncoder encoder%d;\n", encoder_depth);
732*3f982cf4SFabien Sanglard   MemberCountResult member_counts = CountMemberTypes(fd, name_id, members);
733*3f982cf4SFabien Sanglard   if (member_counts.num_optional == 0) {
734*3f982cf4SFabien Sanglard     dprintf(fd,
735*3f982cf4SFabien Sanglard             "  CBOR_RETURN_ON_ERROR(cbor_encoder_create_map(&encoder%d, "
736*3f982cf4SFabien Sanglard             "&encoder%d, "
737*3f982cf4SFabien Sanglard             "%d));\n",
738*3f982cf4SFabien Sanglard             encoder_depth - 1, encoder_depth, member_counts.num_required);
739*3f982cf4SFabien Sanglard   } else {
740*3f982cf4SFabien Sanglard     dprintf(fd,
741*3f982cf4SFabien Sanglard             "  CBOR_RETURN_ON_ERROR(cbor_encoder_create_map(&encoder%d, "
742*3f982cf4SFabien Sanglard             "&encoder%d, "
743*3f982cf4SFabien Sanglard             "%d + num_optionals_present));\n",
744*3f982cf4SFabien Sanglard             encoder_depth - 1, encoder_depth, member_counts.num_required);
745*3f982cf4SFabien Sanglard   }
746*3f982cf4SFabien Sanglard 
747*3f982cf4SFabien Sanglard   for (const auto& x : members) {
748*3f982cf4SFabien Sanglard     std::string fullname = name;
749*3f982cf4SFabien Sanglard     CppType* member_type = x.type;
750*3f982cf4SFabien Sanglard     if (x.type->which != CppType::Which::kStruct ||
751*3f982cf4SFabien Sanglard         x.type->struct_type.key_type != CppType::Struct::KeyType::kPlainGroup) {
752*3f982cf4SFabien Sanglard       if (x.type->which == CppType::Which::kOptional) {
753*3f982cf4SFabien Sanglard         member_type = x.type->optional_type;
754*3f982cf4SFabien Sanglard         dprintf(fd, "  if (%s.has_%s) {\n", name_id.c_str(),
755*3f982cf4SFabien Sanglard                 ToUnderscoreId(x.name).c_str());
756*3f982cf4SFabien Sanglard       }
757*3f982cf4SFabien Sanglard 
758*3f982cf4SFabien Sanglard       if (x.integer_key.has_value()) {
759*3f982cf4SFabien Sanglard         dprintf(fd,
760*3f982cf4SFabien Sanglard                 "  CBOR_RETURN_ON_ERROR(cbor_encode_uint(&encoder%d, %" PRIu64
761*3f982cf4SFabien Sanglard                 "));\n",
762*3f982cf4SFabien Sanglard                 encoder_depth, x.integer_key.value());
763*3f982cf4SFabien Sanglard       } else {
764*3f982cf4SFabien Sanglard         dprintf(fd,
765*3f982cf4SFabien Sanglard                 "  CBOR_RETURN_ON_ERROR(cbor_encode_text_string(&encoder%d, "
766*3f982cf4SFabien Sanglard                 "\"%s\", sizeof(\"%s\") - 1));\n",
767*3f982cf4SFabien Sanglard                 encoder_depth, x.name.c_str(), x.name.c_str());
768*3f982cf4SFabien Sanglard       }
769*3f982cf4SFabien Sanglard       if (x.type->which == CppType::Which::kDiscriminatedUnion) {
770*3f982cf4SFabien Sanglard         dprintf(fd, "  switch (%s.%s.which) {\n", fullname.c_str(),
771*3f982cf4SFabien Sanglard                 x.name.c_str());
772*3f982cf4SFabien Sanglard       }
773*3f982cf4SFabien Sanglard       fullname = fullname + "." + x.name;
774*3f982cf4SFabien Sanglard     }
775*3f982cf4SFabien Sanglard     if (!WriteEncoder(fd, fullname, *member_type, nested_type_scope,
776*3f982cf4SFabien Sanglard                       encoder_depth)) {
777*3f982cf4SFabien Sanglard       return false;
778*3f982cf4SFabien Sanglard     }
779*3f982cf4SFabien Sanglard     if (x.type->which == CppType::Which::kOptional ||
780*3f982cf4SFabien Sanglard         x.type->which == CppType::Which::kDiscriminatedUnion) {
781*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
782*3f982cf4SFabien Sanglard     }
783*3f982cf4SFabien Sanglard   }
784*3f982cf4SFabien Sanglard 
785*3f982cf4SFabien Sanglard   dprintf(fd,
786*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_encoder_close_container(&encoder%d, "
787*3f982cf4SFabien Sanglard           "&encoder%d));\n",
788*3f982cf4SFabien Sanglard           encoder_depth - 1, encoder_depth);
789*3f982cf4SFabien Sanglard   return true;
790*3f982cf4SFabien Sanglard }
791*3f982cf4SFabien Sanglard 
792*3f982cf4SFabien Sanglard // Writes the encoding function for a CBOR array with the C++ type members in
793*3f982cf4SFabien Sanglard // |members| to the file descriptor |fd|.  |name| is the C++ variable name that
794*3f982cf4SFabien Sanglard // needs to be encoded.  |nested_type_scope| is the closest C++ scope name (i.e.
795*3f982cf4SFabien Sanglard // struct name), which may be used to access local enum constants.
796*3f982cf4SFabien Sanglard // |encoder_depth| is used to independently name independent cbor encoders that
797*3f982cf4SFabien Sanglard // need to be created.
WriteArrayEncoder(int fd,const std::string & name,const std::vector<CppType::Struct::CppMember> & members,const std::string & nested_type_scope,int encoder_depth)798*3f982cf4SFabien Sanglard bool WriteArrayEncoder(int fd,
799*3f982cf4SFabien Sanglard                        const std::string& name,
800*3f982cf4SFabien Sanglard                        const std::vector<CppType::Struct::CppMember>& members,
801*3f982cf4SFabien Sanglard                        const std::string& nested_type_scope,
802*3f982cf4SFabien Sanglard                        int encoder_depth) {
803*3f982cf4SFabien Sanglard   std::string name_id = ToUnderscoreId(name);
804*3f982cf4SFabien Sanglard   dprintf(fd, "  CborEncoder encoder%d;\n", encoder_depth);
805*3f982cf4SFabien Sanglard   MemberCountResult member_counts = CountMemberTypes(fd, name_id, members);
806*3f982cf4SFabien Sanglard   if (member_counts.num_optional == 0) {
807*3f982cf4SFabien Sanglard     dprintf(fd,
808*3f982cf4SFabien Sanglard             "  CBOR_RETURN_ON_ERROR(cbor_encoder_create_array(&encoder%d, "
809*3f982cf4SFabien Sanglard             "&encoder%d, %d));\n",
810*3f982cf4SFabien Sanglard             encoder_depth - 1, encoder_depth, member_counts.num_required);
811*3f982cf4SFabien Sanglard   } else {
812*3f982cf4SFabien Sanglard     dprintf(fd,
813*3f982cf4SFabien Sanglard             "  CBOR_RETURN_ON_ERROR(cbor_encoder_create_array(&encoder%d, "
814*3f982cf4SFabien Sanglard             "&encoder%d, %d + num_optionals_present));\n",
815*3f982cf4SFabien Sanglard             encoder_depth - 1, encoder_depth, member_counts.num_required);
816*3f982cf4SFabien Sanglard   }
817*3f982cf4SFabien Sanglard 
818*3f982cf4SFabien Sanglard   for (const auto& x : members) {
819*3f982cf4SFabien Sanglard     std::string fullname = name;
820*3f982cf4SFabien Sanglard     CppType* member_type = x.type;
821*3f982cf4SFabien Sanglard     if (x.type->which != CppType::Which::kStruct ||
822*3f982cf4SFabien Sanglard         x.type->struct_type.key_type != CppType::Struct::KeyType::kPlainGroup) {
823*3f982cf4SFabien Sanglard       if (x.type->which == CppType::Which::kOptional) {
824*3f982cf4SFabien Sanglard         member_type = x.type->optional_type;
825*3f982cf4SFabien Sanglard         dprintf(fd, "  if (%s.has_%s) {\n", name_id.c_str(),
826*3f982cf4SFabien Sanglard                 ToUnderscoreId(x.name).c_str());
827*3f982cf4SFabien Sanglard       }
828*3f982cf4SFabien Sanglard       if (x.type->which == CppType::Which::kDiscriminatedUnion) {
829*3f982cf4SFabien Sanglard         dprintf(fd, "  switch (%s.%s.which) {\n", fullname.c_str(),
830*3f982cf4SFabien Sanglard                 x.name.c_str());
831*3f982cf4SFabien Sanglard       }
832*3f982cf4SFabien Sanglard       fullname = fullname + "." + x.name;
833*3f982cf4SFabien Sanglard     }
834*3f982cf4SFabien Sanglard     if (!WriteEncoder(fd, fullname, *member_type, nested_type_scope,
835*3f982cf4SFabien Sanglard                       encoder_depth)) {
836*3f982cf4SFabien Sanglard       return false;
837*3f982cf4SFabien Sanglard     }
838*3f982cf4SFabien Sanglard     if (x.type->which == CppType::Which::kOptional ||
839*3f982cf4SFabien Sanglard         x.type->which == CppType::Which::kDiscriminatedUnion) {
840*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
841*3f982cf4SFabien Sanglard     }
842*3f982cf4SFabien Sanglard   }
843*3f982cf4SFabien Sanglard 
844*3f982cf4SFabien Sanglard   dprintf(fd,
845*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_encoder_close_container(&encoder%d, "
846*3f982cf4SFabien Sanglard           "&encoder%d));\n",
847*3f982cf4SFabien Sanglard           encoder_depth - 1, encoder_depth);
848*3f982cf4SFabien Sanglard   return true;
849*3f982cf4SFabien Sanglard }
850*3f982cf4SFabien Sanglard 
GetByte(uint64_t value,size_t byte)851*3f982cf4SFabien Sanglard uint8_t GetByte(uint64_t value, size_t byte) {
852*3f982cf4SFabien Sanglard   return static_cast<uint8_t>((value >> (byte * 8)) & 0xFF);
853*3f982cf4SFabien Sanglard }
854*3f982cf4SFabien Sanglard 
GetEncodedTypeKey(const CppType & type)855*3f982cf4SFabien Sanglard std::string GetEncodedTypeKey(const CppType& type) {
856*3f982cf4SFabien Sanglard   if (type.type_key == absl::nullopt) {
857*3f982cf4SFabien Sanglard     return "";
858*3f982cf4SFabien Sanglard   }
859*3f982cf4SFabien Sanglard 
860*3f982cf4SFabien Sanglard   // Determine all constants needed for calculating the encoded id bytes.
861*3f982cf4SFabien Sanglard   uint64_t type_id = type.type_key.value();
862*3f982cf4SFabien Sanglard   uint8_t encoding_size;
863*3f982cf4SFabien Sanglard   uint8_t start_processing_byte;
864*3f982cf4SFabien Sanglard   if (type_id < 0x1 << 6) {
865*3f982cf4SFabien Sanglard     encoding_size = 0x0;
866*3f982cf4SFabien Sanglard     start_processing_byte = 0;
867*3f982cf4SFabien Sanglard   } else if (type_id < 0x1 << 14) {
868*3f982cf4SFabien Sanglard     encoding_size = 0x01;
869*3f982cf4SFabien Sanglard     start_processing_byte = 1;
870*3f982cf4SFabien Sanglard   } else if (type_id < 0x1 << 30) {
871*3f982cf4SFabien Sanglard     encoding_size = 0x02;
872*3f982cf4SFabien Sanglard     start_processing_byte = 3;
873*3f982cf4SFabien Sanglard   } else if (type_id < uint64_t{0x1} << 62) {
874*3f982cf4SFabien Sanglard     encoding_size = 0x03;
875*3f982cf4SFabien Sanglard     start_processing_byte = 7;
876*3f982cf4SFabien Sanglard   } else {
877*3f982cf4SFabien Sanglard     return "";
878*3f982cf4SFabien Sanglard   }
879*3f982cf4SFabien Sanglard 
880*3f982cf4SFabien Sanglard   // Parse the encoded id into a string;
881*3f982cf4SFabien Sanglard   std::stringstream ss;
882*3f982cf4SFabien Sanglard   uint8_t first_byte =
883*3f982cf4SFabien Sanglard       encoding_size << 6 | GetByte(type_id, start_processing_byte);
884*3f982cf4SFabien Sanglard   ss << "{0x" << std::hex << uint32_t{first_byte};
885*3f982cf4SFabien Sanglard   for (int i = start_processing_byte - 1; i >= 0; i--) {
886*3f982cf4SFabien Sanglard     ss << ", 0x" << std::hex << uint32_t{GetByte(type_id, i)};
887*3f982cf4SFabien Sanglard   }
888*3f982cf4SFabien Sanglard   ss << "}";
889*3f982cf4SFabien Sanglard   return ss.str();
890*3f982cf4SFabien Sanglard }
891*3f982cf4SFabien Sanglard 
892*3f982cf4SFabien Sanglard // Writes encoding functions for each type in |table| to the file descriptor
893*3f982cf4SFabien Sanglard // |fd|.
WriteEncoders(int fd,CppSymbolTable * table)894*3f982cf4SFabien Sanglard bool WriteEncoders(int fd, CppSymbolTable* table) {
895*3f982cf4SFabien Sanglard   for (CppType* real_type : table->TypesWithId()) {
896*3f982cf4SFabien Sanglard     const auto& name = real_type->name;
897*3f982cf4SFabien Sanglard     if (real_type->which != CppType::Which::kStruct ||
898*3f982cf4SFabien Sanglard         real_type->struct_type.key_type ==
899*3f982cf4SFabien Sanglard             CppType::Struct::KeyType::kPlainGroup) {
900*3f982cf4SFabien Sanglard       return false;
901*3f982cf4SFabien Sanglard     }
902*3f982cf4SFabien Sanglard     std::string cpp_name = ToCamelCase(name);
903*3f982cf4SFabien Sanglard 
904*3f982cf4SFabien Sanglard     for (const auto& x : real_type->struct_type.members) {
905*3f982cf4SFabien Sanglard       if (x.type->which != CppType::Which::kDiscriminatedUnion)
906*3f982cf4SFabien Sanglard         continue;
907*3f982cf4SFabien Sanglard       std::string dunion_cpp_name = ToCamelCase(x.name);
908*3f982cf4SFabien Sanglard       dprintf(fd, "\n%s::%s::%s()\n", cpp_name.c_str(), dunion_cpp_name.c_str(),
909*3f982cf4SFabien Sanglard               dunion_cpp_name.c_str());
910*3f982cf4SFabien Sanglard       std::string cid = ToUnderscoreId(x.name);
911*3f982cf4SFabien Sanglard       std::string type_name = ToCamelCase(x.name);
912*3f982cf4SFabien Sanglard       dprintf(fd,
913*3f982cf4SFabien Sanglard               "    : which(Which::kUninitialized), placeholder_(false) {}\n");
914*3f982cf4SFabien Sanglard 
915*3f982cf4SFabien Sanglard       dprintf(fd, "\n%s::%s::~%s() {\n", cpp_name.c_str(),
916*3f982cf4SFabien Sanglard               dunion_cpp_name.c_str(), dunion_cpp_name.c_str());
917*3f982cf4SFabien Sanglard       dprintf(fd, "  switch (which) {\n");
918*3f982cf4SFabien Sanglard       for (const auto* y : x.type->discriminated_union.members) {
919*3f982cf4SFabien Sanglard         switch (y->which) {
920*3f982cf4SFabien Sanglard           case CppType::Which::kUint64: {
921*3f982cf4SFabien Sanglard             dprintf(fd, " case Which::kUint64: break;\n");
922*3f982cf4SFabien Sanglard           } break;
923*3f982cf4SFabien Sanglard           case CppType::Which::kString: {
924*3f982cf4SFabien Sanglard             dprintf(fd, "  case Which::kString:\n");
925*3f982cf4SFabien Sanglard             dprintf(fd, "    str.std::string::~basic_string();\n");
926*3f982cf4SFabien Sanglard             dprintf(fd, "    break;\n");
927*3f982cf4SFabien Sanglard           } break;
928*3f982cf4SFabien Sanglard           case CppType::Which::kBytes: {
929*3f982cf4SFabien Sanglard             dprintf(fd, "  case Which::kBytes:\n");
930*3f982cf4SFabien Sanglard             dprintf(fd, "    bytes.std::vector<uint8_t>::~vector();\n");
931*3f982cf4SFabien Sanglard             dprintf(fd, "    break;\n");
932*3f982cf4SFabien Sanglard           } break;
933*3f982cf4SFabien Sanglard           default:
934*3f982cf4SFabien Sanglard             return false;
935*3f982cf4SFabien Sanglard         }
936*3f982cf4SFabien Sanglard       }
937*3f982cf4SFabien Sanglard       dprintf(fd, " case Which::kUninitialized: break;\n");
938*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
939*3f982cf4SFabien Sanglard       dprintf(fd, "}\n");
940*3f982cf4SFabien Sanglard     }
941*3f982cf4SFabien Sanglard 
942*3f982cf4SFabien Sanglard     static const char vector_encode_function[] =
943*3f982cf4SFabien Sanglard         R"(
944*3f982cf4SFabien Sanglard bool Encode%1$s(
945*3f982cf4SFabien Sanglard     const %1$s& data,
946*3f982cf4SFabien Sanglard     CborEncodeBuffer* buffer) {
947*3f982cf4SFabien Sanglard   if (buffer->AvailableLength() == 0 &&
948*3f982cf4SFabien Sanglard       !buffer->Append(CborEncodeBuffer::kDefaultInitialEncodeBufferSize))
949*3f982cf4SFabien Sanglard     return false;
950*3f982cf4SFabien Sanglard   const uint8_t type_id[] = %2$s;
951*3f982cf4SFabien Sanglard   if(!buffer->SetType(type_id, sizeof(type_id))) {
952*3f982cf4SFabien Sanglard     return false;
953*3f982cf4SFabien Sanglard   }
954*3f982cf4SFabien Sanglard   while (true) {
955*3f982cf4SFabien Sanglard     size_t available_length = buffer->AvailableLength();
956*3f982cf4SFabien Sanglard     ssize_t error_or_size = msgs::Encode%1$s(
957*3f982cf4SFabien Sanglard         data, buffer->Position(), available_length);
958*3f982cf4SFabien Sanglard     if (IsError(error_or_size)) {
959*3f982cf4SFabien Sanglard       return false;
960*3f982cf4SFabien Sanglard     } else if (error_or_size > static_cast<ssize_t>(available_length)) {
961*3f982cf4SFabien Sanglard       if (!buffer->ResizeBy(error_or_size - available_length))
962*3f982cf4SFabien Sanglard         return false;
963*3f982cf4SFabien Sanglard     } else {
964*3f982cf4SFabien Sanglard       buffer->ResizeBy(error_or_size - available_length);
965*3f982cf4SFabien Sanglard       return true;
966*3f982cf4SFabien Sanglard     }
967*3f982cf4SFabien Sanglard   }
968*3f982cf4SFabien Sanglard }
969*3f982cf4SFabien Sanglard )";
970*3f982cf4SFabien Sanglard 
971*3f982cf4SFabien Sanglard     std::string encoded_id = GetEncodedTypeKey(*real_type);
972*3f982cf4SFabien Sanglard     if (encoded_id.empty()) {
973*3f982cf4SFabien Sanglard       return false;
974*3f982cf4SFabien Sanglard     }
975*3f982cf4SFabien Sanglard 
976*3f982cf4SFabien Sanglard     dprintf(fd, vector_encode_function, cpp_name.c_str(), encoded_id.c_str());
977*3f982cf4SFabien Sanglard     dprintf(fd, "\nssize_t Encode%s(\n", cpp_name.c_str());
978*3f982cf4SFabien Sanglard     dprintf(fd, "    const %s& data,\n", cpp_name.c_str());
979*3f982cf4SFabien Sanglard     dprintf(fd, "    uint8_t* buffer,\n    size_t length) {\n");
980*3f982cf4SFabien Sanglard     dprintf(fd, "  CborEncoder encoder0;\n");
981*3f982cf4SFabien Sanglard     dprintf(fd, "  cbor_encoder_init(&encoder0, buffer, length, 0);\n");
982*3f982cf4SFabien Sanglard 
983*3f982cf4SFabien Sanglard     if (real_type->struct_type.key_type == CppType::Struct::KeyType::kMap) {
984*3f982cf4SFabien Sanglard       if (!WriteMapEncoder(fd, "data", real_type->struct_type.members, name))
985*3f982cf4SFabien Sanglard         return false;
986*3f982cf4SFabien Sanglard     } else {
987*3f982cf4SFabien Sanglard       if (!WriteArrayEncoder(fd, "data", real_type->struct_type.members,
988*3f982cf4SFabien Sanglard                              name)) {
989*3f982cf4SFabien Sanglard         return false;
990*3f982cf4SFabien Sanglard       }
991*3f982cf4SFabien Sanglard     }
992*3f982cf4SFabien Sanglard 
993*3f982cf4SFabien Sanglard     dprintf(fd,
994*3f982cf4SFabien Sanglard             "  size_t extra_bytes_needed = "
995*3f982cf4SFabien Sanglard             "cbor_encoder_get_extra_bytes_needed(&encoder0);\n");
996*3f982cf4SFabien Sanglard     dprintf(fd, "  if (extra_bytes_needed) {\n");
997*3f982cf4SFabien Sanglard     dprintf(fd,
998*3f982cf4SFabien Sanglard             "    return static_cast<ssize_t>(length + extra_bytes_needed);\n");
999*3f982cf4SFabien Sanglard     dprintf(fd, "  } else {\n");
1000*3f982cf4SFabien Sanglard     dprintf(fd,
1001*3f982cf4SFabien Sanglard             "    return "
1002*3f982cf4SFabien Sanglard             "static_cast<ssize_t>(cbor_encoder_get_buffer_size(&encoder0, "
1003*3f982cf4SFabien Sanglard             "buffer));\n");
1004*3f982cf4SFabien Sanglard     dprintf(fd, "  }\n");
1005*3f982cf4SFabien Sanglard     dprintf(fd, "}\n");
1006*3f982cf4SFabien Sanglard   }
1007*3f982cf4SFabien Sanglard   return true;
1008*3f982cf4SFabien Sanglard }
1009*3f982cf4SFabien Sanglard 
1010*3f982cf4SFabien Sanglard bool WriteMapDecoder(int fd,
1011*3f982cf4SFabien Sanglard                      const std::string& name,
1012*3f982cf4SFabien Sanglard                      const std::string& member_accessor,
1013*3f982cf4SFabien Sanglard                      const std::vector<CppType::Struct::CppMember>& members,
1014*3f982cf4SFabien Sanglard                      int decoder_depth,
1015*3f982cf4SFabien Sanglard                      int* temporary_count);
1016*3f982cf4SFabien Sanglard bool WriteArrayDecoder(int fd,
1017*3f982cf4SFabien Sanglard                        const std::string& name,
1018*3f982cf4SFabien Sanglard                        const std::string& member_accessor,
1019*3f982cf4SFabien Sanglard                        const std::vector<CppType::Struct::CppMember>& members,
1020*3f982cf4SFabien Sanglard                        int decoder_depth,
1021*3f982cf4SFabien Sanglard                        int* temporary_count);
1022*3f982cf4SFabien Sanglard 
1023*3f982cf4SFabien Sanglard // Writes the decoding function for the C++ type |cpp_type| to the file
1024*3f982cf4SFabien Sanglard // descriptor |fd|.  |name| is the C++ variable name that needs to be encoded.
1025*3f982cf4SFabien Sanglard // |member_accessor| is either "." or "->" depending on whether |name| is a
1026*3f982cf4SFabien Sanglard // pointer type.  |decoder_depth| is used to independently name independent cbor
1027*3f982cf4SFabien Sanglard // decoders that need to be created.  |temporary_count| is used to ensure
1028*3f982cf4SFabien Sanglard // temporaries get unique names by appending an automatically incremented
1029*3f982cf4SFabien Sanglard // integer.
WriteDecoder(int fd,const std::string & name,const std::string & member_accessor,const CppType & cpp_type,int decoder_depth,int * temporary_count)1030*3f982cf4SFabien Sanglard bool WriteDecoder(int fd,
1031*3f982cf4SFabien Sanglard                   const std::string& name,
1032*3f982cf4SFabien Sanglard                   const std::string& member_accessor,
1033*3f982cf4SFabien Sanglard                   const CppType& cpp_type,
1034*3f982cf4SFabien Sanglard                   int decoder_depth,
1035*3f982cf4SFabien Sanglard                   int* temporary_count) {
1036*3f982cf4SFabien Sanglard   switch (cpp_type.which) {
1037*3f982cf4SFabien Sanglard     case CppType::Which::kUint64: {
1038*3f982cf4SFabien Sanglard       dprintf(fd,
1039*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_value_get_uint64(&it%d, &%s));\n",
1040*3f982cf4SFabien Sanglard               decoder_depth, name.c_str());
1041*3f982cf4SFabien Sanglard       dprintf(fd, "  CBOR_RETURN_ON_ERROR(cbor_value_advance_fixed(&it%d));\n",
1042*3f982cf4SFabien Sanglard               decoder_depth);
1043*3f982cf4SFabien Sanglard       return true;
1044*3f982cf4SFabien Sanglard     }
1045*3f982cf4SFabien Sanglard     case CppType::Which::kString: {
1046*3f982cf4SFabien Sanglard       int temp_length = (*temporary_count)++;
1047*3f982cf4SFabien Sanglard       dprintf(fd, "  size_t length%d = 0;", temp_length);
1048*3f982cf4SFabien Sanglard       dprintf(fd,
1049*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_value_validate(&it%d, "
1050*3f982cf4SFabien Sanglard               "CborValidateUtf8));\n",
1051*3f982cf4SFabien Sanglard               decoder_depth);
1052*3f982cf4SFabien Sanglard       dprintf(fd, "  if (cbor_value_is_length_known(&it%d)) {\n",
1053*3f982cf4SFabien Sanglard               decoder_depth);
1054*3f982cf4SFabien Sanglard       dprintf(fd,
1055*3f982cf4SFabien Sanglard               "    CBOR_RETURN_ON_ERROR(cbor_value_get_string_length(&it%d, "
1056*3f982cf4SFabien Sanglard               "&length%d));\n",
1057*3f982cf4SFabien Sanglard               decoder_depth, temp_length);
1058*3f982cf4SFabien Sanglard       dprintf(fd, "  } else {\n");
1059*3f982cf4SFabien Sanglard       dprintf(
1060*3f982cf4SFabien Sanglard           fd,
1061*3f982cf4SFabien Sanglard           "    CBOR_RETURN_ON_ERROR(cbor_value_calculate_string_length(&it%d, "
1062*3f982cf4SFabien Sanglard           "&length%d));\n",
1063*3f982cf4SFabien Sanglard           decoder_depth, temp_length);
1064*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1065*3f982cf4SFabien Sanglard       dprintf(fd, "  %s%sresize(length%d);\n", name.c_str(),
1066*3f982cf4SFabien Sanglard               member_accessor.c_str(), temp_length);
1067*3f982cf4SFabien Sanglard       dprintf(fd,
1068*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_value_copy_text_string(&it%d, "
1069*3f982cf4SFabien Sanglard               "const_cast<char*>(%s%sdata()), &length%d, nullptr));\n",
1070*3f982cf4SFabien Sanglard               decoder_depth, name.c_str(), member_accessor.c_str(),
1071*3f982cf4SFabien Sanglard               temp_length);
1072*3f982cf4SFabien Sanglard       dprintf(fd, "  CBOR_RETURN_ON_ERROR(cbor_value_advance(&it%d));\n",
1073*3f982cf4SFabien Sanglard               decoder_depth);
1074*3f982cf4SFabien Sanglard       return true;
1075*3f982cf4SFabien Sanglard     }
1076*3f982cf4SFabien Sanglard     case CppType::Which::kBytes: {
1077*3f982cf4SFabien Sanglard       int temp_length = (*temporary_count)++;
1078*3f982cf4SFabien Sanglard       dprintf(fd, "  size_t length%d = 0;", temp_length);
1079*3f982cf4SFabien Sanglard       dprintf(fd, "  if (cbor_value_is_length_known(&it%d)) {\n",
1080*3f982cf4SFabien Sanglard               decoder_depth);
1081*3f982cf4SFabien Sanglard       dprintf(fd,
1082*3f982cf4SFabien Sanglard               "    CBOR_RETURN_ON_ERROR(cbor_value_get_string_length(&it%d, "
1083*3f982cf4SFabien Sanglard               "&length%d));\n",
1084*3f982cf4SFabien Sanglard               decoder_depth, temp_length);
1085*3f982cf4SFabien Sanglard       dprintf(fd, "  } else {\n");
1086*3f982cf4SFabien Sanglard       dprintf(
1087*3f982cf4SFabien Sanglard           fd,
1088*3f982cf4SFabien Sanglard           "    CBOR_RETURN_ON_ERROR(cbor_value_calculate_string_length(&it%d, "
1089*3f982cf4SFabien Sanglard           "&length%d));\n",
1090*3f982cf4SFabien Sanglard           decoder_depth, temp_length);
1091*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1092*3f982cf4SFabien Sanglard       if (!cpp_type.bytes_type.fixed_size) {
1093*3f982cf4SFabien Sanglard         dprintf(fd, "  %s%sresize(length%d);\n", name.c_str(),
1094*3f982cf4SFabien Sanglard                 member_accessor.c_str(), temp_length);
1095*3f982cf4SFabien Sanglard       } else {
1096*3f982cf4SFabien Sanglard         dprintf(fd, "  if (length%d < %d) {\n", temp_length,
1097*3f982cf4SFabien Sanglard                 static_cast<int>(cpp_type.bytes_type.fixed_size.value()));
1098*3f982cf4SFabien Sanglard         dprintf(fd, "    return -CborErrorTooFewItems;\n");
1099*3f982cf4SFabien Sanglard         dprintf(fd, "  } else if (length%d > %d) {\n", temp_length,
1100*3f982cf4SFabien Sanglard                 static_cast<int>(cpp_type.bytes_type.fixed_size.value()));
1101*3f982cf4SFabien Sanglard         dprintf(fd, "    return -CborErrorTooManyItems;\n");
1102*3f982cf4SFabien Sanglard         dprintf(fd, "  }\n");
1103*3f982cf4SFabien Sanglard       }
1104*3f982cf4SFabien Sanglard       dprintf(fd,
1105*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_value_copy_byte_string(&it%d, "
1106*3f982cf4SFabien Sanglard               "const_cast<uint8_t*>(%s%sdata()), &length%d, nullptr));\n",
1107*3f982cf4SFabien Sanglard               decoder_depth, name.c_str(), member_accessor.c_str(),
1108*3f982cf4SFabien Sanglard               temp_length);
1109*3f982cf4SFabien Sanglard       dprintf(fd, "  CBOR_RETURN_ON_ERROR(cbor_value_advance(&it%d));\n",
1110*3f982cf4SFabien Sanglard               decoder_depth);
1111*3f982cf4SFabien Sanglard       return true;
1112*3f982cf4SFabien Sanglard     }
1113*3f982cf4SFabien Sanglard     case CppType::Which::kVector: {
1114*3f982cf4SFabien Sanglard       dprintf(fd, "  if (cbor_value_get_type(&it%d) != CborArrayType) {\n",
1115*3f982cf4SFabien Sanglard               decoder_depth);
1116*3f982cf4SFabien Sanglard       dprintf(fd, "    return -1;\n");
1117*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1118*3f982cf4SFabien Sanglard       dprintf(fd, "  {\n");
1119*3f982cf4SFabien Sanglard       dprintf(fd, "  CborValue it%d;\n", decoder_depth + 1);
1120*3f982cf4SFabien Sanglard       dprintf(fd, "  size_t it%d_length = 0;\n", decoder_depth + 1);
1121*3f982cf4SFabien Sanglard       dprintf(fd,
1122*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_value_get_array_length(&it%d, "
1123*3f982cf4SFabien Sanglard               "&it%d_length));\n",
1124*3f982cf4SFabien Sanglard               decoder_depth, decoder_depth + 1);
1125*3f982cf4SFabien Sanglard       if (cpp_type.vector_type.min_length !=
1126*3f982cf4SFabien Sanglard           CppType::Vector::kMinLengthUnbounded) {
1127*3f982cf4SFabien Sanglard         dprintf(fd, "  if (it%d_length < %d) {\n", decoder_depth + 1,
1128*3f982cf4SFabien Sanglard                 cpp_type.vector_type.min_length);
1129*3f982cf4SFabien Sanglard         dprintf(fd, "    return -CborErrorTooFewItems;\n");
1130*3f982cf4SFabien Sanglard         dprintf(fd, "  }\n");
1131*3f982cf4SFabien Sanglard       }
1132*3f982cf4SFabien Sanglard       if (cpp_type.vector_type.max_length !=
1133*3f982cf4SFabien Sanglard           CppType::Vector::kMaxLengthUnbounded) {
1134*3f982cf4SFabien Sanglard         dprintf(fd, "  if (it%d_length > %d) {\n", decoder_depth + 1,
1135*3f982cf4SFabien Sanglard                 cpp_type.vector_type.max_length);
1136*3f982cf4SFabien Sanglard         dprintf(fd, "    return -CborErrorTooManyItems;\n");
1137*3f982cf4SFabien Sanglard         dprintf(fd, "  }\n");
1138*3f982cf4SFabien Sanglard       }
1139*3f982cf4SFabien Sanglard       dprintf(fd, "  %s%sresize(it%d_length);\n", name.c_str(),
1140*3f982cf4SFabien Sanglard               member_accessor.c_str(), decoder_depth + 1);
1141*3f982cf4SFabien Sanglard       dprintf(
1142*3f982cf4SFabien Sanglard           fd,
1143*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_enter_container(&it%d, &it%d));\n",
1144*3f982cf4SFabien Sanglard           decoder_depth, decoder_depth + 1);
1145*3f982cf4SFabien Sanglard       dprintf(fd, "  for (auto i = %s%sbegin(); i != %s%send(); ++i) {\n",
1146*3f982cf4SFabien Sanglard               name.c_str(), member_accessor.c_str(), name.c_str(),
1147*3f982cf4SFabien Sanglard               member_accessor.c_str());
1148*3f982cf4SFabien Sanglard       if (!WriteDecoder(fd, "(*i)", ".", *cpp_type.vector_type.element_type,
1149*3f982cf4SFabien Sanglard                         decoder_depth + 1, temporary_count)) {
1150*3f982cf4SFabien Sanglard         return false;
1151*3f982cf4SFabien Sanglard       }
1152*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1153*3f982cf4SFabien Sanglard       dprintf(
1154*3f982cf4SFabien Sanglard           fd,
1155*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_leave_container(&it%d, &it%d));\n",
1156*3f982cf4SFabien Sanglard           decoder_depth, decoder_depth + 1);
1157*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1158*3f982cf4SFabien Sanglard       return true;
1159*3f982cf4SFabien Sanglard     }
1160*3f982cf4SFabien Sanglard     case CppType::Which::kEnum: {
1161*3f982cf4SFabien Sanglard       dprintf(fd,
1162*3f982cf4SFabien Sanglard               "  CBOR_RETURN_ON_ERROR(cbor_value_get_uint64(&it%d, "
1163*3f982cf4SFabien Sanglard               "reinterpret_cast<uint64_t*>(&%s)));\n",
1164*3f982cf4SFabien Sanglard               decoder_depth, name.c_str());
1165*3f982cf4SFabien Sanglard       dprintf(fd, "  CBOR_RETURN_ON_ERROR(cbor_value_advance_fixed(&it%d));\n",
1166*3f982cf4SFabien Sanglard               decoder_depth);
1167*3f982cf4SFabien Sanglard       // TODO(btolsch): Validate against enum members.
1168*3f982cf4SFabien Sanglard       return true;
1169*3f982cf4SFabien Sanglard     }
1170*3f982cf4SFabien Sanglard     case CppType::Which::kStruct: {
1171*3f982cf4SFabien Sanglard       if (cpp_type.struct_type.key_type == CppType::Struct::KeyType::kMap) {
1172*3f982cf4SFabien Sanglard         return WriteMapDecoder(fd, name, member_accessor,
1173*3f982cf4SFabien Sanglard                                cpp_type.struct_type.members, decoder_depth + 1,
1174*3f982cf4SFabien Sanglard                                temporary_count);
1175*3f982cf4SFabien Sanglard       } else if (cpp_type.struct_type.key_type ==
1176*3f982cf4SFabien Sanglard                  CppType::Struct::KeyType::kArray) {
1177*3f982cf4SFabien Sanglard         return WriteArrayDecoder(fd, name, member_accessor,
1178*3f982cf4SFabien Sanglard                                  cpp_type.struct_type.members,
1179*3f982cf4SFabien Sanglard                                  decoder_depth + 1, temporary_count);
1180*3f982cf4SFabien Sanglard       }
1181*3f982cf4SFabien Sanglard     } break;
1182*3f982cf4SFabien Sanglard     case CppType::Which::kDiscriminatedUnion: {
1183*3f982cf4SFabien Sanglard       int temp_value_type = (*temporary_count)++;
1184*3f982cf4SFabien Sanglard       dprintf(fd, "  CborType type%d = cbor_value_get_type(&it%d);\n",
1185*3f982cf4SFabien Sanglard               temp_value_type, decoder_depth);
1186*3f982cf4SFabien Sanglard       bool first = true;
1187*3f982cf4SFabien Sanglard       for (const auto* x : cpp_type.discriminated_union.members) {
1188*3f982cf4SFabien Sanglard         if (first)
1189*3f982cf4SFabien Sanglard           first = false;
1190*3f982cf4SFabien Sanglard         else
1191*3f982cf4SFabien Sanglard           dprintf(fd, " else ");
1192*3f982cf4SFabien Sanglard         switch (x->which) {
1193*3f982cf4SFabien Sanglard           case CppType::Which::kUint64:
1194*3f982cf4SFabien Sanglard             dprintf(fd,
1195*3f982cf4SFabien Sanglard                     "  if (type%d == CborIntegerType && (it%d.flags & "
1196*3f982cf4SFabien Sanglard                     "CborIteratorFlag_NegativeInteger) == 0) {\n",
1197*3f982cf4SFabien Sanglard                     temp_value_type, decoder_depth);
1198*3f982cf4SFabien Sanglard             dprintf(fd, "  %s.which = decltype(%s)::Which::kUint64;\n",
1199*3f982cf4SFabien Sanglard                     name.c_str(), name.c_str());
1200*3f982cf4SFabien Sanglard             if (!WriteDecoder(fd, name + ".uint", ".", *x, decoder_depth,
1201*3f982cf4SFabien Sanglard                               temporary_count)) {
1202*3f982cf4SFabien Sanglard               return false;
1203*3f982cf4SFabien Sanglard             }
1204*3f982cf4SFabien Sanglard             break;
1205*3f982cf4SFabien Sanglard           case CppType::Which::kString: {
1206*3f982cf4SFabien Sanglard             dprintf(fd, "  if (type%d == CborTextStringType) {\n",
1207*3f982cf4SFabien Sanglard                     temp_value_type);
1208*3f982cf4SFabien Sanglard             dprintf(fd, "  %s.which = decltype(%s)::Which::kString;\n",
1209*3f982cf4SFabien Sanglard                     name.c_str(), name.c_str());
1210*3f982cf4SFabien Sanglard             std::string str_name = name + ".str";
1211*3f982cf4SFabien Sanglard             dprintf(fd, "  new (&%s) std::string();\n", str_name.c_str());
1212*3f982cf4SFabien Sanglard             if (!WriteDecoder(fd, str_name, ".", *x, decoder_depth,
1213*3f982cf4SFabien Sanglard                               temporary_count)) {
1214*3f982cf4SFabien Sanglard               return false;
1215*3f982cf4SFabien Sanglard             }
1216*3f982cf4SFabien Sanglard           } break;
1217*3f982cf4SFabien Sanglard           case CppType::Which::kBytes: {
1218*3f982cf4SFabien Sanglard             dprintf(fd, "  if (type%d == CborByteStringType) {\n",
1219*3f982cf4SFabien Sanglard                     temp_value_type);
1220*3f982cf4SFabien Sanglard             std::string bytes_name = name + ".bytes";
1221*3f982cf4SFabien Sanglard             dprintf(fd, "  %s.which = decltype(%s)::Which::kBytes;\n",
1222*3f982cf4SFabien Sanglard                     name.c_str(), name.c_str());
1223*3f982cf4SFabien Sanglard             dprintf(fd, "  new (&%s) std::vector<uint8_t>();\n",
1224*3f982cf4SFabien Sanglard                     bytes_name.c_str());
1225*3f982cf4SFabien Sanglard             if (!WriteDecoder(fd, bytes_name, ".", *x, decoder_depth,
1226*3f982cf4SFabien Sanglard                               temporary_count)) {
1227*3f982cf4SFabien Sanglard               return false;
1228*3f982cf4SFabien Sanglard             }
1229*3f982cf4SFabien Sanglard           } break;
1230*3f982cf4SFabien Sanglard           default:
1231*3f982cf4SFabien Sanglard             return false;
1232*3f982cf4SFabien Sanglard         }
1233*3f982cf4SFabien Sanglard         dprintf(fd, "  }\n");
1234*3f982cf4SFabien Sanglard       }
1235*3f982cf4SFabien Sanglard       dprintf(fd, " else { return -1; }\n");
1236*3f982cf4SFabien Sanglard       return true;
1237*3f982cf4SFabien Sanglard     }
1238*3f982cf4SFabien Sanglard     case CppType::Which::kTaggedType: {
1239*3f982cf4SFabien Sanglard       int temp_tag = (*temporary_count)++;
1240*3f982cf4SFabien Sanglard       dprintf(fd, "  uint64_t tag%d = 0;\n", temp_tag);
1241*3f982cf4SFabien Sanglard       dprintf(fd, "  cbor_value_get_tag(&it%d, &tag%d);\n", decoder_depth,
1242*3f982cf4SFabien Sanglard               temp_tag);
1243*3f982cf4SFabien Sanglard       dprintf(fd, "  if (tag%d != %" PRIu64 "ull) {\n", temp_tag,
1244*3f982cf4SFabien Sanglard               cpp_type.tagged_type.tag);
1245*3f982cf4SFabien Sanglard       dprintf(fd, "    return -1;\n");
1246*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1247*3f982cf4SFabien Sanglard       dprintf(fd, "  CBOR_RETURN_ON_ERROR(cbor_value_advance_fixed(&it%d));\n",
1248*3f982cf4SFabien Sanglard               decoder_depth);
1249*3f982cf4SFabien Sanglard       if (!WriteDecoder(fd, name, member_accessor,
1250*3f982cf4SFabien Sanglard                         *cpp_type.tagged_type.real_type, decoder_depth,
1251*3f982cf4SFabien Sanglard                         temporary_count)) {
1252*3f982cf4SFabien Sanglard         return false;
1253*3f982cf4SFabien Sanglard       }
1254*3f982cf4SFabien Sanglard       return true;
1255*3f982cf4SFabien Sanglard     }
1256*3f982cf4SFabien Sanglard     default:
1257*3f982cf4SFabien Sanglard       break;
1258*3f982cf4SFabien Sanglard   }
1259*3f982cf4SFabien Sanglard   return false;
1260*3f982cf4SFabien Sanglard }
1261*3f982cf4SFabien Sanglard 
1262*3f982cf4SFabien Sanglard // Writes the decoding function for the CBOR map with members in |members| to
1263*3f982cf4SFabien Sanglard // the file descriptor |fd|.  |name| is the C++ variable name that needs to be
1264*3f982cf4SFabien Sanglard // encoded.  |member_accessor| is either "." or "->" depending on whether |name|
1265*3f982cf4SFabien Sanglard // is a pointer type.  |decoder_depth| is used to independently name independent
1266*3f982cf4SFabien Sanglard // cbor decoders that need to be created.  |temporary_count| is used to ensure
1267*3f982cf4SFabien Sanglard // temporaries get unique names by appending an automatically incremented
1268*3f982cf4SFabien Sanglard // integer.
WriteMapDecoder(int fd,const std::string & name,const std::string & member_accessor,const std::vector<CppType::Struct::CppMember> & members,int decoder_depth,int * temporary_count)1269*3f982cf4SFabien Sanglard bool WriteMapDecoder(int fd,
1270*3f982cf4SFabien Sanglard                      const std::string& name,
1271*3f982cf4SFabien Sanglard                      const std::string& member_accessor,
1272*3f982cf4SFabien Sanglard                      const std::vector<CppType::Struct::CppMember>& members,
1273*3f982cf4SFabien Sanglard                      int decoder_depth,
1274*3f982cf4SFabien Sanglard                      int* temporary_count) {
1275*3f982cf4SFabien Sanglard   dprintf(fd, "  if (cbor_value_get_type(&it%d) != CborMapType) {\n",
1276*3f982cf4SFabien Sanglard           decoder_depth - 1);
1277*3f982cf4SFabien Sanglard   dprintf(fd, "    return -1;\n");
1278*3f982cf4SFabien Sanglard   dprintf(fd, "  }\n");
1279*3f982cf4SFabien Sanglard   dprintf(fd, "  CborValue it%d;\n", decoder_depth);
1280*3f982cf4SFabien Sanglard   dprintf(fd, "  size_t it%d_length = 0;\n", decoder_depth);
1281*3f982cf4SFabien Sanglard   dprintf(fd,
1282*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_get_map_length(&it%d, "
1283*3f982cf4SFabien Sanglard           "&it%d_length));\n",
1284*3f982cf4SFabien Sanglard           decoder_depth - 1, decoder_depth);
1285*3f982cf4SFabien Sanglard   int optional_members = 0;
1286*3f982cf4SFabien Sanglard   for (const auto& member : members) {
1287*3f982cf4SFabien Sanglard     if (member.type->which == CppType::Which::kOptional) {
1288*3f982cf4SFabien Sanglard       ++optional_members;
1289*3f982cf4SFabien Sanglard     }
1290*3f982cf4SFabien Sanglard   }
1291*3f982cf4SFabien Sanglard   dprintf(fd, "  if (it%d_length != %d", decoder_depth,
1292*3f982cf4SFabien Sanglard           static_cast<int>(members.size()));
1293*3f982cf4SFabien Sanglard   for (int i = 0; i < optional_members; ++i) {
1294*3f982cf4SFabien Sanglard     dprintf(fd, " && it%d_length != %d", decoder_depth,
1295*3f982cf4SFabien Sanglard             static_cast<int>(members.size()) - i - 1);
1296*3f982cf4SFabien Sanglard   }
1297*3f982cf4SFabien Sanglard   dprintf(fd, ") {\n");
1298*3f982cf4SFabien Sanglard   dprintf(fd, "    return -1;\n");
1299*3f982cf4SFabien Sanglard   dprintf(fd, "  }\n");
1300*3f982cf4SFabien Sanglard   dprintf(fd,
1301*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_enter_container(&it%d, &it%d));\n",
1302*3f982cf4SFabien Sanglard           decoder_depth - 1, decoder_depth);
1303*3f982cf4SFabien Sanglard   int member_pos = 0;
1304*3f982cf4SFabien Sanglard   for (const auto& x : members) {
1305*3f982cf4SFabien Sanglard     std::string cid = ToUnderscoreId(x.name);
1306*3f982cf4SFabien Sanglard     std::string fullname = name + member_accessor + cid;
1307*3f982cf4SFabien Sanglard     if (x.type->which == CppType::Which::kOptional) {
1308*3f982cf4SFabien Sanglard       // TODO(btolsch): This is wrong for the same reason as arrays, but will be
1309*3f982cf4SFabien Sanglard       // easier to handle when doing out-of-order keys.
1310*3f982cf4SFabien Sanglard       dprintf(fd, "  if (it%d_length > %d) {\n", decoder_depth, member_pos);
1311*3f982cf4SFabien Sanglard 
1312*3f982cf4SFabien Sanglard       if (x.integer_key.has_value()) {
1313*3f982cf4SFabien Sanglard         dprintf(fd,
1314*3f982cf4SFabien Sanglard                 "  CBOR_RETURN_ON_ERROR(EXPECT_INT_KEY_CONSTANT(&it%d, %" PRIu64
1315*3f982cf4SFabien Sanglard                 "));\n",
1316*3f982cf4SFabien Sanglard                 decoder_depth, x.integer_key.value());
1317*3f982cf4SFabien Sanglard       } else {
1318*3f982cf4SFabien Sanglard         dprintf(fd,
1319*3f982cf4SFabien Sanglard                 "  CBOR_RETURN_ON_ERROR(EXPECT_KEY_CONSTANT(&it%d, \"%s\"));\n",
1320*3f982cf4SFabien Sanglard                 decoder_depth, x.name.c_str());
1321*3f982cf4SFabien Sanglard       }
1322*3f982cf4SFabien Sanglard       dprintf(fd, "    %s%shas_%s = true;\n", name.c_str(),
1323*3f982cf4SFabien Sanglard               member_accessor.c_str(), cid.c_str());
1324*3f982cf4SFabien Sanglard       if (!WriteDecoder(fd, fullname, ".", *x.type->optional_type,
1325*3f982cf4SFabien Sanglard                         decoder_depth, temporary_count)) {
1326*3f982cf4SFabien Sanglard         return false;
1327*3f982cf4SFabien Sanglard       }
1328*3f982cf4SFabien Sanglard       dprintf(fd, "  } else {\n");
1329*3f982cf4SFabien Sanglard       dprintf(fd, "    %s%shas_%s = false;\n", name.c_str(),
1330*3f982cf4SFabien Sanglard               member_accessor.c_str(), cid.c_str());
1331*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1332*3f982cf4SFabien Sanglard     } else {
1333*3f982cf4SFabien Sanglard       if (x.integer_key.has_value()) {
1334*3f982cf4SFabien Sanglard         dprintf(fd,
1335*3f982cf4SFabien Sanglard                 "  CBOR_RETURN_ON_ERROR(EXPECT_INT_KEY_CONSTANT(&it%d, %" PRIu64
1336*3f982cf4SFabien Sanglard                 "));\n",
1337*3f982cf4SFabien Sanglard                 decoder_depth, x.integer_key.value());
1338*3f982cf4SFabien Sanglard       } else {
1339*3f982cf4SFabien Sanglard         dprintf(fd,
1340*3f982cf4SFabien Sanglard                 "  CBOR_RETURN_ON_ERROR(EXPECT_KEY_CONSTANT(&it%d, \"%s\"));\n",
1341*3f982cf4SFabien Sanglard                 decoder_depth, x.name.c_str());
1342*3f982cf4SFabien Sanglard       }
1343*3f982cf4SFabien Sanglard       if (!WriteDecoder(fd, fullname, ".", *x.type, decoder_depth,
1344*3f982cf4SFabien Sanglard                         temporary_count)) {
1345*3f982cf4SFabien Sanglard         return false;
1346*3f982cf4SFabien Sanglard       }
1347*3f982cf4SFabien Sanglard     }
1348*3f982cf4SFabien Sanglard     ++member_pos;
1349*3f982cf4SFabien Sanglard   }
1350*3f982cf4SFabien Sanglard   dprintf(fd,
1351*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_leave_container(&it%d, &it%d));\n",
1352*3f982cf4SFabien Sanglard           decoder_depth - 1, decoder_depth);
1353*3f982cf4SFabien Sanglard   return true;
1354*3f982cf4SFabien Sanglard }
1355*3f982cf4SFabien Sanglard 
1356*3f982cf4SFabien Sanglard // Writes the decoding function for the CBOR array with members in |members| to
1357*3f982cf4SFabien Sanglard // the file descriptor |fd|.  |name| is the C++ variable name that needs to be
1358*3f982cf4SFabien Sanglard // encoded.  |member_accessor| is either "." or "->" depending on whether |name|
1359*3f982cf4SFabien Sanglard // is a pointer type.  |decoder_depth| is used to independently name independent
1360*3f982cf4SFabien Sanglard // cbor decoders that need to be created.  |temporary_count| is used to ensure
1361*3f982cf4SFabien Sanglard // temporaries get unique names by appending an automatically incremented
1362*3f982cf4SFabien Sanglard // integer.
WriteArrayDecoder(int fd,const std::string & name,const std::string & member_accessor,const std::vector<CppType::Struct::CppMember> & members,int decoder_depth,int * temporary_count)1363*3f982cf4SFabien Sanglard bool WriteArrayDecoder(int fd,
1364*3f982cf4SFabien Sanglard                        const std::string& name,
1365*3f982cf4SFabien Sanglard                        const std::string& member_accessor,
1366*3f982cf4SFabien Sanglard                        const std::vector<CppType::Struct::CppMember>& members,
1367*3f982cf4SFabien Sanglard                        int decoder_depth,
1368*3f982cf4SFabien Sanglard                        int* temporary_count) {
1369*3f982cf4SFabien Sanglard   dprintf(fd, "  if (cbor_value_get_type(&it%d) != CborArrayType) {\n",
1370*3f982cf4SFabien Sanglard           decoder_depth - 1);
1371*3f982cf4SFabien Sanglard   dprintf(fd, "    return -1;\n");
1372*3f982cf4SFabien Sanglard   dprintf(fd, "  }\n");
1373*3f982cf4SFabien Sanglard   dprintf(fd, "  CborValue it%d;\n", decoder_depth);
1374*3f982cf4SFabien Sanglard   dprintf(fd, "  size_t it%d_length = 0;\n", decoder_depth);
1375*3f982cf4SFabien Sanglard   dprintf(fd,
1376*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_get_array_length(&it%d, "
1377*3f982cf4SFabien Sanglard           "&it%d_length));\n",
1378*3f982cf4SFabien Sanglard           decoder_depth - 1, decoder_depth);
1379*3f982cf4SFabien Sanglard   int optional_members = 0;
1380*3f982cf4SFabien Sanglard   for (const auto& member : members) {
1381*3f982cf4SFabien Sanglard     if (member.type->which == CppType::Which::kOptional) {
1382*3f982cf4SFabien Sanglard       ++optional_members;
1383*3f982cf4SFabien Sanglard     }
1384*3f982cf4SFabien Sanglard   }
1385*3f982cf4SFabien Sanglard   dprintf(fd, "  if (it%d_length != %d", decoder_depth,
1386*3f982cf4SFabien Sanglard           static_cast<int>(members.size()));
1387*3f982cf4SFabien Sanglard   for (int i = 0; i < optional_members; ++i) {
1388*3f982cf4SFabien Sanglard     dprintf(fd, " && it%d_length != %d", decoder_depth,
1389*3f982cf4SFabien Sanglard             static_cast<int>(members.size()) - i - 1);
1390*3f982cf4SFabien Sanglard   }
1391*3f982cf4SFabien Sanglard   dprintf(fd, ") {\n");
1392*3f982cf4SFabien Sanglard   dprintf(fd, "    return -1;\n");
1393*3f982cf4SFabien Sanglard   dprintf(fd, "  }\n");
1394*3f982cf4SFabien Sanglard   dprintf(fd,
1395*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_enter_container(&it%d, &it%d));\n",
1396*3f982cf4SFabien Sanglard           decoder_depth - 1, decoder_depth);
1397*3f982cf4SFabien Sanglard   int member_pos = 0;
1398*3f982cf4SFabien Sanglard   for (const auto& x : members) {
1399*3f982cf4SFabien Sanglard     std::string cid = ToUnderscoreId(x.name);
1400*3f982cf4SFabien Sanglard     std::string fullname = name + member_accessor + cid;
1401*3f982cf4SFabien Sanglard     if (x.type->which == CppType::Which::kOptional) {
1402*3f982cf4SFabien Sanglard       // TODO(btolsch): This only handles a single block of optionals and only
1403*3f982cf4SFabien Sanglard       // the ones present form a contiguous range from the start of the block.
1404*3f982cf4SFabien Sanglard       // However, we likely don't really need more than one optional for arrays
1405*3f982cf4SFabien Sanglard       // for the foreseeable future.  The proper approach would be to have a set
1406*3f982cf4SFabien Sanglard       // of possible types for the next element and a map for the member to
1407*3f982cf4SFabien Sanglard       // which each corresponds.
1408*3f982cf4SFabien Sanglard       dprintf(fd, "  if (it%d_length > %d) {\n", decoder_depth, member_pos);
1409*3f982cf4SFabien Sanglard       dprintf(fd, "    %s%shas_%s = true;\n", name.c_str(),
1410*3f982cf4SFabien Sanglard               member_accessor.c_str(), cid.c_str());
1411*3f982cf4SFabien Sanglard       if (!WriteDecoder(fd, fullname, ".", *x.type->optional_type,
1412*3f982cf4SFabien Sanglard                         decoder_depth, temporary_count)) {
1413*3f982cf4SFabien Sanglard         return false;
1414*3f982cf4SFabien Sanglard       }
1415*3f982cf4SFabien Sanglard       dprintf(fd, "  } else {\n");
1416*3f982cf4SFabien Sanglard       dprintf(fd, "    %s%shas_%s = false;\n", name.c_str(),
1417*3f982cf4SFabien Sanglard               member_accessor.c_str(), cid.c_str());
1418*3f982cf4SFabien Sanglard       dprintf(fd, "  }\n");
1419*3f982cf4SFabien Sanglard     } else {
1420*3f982cf4SFabien Sanglard       if (!WriteDecoder(fd, fullname, ".", *x.type, decoder_depth,
1421*3f982cf4SFabien Sanglard                         temporary_count)) {
1422*3f982cf4SFabien Sanglard         return false;
1423*3f982cf4SFabien Sanglard       }
1424*3f982cf4SFabien Sanglard     }
1425*3f982cf4SFabien Sanglard     ++member_pos;
1426*3f982cf4SFabien Sanglard   }
1427*3f982cf4SFabien Sanglard   dprintf(fd,
1428*3f982cf4SFabien Sanglard           "  CBOR_RETURN_ON_ERROR(cbor_value_leave_container(&it%d, &it%d));\n",
1429*3f982cf4SFabien Sanglard           decoder_depth - 1, decoder_depth);
1430*3f982cf4SFabien Sanglard   return true;
1431*3f982cf4SFabien Sanglard }
1432*3f982cf4SFabien Sanglard 
1433*3f982cf4SFabien Sanglard // Writes the equality operators for all structs.
WriteEqualityOperators(int fd,CppSymbolTable * table)1434*3f982cf4SFabien Sanglard bool WriteEqualityOperators(int fd, CppSymbolTable* table) {
1435*3f982cf4SFabien Sanglard   for (const auto& pair : table->cpp_type_map) {
1436*3f982cf4SFabien Sanglard     CppType* real_type = pair.second;
1437*3f982cf4SFabien Sanglard     if (real_type->which == CppType::Which::kStruct &&
1438*3f982cf4SFabien Sanglard         real_type->struct_type.key_type !=
1439*3f982cf4SFabien Sanglard             CppType::Struct::KeyType::kPlainGroup) {
1440*3f982cf4SFabien Sanglard       if (!WriteStructEqualityOperator(fd, *real_type)) {
1441*3f982cf4SFabien Sanglard         return false;
1442*3f982cf4SFabien Sanglard       }
1443*3f982cf4SFabien Sanglard     }
1444*3f982cf4SFabien Sanglard   }
1445*3f982cf4SFabien Sanglard   return true;
1446*3f982cf4SFabien Sanglard }
1447*3f982cf4SFabien Sanglard 
1448*3f982cf4SFabien Sanglard // Writes a decoder function definition for every type in |table| to the file
1449*3f982cf4SFabien Sanglard // descriptor |fd|.
WriteDecoders(int fd,CppSymbolTable * table)1450*3f982cf4SFabien Sanglard bool WriteDecoders(int fd, CppSymbolTable* table) {
1451*3f982cf4SFabien Sanglard   if (!WriteTypeParserDefinition(fd, table)) {
1452*3f982cf4SFabien Sanglard     return false;
1453*3f982cf4SFabien Sanglard   }
1454*3f982cf4SFabien Sanglard   for (CppType* real_type : table->TypesWithId()) {
1455*3f982cf4SFabien Sanglard     const auto& name = real_type->name;
1456*3f982cf4SFabien Sanglard     int temporary_count = 0;
1457*3f982cf4SFabien Sanglard     if (real_type->which != CppType::Which::kStruct ||
1458*3f982cf4SFabien Sanglard         real_type->struct_type.key_type ==
1459*3f982cf4SFabien Sanglard             CppType::Struct::KeyType::kPlainGroup) {
1460*3f982cf4SFabien Sanglard       continue;
1461*3f982cf4SFabien Sanglard     }
1462*3f982cf4SFabien Sanglard     std::string cpp_name = ToCamelCase(name);
1463*3f982cf4SFabien Sanglard     dprintf(fd, "\nssize_t Decode%s(\n", cpp_name.c_str());
1464*3f982cf4SFabien Sanglard     dprintf(fd, "    const uint8_t* buffer,\n    size_t length,\n");
1465*3f982cf4SFabien Sanglard     dprintf(fd, "    %s* data) {\n", cpp_name.c_str());
1466*3f982cf4SFabien Sanglard     dprintf(fd, "  CborParser parser;\n");
1467*3f982cf4SFabien Sanglard     dprintf(fd, "  CborValue it0;\n");
1468*3f982cf4SFabien Sanglard     dprintf(
1469*3f982cf4SFabien Sanglard         fd,
1470*3f982cf4SFabien Sanglard         "  CBOR_RETURN_ON_ERROR(cbor_parser_init(buffer, length, 0, &parser, "
1471*3f982cf4SFabien Sanglard         "&it0));\n");
1472*3f982cf4SFabien Sanglard     if (real_type->struct_type.key_type == CppType::Struct::KeyType::kMap) {
1473*3f982cf4SFabien Sanglard       if (!WriteMapDecoder(fd, "data", "->", real_type->struct_type.members, 1,
1474*3f982cf4SFabien Sanglard                            &temporary_count)) {
1475*3f982cf4SFabien Sanglard         return false;
1476*3f982cf4SFabien Sanglard       }
1477*3f982cf4SFabien Sanglard     } else {
1478*3f982cf4SFabien Sanglard       if (!WriteArrayDecoder(fd, "data", "->", real_type->struct_type.members,
1479*3f982cf4SFabien Sanglard                              1, &temporary_count)) {
1480*3f982cf4SFabien Sanglard         return false;
1481*3f982cf4SFabien Sanglard       }
1482*3f982cf4SFabien Sanglard     }
1483*3f982cf4SFabien Sanglard     dprintf(
1484*3f982cf4SFabien Sanglard         fd,
1485*3f982cf4SFabien Sanglard         "  auto result = static_cast<ssize_t>(cbor_value_get_next_byte(&it0) - "
1486*3f982cf4SFabien Sanglard         "buffer);\n");
1487*3f982cf4SFabien Sanglard     dprintf(fd, "  return result;\n");
1488*3f982cf4SFabien Sanglard     dprintf(fd, "}\n");
1489*3f982cf4SFabien Sanglard   }
1490*3f982cf4SFabien Sanglard   return true;
1491*3f982cf4SFabien Sanglard }
1492*3f982cf4SFabien Sanglard 
1493*3f982cf4SFabien Sanglard // Converts the filename |header_filename| to a preprocessor token that can be
1494*3f982cf4SFabien Sanglard // used as a header guard macro name.
ToHeaderGuard(const std::string & header_filename)1495*3f982cf4SFabien Sanglard std::string ToHeaderGuard(const std::string& header_filename) {
1496*3f982cf4SFabien Sanglard   std::string result = header_filename;
1497*3f982cf4SFabien Sanglard   for (auto& c : result) {
1498*3f982cf4SFabien Sanglard     if (c == '/' || c == '.')
1499*3f982cf4SFabien Sanglard       c = '_';
1500*3f982cf4SFabien Sanglard     else
1501*3f982cf4SFabien Sanglard       c = toupper(c);
1502*3f982cf4SFabien Sanglard   }
1503*3f982cf4SFabien Sanglard   result += "_";
1504*3f982cf4SFabien Sanglard   return result;
1505*3f982cf4SFabien Sanglard }
1506*3f982cf4SFabien Sanglard 
WriteHeaderPrologue(int fd,const std::string & header_filename)1507*3f982cf4SFabien Sanglard bool WriteHeaderPrologue(int fd, const std::string& header_filename) {
1508*3f982cf4SFabien Sanglard   static const char prologue[] =
1509*3f982cf4SFabien Sanglard       R"(#ifndef %s
1510*3f982cf4SFabien Sanglard #define %s
1511*3f982cf4SFabien Sanglard 
1512*3f982cf4SFabien Sanglard #include <array>
1513*3f982cf4SFabien Sanglard #include <cstdint>
1514*3f982cf4SFabien Sanglard #include <iostream>
1515*3f982cf4SFabien Sanglard #include <string>
1516*3f982cf4SFabien Sanglard #include <vector>
1517*3f982cf4SFabien Sanglard 
1518*3f982cf4SFabien Sanglard #include "third_party/tinycbor/src/src/cbor.h"
1519*3f982cf4SFabien Sanglard 
1520*3f982cf4SFabien Sanglard namespace openscreen {
1521*3f982cf4SFabien Sanglard namespace msgs {
1522*3f982cf4SFabien Sanglard 
1523*3f982cf4SFabien Sanglard enum CborErrors {
1524*3f982cf4SFabien Sanglard   kParserEOF = -CborErrorUnexpectedEOF,
1525*3f982cf4SFabien Sanglard };
1526*3f982cf4SFabien Sanglard 
1527*3f982cf4SFabien Sanglard class CborEncodeBuffer;
1528*3f982cf4SFabien Sanglard )";
1529*3f982cf4SFabien Sanglard   std::string header_guard = ToHeaderGuard(header_filename);
1530*3f982cf4SFabien Sanglard   dprintf(fd, prologue, header_guard.c_str(), header_guard.c_str());
1531*3f982cf4SFabien Sanglard   return true;
1532*3f982cf4SFabien Sanglard }
1533*3f982cf4SFabien Sanglard 
WriteHeaderEpilogue(int fd,const std::string & header_filename)1534*3f982cf4SFabien Sanglard bool WriteHeaderEpilogue(int fd, const std::string& header_filename) {
1535*3f982cf4SFabien Sanglard   static const char epilogue[] = R"(
1536*3f982cf4SFabien Sanglard class TypeEnumValidator {
1537*3f982cf4SFabien Sanglard  public:
1538*3f982cf4SFabien Sanglard   static Type SafeCast(uint64_t type_id);
1539*3f982cf4SFabien Sanglard };
1540*3f982cf4SFabien Sanglard 
1541*3f982cf4SFabien Sanglard class CborEncodeBuffer {
1542*3f982cf4SFabien Sanglard  public:
1543*3f982cf4SFabien Sanglard   static constexpr size_t kDefaultInitialEncodeBufferSize = 250;
1544*3f982cf4SFabien Sanglard   static constexpr size_t kDefaultMaxEncodeBufferSize = 64000;
1545*3f982cf4SFabien Sanglard 
1546*3f982cf4SFabien Sanglard   CborEncodeBuffer();
1547*3f982cf4SFabien Sanglard   CborEncodeBuffer(size_t initial_size, size_t max_size);
1548*3f982cf4SFabien Sanglard   ~CborEncodeBuffer();
1549*3f982cf4SFabien Sanglard 
1550*3f982cf4SFabien Sanglard   bool Append(size_t length);
1551*3f982cf4SFabien Sanglard   bool ResizeBy(ssize_t length);
1552*3f982cf4SFabien Sanglard   bool SetType(const uint8_t encoded_id[], size_t size);
1553*3f982cf4SFabien Sanglard 
1554*3f982cf4SFabien Sanglard   const uint8_t* data() const { return data_.data(); }
1555*3f982cf4SFabien Sanglard   size_t size() const { return data_.size(); }
1556*3f982cf4SFabien Sanglard 
1557*3f982cf4SFabien Sanglard   uint8_t* Position() { return &data_[0] + position_; }
1558*3f982cf4SFabien Sanglard   size_t AvailableLength() { return data_.size() - position_; }
1559*3f982cf4SFabien Sanglard 
1560*3f982cf4SFabien Sanglard  private:
1561*3f982cf4SFabien Sanglard   size_t max_size_;
1562*3f982cf4SFabien Sanglard   size_t position_;
1563*3f982cf4SFabien Sanglard   std::vector<uint8_t> data_;
1564*3f982cf4SFabien Sanglard };
1565*3f982cf4SFabien Sanglard 
1566*3f982cf4SFabien Sanglard CborError ExpectKey(CborValue* it, const uint64_t key);
1567*3f982cf4SFabien Sanglard CborError ExpectKey(CborValue* it, const char* key, size_t key_length);
1568*3f982cf4SFabien Sanglard 
1569*3f982cf4SFabien Sanglard }  // namespace msgs
1570*3f982cf4SFabien Sanglard }  // namespace openscreen
1571*3f982cf4SFabien Sanglard #endif  // %s)";
1572*3f982cf4SFabien Sanglard   std::string header_guard = ToHeaderGuard(header_filename);
1573*3f982cf4SFabien Sanglard   dprintf(fd, epilogue, header_guard.c_str());
1574*3f982cf4SFabien Sanglard   return true;
1575*3f982cf4SFabien Sanglard }
1576*3f982cf4SFabien Sanglard 
WriteSourcePrologue(int fd,const std::string & header_filename)1577*3f982cf4SFabien Sanglard bool WriteSourcePrologue(int fd, const std::string& header_filename) {
1578*3f982cf4SFabien Sanglard   static const char prologue[] =
1579*3f982cf4SFabien Sanglard       R"(#include "%s"
1580*3f982cf4SFabien Sanglard 
1581*3f982cf4SFabien Sanglard #include "third_party/tinycbor/src/src/utf8_p.h"
1582*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
1583*3f982cf4SFabien Sanglard 
1584*3f982cf4SFabien Sanglard namespace openscreen {
1585*3f982cf4SFabien Sanglard namespace msgs {
1586*3f982cf4SFabien Sanglard namespace {
1587*3f982cf4SFabien Sanglard 
1588*3f982cf4SFabien Sanglard /*
1589*3f982cf4SFabien Sanglard  * Encoder-specific errors, so it's fine to check these even in the
1590*3f982cf4SFabien Sanglard  * parser.
1591*3f982cf4SFabien Sanglard  */
1592*3f982cf4SFabien Sanglard #define CBOR_RETURN_WHAT_ON_ERROR(stmt, what)                           \
1593*3f982cf4SFabien Sanglard   {                                                                     \
1594*3f982cf4SFabien Sanglard     CborError error = stmt;                                             \
1595*3f982cf4SFabien Sanglard     OSP_DCHECK_NE(error, CborErrorTooFewItems);                         \
1596*3f982cf4SFabien Sanglard     OSP_DCHECK_NE(error, CborErrorTooManyItems);                        \
1597*3f982cf4SFabien Sanglard     OSP_DCHECK_NE(error, CborErrorDataTooLarge);                        \
1598*3f982cf4SFabien Sanglard     if (error != CborNoError && error != CborErrorOutOfMemory)          \
1599*3f982cf4SFabien Sanglard       return what;                                                      \
1600*3f982cf4SFabien Sanglard   }
1601*3f982cf4SFabien Sanglard #define CBOR_RETURN_ON_ERROR_INTERNAL(stmt) \
1602*3f982cf4SFabien Sanglard   CBOR_RETURN_WHAT_ON_ERROR(stmt, error)
1603*3f982cf4SFabien Sanglard #define CBOR_RETURN_ON_ERROR(stmt) CBOR_RETURN_WHAT_ON_ERROR(stmt, -error)
1604*3f982cf4SFabien Sanglard 
1605*3f982cf4SFabien Sanglard #define EXPECT_KEY_CONSTANT(it, key) ExpectKey(it, key, sizeof(key) - 1)
1606*3f982cf4SFabien Sanglard #define EXPECT_INT_KEY_CONSTANT(it, key) ExpectKey(it, key)
1607*3f982cf4SFabien Sanglard 
1608*3f982cf4SFabien Sanglard bool IsValidUtf8(const std::string& s) {
1609*3f982cf4SFabien Sanglard   const uint8_t* buffer = reinterpret_cast<const uint8_t*>(s.data());
1610*3f982cf4SFabien Sanglard   const uint8_t* end = buffer + s.size();
1611*3f982cf4SFabien Sanglard   while (buffer < end) {
1612*3f982cf4SFabien Sanglard     // TODO(btolsch): This is an implementation detail of tinycbor so we should
1613*3f982cf4SFabien Sanglard     // eventually replace this call with our own utf8 validation.
1614*3f982cf4SFabien Sanglard     if (get_utf8(&buffer, end) == ~0u)
1615*3f982cf4SFabien Sanglard       return false;
1616*3f982cf4SFabien Sanglard   }
1617*3f982cf4SFabien Sanglard   return true;
1618*3f982cf4SFabien Sanglard }
1619*3f982cf4SFabien Sanglard }  // namespace
1620*3f982cf4SFabien Sanglard 
1621*3f982cf4SFabien Sanglard CborError ExpectKey(CborValue* it, const uint64_t key) {
1622*3f982cf4SFabien Sanglard   if  (!cbor_value_is_unsigned_integer(it))
1623*3f982cf4SFabien Sanglard     return CborErrorImproperValue;
1624*3f982cf4SFabien Sanglard   uint64_t observed_key;
1625*3f982cf4SFabien Sanglard   CBOR_RETURN_ON_ERROR_INTERNAL(cbor_value_get_uint64(it, &observed_key));
1626*3f982cf4SFabien Sanglard   if (observed_key != key)
1627*3f982cf4SFabien Sanglard     return CborErrorImproperValue;
1628*3f982cf4SFabien Sanglard   CBOR_RETURN_ON_ERROR_INTERNAL(cbor_value_advance_fixed(it));
1629*3f982cf4SFabien Sanglard   return CborNoError;
1630*3f982cf4SFabien Sanglard }
1631*3f982cf4SFabien Sanglard 
1632*3f982cf4SFabien Sanglard CborError ExpectKey(CborValue* it, const char* key, size_t key_length) {
1633*3f982cf4SFabien Sanglard   if(!cbor_value_is_text_string(it))
1634*3f982cf4SFabien Sanglard     return CborErrorImproperValue;
1635*3f982cf4SFabien Sanglard   size_t observed_length = 0;
1636*3f982cf4SFabien Sanglard   CBOR_RETURN_ON_ERROR_INTERNAL(
1637*3f982cf4SFabien Sanglard       cbor_value_get_string_length(it, &observed_length));
1638*3f982cf4SFabien Sanglard   if (observed_length != key_length)
1639*3f982cf4SFabien Sanglard     return CborErrorImproperValue;
1640*3f982cf4SFabien Sanglard   std::string observed_key(key_length, 0);
1641*3f982cf4SFabien Sanglard   CBOR_RETURN_ON_ERROR_INTERNAL(cbor_value_copy_text_string(
1642*3f982cf4SFabien Sanglard       it, const_cast<char*>(observed_key.data()), &observed_length, nullptr));
1643*3f982cf4SFabien Sanglard   if (observed_key != key)
1644*3f982cf4SFabien Sanglard     return CborErrorImproperValue;
1645*3f982cf4SFabien Sanglard   CBOR_RETURN_ON_ERROR_INTERNAL(cbor_value_advance(it));
1646*3f982cf4SFabien Sanglard   return CborNoError;
1647*3f982cf4SFabien Sanglard }
1648*3f982cf4SFabien Sanglard 
1649*3f982cf4SFabien Sanglard // static
1650*3f982cf4SFabien Sanglard constexpr size_t CborEncodeBuffer::kDefaultInitialEncodeBufferSize;
1651*3f982cf4SFabien Sanglard 
1652*3f982cf4SFabien Sanglard // static
1653*3f982cf4SFabien Sanglard constexpr size_t CborEncodeBuffer::kDefaultMaxEncodeBufferSize;
1654*3f982cf4SFabien Sanglard 
1655*3f982cf4SFabien Sanglard CborEncodeBuffer::CborEncodeBuffer()
1656*3f982cf4SFabien Sanglard     : max_size_(kDefaultMaxEncodeBufferSize),
1657*3f982cf4SFabien Sanglard       position_(0),
1658*3f982cf4SFabien Sanglard       data_(kDefaultInitialEncodeBufferSize) {}
1659*3f982cf4SFabien Sanglard CborEncodeBuffer::CborEncodeBuffer(size_t initial_size, size_t max_size)
1660*3f982cf4SFabien Sanglard     : max_size_(max_size), position_(0), data_(initial_size) {}
1661*3f982cf4SFabien Sanglard CborEncodeBuffer::~CborEncodeBuffer() = default;
1662*3f982cf4SFabien Sanglard 
1663*3f982cf4SFabien Sanglard bool CborEncodeBuffer::SetType(const uint8_t encoded_id[], size_t size) {
1664*3f982cf4SFabien Sanglard   if (this->AvailableLength() < size) {
1665*3f982cf4SFabien Sanglard     if (!this->ResizeBy(size)) {
1666*3f982cf4SFabien Sanglard       return false;
1667*3f982cf4SFabien Sanglard     }
1668*3f982cf4SFabien Sanglard   }
1669*3f982cf4SFabien Sanglard   memcpy(&data_[position_], encoded_id, size);
1670*3f982cf4SFabien Sanglard   position_ += size;
1671*3f982cf4SFabien Sanglard   return true;
1672*3f982cf4SFabien Sanglard }
1673*3f982cf4SFabien Sanglard 
1674*3f982cf4SFabien Sanglard bool CborEncodeBuffer::Append(size_t length) {
1675*3f982cf4SFabien Sanglard   if (length == 0)
1676*3f982cf4SFabien Sanglard     return false;
1677*3f982cf4SFabien Sanglard   if ((data_.size() + length) > max_size_) {
1678*3f982cf4SFabien Sanglard     length = max_size_ - data_.size();
1679*3f982cf4SFabien Sanglard     if (length == 0)
1680*3f982cf4SFabien Sanglard       return false;
1681*3f982cf4SFabien Sanglard   }
1682*3f982cf4SFabien Sanglard   size_t append_area = data_.size();
1683*3f982cf4SFabien Sanglard   data_.resize(append_area + length);
1684*3f982cf4SFabien Sanglard   position_ = append_area;
1685*3f982cf4SFabien Sanglard   return true;
1686*3f982cf4SFabien Sanglard }
1687*3f982cf4SFabien Sanglard 
1688*3f982cf4SFabien Sanglard bool CborEncodeBuffer::ResizeBy(ssize_t delta) {
1689*3f982cf4SFabien Sanglard   if (delta == 0)
1690*3f982cf4SFabien Sanglard     return true;
1691*3f982cf4SFabien Sanglard   if (delta < 0 && static_cast<size_t>(-delta) > data_.size())
1692*3f982cf4SFabien Sanglard     return false;
1693*3f982cf4SFabien Sanglard   if (delta > 0 && (data_.size() + delta) > max_size_)
1694*3f982cf4SFabien Sanglard     return false;
1695*3f982cf4SFabien Sanglard   data_.resize(data_.size() + delta);
1696*3f982cf4SFabien Sanglard   return true;
1697*3f982cf4SFabien Sanglard }
1698*3f982cf4SFabien Sanglard 
1699*3f982cf4SFabien Sanglard bool IsError(ssize_t x) {
1700*3f982cf4SFabien Sanglard   return x < 0;
1701*3f982cf4SFabien Sanglard }
1702*3f982cf4SFabien Sanglard )";
1703*3f982cf4SFabien Sanglard   dprintf(fd, prologue, header_filename.c_str());
1704*3f982cf4SFabien Sanglard   return true;
1705*3f982cf4SFabien Sanglard }
1706*3f982cf4SFabien Sanglard 
WriteSourceEpilogue(int fd)1707*3f982cf4SFabien Sanglard bool WriteSourceEpilogue(int fd) {
1708*3f982cf4SFabien Sanglard   static const char epilogue[] = R"(
1709*3f982cf4SFabien Sanglard }  // namespace msgs
1710*3f982cf4SFabien Sanglard }  // namespace openscreen)";
1711*3f982cf4SFabien Sanglard   dprintf(fd, epilogue);
1712*3f982cf4SFabien Sanglard   return true;
1713*3f982cf4SFabien Sanglard }
1714