1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18 #include <list>
19 #include <string>
20
21 #include <math.h>
22
23 #include "flatbuffers/idl.h"
24 #include "flatbuffers/util.h"
25
26 namespace flatbuffers {
27
28 const double kPi = 3.14159265358979323846;
29
30 const char *const kTypeNames[] = {
31 // clang-format off
32 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
33 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
34 IDLTYPE,
35 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
36 #undef FLATBUFFERS_TD
37 // clang-format on
38 nullptr
39 };
40
41 const char kTypeSizes[] = {
42 // clang-format off
43 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
44 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
45 sizeof(CTYPE),
46 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
47 #undef FLATBUFFERS_TD
48 // clang-format on
49 };
50
51 // The enums in the reflection schema should match the ones we use internally.
52 // Compare the last element to check if these go out of sync.
53 static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::Union),
54 "enums don't match");
55
56 // Any parsing calls have to be wrapped in this macro, which automates
57 // handling of recursive error checking a bit. It will check the received
58 // CheckedError object, and return straight away on error.
59 #define ECHECK(call) \
60 { \
61 auto ce = (call); \
62 if (ce.Check()) return ce; \
63 }
64
65 // These two functions are called hundreds of times below, so define a short
66 // form:
67 #define NEXT() ECHECK(Next())
68 #define EXPECT(tok) ECHECK(Expect(tok))
69
ValidateUTF8(const std::string & str)70 static bool ValidateUTF8(const std::string &str) {
71 const char *s = &str[0];
72 const char *const sEnd = s + str.length();
73 while (s < sEnd) {
74 if (FromUTF8(&s) < 0) { return false; }
75 }
76 return true;
77 }
78
79 // Convert an underscore_based_indentifier in to camelCase.
80 // Also uppercases the first character if first is true.
MakeCamel(const std::string & in,bool first)81 std::string MakeCamel(const std::string &in, bool first) {
82 std::string s;
83 for (size_t i = 0; i < in.length(); i++) {
84 if (!i && first)
85 s += static_cast<char>(toupper(in[0]));
86 else if (in[i] == '_' && i + 1 < in.length())
87 s += static_cast<char>(toupper(in[++i]));
88 else
89 s += in[i];
90 }
91 return s;
92 }
93
DeserializeDoc(std::vector<std::string> & doc,const Vector<Offset<String>> * documentation)94 void DeserializeDoc( std::vector<std::string> &doc,
95 const Vector<Offset<String>> *documentation) {
96 if (documentation == nullptr) return;
97 for (uoffset_t index = 0; index < documentation->Length(); index++)
98 doc.push_back(documentation->Get(index)->str());
99 }
100
Message(const std::string & msg)101 void Parser::Message(const std::string &msg) {
102 error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
103 // clang-format off
104 #ifdef _WIN32 // MSVC alike
105 error_ +=
106 "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")";
107 #else // gcc alike
108 if (file_being_parsed_.length()) error_ += ":";
109 error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
110 #endif
111 // clang-format on
112 error_ += ": " + msg;
113 }
114
Warning(const std::string & msg)115 void Parser::Warning(const std::string &msg) { Message("warning: " + msg); }
116
Error(const std::string & msg)117 CheckedError Parser::Error(const std::string &msg) {
118 Message("error: " + msg);
119 return CheckedError(true);
120 }
121
NoError()122 inline CheckedError NoError() { return CheckedError(false); }
123
RecurseError()124 CheckedError Parser::RecurseError() {
125 return Error("maximum parsing recursion of " +
126 NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached");
127 }
128
Recurse(F f)129 template<typename F> CheckedError Parser::Recurse(F f) {
130 if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH))
131 return RecurseError();
132 recurse_protection_counter++;
133 auto ce = f();
134 recurse_protection_counter--;
135 return ce;
136 }
137
InvalidNumber(const char * number,const std::string & msg)138 CheckedError Parser::InvalidNumber(const char *number, const std::string &msg) {
139 return Error("invalid number: \"" + std::string(number) + "\"" + msg);
140 }
141 // atot: templated version of atoi/atof: convert a string to an instance of T.
142 template<typename T>
atot(const char * s,Parser & parser,T * val)143 inline CheckedError atot(const char *s, Parser &parser, T *val) {
144 auto done = StringToNumber(s, val);
145 if (done) return NoError();
146
147 return parser.InvalidNumber(
148 s, (0 == *val)
149 ? ""
150 : (", constant does not fit [" +
151 NumToString(flatbuffers::numeric_limits<T>::lowest()) + "; " +
152 NumToString(flatbuffers::numeric_limits<T>::max()) + "]"));
153 }
154 template<>
atot(const char * s,Parser & parser,Offset<void> * val)155 inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
156 Offset<void> *val) {
157 (void)parser;
158 *val = Offset<void>(atoi(s));
159 return NoError();
160 }
161
GetFullyQualifiedName(const std::string & name,size_t max_components) const162 std::string Namespace::GetFullyQualifiedName(const std::string &name,
163 size_t max_components) const {
164 // Early exit if we don't have a defined namespace.
165 if (components.empty() || !max_components) { return name; }
166 std::string stream_str;
167 for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
168 if (i) { stream_str += '.'; }
169 stream_str += std::string(components[i]);
170 }
171 if (name.length()) {
172 stream_str += '.';
173 stream_str += name;
174 }
175 return stream_str;
176 }
177
178 // Declare tokens we'll use. Single character tokens are represented by their
179 // ascii character code (e.g. '{'), others above 256.
180 // clang-format off
181 #define FLATBUFFERS_GEN_TOKENS(TD) \
182 TD(Eof, 256, "end of file") \
183 TD(StringConstant, 257, "string constant") \
184 TD(IntegerConstant, 258, "integer constant") \
185 TD(FloatConstant, 259, "float constant") \
186 TD(Identifier, 260, "identifier")
187 #ifdef __GNUC__
188 __extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
189 #endif
190 enum {
191 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
192 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
193 #undef FLATBUFFERS_TOKEN
194 };
195
TokenToString(int t)196 static std::string TokenToString(int t) {
197 static const char * const tokens[] = {
198 #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
199 FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
200 #undef FLATBUFFERS_TOKEN
201 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
202 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
203 IDLTYPE,
204 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
205 #undef FLATBUFFERS_TD
206 };
207 if (t < 256) { // A single ascii char token.
208 std::string s;
209 s.append(1, static_cast<char>(t));
210 return s;
211 } else { // Other tokens.
212 return tokens[t - 256];
213 }
214 }
215 // clang-format on
216
TokenToStringId(int t) const217 std::string Parser::TokenToStringId(int t) const {
218 return t == kTokenIdentifier ? attribute_ : TokenToString(t);
219 }
220
221 // Parses exactly nibbles worth of hex digits into a number, or error.
ParseHexNum(int nibbles,uint64_t * val)222 CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
223 FLATBUFFERS_ASSERT(nibbles > 0);
224 for (int i = 0; i < nibbles; i++)
225 if (!is_xdigit(cursor_[i]))
226 return Error("escape code must be followed by " + NumToString(nibbles) +
227 " hex digits");
228 std::string target(cursor_, cursor_ + nibbles);
229 *val = StringToUInt(target.c_str(), 16);
230 cursor_ += nibbles;
231 return NoError();
232 }
233
SkipByteOrderMark()234 CheckedError Parser::SkipByteOrderMark() {
235 if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
236 cursor_++;
237 if (static_cast<unsigned char>(*cursor_) != 0xbb)
238 return Error("invalid utf-8 byte order mark");
239 cursor_++;
240 if (static_cast<unsigned char>(*cursor_) != 0xbf)
241 return Error("invalid utf-8 byte order mark");
242 cursor_++;
243 return NoError();
244 }
245
IsIdentifierStart(char c)246 static inline bool IsIdentifierStart(char c) {
247 return is_alpha(c) || (c == '_');
248 }
249
Next()250 CheckedError Parser::Next() {
251 doc_comment_.clear();
252 bool seen_newline = cursor_ == source_;
253 attribute_.clear();
254 attr_is_trivial_ascii_string_ = true;
255 for (;;) {
256 char c = *cursor_++;
257 token_ = c;
258 switch (c) {
259 case '\0':
260 cursor_--;
261 token_ = kTokenEof;
262 return NoError();
263 case ' ':
264 case '\r':
265 case '\t': break;
266 case '\n':
267 MarkNewLine();
268 seen_newline = true;
269 break;
270 case '{':
271 case '}':
272 case '(':
273 case ')':
274 case '[':
275 case ']':
276 case ',':
277 case ':':
278 case ';':
279 case '=': return NoError();
280 case '\"':
281 case '\'': {
282 int unicode_high_surrogate = -1;
283
284 while (*cursor_ != c) {
285 if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
286 return Error("illegal character in string constant");
287 if (*cursor_ == '\\') {
288 attr_is_trivial_ascii_string_ = false; // has escape sequence
289 cursor_++;
290 if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
291 return Error(
292 "illegal Unicode sequence (unpaired high surrogate)");
293 }
294 switch (*cursor_) {
295 case 'n':
296 attribute_ += '\n';
297 cursor_++;
298 break;
299 case 't':
300 attribute_ += '\t';
301 cursor_++;
302 break;
303 case 'r':
304 attribute_ += '\r';
305 cursor_++;
306 break;
307 case 'b':
308 attribute_ += '\b';
309 cursor_++;
310 break;
311 case 'f':
312 attribute_ += '\f';
313 cursor_++;
314 break;
315 case '\"':
316 attribute_ += '\"';
317 cursor_++;
318 break;
319 case '\'':
320 attribute_ += '\'';
321 cursor_++;
322 break;
323 case '\\':
324 attribute_ += '\\';
325 cursor_++;
326 break;
327 case '/':
328 attribute_ += '/';
329 cursor_++;
330 break;
331 case 'x': { // Not in the JSON standard
332 cursor_++;
333 uint64_t val;
334 ECHECK(ParseHexNum(2, &val));
335 attribute_ += static_cast<char>(val);
336 break;
337 }
338 case 'u': {
339 cursor_++;
340 uint64_t val;
341 ECHECK(ParseHexNum(4, &val));
342 if (val >= 0xD800 && val <= 0xDBFF) {
343 if (unicode_high_surrogate != -1) {
344 return Error(
345 "illegal Unicode sequence (multiple high surrogates)");
346 } else {
347 unicode_high_surrogate = static_cast<int>(val);
348 }
349 } else if (val >= 0xDC00 && val <= 0xDFFF) {
350 if (unicode_high_surrogate == -1) {
351 return Error(
352 "illegal Unicode sequence (unpaired low surrogate)");
353 } else {
354 int code_point = 0x10000 +
355 ((unicode_high_surrogate & 0x03FF) << 10) +
356 (val & 0x03FF);
357 ToUTF8(code_point, &attribute_);
358 unicode_high_surrogate = -1;
359 }
360 } else {
361 if (unicode_high_surrogate != -1) {
362 return Error(
363 "illegal Unicode sequence (unpaired high surrogate)");
364 }
365 ToUTF8(static_cast<int>(val), &attribute_);
366 }
367 break;
368 }
369 default: return Error("unknown escape code in string constant");
370 }
371 } else { // printable chars + UTF-8 bytes
372 if (unicode_high_surrogate != -1) {
373 return Error(
374 "illegal Unicode sequence (unpaired high surrogate)");
375 }
376 // reset if non-printable
377 attr_is_trivial_ascii_string_ &= check_in_range(*cursor_, ' ', '~');
378
379 attribute_ += *cursor_++;
380 }
381 }
382 if (unicode_high_surrogate != -1) {
383 return Error("illegal Unicode sequence (unpaired high surrogate)");
384 }
385 cursor_++;
386 if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
387 !ValidateUTF8(attribute_)) {
388 return Error("illegal UTF-8 sequence");
389 }
390 token_ = kTokenStringConstant;
391 return NoError();
392 }
393 case '/':
394 if (*cursor_ == '/') {
395 const char *start = ++cursor_;
396 while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
397 if (*start == '/') { // documentation comment
398 if (!seen_newline)
399 return Error(
400 "a documentation comment should be on a line on its own");
401 doc_comment_.push_back(std::string(start + 1, cursor_));
402 }
403 break;
404 } else if (*cursor_ == '*') {
405 cursor_++;
406 // TODO: make nested.
407 while (*cursor_ != '*' || cursor_[1] != '/') {
408 if (*cursor_ == '\n') MarkNewLine();
409 if (!*cursor_) return Error("end of file in comment");
410 cursor_++;
411 }
412 cursor_ += 2;
413 break;
414 }
415 // fall thru
416 default:
417 const auto has_sign = (c == '+') || (c == '-');
418 // '-'/'+' and following identifier - can be a predefined constant like:
419 // NAN, INF, PI, etc.
420 if (IsIdentifierStart(c) || (has_sign && IsIdentifierStart(*cursor_))) {
421 // Collect all chars of an identifier:
422 const char *start = cursor_ - 1;
423 while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
424 attribute_.append(start, cursor_);
425 token_ = has_sign ? kTokenStringConstant : kTokenIdentifier;
426 return NoError();
427 }
428
429 auto dot_lvl = (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen
430 if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
431 // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
432 if (is_digit(c) || has_sign || !dot_lvl) {
433 const auto start = cursor_ - 1;
434 auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
435 if (!is_digit(c) && is_digit(*cursor_)){
436 start_digits = cursor_; // see digit in cursor_ position
437 c = *cursor_++;
438 }
439 // hex-float can't begind with '.'
440 auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
441 if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it
442 // Read an integer number or mantisa of float-point number.
443 do {
444 if (use_hex) {
445 while (is_xdigit(*cursor_)) cursor_++;
446 } else {
447 while (is_digit(*cursor_)) cursor_++;
448 }
449 } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
450 // Exponent of float-point number.
451 if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
452 // The exponent suffix of hexadecimal float number is mandatory.
453 if (use_hex && !dot_lvl) start_digits = cursor_;
454 if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
455 is_alpha_char(*cursor_, 'E')) {
456 dot_lvl = 0; // Emulate dot to signal about float-point number.
457 cursor_++;
458 if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
459 start_digits = cursor_; // the exponent-part has to have digits
460 // Exponent is decimal integer number
461 while (is_digit(*cursor_)) cursor_++;
462 if (*cursor_ == '.') {
463 cursor_++; // If see a dot treat it as part of invalid number.
464 dot_lvl = -1; // Fall thru to Error().
465 }
466 }
467 }
468 // Finalize.
469 if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
470 attribute_.append(start, cursor_);
471 token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
472 return NoError();
473 } else {
474 return Error("invalid number: " + std::string(start, cursor_));
475 }
476 }
477 std::string ch;
478 ch = c;
479 if (false == check_in_range(c, ' ', '~')) ch = "code: " + NumToString(c);
480 return Error("illegal character: " + ch);
481 }
482 }
483 }
484
485 // Check if a given token is next.
Is(int t) const486 bool Parser::Is(int t) const { return t == token_; }
487
IsIdent(const char * id) const488 bool Parser::IsIdent(const char *id) const {
489 return token_ == kTokenIdentifier && attribute_ == id;
490 }
491
492 // Expect a given token to be next, consume it, or error if not present.
Expect(int t)493 CheckedError Parser::Expect(int t) {
494 if (t != token_) {
495 return Error("expecting: " + TokenToString(t) +
496 " instead got: " + TokenToStringId(token_));
497 }
498 NEXT();
499 return NoError();
500 }
501
ParseNamespacing(std::string * id,std::string * last)502 CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
503 while (Is('.')) {
504 NEXT();
505 *id += ".";
506 *id += attribute_;
507 if (last) *last = attribute_;
508 EXPECT(kTokenIdentifier);
509 }
510 return NoError();
511 }
512
LookupEnum(const std::string & id)513 EnumDef *Parser::LookupEnum(const std::string &id) {
514 // Search thru parent namespaces.
515 for (int components = static_cast<int>(current_namespace_->components.size());
516 components >= 0; components--) {
517 auto ed = enums_.Lookup(
518 current_namespace_->GetFullyQualifiedName(id, components));
519 if (ed) return ed;
520 }
521 return nullptr;
522 }
523
LookupStruct(const std::string & id) const524 StructDef *Parser::LookupStruct(const std::string &id) const {
525 auto sd = structs_.Lookup(id);
526 if (sd) sd->refcount++;
527 return sd;
528 }
529
ParseTypeIdent(Type & type)530 CheckedError Parser::ParseTypeIdent(Type &type) {
531 std::string id = attribute_;
532 EXPECT(kTokenIdentifier);
533 ECHECK(ParseNamespacing(&id, nullptr));
534 auto enum_def = LookupEnum(id);
535 if (enum_def) {
536 type = enum_def->underlying_type;
537 if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
538 } else {
539 type.base_type = BASE_TYPE_STRUCT;
540 type.struct_def = LookupCreateStruct(id);
541 }
542 return NoError();
543 }
544
545 // Parse any IDL type.
ParseType(Type & type)546 CheckedError Parser::ParseType(Type &type) {
547 if (token_ == kTokenIdentifier) {
548 if (IsIdent("bool")) {
549 type.base_type = BASE_TYPE_BOOL;
550 NEXT();
551 } else if (IsIdent("byte") || IsIdent("int8")) {
552 type.base_type = BASE_TYPE_CHAR;
553 NEXT();
554 } else if (IsIdent("ubyte") || IsIdent("uint8")) {
555 type.base_type = BASE_TYPE_UCHAR;
556 NEXT();
557 } else if (IsIdent("short") || IsIdent("int16")) {
558 type.base_type = BASE_TYPE_SHORT;
559 NEXT();
560 } else if (IsIdent("ushort") || IsIdent("uint16")) {
561 type.base_type = BASE_TYPE_USHORT;
562 NEXT();
563 } else if (IsIdent("int") || IsIdent("int32")) {
564 type.base_type = BASE_TYPE_INT;
565 NEXT();
566 } else if (IsIdent("uint") || IsIdent("uint32")) {
567 type.base_type = BASE_TYPE_UINT;
568 NEXT();
569 } else if (IsIdent("long") || IsIdent("int64")) {
570 type.base_type = BASE_TYPE_LONG;
571 NEXT();
572 } else if (IsIdent("ulong") || IsIdent("uint64")) {
573 type.base_type = BASE_TYPE_ULONG;
574 NEXT();
575 } else if (IsIdent("float") || IsIdent("float32")) {
576 type.base_type = BASE_TYPE_FLOAT;
577 NEXT();
578 } else if (IsIdent("double") || IsIdent("float64")) {
579 type.base_type = BASE_TYPE_DOUBLE;
580 NEXT();
581 } else if (IsIdent("string")) {
582 type.base_type = BASE_TYPE_STRING;
583 NEXT();
584 } else {
585 ECHECK(ParseTypeIdent(type));
586 }
587 } else if (token_ == '[') {
588 NEXT();
589 Type subtype;
590 ECHECK(Recurse([&]() { return ParseType(subtype); }));
591 if (subtype.base_type == BASE_TYPE_VECTOR) {
592 // We could support this, but it will complicate things, and it's
593 // easier to work around with a struct around the inner vector.
594 return Error("nested vector types not supported (wrap in table first).");
595 }
596 type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
597 type.element = subtype.base_type;
598 EXPECT(']');
599 } else {
600 return Error("illegal type syntax");
601 }
602 return NoError();
603 }
604
AddField(StructDef & struct_def,const std::string & name,const Type & type,FieldDef ** dest)605 CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
606 const Type &type, FieldDef **dest) {
607 auto &field = *new FieldDef();
608 field.value.offset =
609 FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
610 field.name = name;
611 field.file = struct_def.file;
612 field.value.type = type;
613 if (struct_def.fixed) { // statically compute the field offset
614 auto size = InlineSize(type);
615 auto alignment = InlineAlignment(type);
616 // structs_ need to have a predictable format, so we need to align to
617 // the largest scalar
618 struct_def.minalign = std::max(struct_def.minalign, alignment);
619 struct_def.PadLastField(alignment);
620 field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
621 struct_def.bytesize += size;
622 }
623 if (struct_def.fields.Add(name, &field))
624 return Error("field already exists: " + name);
625 *dest = &field;
626 return NoError();
627 }
628
ParseField(StructDef & struct_def)629 CheckedError Parser::ParseField(StructDef &struct_def) {
630 std::string name = attribute_;
631
632 if (LookupStruct(name))
633 return Error("field name can not be the same as table/struct name");
634
635 std::vector<std::string> dc = doc_comment_;
636 EXPECT(kTokenIdentifier);
637 EXPECT(':');
638 Type type;
639 ECHECK(ParseType(type));
640
641 if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
642 return Error("structs_ may contain only scalar or struct fields");
643
644 FieldDef *typefield = nullptr;
645 if (type.base_type == BASE_TYPE_UNION) {
646 // For union fields, add a second auto-generated field to hold the type,
647 // with a special suffix.
648 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
649 type.enum_def->underlying_type, &typefield));
650 } else if (type.base_type == BASE_TYPE_VECTOR &&
651 type.element == BASE_TYPE_UNION) {
652 // Only cpp, js and ts supports the union vector feature so far.
653 if (!SupportsVectorOfUnions()) {
654 return Error(
655 "Vectors of unions are not yet supported in all "
656 "the specified programming languages.");
657 }
658 // For vector of union fields, add a second auto-generated vector field to
659 // hold the types, with a special suffix.
660 Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
661 union_vector.element = BASE_TYPE_UTYPE;
662 ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
663 &typefield));
664 }
665
666 FieldDef *field;
667 ECHECK(AddField(struct_def, name, type, &field));
668
669 if (token_ == '=') {
670 NEXT();
671 if (!IsScalar(type.base_type) ||
672 (struct_def.fixed && field->value.constant != "0"))
673 return Error(
674 "default values currently only supported for scalars in tables");
675 ECHECK(ParseSingleValue(&field->name, field->value, true));
676 }
677 if (type.enum_def &&
678 !type.enum_def->is_union &&
679 !type.enum_def->attributes.Lookup("bit_flags") &&
680 !type.enum_def->ReverseLookup(StringToInt(
681 field->value.constant.c_str()))) {
682 return Error("default value of " + field->value.constant + " for field " +
683 name + " is not part of enum " + type.enum_def->name);
684 }
685 // Append .0 if the value has not it (skip hex and scientific floats).
686 // This suffix needed for generated C++ code.
687 if (IsFloat(type.base_type)) {
688 auto &text = field->value.constant;
689 FLATBUFFERS_ASSERT(false == text.empty());
690 auto s = text.c_str();
691 while(*s == ' ') s++;
692 if (*s == '-' || *s == '+') s++;
693 // 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
694 // 2) A float number needn't ".0" at the end if it has exponent.
695 if ((false == IsIdentifierStart(*s)) &&
696 (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
697 field->value.constant += ".0";
698 }
699 }
700
701 if (type.enum_def && IsScalar(type.base_type) && !struct_def.fixed &&
702 !type.enum_def->attributes.Lookup("bit_flags") &&
703 !type.enum_def->ReverseLookup(StringToInt(
704 field->value.constant.c_str())))
705 Warning("enum " + type.enum_def->name +
706 " does not have a declaration for this field\'s default of " +
707 field->value.constant);
708
709 field->doc_comment = dc;
710 ECHECK(ParseMetaData(&field->attributes));
711 field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
712 auto hash_name = field->attributes.Lookup("hash");
713 if (hash_name) {
714 switch ((type.base_type == BASE_TYPE_VECTOR) ? type.element : type.base_type) {
715 case BASE_TYPE_SHORT:
716 case BASE_TYPE_USHORT: {
717 if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
718 return Error("Unknown hashing algorithm for 16 bit types: " +
719 hash_name->constant);
720 break;
721 }
722 case BASE_TYPE_INT:
723 case BASE_TYPE_UINT: {
724 if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
725 return Error("Unknown hashing algorithm for 32 bit types: " +
726 hash_name->constant);
727 break;
728 }
729 case BASE_TYPE_LONG:
730 case BASE_TYPE_ULONG: {
731 if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
732 return Error("Unknown hashing algorithm for 64 bit types: " +
733 hash_name->constant);
734 break;
735 }
736 default:
737 return Error(
738 "only short, ushort, int, uint, long and ulong data types support hashing.");
739 }
740 }
741 auto cpp_type = field->attributes.Lookup("cpp_type");
742 if (cpp_type) {
743 if (!hash_name)
744 return Error("cpp_type can only be used with a hashed field");
745 /// forcing cpp_ptr_type to 'naked' if unset
746 auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
747 if (!cpp_ptr_type) {
748 auto val = new Value();
749 val->type = cpp_type->type;
750 val->constant = "naked";
751 field->attributes.Add("cpp_ptr_type", val);
752 }
753 }
754 if (field->deprecated && struct_def.fixed)
755 return Error("can't deprecate fields in a struct");
756 field->required = field->attributes.Lookup("required") != nullptr;
757 if (field->required &&
758 (struct_def.fixed || IsScalar(type.base_type)))
759 return Error("only non-scalar fields in tables may be 'required'");
760 field->key = field->attributes.Lookup("key") != nullptr;
761 if (field->key) {
762 if (struct_def.has_key) return Error("only one field may be set as 'key'");
763 struct_def.has_key = true;
764 if (!IsScalar(type.base_type)) {
765 field->required = true;
766 if (type.base_type != BASE_TYPE_STRING)
767 return Error("'key' field must be string or scalar type");
768 }
769 }
770
771 auto field_native_custom_alloc =
772 field->attributes.Lookup("native_custom_alloc");
773 if (field_native_custom_alloc)
774 return Error(
775 "native_custom_alloc can only be used with a table or struct "
776 "definition");
777
778 field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
779 if (field->native_inline && !IsStruct(field->value.type))
780 return Error("native_inline can only be defined on structs'");
781
782 auto nested = field->attributes.Lookup("nested_flatbuffer");
783 if (nested) {
784 if (nested->type.base_type != BASE_TYPE_STRING)
785 return Error(
786 "nested_flatbuffer attribute must be a string (the root type)");
787 if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
788 return Error(
789 "nested_flatbuffer attribute may only apply to a vector of ubyte");
790 // This will cause an error if the root type of the nested flatbuffer
791 // wasn't defined elsewhere.
792 LookupCreateStruct(nested->constant);
793
794 // Keep a pointer to StructDef in FieldDef to simplify re-use later
795 auto nested_qualified_name =
796 current_namespace_->GetFullyQualifiedName(nested->constant);
797 field->nested_flatbuffer = LookupStruct(nested_qualified_name);
798 }
799
800 if (field->attributes.Lookup("flexbuffer")) {
801 field->flexbuffer = true;
802 uses_flexbuffers_ = true;
803 if (type.base_type != BASE_TYPE_VECTOR ||
804 type.element != BASE_TYPE_UCHAR)
805 return Error("flexbuffer attribute may only apply to a vector of ubyte");
806 }
807
808 if (typefield) {
809 if (!IsScalar(typefield->value.type.base_type)) {
810 // this is a union vector field
811 typefield->required = field->required;
812 }
813 // If this field is a union, and it has a manually assigned id,
814 // the automatically added type field should have an id as well (of N - 1).
815 auto attr = field->attributes.Lookup("id");
816 if (attr) {
817 auto id = atoi(attr->constant.c_str());
818 auto val = new Value();
819 val->type = attr->type;
820 val->constant = NumToString(id - 1);
821 typefield->attributes.Add("id", val);
822 }
823 }
824
825 EXPECT(';');
826 return NoError();
827 }
828
ParseString(Value & val)829 CheckedError Parser::ParseString(Value &val) {
830 auto s = attribute_;
831 EXPECT(kTokenStringConstant);
832 val.constant = NumToString(builder_.CreateString(s).o);
833 return NoError();
834 }
835
ParseComma()836 CheckedError Parser::ParseComma() {
837 if (!opts.protobuf_ascii_alike) EXPECT(',');
838 return NoError();
839 }
840
ParseAnyValue(Value & val,FieldDef * field,size_t parent_fieldn,const StructDef * parent_struct_def)841 CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
842 size_t parent_fieldn,
843 const StructDef *parent_struct_def) {
844 switch (val.type.base_type) {
845 case BASE_TYPE_UNION: {
846 FLATBUFFERS_ASSERT(field);
847 std::string constant;
848 // Find corresponding type field we may have already parsed.
849 for (auto elem = field_stack_.rbegin();
850 elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
851 auto &type = elem->second->value.type;
852 if (type.base_type == BASE_TYPE_UTYPE &&
853 type.enum_def == val.type.enum_def) {
854 constant = elem->first.constant;
855 break;
856 }
857 }
858 if (constant.empty()) {
859 // We haven't seen the type field yet. Sadly a lot of JSON writers
860 // output these in alphabetical order, meaning it comes after this
861 // value. So we scan past the value to find it, then come back here.
862 auto type_name = field->name + UnionTypeFieldSuffix();
863 FLATBUFFERS_ASSERT(parent_struct_def);
864 auto type_field = parent_struct_def->fields.Lookup(type_name);
865 FLATBUFFERS_ASSERT(type_field); // Guaranteed by ParseField().
866 // Remember where we are in the source file, so we can come back here.
867 auto backup = *static_cast<ParserState *>(this);
868 ECHECK(SkipAnyJsonValue()); // The table.
869 ECHECK(ParseComma());
870 auto next_name = attribute_;
871 if (Is(kTokenStringConstant)) {
872 NEXT();
873 } else {
874 EXPECT(kTokenIdentifier);
875 }
876 if (next_name != type_name)
877 return Error("missing type field after this union value: " +
878 type_name);
879 EXPECT(':');
880 Value type_val = type_field->value;
881 ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
882 constant = type_val.constant;
883 // Got the information we needed, now rewind:
884 *static_cast<ParserState *>(this) = backup;
885 }
886 uint8_t enum_idx;
887 ECHECK(atot(constant.c_str(), *this, &enum_idx));
888 auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
889 if (!enum_val) return Error("illegal type id for: " + field->name);
890 if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
891 ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
892 nullptr));
893 if (enum_val->union_type.struct_def->fixed) {
894 // All BASE_TYPE_UNION values are offsets, so turn this into one.
895 SerializeStruct(*enum_val->union_type.struct_def, val);
896 builder_.ClearOffsets();
897 val.constant = NumToString(builder_.GetSize());
898 }
899 } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
900 ECHECK(ParseString(val));
901 } else {
902 FLATBUFFERS_ASSERT(false);
903 }
904 break;
905 }
906 case BASE_TYPE_STRUCT:
907 ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
908 break;
909 case BASE_TYPE_STRING: {
910 ECHECK(ParseString(val));
911 break;
912 }
913 case BASE_TYPE_VECTOR: {
914 uoffset_t off;
915 ECHECK(ParseVector(val.type.VectorType(), &off));
916 val.constant = NumToString(off);
917 break;
918 }
919 case BASE_TYPE_INT:
920 case BASE_TYPE_UINT:
921 case BASE_TYPE_LONG:
922 case BASE_TYPE_ULONG: {
923 if (field && field->attributes.Lookup("hash") &&
924 (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
925 ECHECK(ParseHash(val, field));
926 } else {
927 ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
928 }
929 break;
930 }
931 default:
932 ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
933 break;
934 }
935 return NoError();
936 }
937
SerializeStruct(const StructDef & struct_def,const Value & val)938 void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
939 FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
940 builder_.Align(struct_def.minalign);
941 builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
942 struct_def.bytesize);
943 builder_.AddStructOffset(val.offset, builder_.GetSize());
944 }
945
946 template <typename F>
ParseTableDelimiters(size_t & fieldn,const StructDef * struct_def,F body)947 CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
948 const StructDef *struct_def,
949 F body) {
950 // We allow tables both as JSON object{ .. } with field names
951 // or vector[..] with all fields in order
952 char terminator = '}';
953 bool is_nested_vector = struct_def && Is('[');
954 if (is_nested_vector) {
955 NEXT();
956 terminator = ']';
957 } else {
958 EXPECT('{');
959 }
960 for (;;) {
961 if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
962 std::string name;
963 if (is_nested_vector) {
964 if (fieldn >= struct_def->fields.vec.size()) {
965 return Error("too many unnamed fields in nested array");
966 }
967 name = struct_def->fields.vec[fieldn]->name;
968 } else {
969 name = attribute_;
970 if (Is(kTokenStringConstant)) {
971 NEXT();
972 } else {
973 EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
974 }
975 if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
976 }
977 ECHECK(body(name, fieldn, struct_def));
978 if (Is(terminator)) break;
979 ECHECK(ParseComma());
980 }
981 NEXT();
982 if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
983 return Error("wrong number of unnamed fields in table vector");
984 }
985 return NoError();
986 }
987
ParseTable(const StructDef & struct_def,std::string * value,uoffset_t * ovalue)988 CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
989 uoffset_t *ovalue) {
990 size_t fieldn_outer = 0;
991 auto err = ParseTableDelimiters(
992 fieldn_outer, &struct_def,
993 [&](const std::string &name, size_t &fieldn,
994 const StructDef *struct_def_inner) -> CheckedError {
995 if (name == "$schema") {
996 ECHECK(Expect(kTokenStringConstant));
997 return NoError();
998 }
999 auto field = struct_def_inner->fields.Lookup(name);
1000 if (!field) {
1001 if (!opts.skip_unexpected_fields_in_json) {
1002 return Error("unknown field: " + name);
1003 } else {
1004 ECHECK(SkipAnyJsonValue());
1005 }
1006 } else {
1007 if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
1008 ECHECK(Next()); // Ignore this field.
1009 } else {
1010 Value val = field->value;
1011 if (field->flexbuffer) {
1012 flexbuffers::Builder builder(1024,
1013 flexbuffers::BUILDER_FLAG_SHARE_ALL);
1014 ECHECK(ParseFlexBufferValue(&builder));
1015 builder.Finish();
1016 // Force alignment for nested flexbuffer
1017 builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
1018 sizeof(largest_scalar_t));
1019 auto off = builder_.CreateVector(builder.GetBuffer());
1020 val.constant = NumToString(off.o);
1021 } else if (field->nested_flatbuffer) {
1022 ECHECK(
1023 ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
1024 } else {
1025 ECHECK(Recurse([&]() {
1026 return ParseAnyValue(val, field, fieldn, struct_def_inner);
1027 }));
1028 }
1029 // Hardcoded insertion-sort with error-check.
1030 // If fields are specified in order, then this loop exits
1031 // immediately.
1032 auto elem = field_stack_.rbegin();
1033 for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
1034 auto existing_field = elem->second;
1035 if (existing_field == field)
1036 return Error("field set more than once: " + field->name);
1037 if (existing_field->value.offset < field->value.offset) break;
1038 }
1039 // Note: elem points to before the insertion point, thus .base()
1040 // points to the correct spot.
1041 field_stack_.insert(elem.base(), std::make_pair(val, field));
1042 fieldn++;
1043 }
1044 }
1045 return NoError();
1046 });
1047 ECHECK(err);
1048
1049 // Check if all required fields are parsed.
1050 for (auto field_it = struct_def.fields.vec.begin();
1051 field_it != struct_def.fields.vec.end(); ++field_it) {
1052 auto required_field = *field_it;
1053 if (!required_field->required) { continue; }
1054 bool found = false;
1055 for (auto pf_it = field_stack_.end() - fieldn_outer;
1056 pf_it != field_stack_.end(); ++pf_it) {
1057 auto parsed_field = pf_it->second;
1058 if (parsed_field == required_field) {
1059 found = true;
1060 break;
1061 }
1062 }
1063 if (!found) {
1064 return Error("required field is missing: " + required_field->name +
1065 " in " + struct_def.name);
1066 }
1067 }
1068
1069 if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
1070 return Error("struct: wrong number of initializers: " + struct_def.name);
1071
1072 auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
1073 : builder_.StartTable();
1074
1075 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
1076 size /= 2) {
1077 // Go through elements in reverse, since we're building the data backwards.
1078 for (auto it = field_stack_.rbegin();
1079 it != field_stack_.rbegin() + fieldn_outer; ++it) {
1080 auto &field_value = it->first;
1081 auto field = it->second;
1082 if (!struct_def.sortbysize ||
1083 size == SizeOf(field_value.type.base_type)) {
1084 switch (field_value.type.base_type) {
1085 // clang-format off
1086 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1087 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
1088 case BASE_TYPE_ ## ENUM: \
1089 builder_.Pad(field->padding); \
1090 if (struct_def.fixed) { \
1091 CTYPE val; \
1092 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1093 builder_.PushElement(val); \
1094 } else { \
1095 CTYPE val, valdef; \
1096 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1097 ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1098 builder_.AddElement(field_value.offset, val, valdef); \
1099 } \
1100 break;
1101 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
1102 #undef FLATBUFFERS_TD
1103 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1104 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
1105 case BASE_TYPE_ ## ENUM: \
1106 builder_.Pad(field->padding); \
1107 if (IsStruct(field->value.type)) { \
1108 SerializeStruct(*field->value.type.struct_def, field_value); \
1109 } else { \
1110 CTYPE val; \
1111 ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1112 builder_.AddOffset(field_value.offset, val); \
1113 } \
1114 break;
1115 FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
1116 #undef FLATBUFFERS_TD
1117 // clang-format on
1118 }
1119 }
1120 }
1121 }
1122 for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
1123
1124 if (struct_def.fixed) {
1125 builder_.ClearOffsets();
1126 builder_.EndStruct();
1127 FLATBUFFERS_ASSERT(value);
1128 // Temporarily store this struct in the value string, since it is to
1129 // be serialized in-place elsewhere.
1130 value->assign(
1131 reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
1132 struct_def.bytesize);
1133 builder_.PopBytes(struct_def.bytesize);
1134 FLATBUFFERS_ASSERT(!ovalue);
1135 } else {
1136 auto val = builder_.EndTable(start);
1137 if (ovalue) *ovalue = val;
1138 if (value) *value = NumToString(val);
1139 }
1140 return NoError();
1141 }
1142
1143 template <typename F>
ParseVectorDelimiters(size_t & count,F body)1144 CheckedError Parser::ParseVectorDelimiters(size_t &count, F body) {
1145 EXPECT('[');
1146 for (;;) {
1147 if ((!opts.strict_json || !count) && Is(']')) break;
1148 ECHECK(body(count));
1149 count++;
1150 if (Is(']')) break;
1151 ECHECK(ParseComma());
1152 }
1153 NEXT();
1154 return NoError();
1155 }
1156
ParseVector(const Type & type,uoffset_t * ovalue)1157 CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
1158 size_t count = 0;
1159 auto err = ParseVectorDelimiters(count, [&](size_t &) -> CheckedError {
1160 Value val;
1161 val.type = type;
1162 ECHECK(Recurse([&]() { return ParseAnyValue(val, nullptr, 0, nullptr); }));
1163 field_stack_.push_back(std::make_pair(val, nullptr));
1164 return NoError();
1165 });
1166 ECHECK(err);
1167
1168 builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
1169 InlineAlignment(type));
1170 for (size_t i = 0; i < count; i++) {
1171 // start at the back, since we're building the data backwards.
1172 auto &val = field_stack_.back().first;
1173 switch (val.type.base_type) {
1174 // clang-format off
1175 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1176 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
1177 case BASE_TYPE_ ## ENUM: \
1178 if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
1179 else { \
1180 CTYPE elem; \
1181 ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1182 builder_.PushElement(elem); \
1183 } \
1184 break;
1185 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1186 #undef FLATBUFFERS_TD
1187 // clang-format on
1188 }
1189 field_stack_.pop_back();
1190 }
1191
1192 builder_.ClearOffsets();
1193 *ovalue = builder_.EndVector(count);
1194 return NoError();
1195 }
1196
ParseNestedFlatbuffer(Value & val,FieldDef * field,size_t fieldn,const StructDef * parent_struct_def)1197 CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
1198 size_t fieldn,
1199 const StructDef *parent_struct_def) {
1200 if (token_ == '[') { // backwards compat for 'legacy' ubyte buffers
1201 ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def));
1202 } else {
1203 auto cursor_at_value_begin = cursor_;
1204 ECHECK(SkipAnyJsonValue());
1205 std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
1206
1207 // Create and initialize new parser
1208 Parser nested_parser;
1209 FLATBUFFERS_ASSERT(field->nested_flatbuffer);
1210 nested_parser.root_struct_def_ = field->nested_flatbuffer;
1211 nested_parser.enums_ = enums_;
1212 nested_parser.opts = opts;
1213 nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1214
1215 // Parse JSON substring into new flatbuffer builder using nested_parser
1216 if (!nested_parser.Parse(substring.c_str(), nullptr, nullptr)) {
1217 ECHECK(Error(nested_parser.error_));
1218 }
1219 // Force alignment for nested flatbuffer
1220 builder_.ForceVectorAlignment(nested_parser.builder_.GetSize(), sizeof(uint8_t),
1221 nested_parser.builder_.GetBufferMinAlignment());
1222
1223 auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
1224 nested_parser.builder_.GetSize());
1225 val.constant = NumToString(off.o);
1226
1227 // Clean nested_parser before destruction to avoid deleting the elements in
1228 // the SymbolTables
1229 nested_parser.enums_.dict.clear();
1230 nested_parser.enums_.vec.clear();
1231 }
1232 return NoError();
1233 }
1234
ParseMetaData(SymbolTable<Value> * attributes)1235 CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
1236 if (Is('(')) {
1237 NEXT();
1238 for (;;) {
1239 auto name = attribute_;
1240 if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
1241 return Error("attribute name must be either identifier or string: " +
1242 name);
1243 if (known_attributes_.find(name) == known_attributes_.end())
1244 return Error("user define attributes must be declared before use: " +
1245 name);
1246 NEXT();
1247 auto e = new Value();
1248 attributes->Add(name, e);
1249 if (Is(':')) {
1250 NEXT();
1251 ECHECK(ParseSingleValue(&name, *e, true));
1252 }
1253 if (Is(')')) {
1254 NEXT();
1255 break;
1256 }
1257 EXPECT(',');
1258 }
1259 }
1260 return NoError();
1261 }
1262
TryTypedValue(const std::string * name,int dtoken,bool check,Value & e,BaseType req,bool * destmatch)1263 CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
1264 bool check, Value &e, BaseType req,
1265 bool *destmatch) {
1266 bool match = dtoken == token_;
1267 if (match) {
1268 FLATBUFFERS_ASSERT(*destmatch == false);
1269 *destmatch = true;
1270 e.constant = attribute_;
1271 // Check token match
1272 if (!check) {
1273 if (e.type.base_type == BASE_TYPE_NONE) {
1274 e.type.base_type = req;
1275 } else {
1276 return Error(
1277 std::string("type mismatch: expecting: ") +
1278 kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] +
1279 ", name: " + (name ? *name : "") + ", value: " + e.constant);
1280 }
1281 }
1282 // The exponent suffix of hexadecimal float-point number is mandatory.
1283 // A hex-integer constant is forbidden as an initializer of float number.
1284 if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
1285 const auto &s = e.constant;
1286 const auto k = s.find_first_of("0123456789.");
1287 if ((std::string::npos != k) && (s.length() > (k + 1)) &&
1288 (s.at(k) == '0' && is_alpha_char(s.at(k + 1), 'X')) &&
1289 (std::string::npos == s.find_first_of("pP", k + 2))) {
1290 return Error(
1291 "invalid number, the exponent suffix of hexadecimal "
1292 "floating-point literals is mandatory: \"" +
1293 s + "\"");
1294 }
1295 }
1296
1297 NEXT();
1298 }
1299 return NoError();
1300 }
1301
ParseEnumFromString(Type & type,int64_t * result)1302 CheckedError Parser::ParseEnumFromString(Type &type, int64_t *result) {
1303 *result = 0;
1304 // Parse one or more enum identifiers, separated by spaces.
1305 const char *next = attribute_.c_str();
1306 do {
1307 const char *divider = strchr(next, ' ');
1308 std::string word;
1309 if (divider) {
1310 word = std::string(next, divider);
1311 next = divider + strspn(divider, " ");
1312 } else {
1313 word = next;
1314 next += word.length();
1315 }
1316 if (type.enum_def) { // The field has an enum type
1317 auto enum_val = type.enum_def->vals.Lookup(word);
1318 if (!enum_val)
1319 return Error("unknown enum value: " + word +
1320 ", for enum: " + type.enum_def->name);
1321 *result |= enum_val->value;
1322 } else { // No enum type, probably integral field.
1323 if (!IsInteger(type.base_type))
1324 return Error("not a valid value for this field: " + word);
1325 // TODO: could check if its a valid number constant here.
1326 const char *dot = strrchr(word.c_str(), '.');
1327 if (!dot)
1328 return Error("enum values need to be qualified by an enum type");
1329 std::string enum_def_str(word.c_str(), dot);
1330 std::string enum_val_str(dot + 1, word.c_str() + word.length());
1331 auto enum_def = LookupEnum(enum_def_str);
1332 if (!enum_def) return Error("unknown enum: " + enum_def_str);
1333 auto enum_val = enum_def->vals.Lookup(enum_val_str);
1334 if (!enum_val) return Error("unknown enum value: " + enum_val_str);
1335 *result |= enum_val->value;
1336 }
1337 } while (*next);
1338 return NoError();
1339 }
1340
ParseHash(Value & e,FieldDef * field)1341 CheckedError Parser::ParseHash(Value &e, FieldDef *field) {
1342 FLATBUFFERS_ASSERT(field);
1343 Value *hash_name = field->attributes.Lookup("hash");
1344 switch (e.type.base_type) {
1345 case BASE_TYPE_SHORT: {
1346 auto hash = FindHashFunction16(hash_name->constant.c_str());
1347 int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str()));
1348 e.constant = NumToString(hashed_value);
1349 break;
1350 }
1351 case BASE_TYPE_USHORT: {
1352 auto hash = FindHashFunction16(hash_name->constant.c_str());
1353 uint16_t hashed_value = hash(attribute_.c_str());
1354 e.constant = NumToString(hashed_value);
1355 break;
1356 }
1357 case BASE_TYPE_INT: {
1358 auto hash = FindHashFunction32(hash_name->constant.c_str());
1359 int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
1360 e.constant = NumToString(hashed_value);
1361 break;
1362 }
1363 case BASE_TYPE_UINT: {
1364 auto hash = FindHashFunction32(hash_name->constant.c_str());
1365 uint32_t hashed_value = hash(attribute_.c_str());
1366 e.constant = NumToString(hashed_value);
1367 break;
1368 }
1369 case BASE_TYPE_LONG: {
1370 auto hash = FindHashFunction64(hash_name->constant.c_str());
1371 int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
1372 e.constant = NumToString(hashed_value);
1373 break;
1374 }
1375 case BASE_TYPE_ULONG: {
1376 auto hash = FindHashFunction64(hash_name->constant.c_str());
1377 uint64_t hashed_value = hash(attribute_.c_str());
1378 e.constant = NumToString(hashed_value);
1379 break;
1380 }
1381 default: FLATBUFFERS_ASSERT(0);
1382 }
1383 NEXT();
1384 return NoError();
1385 }
1386
TokenError()1387 CheckedError Parser::TokenError() {
1388 return Error("cannot parse value starting with: " + TokenToStringId(token_));
1389 }
1390
ParseSingleValue(const std::string * name,Value & e,bool check_now)1391 CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
1392 bool check_now) {
1393 // First see if this could be a conversion function:
1394 if (token_ == kTokenIdentifier && *cursor_ == '(') {
1395 // todo: Extract processing of conversion functions to ParseFunction.
1396 const auto functionname = attribute_;
1397 if (!IsFloat(e.type.base_type)) {
1398 return Error(functionname + ": type of argument mismatch, expecting: " +
1399 kTypeNames[BASE_TYPE_DOUBLE] +
1400 ", found: " + kTypeNames[e.type.base_type] +
1401 ", name: " + (name ? *name : "") + ", value: " + e.constant);
1402 }
1403 NEXT();
1404 EXPECT('(');
1405 ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); }));
1406 EXPECT(')');
1407 // calculate with double precision
1408 double x, y = 0.0;
1409 ECHECK(atot(e.constant.c_str(), *this, &x));
1410 auto func_match = false;
1411 // clang-format off
1412 #define FLATBUFFERS_FN_DOUBLE(name, op) \
1413 if (!func_match && functionname == name) { y = op; func_match = true; }
1414 FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
1415 FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
1416 FLATBUFFERS_FN_DOUBLE("sin", sin(x));
1417 FLATBUFFERS_FN_DOUBLE("cos", cos(x));
1418 FLATBUFFERS_FN_DOUBLE("tan", tan(x));
1419 FLATBUFFERS_FN_DOUBLE("asin", asin(x));
1420 FLATBUFFERS_FN_DOUBLE("acos", acos(x));
1421 FLATBUFFERS_FN_DOUBLE("atan", atan(x));
1422 // TODO(wvo): add more useful conversion functions here.
1423 #undef FLATBUFFERS_FN_DOUBLE
1424 // clang-format on
1425 if (true != func_match) {
1426 return Error(std::string("Unknown conversion function: ") + functionname +
1427 ", field name: " + (name ? *name : "") +
1428 ", value: " + e.constant);
1429 }
1430 e.constant = NumToString(y);
1431 return NoError();
1432 }
1433
1434 auto match = false;
1435 // clang-format off
1436 #define TRY_ECHECK(force, dtoken, check, req) \
1437 if (!match && ((check) || IsConstTrue(force))) \
1438 ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
1439 // clang-format on
1440
1441 if (token_ == kTokenStringConstant || token_ == kTokenIdentifier) {
1442 const auto kTokenStringOrIdent = token_;
1443 // The string type is a most probable type, check it first.
1444 TRY_ECHECK(false, kTokenStringConstant,
1445 e.type.base_type == BASE_TYPE_STRING, BASE_TYPE_STRING);
1446
1447 // avoid escaped and non-ascii in the string
1448 if ((token_ == kTokenStringConstant) && IsScalar(e.type.base_type) &&
1449 !attr_is_trivial_ascii_string_) {
1450 return Error(
1451 std::string("type mismatch or invalid value, an initializer of "
1452 "non-string field must be trivial ASCII string: type: ") +
1453 kTypeNames[e.type.base_type] + ", name: " + (name ? *name : "") +
1454 ", value: " + attribute_);
1455 }
1456
1457 // A boolean as true/false. Boolean as Integer check below.
1458 if (!match && IsBool(e.type.base_type)) {
1459 auto is_true = attribute_ == "true";
1460 if (is_true || attribute_ == "false") {
1461 attribute_ = is_true ? "1" : "0";
1462 // accepts both kTokenStringConstant and kTokenIdentifier
1463 TRY_ECHECK(false, kTokenStringOrIdent, IsBool(e.type.base_type),
1464 BASE_TYPE_BOOL);
1465 }
1466 }
1467 // Check if this could be a string/identifier enum value.
1468 // Enum can have only true integer base type.
1469 if (!match && IsInteger(e.type.base_type) && !IsBool(e.type.base_type) &&
1470 IsIdentifierStart(*attribute_.c_str())) {
1471 int64_t val;
1472 ECHECK(ParseEnumFromString(e.type, &val));
1473 e.constant = NumToString(val);
1474 NEXT();
1475 match = true;
1476 }
1477 // float/integer number in string
1478 if ((token_ == kTokenStringConstant) && IsScalar(e.type.base_type)) {
1479 // remove trailing whitespaces from attribute_
1480 auto last = attribute_.find_last_not_of(' ');
1481 if (std::string::npos != last) // has non-whitespace
1482 attribute_.resize(last + 1);
1483 }
1484 // Float numbers or nan, inf, pi, etc.
1485 TRY_ECHECK(false, kTokenStringOrIdent, IsFloat(e.type.base_type),
1486 BASE_TYPE_FLOAT);
1487 // An integer constant in string.
1488 TRY_ECHECK(false, kTokenStringOrIdent, IsInteger(e.type.base_type),
1489 BASE_TYPE_INT);
1490 // Unknown tokens will be interpreted as string type.
1491 TRY_ECHECK(true, kTokenStringConstant, e.type.base_type == BASE_TYPE_STRING,
1492 BASE_TYPE_STRING);
1493 } else {
1494 // Try a float number.
1495 TRY_ECHECK(false, kTokenFloatConstant, IsFloat(e.type.base_type),
1496 BASE_TYPE_FLOAT);
1497 // Integer token can init any scalar (integer of float).
1498 TRY_ECHECK(true, kTokenIntegerConstant, IsScalar(e.type.base_type),
1499 BASE_TYPE_INT);
1500 }
1501 #undef TRY_ECHECK
1502
1503 if (!match) return TokenError();
1504
1505 // The check_now flag must be true when parse a fbs-schema.
1506 // This flag forces to check default scalar values or metadata of field.
1507 // For JSON parser the flag should be false.
1508 // If it is set for JSON each value will be checked twice (see ParseTable).
1509 if (check_now && IsScalar(e.type.base_type)) {
1510 // "re-pack" an integer scalar to remove any ambiguities like leading zeros
1511 // which can be treated as octal-literal (idl_gen_cpp/GenDefaultConstant).
1512 const auto repack = IsInteger(e.type.base_type);
1513 switch (e.type.base_type) {
1514 // clang-format off
1515 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1516 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
1517 case BASE_TYPE_ ## ENUM: {\
1518 CTYPE val; \
1519 ECHECK(atot(e.constant.c_str(), *this, &val)); \
1520 if(repack) e.constant = NumToString(val); \
1521 break; }
1522 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
1523 #undef FLATBUFFERS_TD
1524 default: break;
1525 // clang-format on
1526 }
1527 }
1528 return NoError();
1529 }
1530
LookupCreateStruct(const std::string & name,bool create_if_new,bool definition)1531 StructDef *Parser::LookupCreateStruct(const std::string &name,
1532 bool create_if_new, bool definition) {
1533 std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
1534 // See if it exists pre-declared by an unqualified use.
1535 auto struct_def = LookupStruct(name);
1536 if (struct_def && struct_def->predecl) {
1537 if (definition) {
1538 // Make sure it has the current namespace, and is registered under its
1539 // qualified name.
1540 struct_def->defined_namespace = current_namespace_;
1541 structs_.Move(name, qualified_name);
1542 }
1543 return struct_def;
1544 }
1545 // See if it exists pre-declared by an qualified use.
1546 struct_def = LookupStruct(qualified_name);
1547 if (struct_def && struct_def->predecl) {
1548 if (definition) {
1549 // Make sure it has the current namespace.
1550 struct_def->defined_namespace = current_namespace_;
1551 }
1552 return struct_def;
1553 }
1554 if (!definition) {
1555 // Search thru parent namespaces.
1556 for (size_t components = current_namespace_->components.size();
1557 components && !struct_def; components--) {
1558 struct_def = LookupStruct(
1559 current_namespace_->GetFullyQualifiedName(name, components - 1));
1560 }
1561 }
1562 if (!struct_def && create_if_new) {
1563 struct_def = new StructDef();
1564 if (definition) {
1565 structs_.Add(qualified_name, struct_def);
1566 struct_def->name = name;
1567 struct_def->defined_namespace = current_namespace_;
1568 } else {
1569 // Not a definition.
1570 // Rather than failing, we create a "pre declared" StructDef, due to
1571 // circular references, and check for errors at the end of parsing.
1572 // It is defined in the current namespace, as the best guess what the
1573 // final namespace will be.
1574 structs_.Add(name, struct_def);
1575 struct_def->name = name;
1576 struct_def->defined_namespace = current_namespace_;
1577 struct_def->original_location.reset(
1578 new std::string(file_being_parsed_ + ":" + NumToString(line_)));
1579 }
1580 }
1581 return struct_def;
1582 }
1583
ParseEnum(bool is_union,EnumDef ** dest)1584 CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
1585 std::vector<std::string> enum_comment = doc_comment_;
1586 NEXT();
1587 std::string enum_name = attribute_;
1588 EXPECT(kTokenIdentifier);
1589 EnumDef *enum_def;
1590 ECHECK(StartEnum(enum_name, is_union, &enum_def));
1591 enum_def->doc_comment = enum_comment;
1592 if (!is_union && !opts.proto_mode) {
1593 // Give specialized error message, since this type spec used to
1594 // be optional in the first FlatBuffers release.
1595 if (!Is(':')) {
1596 return Error(
1597 "must specify the underlying integer type for this"
1598 " enum (e.g. \': short\', which was the default).");
1599 } else {
1600 NEXT();
1601 }
1602 // Specify the integer type underlying this enum.
1603 ECHECK(ParseType(enum_def->underlying_type));
1604 if (!IsInteger(enum_def->underlying_type.base_type) ||
1605 IsBool(enum_def->underlying_type.base_type))
1606 return Error("underlying enum type must be integral");
1607 // Make this type refer back to the enum it was derived from.
1608 enum_def->underlying_type.enum_def = enum_def;
1609 }
1610 ECHECK(ParseMetaData(&enum_def->attributes));
1611 EXPECT('{');
1612 if (is_union) enum_def->vals.Add("NONE", new EnumVal("NONE", 0));
1613 std::set<std::pair<BaseType, StructDef*>> union_types;
1614 for (;;) {
1615 if (opts.proto_mode && attribute_ == "option") {
1616 ECHECK(ParseProtoOption());
1617 } else {
1618 auto value_name = attribute_;
1619 auto full_name = value_name;
1620 std::vector<std::string> value_comment = doc_comment_;
1621 EXPECT(kTokenIdentifier);
1622 if (is_union) {
1623 ECHECK(ParseNamespacing(&full_name, &value_name));
1624 if (opts.union_value_namespacing) {
1625 // Since we can't namespace the actual enum identifiers, turn
1626 // namespace parts into part of the identifier.
1627 value_name = full_name;
1628 std::replace(value_name.begin(), value_name.end(), '.', '_');
1629 }
1630 }
1631 auto prevsize = enum_def->vals.vec.size();
1632 auto prevvalue = prevsize > 0 ? enum_def->vals.vec.back()->value : 0;
1633 auto &ev = *new EnumVal(value_name, 0);
1634 if (enum_def->vals.Add(value_name, &ev))
1635 return Error("enum value already exists: " + value_name);
1636 ev.doc_comment = value_comment;
1637 if (is_union) {
1638 if (Is(':')) {
1639 NEXT();
1640 ECHECK(ParseType(ev.union_type));
1641 if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
1642 ev.union_type.base_type != BASE_TYPE_STRING)
1643 return Error("union value type may only be table/struct/string");
1644 } else {
1645 ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
1646 }
1647 if (!enum_def->uses_multiple_type_instances) {
1648 auto union_type_key = std::make_pair(ev.union_type.base_type, ev.union_type.struct_def);
1649 if (union_types.count(union_type_key) > 0) {
1650 enum_def->uses_multiple_type_instances = true;
1651 } else {
1652 union_types.insert(union_type_key);
1653 }
1654 }
1655 }
1656 if (Is('=')) {
1657 NEXT();
1658 ECHECK(atot(attribute_.c_str(), *this, &ev.value));
1659 EXPECT(kTokenIntegerConstant);
1660 if (!opts.proto_mode && prevsize &&
1661 enum_def->vals.vec[prevsize - 1]->value >= ev.value)
1662 return Error("enum values must be specified in ascending order");
1663 } else if (prevsize == 0) {
1664 // already set to zero
1665 } else if (prevvalue != flatbuffers::numeric_limits<int64_t>::max()) {
1666 ev.value = prevvalue + 1;
1667 } else {
1668 return Error("enum value overflows");
1669 }
1670
1671 // Check that value fits into the underlying type.
1672 switch (enum_def->underlying_type.base_type) {
1673 // clang-format off
1674 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
1675 PTYPE, RTYPE) \
1676 case BASE_TYPE_##ENUM: { \
1677 int64_t min_value = static_cast<int64_t>( \
1678 flatbuffers::numeric_limits<CTYPE>::lowest()); \
1679 int64_t max_value = static_cast<int64_t>( \
1680 flatbuffers::numeric_limits<CTYPE>::max()); \
1681 if (ev.value < min_value || ev.value > max_value) { \
1682 return Error( \
1683 "enum value does not fit [" + NumToString(min_value) + \
1684 "; " + NumToString(max_value) + "]"); \
1685 } \
1686 break; \
1687 }
1688 FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
1689 #undef FLATBUFFERS_TD
1690 default: break;
1691 // clang-format on
1692 }
1693
1694 if (opts.proto_mode && Is('[')) {
1695 NEXT();
1696 // ignore attributes on enums.
1697 while (token_ != ']') NEXT();
1698 NEXT();
1699 }
1700 }
1701 if (!Is(opts.proto_mode ? ';' : ',')) break;
1702 NEXT();
1703 if (Is('}')) break;
1704 }
1705 EXPECT('}');
1706 if (enum_def->attributes.Lookup("bit_flags")) {
1707 for (auto it = enum_def->vals.vec.begin(); it != enum_def->vals.vec.end();
1708 ++it) {
1709 if (static_cast<size_t>((*it)->value) >=
1710 SizeOf(enum_def->underlying_type.base_type) * 8)
1711 return Error("bit flag out of range of underlying integral type");
1712 (*it)->value = 1LL << (*it)->value;
1713 }
1714 }
1715 if (dest) *dest = enum_def;
1716 types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
1717 new Type(BASE_TYPE_UNION, nullptr, enum_def));
1718 return NoError();
1719 }
1720
StartStruct(const std::string & name,StructDef ** dest)1721 CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
1722 auto &struct_def = *LookupCreateStruct(name, true, true);
1723 if (!struct_def.predecl) return Error("datatype already exists: " + name);
1724 struct_def.predecl = false;
1725 struct_def.name = name;
1726 struct_def.file = file_being_parsed_;
1727 // Move this struct to the back of the vector just in case it was predeclared,
1728 // to preserve declaration order.
1729 *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
1730 &struct_def;
1731 *dest = &struct_def;
1732 return NoError();
1733 }
1734
CheckClash(std::vector<FieldDef * > & fields,StructDef * struct_def,const char * suffix,BaseType basetype)1735 CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
1736 StructDef *struct_def, const char *suffix,
1737 BaseType basetype) {
1738 auto len = strlen(suffix);
1739 for (auto it = fields.begin(); it != fields.end(); ++it) {
1740 auto &fname = (*it)->name;
1741 if (fname.length() > len &&
1742 fname.compare(fname.length() - len, len, suffix) == 0 &&
1743 (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
1744 auto field =
1745 struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
1746 if (field && field->value.type.base_type == basetype)
1747 return Error("Field " + fname +
1748 " would clash with generated functions for field " +
1749 field->name);
1750 }
1751 }
1752 return NoError();
1753 }
1754
SupportsVectorOfUnions() const1755 bool Parser::SupportsVectorOfUnions() const {
1756 return opts.lang_to_generate != 0 &&
1757 (opts.lang_to_generate & ~(IDLOptions::kCpp | IDLOptions::kJs |
1758 IDLOptions::kTs | IDLOptions::kPhp |
1759 IDLOptions::kJava | IDLOptions::kCSharp)) == 0;
1760 }
1761
UniqueNamespace(Namespace * ns)1762 Namespace *Parser::UniqueNamespace(Namespace *ns) {
1763 for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
1764 if (ns->components == (*it)->components) {
1765 delete ns;
1766 return *it;
1767 }
1768 }
1769 namespaces_.push_back(ns);
1770 return ns;
1771 }
1772
UnqualifiedName(std::string full_qualified_name)1773 std::string Parser::UnqualifiedName(std::string full_qualified_name) {
1774 Namespace *ns = new Namespace();
1775
1776 std::size_t current, previous = 0;
1777 current = full_qualified_name.find('.');
1778 while (current != std::string::npos) {
1779 ns->components.push_back(
1780 full_qualified_name.substr(previous, current - previous));
1781 previous = current + 1;
1782 current = full_qualified_name.find('.', previous);
1783 }
1784 current_namespace_ = UniqueNamespace(ns);
1785 return full_qualified_name.substr(previous, current - previous);
1786 }
1787
compareFieldDefs(const FieldDef * a,const FieldDef * b)1788 static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
1789 auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
1790 auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
1791 return a_id < b_id;
1792 }
1793
ParseDecl()1794 CheckedError Parser::ParseDecl() {
1795 std::vector<std::string> dc = doc_comment_;
1796 bool fixed = IsIdent("struct");
1797 if (!fixed && !IsIdent("table")) return Error("declaration expected");
1798 NEXT();
1799 std::string name = attribute_;
1800 EXPECT(kTokenIdentifier);
1801 StructDef *struct_def;
1802 ECHECK(StartStruct(name, &struct_def));
1803 struct_def->doc_comment = dc;
1804 struct_def->fixed = fixed;
1805 ECHECK(ParseMetaData(&struct_def->attributes));
1806 struct_def->sortbysize =
1807 struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
1808 EXPECT('{');
1809 while (token_ != '}') ECHECK(ParseField(*struct_def));
1810 auto force_align = struct_def->attributes.Lookup("force_align");
1811 if (fixed) {
1812 if (force_align) {
1813 auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
1814 if (force_align->type.base_type != BASE_TYPE_INT ||
1815 align < struct_def->minalign || align > FLATBUFFERS_MAX_ALIGNMENT ||
1816 align & (align - 1))
1817 return Error(
1818 "force_align must be a power of two integer ranging from the"
1819 "struct\'s natural alignment to " +
1820 NumToString(FLATBUFFERS_MAX_ALIGNMENT));
1821 struct_def->minalign = align;
1822 }
1823 if (!struct_def->bytesize) return Error("size 0 structs not allowed");
1824 }
1825 struct_def->PadLastField(struct_def->minalign);
1826 // Check if this is a table that has manual id assignments
1827 auto &fields = struct_def->fields.vec;
1828 if (!fixed && fields.size()) {
1829 size_t num_id_fields = 0;
1830 for (auto it = fields.begin(); it != fields.end(); ++it) {
1831 if ((*it)->attributes.Lookup("id")) num_id_fields++;
1832 }
1833 // If any fields have ids..
1834 if (num_id_fields) {
1835 // Then all fields must have them.
1836 if (num_id_fields != fields.size())
1837 return Error(
1838 "either all fields or no fields must have an 'id' attribute");
1839 // Simply sort by id, then the fields are the same as if no ids had
1840 // been specified.
1841 std::sort(fields.begin(), fields.end(), compareFieldDefs);
1842 // Verify we have a contiguous set, and reassign vtable offsets.
1843 for (int i = 0; i < static_cast<int>(fields.size()); i++) {
1844 if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
1845 return Error("field id\'s must be consecutive from 0, id " +
1846 NumToString(i) + " missing or set twice");
1847 fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
1848 }
1849 }
1850 }
1851
1852 ECHECK(
1853 CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
1854 ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
1855 ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
1856 ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
1857 ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
1858 ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
1859 EXPECT('}');
1860 types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
1861 new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
1862 return NoError();
1863 }
1864
ParseService()1865 CheckedError Parser::ParseService() {
1866 std::vector<std::string> service_comment = doc_comment_;
1867 NEXT();
1868 auto service_name = attribute_;
1869 EXPECT(kTokenIdentifier);
1870 auto &service_def = *new ServiceDef();
1871 service_def.name = service_name;
1872 service_def.file = file_being_parsed_;
1873 service_def.doc_comment = service_comment;
1874 service_def.defined_namespace = current_namespace_;
1875 if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
1876 &service_def))
1877 return Error("service already exists: " + service_name);
1878 ECHECK(ParseMetaData(&service_def.attributes));
1879 EXPECT('{');
1880 do {
1881 std::vector<std::string> doc_comment = doc_comment_;
1882 auto rpc_name = attribute_;
1883 EXPECT(kTokenIdentifier);
1884 EXPECT('(');
1885 Type reqtype, resptype;
1886 ECHECK(ParseTypeIdent(reqtype));
1887 EXPECT(')');
1888 EXPECT(':');
1889 ECHECK(ParseTypeIdent(resptype));
1890 if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
1891 resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
1892 return Error("rpc request and response types must be tables");
1893 auto &rpc = *new RPCCall();
1894 rpc.name = rpc_name;
1895 rpc.request = reqtype.struct_def;
1896 rpc.response = resptype.struct_def;
1897 rpc.doc_comment = doc_comment;
1898 if (service_def.calls.Add(rpc_name, &rpc))
1899 return Error("rpc already exists: " + rpc_name);
1900 ECHECK(ParseMetaData(&rpc.attributes));
1901 EXPECT(';');
1902 } while (token_ != '}');
1903 NEXT();
1904 return NoError();
1905 }
1906
SetRootType(const char * name)1907 bool Parser::SetRootType(const char *name) {
1908 root_struct_def_ = LookupStruct(name);
1909 if (!root_struct_def_)
1910 root_struct_def_ =
1911 LookupStruct(current_namespace_->GetFullyQualifiedName(name));
1912 return root_struct_def_ != nullptr;
1913 }
1914
MarkGenerated()1915 void Parser::MarkGenerated() {
1916 // This function marks all existing definitions as having already
1917 // been generated, which signals no code for included files should be
1918 // generated.
1919 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
1920 (*it)->generated = true;
1921 }
1922 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
1923 if (!(*it)->predecl) { (*it)->generated = true; }
1924 }
1925 for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
1926 (*it)->generated = true;
1927 }
1928 }
1929
ParseNamespace()1930 CheckedError Parser::ParseNamespace() {
1931 NEXT();
1932 auto ns = new Namespace();
1933 namespaces_.push_back(ns); // Store it here to not leak upon error.
1934 if (token_ != ';') {
1935 for (;;) {
1936 ns->components.push_back(attribute_);
1937 EXPECT(kTokenIdentifier);
1938 if (Is('.')) NEXT() else break;
1939 }
1940 }
1941 namespaces_.pop_back();
1942 current_namespace_ = UniqueNamespace(ns);
1943 EXPECT(';');
1944 return NoError();
1945 }
1946
compareEnumVals(const EnumVal * a,const EnumVal * b)1947 static bool compareEnumVals(const EnumVal *a, const EnumVal *b) {
1948 return a->value < b->value;
1949 }
1950
1951 // Best effort parsing of .proto declarations, with the aim to turn them
1952 // in the closest corresponding FlatBuffer equivalent.
1953 // We parse everything as identifiers instead of keywords, since we don't
1954 // want protobuf keywords to become invalid identifiers in FlatBuffers.
ParseProtoDecl()1955 CheckedError Parser::ParseProtoDecl() {
1956 bool isextend = IsIdent("extend");
1957 if (IsIdent("package")) {
1958 // These are identical in syntax to FlatBuffer's namespace decl.
1959 ECHECK(ParseNamespace());
1960 } else if (IsIdent("message") || isextend) {
1961 std::vector<std::string> struct_comment = doc_comment_;
1962 NEXT();
1963 StructDef *struct_def = nullptr;
1964 Namespace *parent_namespace = nullptr;
1965 if (isextend) {
1966 if (Is('.')) NEXT(); // qualified names may start with a . ?
1967 auto id = attribute_;
1968 EXPECT(kTokenIdentifier);
1969 ECHECK(ParseNamespacing(&id, nullptr));
1970 struct_def = LookupCreateStruct(id, false);
1971 if (!struct_def)
1972 return Error("cannot extend unknown message type: " + id);
1973 } else {
1974 std::string name = attribute_;
1975 EXPECT(kTokenIdentifier);
1976 ECHECK(StartStruct(name, &struct_def));
1977 // Since message definitions can be nested, we create a new namespace.
1978 auto ns = new Namespace();
1979 // Copy of current namespace.
1980 *ns = *current_namespace_;
1981 // But with current message name.
1982 ns->components.push_back(name);
1983 ns->from_table++;
1984 parent_namespace = current_namespace_;
1985 current_namespace_ = UniqueNamespace(ns);
1986 }
1987 struct_def->doc_comment = struct_comment;
1988 ECHECK(ParseProtoFields(struct_def, isextend, false));
1989 if (!isextend) { current_namespace_ = parent_namespace; }
1990 if (Is(';')) NEXT();
1991 } else if (IsIdent("enum")) {
1992 // These are almost the same, just with different terminator:
1993 EnumDef *enum_def;
1994 ECHECK(ParseEnum(false, &enum_def));
1995 if (Is(';')) NEXT();
1996 // Protobuf allows them to be specified in any order, so sort afterwards.
1997 auto &v = enum_def->vals.vec;
1998 std::sort(v.begin(), v.end(), compareEnumVals);
1999
2000 // Temp: remove any duplicates, as .fbs files can't handle them.
2001 for (auto it = v.begin(); it != v.end();) {
2002 if (it != v.begin() && it[0]->value == it[-1]->value)
2003 it = v.erase(it);
2004 else
2005 ++it;
2006 }
2007 } else if (IsIdent("syntax")) { // Skip these.
2008 NEXT();
2009 EXPECT('=');
2010 EXPECT(kTokenStringConstant);
2011 EXPECT(';');
2012 } else if (IsIdent("option")) { // Skip these.
2013 ECHECK(ParseProtoOption());
2014 EXPECT(';');
2015 } else if (IsIdent("service")) { // Skip these.
2016 NEXT();
2017 EXPECT(kTokenIdentifier);
2018 ECHECK(ParseProtoCurliesOrIdent());
2019 } else {
2020 return Error("don\'t know how to parse .proto declaration starting with " +
2021 TokenToStringId(token_));
2022 }
2023 return NoError();
2024 }
2025
StartEnum(const std::string & enum_name,bool is_union,EnumDef ** dest)2026 CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union,
2027 EnumDef **dest) {
2028 auto &enum_def = *new EnumDef();
2029 enum_def.name = enum_name;
2030 enum_def.file = file_being_parsed_;
2031 enum_def.doc_comment = doc_comment_;
2032 enum_def.is_union = is_union;
2033 enum_def.defined_namespace = current_namespace_;
2034 if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
2035 &enum_def))
2036 return Error("enum already exists: " + enum_name);
2037 enum_def.underlying_type.base_type = is_union ? BASE_TYPE_UTYPE
2038 : BASE_TYPE_INT;
2039 enum_def.underlying_type.enum_def = &enum_def;
2040 if (dest) *dest = &enum_def;
2041 return NoError();
2042 }
2043
ParseProtoFields(StructDef * struct_def,bool isextend,bool inside_oneof)2044 CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
2045 bool inside_oneof) {
2046 EXPECT('{');
2047 while (token_ != '}') {
2048 if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
2049 // Nested declarations.
2050 ECHECK(ParseProtoDecl());
2051 } else if (IsIdent("extensions")) { // Skip these.
2052 NEXT();
2053 EXPECT(kTokenIntegerConstant);
2054 if (Is(kTokenIdentifier)) {
2055 NEXT(); // to
2056 NEXT(); // num
2057 }
2058 EXPECT(';');
2059 } else if (IsIdent("option")) { // Skip these.
2060 ECHECK(ParseProtoOption());
2061 EXPECT(';');
2062 } else if (IsIdent("reserved")) { // Skip these.
2063 NEXT();
2064 while (!Is(';')) { NEXT(); } // A variety of formats, just skip.
2065 NEXT();
2066 } else {
2067 std::vector<std::string> field_comment = doc_comment_;
2068 // Parse the qualifier.
2069 bool required = false;
2070 bool repeated = false;
2071 bool oneof = false;
2072 if (!inside_oneof) {
2073 if (IsIdent("optional")) {
2074 // This is the default.
2075 NEXT();
2076 } else if (IsIdent("required")) {
2077 required = true;
2078 NEXT();
2079 } else if (IsIdent("repeated")) {
2080 repeated = true;
2081 NEXT();
2082 } else if (IsIdent("oneof")) {
2083 oneof = true;
2084 NEXT();
2085 } else {
2086 // can't error, proto3 allows decls without any of the above.
2087 }
2088 }
2089 StructDef *anonymous_struct = nullptr;
2090 EnumDef *oneof_union = nullptr;
2091 Type type;
2092 if (IsIdent("group") || oneof) {
2093 if (!oneof) NEXT();
2094 if (oneof && opts.proto_oneof_union) {
2095 auto name = MakeCamel(attribute_, true) + "Union";
2096 ECHECK(StartEnum(name, true, &oneof_union));
2097 type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
2098 } else {
2099 auto name = "Anonymous" + NumToString(anonymous_counter++);
2100 ECHECK(StartStruct(name, &anonymous_struct));
2101 type = Type(BASE_TYPE_STRUCT, anonymous_struct);
2102 }
2103 } else {
2104 ECHECK(ParseTypeFromProtoType(&type));
2105 }
2106 // Repeated elements get mapped to a vector.
2107 if (repeated) {
2108 type.element = type.base_type;
2109 type.base_type = BASE_TYPE_VECTOR;
2110 if (type.element == BASE_TYPE_VECTOR) {
2111 // We have a vector or vectors, which FlatBuffers doesn't support.
2112 // For now make it a vector of string (since the source is likely
2113 // "repeated bytes").
2114 // TODO(wvo): A better solution would be to wrap this in a table.
2115 type.element = BASE_TYPE_STRING;
2116 }
2117 }
2118 std::string name = attribute_;
2119 EXPECT(kTokenIdentifier);
2120 if (!oneof) {
2121 // Parse the field id. Since we're just translating schemas, not
2122 // any kind of binary compatibility, we can safely ignore these, and
2123 // assign our own.
2124 EXPECT('=');
2125 EXPECT(kTokenIntegerConstant);
2126 }
2127 FieldDef *field = nullptr;
2128 if (isextend) {
2129 // We allow a field to be re-defined when extending.
2130 // TODO: are there situations where that is problematic?
2131 field = struct_def->fields.Lookup(name);
2132 }
2133 if (!field) ECHECK(AddField(*struct_def, name, type, &field));
2134 field->doc_comment = field_comment;
2135 if (!IsScalar(type.base_type)) field->required = required;
2136 // See if there's a default specified.
2137 if (Is('[')) {
2138 NEXT();
2139 for (;;) {
2140 auto key = attribute_;
2141 ECHECK(ParseProtoKey());
2142 EXPECT('=');
2143 auto val = attribute_;
2144 ECHECK(ParseProtoCurliesOrIdent());
2145 if (key == "default") {
2146 // Temp: skip non-numeric defaults (enums).
2147 auto numeric = strpbrk(val.c_str(), "0123456789-+.");
2148 if (IsScalar(type.base_type) && numeric == val.c_str())
2149 field->value.constant = val;
2150 } else if (key == "deprecated") {
2151 field->deprecated = val == "true";
2152 }
2153 if (!Is(',')) break;
2154 NEXT();
2155 }
2156 EXPECT(']');
2157 }
2158 if (anonymous_struct) {
2159 ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
2160 if (Is(';')) NEXT();
2161 } else if (oneof_union) {
2162 // Parse into a temporary StructDef, then transfer fields into an
2163 // EnumDef describing the oneof as a union.
2164 StructDef oneof_struct;
2165 ECHECK(ParseProtoFields(&oneof_struct, false, oneof));
2166 if (Is(';')) NEXT();
2167 for (auto field_it = oneof_struct.fields.vec.begin();
2168 field_it != oneof_struct.fields.vec.end(); ++field_it) {
2169 const auto &oneof_field = **field_it;
2170 const auto &oneof_type = oneof_field.value.type;
2171 if (oneof_type.base_type != BASE_TYPE_STRUCT ||
2172 !oneof_type.struct_def || oneof_type.struct_def->fixed)
2173 return Error("oneof '" + name +
2174 "' cannot be mapped to a union because member '" +
2175 oneof_field.name + "' is not a table type.");
2176 auto enum_val = new EnumVal(oneof_type.struct_def->name,
2177 oneof_union->vals.vec.size());
2178 enum_val->union_type = oneof_type;
2179 enum_val->doc_comment = oneof_field.doc_comment;
2180 oneof_union->vals.Add(oneof_field.name, enum_val);
2181 }
2182 } else {
2183 EXPECT(';');
2184 }
2185 }
2186 }
2187 NEXT();
2188 return NoError();
2189 }
2190
ParseProtoKey()2191 CheckedError Parser::ParseProtoKey() {
2192 if (token_ == '(') {
2193 NEXT();
2194 // Skip "(a.b)" style custom attributes.
2195 while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
2196 EXPECT(')');
2197 while (Is('.')) {
2198 NEXT();
2199 EXPECT(kTokenIdentifier);
2200 }
2201 } else {
2202 EXPECT(kTokenIdentifier);
2203 }
2204 return NoError();
2205 }
2206
ParseProtoCurliesOrIdent()2207 CheckedError Parser::ParseProtoCurliesOrIdent() {
2208 if (Is('{')) {
2209 NEXT();
2210 for (int nesting = 1; nesting;) {
2211 if (token_ == '{')
2212 nesting++;
2213 else if (token_ == '}')
2214 nesting--;
2215 NEXT();
2216 }
2217 } else {
2218 NEXT(); // Any single token.
2219 }
2220 return NoError();
2221 }
2222
ParseProtoOption()2223 CheckedError Parser::ParseProtoOption() {
2224 NEXT();
2225 ECHECK(ParseProtoKey());
2226 EXPECT('=');
2227 ECHECK(ParseProtoCurliesOrIdent());
2228 return NoError();
2229 }
2230
2231 // Parse a protobuf type, and map it to the corresponding FlatBuffer one.
ParseTypeFromProtoType(Type * type)2232 CheckedError Parser::ParseTypeFromProtoType(Type *type) {
2233 struct type_lookup {
2234 const char *proto_type;
2235 BaseType fb_type, element;
2236 };
2237 static type_lookup lookup[] = {
2238 { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
2239 { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
2240 { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
2241 { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
2242 { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
2243 { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
2244 { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
2245 { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
2246 { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
2247 { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
2248 { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
2249 { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
2250 { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
2251 { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
2252 { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
2253 { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
2254 };
2255 for (auto tl = lookup; tl->proto_type; tl++) {
2256 if (attribute_ == tl->proto_type) {
2257 type->base_type = tl->fb_type;
2258 type->element = tl->element;
2259 NEXT();
2260 return NoError();
2261 }
2262 }
2263 if (Is('.')) NEXT(); // qualified names may start with a . ?
2264 ECHECK(ParseTypeIdent(*type));
2265 return NoError();
2266 }
2267
SkipAnyJsonValue()2268 CheckedError Parser::SkipAnyJsonValue() {
2269 switch (token_) {
2270 case '{': {
2271 size_t fieldn_outer = 0;
2272 return ParseTableDelimiters(
2273 fieldn_outer, nullptr,
2274 [&](const std::string &, size_t &fieldn,
2275 const StructDef *) -> CheckedError {
2276 ECHECK(Recurse([&]() { return SkipAnyJsonValue(); }));
2277 fieldn++;
2278 return NoError();
2279 });
2280 }
2281 case '[': {
2282 size_t count = 0;
2283 return ParseVectorDelimiters(count, [&](size_t &) -> CheckedError {
2284 return Recurse([&]() { return SkipAnyJsonValue(); });
2285 });
2286 }
2287 case kTokenStringConstant:
2288 case kTokenIntegerConstant:
2289 case kTokenFloatConstant: NEXT(); break;
2290 default:
2291 if (IsIdent("true") || IsIdent("false") || IsIdent("null")) {
2292 NEXT();
2293 } else
2294 return TokenError();
2295 }
2296 return NoError();
2297 }
2298
ParseFlexBufferValue(flexbuffers::Builder * builder)2299 CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
2300 switch (token_) {
2301 case '{': {
2302 auto start = builder->StartMap();
2303 size_t fieldn_outer = 0;
2304 auto err =
2305 ParseTableDelimiters(fieldn_outer, nullptr,
2306 [&](const std::string &name, size_t &fieldn,
2307 const StructDef *) -> CheckedError {
2308 builder->Key(name);
2309 ECHECK(ParseFlexBufferValue(builder));
2310 fieldn++;
2311 return NoError();
2312 });
2313 ECHECK(err);
2314 builder->EndMap(start);
2315 break;
2316 }
2317 case '[': {
2318 auto start = builder->StartVector();
2319 size_t count = 0;
2320 ECHECK(ParseVectorDelimiters(count, [&](size_t &) -> CheckedError {
2321 return ParseFlexBufferValue(builder);
2322 }));
2323 builder->EndVector(start, false, false);
2324 break;
2325 }
2326 case kTokenStringConstant:
2327 builder->String(attribute_);
2328 EXPECT(kTokenStringConstant);
2329 break;
2330 case kTokenIntegerConstant:
2331 builder->Int(StringToInt(attribute_.c_str()));
2332 EXPECT(kTokenIntegerConstant);
2333 break;
2334 case kTokenFloatConstant:
2335 builder->Double(strtod(attribute_.c_str(), nullptr));
2336 EXPECT(kTokenFloatConstant);
2337 break;
2338 default:
2339 if (IsIdent("true")) {
2340 builder->Bool(true);
2341 NEXT();
2342 } else if (IsIdent("false")) {
2343 builder->Bool(false);
2344 NEXT();
2345 } else if (IsIdent("null")) {
2346 builder->Null();
2347 NEXT();
2348 } else
2349 return TokenError();
2350 }
2351 return NoError();
2352 }
2353
ParseFlexBuffer(const char * source,const char * source_filename,flexbuffers::Builder * builder)2354 bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
2355 flexbuffers::Builder *builder) {
2356 auto ok = !StartParseFile(source, source_filename).Check() &&
2357 !ParseFlexBufferValue(builder).Check();
2358 if (ok) builder->Finish();
2359 return ok;
2360 }
2361
Parse(const char * source,const char ** include_paths,const char * source_filename)2362 bool Parser::Parse(const char *source, const char **include_paths,
2363 const char *source_filename) {
2364 FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
2365 auto r = !ParseRoot(source, include_paths, source_filename).Check();
2366 FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
2367 return r;
2368 }
2369
StartParseFile(const char * source,const char * source_filename)2370 CheckedError Parser::StartParseFile(const char *source,
2371 const char *source_filename) {
2372 file_being_parsed_ = source_filename ? source_filename : "";
2373 source_ = source;
2374 ResetState(source_);
2375 error_.clear();
2376 ECHECK(SkipByteOrderMark());
2377 NEXT();
2378 if (Is(kTokenEof)) return Error("input file is empty");
2379 return NoError();
2380 }
2381
ParseRoot(const char * source,const char ** include_paths,const char * source_filename)2382 CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
2383 const char *source_filename) {
2384 ECHECK(DoParse(source, include_paths, source_filename, nullptr));
2385
2386 // Check that all types were defined.
2387 for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
2388 auto &struct_def = **it;
2389 if (struct_def.predecl) {
2390 if (opts.proto_mode) {
2391 // Protos allow enums to be used before declaration, so check if that
2392 // is the case here.
2393 EnumDef *enum_def = nullptr;
2394 for (size_t components =
2395 struct_def.defined_namespace->components.size() + 1;
2396 components && !enum_def; components--) {
2397 auto qualified_name =
2398 struct_def.defined_namespace->GetFullyQualifiedName(
2399 struct_def.name, components - 1);
2400 enum_def = LookupEnum(qualified_name);
2401 }
2402 if (enum_def) {
2403 // This is pretty slow, but a simple solution for now.
2404 auto initial_count = struct_def.refcount;
2405 for (auto struct_it = structs_.vec.begin();
2406 struct_it != structs_.vec.end(); ++struct_it) {
2407 auto &sd = **struct_it;
2408 for (auto field_it = sd.fields.vec.begin();
2409 field_it != sd.fields.vec.end(); ++field_it) {
2410 auto &field = **field_it;
2411 if (field.value.type.struct_def == &struct_def) {
2412 field.value.type.struct_def = nullptr;
2413 field.value.type.enum_def = enum_def;
2414 auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR
2415 ? field.value.type.element
2416 : field.value.type.base_type;
2417 FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
2418 bt = enum_def->underlying_type.base_type;
2419 struct_def.refcount--;
2420 enum_def->refcount++;
2421 }
2422 }
2423 }
2424 if (struct_def.refcount)
2425 return Error("internal: " + NumToString(struct_def.refcount) + "/" +
2426 NumToString(initial_count) +
2427 " use(s) of pre-declaration enum not accounted for: " +
2428 enum_def->name);
2429 structs_.dict.erase(structs_.dict.find(struct_def.name));
2430 it = structs_.vec.erase(it);
2431 delete &struct_def;
2432 continue; // Skip error.
2433 }
2434 }
2435 auto err = "type referenced but not defined (check namespace): " +
2436 struct_def.name;
2437 if (struct_def.original_location)
2438 err += ", originally at: " + *struct_def.original_location;
2439 return Error(err);
2440 }
2441 ++it;
2442 }
2443
2444 // This check has to happen here and not earlier, because only now do we
2445 // know for sure what the type of these are.
2446 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2447 auto &enum_def = **it;
2448 if (enum_def.is_union) {
2449 for (auto val_it = enum_def.vals.vec.begin();
2450 val_it != enum_def.vals.vec.end(); ++val_it) {
2451 auto &val = **val_it;
2452 if (!SupportsVectorOfUnions() && val.union_type.struct_def &&
2453 val.union_type.struct_def->fixed)
2454 return Error(
2455 "only tables can be union elements in the generated language: " +
2456 val.name);
2457 }
2458 }
2459 }
2460 return NoError();
2461 }
2462
DoParse(const char * source,const char ** include_paths,const char * source_filename,const char * include_filename)2463 CheckedError Parser::DoParse(const char *source, const char **include_paths,
2464 const char *source_filename,
2465 const char *include_filename) {
2466 if (source_filename) {
2467 if (included_files_.find(source_filename) == included_files_.end()) {
2468 included_files_[source_filename] =
2469 include_filename ? include_filename : "";
2470 files_included_per_file_[source_filename] = std::set<std::string>();
2471 } else {
2472 return NoError();
2473 }
2474 }
2475 if (!include_paths) {
2476 static const char *current_directory[] = { "", nullptr };
2477 include_paths = current_directory;
2478 }
2479 field_stack_.clear();
2480 builder_.Clear();
2481 // Start with a blank namespace just in case this file doesn't have one.
2482 current_namespace_ = empty_namespace_;
2483
2484 ECHECK(StartParseFile(source, source_filename));
2485
2486 // Includes must come before type declarations:
2487 for (;;) {
2488 // Parse pre-include proto statements if any:
2489 if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
2490 attribute_ == "package")) {
2491 ECHECK(ParseProtoDecl());
2492 } else if (IsIdent("native_include")) {
2493 NEXT();
2494 vector_emplace_back(&native_included_files_, attribute_);
2495 EXPECT(kTokenStringConstant);
2496 EXPECT(';');
2497 } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
2498 NEXT();
2499 if (opts.proto_mode && attribute_ == "public") NEXT();
2500 auto name = flatbuffers::PosixPath(attribute_.c_str());
2501 EXPECT(kTokenStringConstant);
2502 // Look for the file in include_paths.
2503 std::string filepath;
2504 for (auto paths = include_paths; paths && *paths; paths++) {
2505 filepath = flatbuffers::ConCatPathFileName(*paths, name);
2506 if (FileExists(filepath.c_str())) break;
2507 }
2508 if (filepath.empty())
2509 return Error("unable to locate include file: " + name);
2510 if (source_filename)
2511 files_included_per_file_[source_filename].insert(filepath);
2512 if (included_files_.find(filepath) == included_files_.end()) {
2513 // We found an include file that we have not parsed yet.
2514 // Load it and parse it.
2515 std::string contents;
2516 if (!LoadFile(filepath.c_str(), true, &contents))
2517 return Error("unable to load include file: " + name);
2518 ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
2519 name.c_str()));
2520 // We generally do not want to output code for any included files:
2521 if (!opts.generate_all) MarkGenerated();
2522 // Reset these just in case the included file had them, and the
2523 // parent doesn't.
2524 root_struct_def_ = nullptr;
2525 file_identifier_.clear();
2526 file_extension_.clear();
2527 // This is the easiest way to continue this file after an include:
2528 // instead of saving and restoring all the state, we simply start the
2529 // file anew. This will cause it to encounter the same include
2530 // statement again, but this time it will skip it, because it was
2531 // entered into included_files_.
2532 // This is recursive, but only go as deep as the number of include
2533 // statements.
2534 if (source_filename) {
2535 included_files_.erase(source_filename);
2536 }
2537 return DoParse(source, include_paths, source_filename,
2538 include_filename);
2539 }
2540 EXPECT(';');
2541 } else {
2542 break;
2543 }
2544 }
2545 // Now parse all other kinds of declarations:
2546 while (token_ != kTokenEof) {
2547 if (opts.proto_mode) {
2548 ECHECK(ParseProtoDecl());
2549 } else if (IsIdent("namespace")) {
2550 ECHECK(ParseNamespace());
2551 } else if (token_ == '{') {
2552 if (!root_struct_def_)
2553 return Error("no root type set to parse json with");
2554 if (builder_.GetSize()) {
2555 return Error("cannot have more than one json object in a file");
2556 }
2557 uoffset_t toff;
2558 ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
2559 if (opts.size_prefixed) {
2560 builder_.FinishSizePrefixed(Offset<Table>(toff), file_identifier_.length()
2561 ? file_identifier_.c_str()
2562 : nullptr);
2563 } else {
2564 builder_.Finish(Offset<Table>(toff), file_identifier_.length()
2565 ? file_identifier_.c_str()
2566 : nullptr);
2567 }
2568 // Check that JSON file doesn't contain more objects or IDL directives.
2569 // Comments after JSON are allowed.
2570 EXPECT(kTokenEof);
2571 } else if (IsIdent("enum")) {
2572 ECHECK(ParseEnum(false, nullptr));
2573 } else if (IsIdent("union")) {
2574 ECHECK(ParseEnum(true, nullptr));
2575 } else if (IsIdent("root_type")) {
2576 NEXT();
2577 auto root_type = attribute_;
2578 EXPECT(kTokenIdentifier);
2579 ECHECK(ParseNamespacing(&root_type, nullptr));
2580 if (opts.root_type.empty()) {
2581 if (!SetRootType(root_type.c_str()))
2582 return Error("unknown root type: " + root_type);
2583 if (root_struct_def_->fixed)
2584 return Error("root type must be a table");
2585 }
2586 EXPECT(';');
2587 } else if (IsIdent("file_identifier")) {
2588 NEXT();
2589 file_identifier_ = attribute_;
2590 EXPECT(kTokenStringConstant);
2591 if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength)
2592 return Error("file_identifier must be exactly " +
2593 NumToString(FlatBufferBuilder::kFileIdentifierLength) +
2594 " characters");
2595 EXPECT(';');
2596 } else if (IsIdent("file_extension")) {
2597 NEXT();
2598 file_extension_ = attribute_;
2599 EXPECT(kTokenStringConstant);
2600 EXPECT(';');
2601 } else if (IsIdent("include")) {
2602 return Error("includes must come before declarations");
2603 } else if (IsIdent("attribute")) {
2604 NEXT();
2605 auto name = attribute_;
2606 if (Is(kTokenIdentifier)) {
2607 NEXT();
2608 } else {
2609 EXPECT(kTokenStringConstant);
2610 }
2611 EXPECT(';');
2612 known_attributes_[name] = false;
2613 } else if (IsIdent("rpc_service")) {
2614 ECHECK(ParseService());
2615 } else {
2616 ECHECK(ParseDecl());
2617 }
2618 }
2619 return NoError();
2620 }
2621
GetIncludedFilesRecursive(const std::string & file_name) const2622 std::set<std::string> Parser::GetIncludedFilesRecursive(
2623 const std::string &file_name) const {
2624 std::set<std::string> included_files;
2625 std::list<std::string> to_process;
2626
2627 if (file_name.empty()) return included_files;
2628 to_process.push_back(file_name);
2629
2630 while (!to_process.empty()) {
2631 std::string current = to_process.front();
2632 to_process.pop_front();
2633 included_files.insert(current);
2634
2635 // Workaround the lack of const accessor in C++98 maps.
2636 auto &new_files =
2637 (*const_cast<std::map<std::string, std::set<std::string>> *>(
2638 &files_included_per_file_))[current];
2639 for (auto it = new_files.begin(); it != new_files.end(); ++it) {
2640 if (included_files.find(*it) == included_files.end())
2641 to_process.push_back(*it);
2642 }
2643 }
2644
2645 return included_files;
2646 }
2647
2648 // Schema serialization functionality:
2649
compareName(const T * a,const T * b)2650 template<typename T> bool compareName(const T *a, const T *b) {
2651 return a->defined_namespace->GetFullyQualifiedName(a->name) <
2652 b->defined_namespace->GetFullyQualifiedName(b->name);
2653 }
2654
AssignIndices(const std::vector<T * > & defvec)2655 template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
2656 // Pre-sort these vectors, such that we can set the correct indices for them.
2657 auto vec = defvec;
2658 std::sort(vec.begin(), vec.end(), compareName<T>);
2659 for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
2660 }
2661
Serialize()2662 void Parser::Serialize() {
2663 builder_.Clear();
2664 AssignIndices(structs_.vec);
2665 AssignIndices(enums_.vec);
2666 std::vector<Offset<reflection::Object>> object_offsets;
2667 for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
2668 auto offset = (*it)->Serialize(&builder_, *this);
2669 object_offsets.push_back(offset);
2670 (*it)->serialized_location = offset.o;
2671 }
2672 std::vector<Offset<reflection::Enum>> enum_offsets;
2673 for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
2674 auto offset = (*it)->Serialize(&builder_, *this);
2675 enum_offsets.push_back(offset);
2676 (*it)->serialized_location = offset.o;
2677 }
2678 std::vector<Offset<reflection::Service>> service_offsets;
2679 for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
2680 auto offset = (*it)->Serialize(&builder_, *this);
2681 service_offsets.push_back(offset);
2682 (*it)->serialized_location = offset.o;
2683 }
2684 auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
2685 auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
2686 auto fiid__ = builder_.CreateString(file_identifier_);
2687 auto fext__ = builder_.CreateString(file_extension_);
2688 auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
2689 auto schema_offset =
2690 reflection::CreateSchema(builder_, objs__, enum__, fiid__, fext__,
2691 (root_struct_def_ ? root_struct_def_->serialized_location : 0),
2692 serv__);
2693 if (opts.size_prefixed) {
2694 builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
2695 } else {
2696 builder_.Finish(schema_offset, reflection::SchemaIdentifier());
2697 }
2698 }
2699
GetNamespace(const std::string & qualified_name,std::vector<Namespace * > & namespaces,std::map<std::string,Namespace * > & namespaces_index)2700 static Namespace *GetNamespace(
2701 const std::string &qualified_name, std::vector<Namespace *> &namespaces,
2702 std::map<std::string, Namespace *> &namespaces_index) {
2703 size_t dot = qualified_name.find_last_of('.');
2704 std::string namespace_name = (dot != std::string::npos)
2705 ? std::string(qualified_name.c_str(), dot)
2706 : "";
2707 Namespace *&ns = namespaces_index[namespace_name];
2708
2709 if (!ns) {
2710 ns = new Namespace();
2711 namespaces.push_back(ns);
2712
2713 size_t pos = 0;
2714
2715 for (;;) {
2716 dot = qualified_name.find('.', pos);
2717 if (dot == std::string::npos) { break; }
2718 ns->components.push_back(qualified_name.substr(pos, dot-pos));
2719 pos = dot + 1;
2720 }
2721 }
2722
2723 return ns;
2724 }
2725
Serialize(FlatBufferBuilder * builder,const Parser & parser) const2726 Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
2727 const Parser &parser) const {
2728 std::vector<Offset<reflection::Field>> field_offsets;
2729 for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
2730 field_offsets.push_back((*it)->Serialize(
2731 builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
2732 }
2733 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
2734 auto name__ = builder->CreateString(qualified_name);
2735 auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
2736 auto attr__ = SerializeAttributes(builder, parser);
2737 auto docs__ = parser.opts.binary_schema_comments
2738 ? builder->CreateVectorOfStrings(doc_comment)
2739 : 0;
2740 return reflection::CreateObject(*builder, name__, flds__, fixed,
2741 static_cast<int>(minalign),
2742 static_cast<int>(bytesize),
2743 attr__, docs__);
2744 }
2745
Deserialize(Parser & parser,const reflection::Object * object)2746 bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
2747 if (!DeserializeAttributes(parser, object->attributes()))
2748 return false;
2749 DeserializeDoc(doc_comment, object->documentation());
2750 name = parser.UnqualifiedName(object->name()->str());
2751 fixed = object->is_struct();
2752 minalign = object->minalign();
2753 predecl = false;
2754 sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
2755 std::vector<uoffset_t> indexes =
2756 std::vector<uoffset_t>(object->fields()->Length());
2757 for (uoffset_t i = 0; i < object->fields()->Length(); i++)
2758 indexes[object->fields()->Get(i)->id()] = i;
2759 for (size_t i = 0; i < indexes.size(); i++) {
2760 auto field = object->fields()->Get(indexes[i]);
2761 auto field_def = new FieldDef();
2762 if (!field_def->Deserialize(parser, field) ||
2763 fields.Add(field_def->name, field_def)) {
2764 delete field_def;
2765 return false;
2766 }
2767 if (fixed) {
2768 // Recompute padding since that's currently not serialized.
2769 auto size = InlineSize(field_def->value.type);
2770 auto next_field =
2771 i + 1 < indexes.size()
2772 ? object->fields()->Get(indexes[i+1])
2773 : nullptr;
2774 bytesize += size;
2775 field_def->padding =
2776 next_field ? (next_field->offset() - field_def->value.offset) - size
2777 : PaddingBytes(bytesize, minalign);
2778 bytesize += field_def->padding;
2779 }
2780 }
2781 FLATBUFFERS_ASSERT(static_cast<int>(bytesize) == object->bytesize());
2782 return true;
2783 }
2784
Serialize(FlatBufferBuilder * builder,uint16_t id,const Parser & parser) const2785 Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
2786 uint16_t id,
2787 const Parser &parser) const {
2788 auto name__ = builder->CreateString(name);
2789 auto type__ = value.type.Serialize(builder);
2790 auto attr__ = SerializeAttributes(builder, parser);
2791 auto docs__ = parser.opts.binary_schema_comments
2792 ? builder->CreateVectorOfStrings(doc_comment)
2793 : 0;
2794 return reflection::CreateField(*builder, name__, type__, id, value.offset,
2795 // Is uint64>max(int64) tested?
2796 IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
2797 // result may be platform-dependent if underlying is float (not double)
2798 IsFloat(value.type.base_type) ? strtod(value.constant.c_str(), nullptr)
2799 : 0.0,
2800 deprecated, required, key, attr__, docs__);
2801 // TODO: value.constant is almost always "0", we could save quite a bit of
2802 // space by sharing it. Same for common values of value.type.
2803 }
2804
Deserialize(Parser & parser,const reflection::Field * field)2805 bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) {
2806 name = parser.UnqualifiedName(field->name()->str());
2807 defined_namespace = parser.current_namespace_;
2808 if (!value.type.Deserialize(parser, field->type()))
2809 return false;
2810 value.offset = field->offset();
2811 if (IsInteger(value.type.base_type)) {
2812 value.constant = NumToString(field->default_integer());
2813 } else if (IsFloat(value.type.base_type)) {
2814 value.constant = FloatToString(field->default_real(), 16);
2815 size_t last_zero = value.constant.find_last_not_of('0');
2816 if (last_zero != std::string::npos && last_zero != 0) {
2817 value.constant.erase(last_zero, std::string::npos);
2818 }
2819 }
2820 deprecated = field->deprecated();
2821 required = field->required();
2822 key = field->key();
2823 if (!DeserializeAttributes(parser, field->attributes()))
2824 return false;
2825 // TODO: this should probably be handled by a separate attribute
2826 if (attributes.Lookup("flexbuffer")) {
2827 flexbuffer = true;
2828 parser.uses_flexbuffers_ = true;
2829 if (value.type.base_type != BASE_TYPE_VECTOR ||
2830 value.type.element != BASE_TYPE_UCHAR)
2831 return false;
2832 }
2833 DeserializeDoc(doc_comment, field->documentation());
2834 return true;
2835 }
2836
Serialize(FlatBufferBuilder * builder,const Parser & parser) const2837 Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder,
2838 const Parser &parser) const {
2839 auto name__ = builder->CreateString(name);
2840 auto attr__ = SerializeAttributes(builder, parser);
2841 auto docs__ = parser.opts.binary_schema_comments
2842 ? builder->CreateVectorOfStrings(doc_comment)
2843 : 0;
2844 return reflection::CreateRPCCall(*builder, name__,
2845 request->serialized_location,
2846 response->serialized_location,
2847 attr__, docs__);
2848 }
2849
Deserialize(Parser & parser,const reflection::RPCCall * call)2850 bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) {
2851 name = call->name()->str();
2852 if (!DeserializeAttributes(parser, call->attributes()))
2853 return false;
2854 DeserializeDoc(doc_comment, call->documentation());
2855 request = parser.structs_.Lookup(call->request()->name()->str());
2856 response = parser.structs_.Lookup(call->response()->name()->str());
2857 if (!request || !response) { return false; }
2858 return true;
2859 }
2860
Serialize(FlatBufferBuilder * builder,const Parser & parser) const2861 Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
2862 const Parser &parser) const {
2863 std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
2864 for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
2865 servicecall_offsets.push_back((*it)->Serialize(builder, parser));
2866 }
2867 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
2868 auto name__ = builder->CreateString(qualified_name);
2869 auto call__ = builder->CreateVector(servicecall_offsets);
2870 auto attr__ = SerializeAttributes(builder, parser);
2871 auto docs__ = parser.opts.binary_schema_comments
2872 ? builder->CreateVectorOfStrings(doc_comment)
2873 : 0;
2874 return reflection::CreateService(*builder, name__, call__, attr__, docs__);
2875 }
2876
Deserialize(Parser & parser,const reflection::Service * service)2877 bool ServiceDef::Deserialize(Parser &parser,
2878 const reflection::Service *service) {
2879 name = parser.UnqualifiedName(service->name()->str());
2880 if (service->calls()) {
2881 for (uoffset_t i = 0; i < service->calls()->size(); ++i) {
2882 auto call = new RPCCall();
2883 if (!call->Deserialize(parser, service->calls()->Get(i)) ||
2884 calls.Add(call->name, call)) {
2885 delete call;
2886 return false;
2887 }
2888 }
2889 }
2890 if (!DeserializeAttributes(parser, service->attributes()))
2891 return false;
2892 DeserializeDoc(doc_comment, service->documentation());
2893 return true;
2894 }
2895
Serialize(FlatBufferBuilder * builder,const Parser & parser) const2896 Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
2897 const Parser &parser) const {
2898 std::vector<Offset<reflection::EnumVal>> enumval_offsets;
2899 for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
2900 enumval_offsets.push_back((*it)->Serialize(builder, parser));
2901 }
2902 auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
2903 auto name__ = builder->CreateString(qualified_name);
2904 auto vals__ = builder->CreateVector(enumval_offsets);
2905 auto type__ = underlying_type.Serialize(builder);
2906 auto attr__ = SerializeAttributes(builder, parser);
2907 auto docs__ = parser.opts.binary_schema_comments
2908 ? builder->CreateVectorOfStrings(doc_comment)
2909 : 0;
2910 return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
2911 attr__, docs__);
2912 }
2913
Deserialize(Parser & parser,const reflection::Enum * _enum)2914 bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {
2915 name = parser.UnqualifiedName(_enum->name()->str());
2916 for (uoffset_t i = 0; i < _enum->values()->size(); ++i) {
2917 auto val = new EnumVal();
2918 if (!val->Deserialize(parser, _enum->values()->Get(i)) ||
2919 vals.Add(val->name, val)) {
2920 delete val;
2921 return false;
2922 }
2923 }
2924 is_union = _enum->is_union();
2925 if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
2926 return false;
2927 }
2928 if (!DeserializeAttributes(parser, _enum->attributes()))
2929 return false;
2930 DeserializeDoc(doc_comment, _enum->documentation());
2931 return true;
2932 }
2933
Serialize(FlatBufferBuilder * builder,const Parser & parser) const2934 Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
2935 const Parser &parser) const {
2936 auto name__ = builder->CreateString(name);
2937 auto type__ = union_type.Serialize(builder);
2938 auto docs__ = parser.opts.binary_schema_comments
2939 ? builder->CreateVectorOfStrings(doc_comment)
2940 : 0;
2941 return reflection::CreateEnumVal(*builder, name__, value,
2942 union_type.struct_def ? union_type.struct_def->serialized_location : 0,
2943 type__, docs__);
2944 }
2945
Deserialize(const Parser & parser,const reflection::EnumVal * val)2946 bool EnumVal::Deserialize(const Parser &parser,
2947 const reflection::EnumVal *val) {
2948 name = val->name()->str();
2949 value = val->value();
2950 if (!union_type.Deserialize(parser, val->union_type()))
2951 return false;
2952 DeserializeDoc(doc_comment, val->documentation());
2953 return true;
2954 }
2955
Serialize(FlatBufferBuilder * builder) const2956 Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
2957 return reflection::CreateType(
2958 *builder,
2959 static_cast<reflection::BaseType>(base_type),
2960 static_cast<reflection::BaseType>(element),
2961 struct_def ? struct_def->index : (enum_def ? enum_def->index : -1));
2962 }
2963
Deserialize(const Parser & parser,const reflection::Type * type)2964 bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
2965 if (type == nullptr) return true;
2966 base_type = static_cast<BaseType>(type->base_type());
2967 element = static_cast<BaseType>(type->element());
2968 if (type->index() >= 0) {
2969 if (type->base_type() == reflection::Obj ||
2970 (type->base_type() == reflection::Vector &&
2971 type->element() == reflection::Obj)) {
2972 if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
2973 struct_def = parser.structs_.vec[type->index()];
2974 struct_def->refcount++;
2975 } else {
2976 return false;
2977 }
2978 } else {
2979 if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) {
2980 enum_def = parser.enums_.vec[type->index()];
2981 } else {
2982 return false;
2983 }
2984 }
2985 }
2986 return true;
2987 }
2988
2989 flatbuffers::Offset<
2990 flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
SerializeAttributes(FlatBufferBuilder * builder,const Parser & parser) const2991 Definition::SerializeAttributes(FlatBufferBuilder *builder,
2992 const Parser &parser) const {
2993 std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
2994 for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
2995 auto it = parser.known_attributes_.find(kv->first);
2996 FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
2997 if (parser.opts.binary_schema_builtins || !it->second) {
2998 auto key = builder->CreateString(kv->first);
2999 auto val = builder->CreateString(kv->second->constant);
3000 attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
3001 }
3002 }
3003 if (attrs.size()) {
3004 return builder->CreateVectorOfSortedTables(&attrs);
3005 } else {
3006 return 0;
3007 }
3008 }
3009
DeserializeAttributes(Parser & parser,const Vector<Offset<reflection::KeyValue>> * attrs)3010 bool Definition::DeserializeAttributes(
3011 Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
3012 if (attrs == nullptr)
3013 return true;
3014 for (uoffset_t i = 0; i < attrs->size(); ++i) {
3015 auto kv = attrs->Get(i);
3016 auto value = new Value();
3017 if (kv->value()) { value->constant = kv->value()->str(); }
3018 if (attributes.Add(kv->key()->str(), value)) {
3019 delete value;
3020 return false;
3021 }
3022 parser.known_attributes_[kv->key()->str()];
3023 }
3024 return true;
3025 }
3026
3027 /************************************************************************/
3028 /* DESERIALIZATION */
3029 /************************************************************************/
Deserialize(const uint8_t * buf,const size_t size)3030 bool Parser::Deserialize(const uint8_t *buf, const size_t size) {
3031 flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size);
3032 bool size_prefixed = false;
3033 if(!reflection::SchemaBufferHasIdentifier(buf)) {
3034 if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
3035 true))
3036 return false;
3037 else
3038 size_prefixed = true;
3039 }
3040 auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer
3041 : &reflection::VerifySchemaBuffer;
3042 if (!verify_fn(verifier)) {
3043 return false;
3044 }
3045 auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
3046 : reflection::GetSchema(buf);
3047 return Deserialize(schema);
3048 }
3049
Deserialize(const reflection::Schema * schema)3050 bool Parser::Deserialize(const reflection::Schema *schema) {
3051 file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : "";
3052 file_extension_ = schema->file_ext() ? schema->file_ext()->str() : "";
3053 std::map<std::string, Namespace *> namespaces_index;
3054
3055 // Create defs without deserializing so references from fields to structs and
3056 // enums can be resolved.
3057 for (auto it = schema->objects()->begin(); it != schema->objects()->end();
3058 ++it) {
3059 auto struct_def = new StructDef();
3060 if (structs_.Add(it->name()->str(), struct_def)) {
3061 delete struct_def;
3062 return false;
3063 }
3064 auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr);
3065 if (types_.Add(it->name()->str(), type)) {
3066 delete type;
3067 return false;
3068 }
3069 }
3070 for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
3071 auto enum_def = new EnumDef();
3072 if (enums_.Add(it->name()->str(), enum_def)) {
3073 delete enum_def;
3074 return false;
3075 }
3076 auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def);
3077 if (types_.Add(it->name()->str(), type)) {
3078 delete type;
3079 return false;
3080 }
3081 }
3082
3083 // Now fields can refer to structs and enums by index.
3084 for (auto it = schema->objects()->begin(); it != schema->objects()->end();
3085 ++it) {
3086 std::string qualified_name = it->name()->str();
3087 auto struct_def = structs_.Lookup(qualified_name);
3088 struct_def->defined_namespace =
3089 GetNamespace(qualified_name, namespaces_, namespaces_index);
3090 if (!struct_def->Deserialize(*this, * it)) { return false; }
3091 if (schema->root_table() == *it) { root_struct_def_ = struct_def; }
3092 }
3093 for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
3094 std::string qualified_name = it->name()->str();
3095 auto enum_def = enums_.Lookup(qualified_name);
3096 enum_def->defined_namespace =
3097 GetNamespace(qualified_name, namespaces_, namespaces_index);
3098 if (!enum_def->Deserialize(*this, *it)) { return false; }
3099 }
3100
3101 if (schema->services()) {
3102 for (auto it = schema->services()->begin(); it != schema->services()->end();
3103 ++it) {
3104 std::string qualified_name = it->name()->str();
3105 auto service_def = new ServiceDef();
3106 service_def->defined_namespace =
3107 GetNamespace(qualified_name, namespaces_, namespaces_index);
3108 if (!service_def->Deserialize(*this, *it) ||
3109 services_.Add(qualified_name, service_def)) {
3110 delete service_def;
3111 return false;
3112 }
3113 }
3114 }
3115
3116 return true;
3117 }
3118
ConformTo(const Parser & base)3119 std::string Parser::ConformTo(const Parser &base) {
3120 for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
3121 auto &struct_def = **sit;
3122 auto qualified_name =
3123 struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
3124 auto struct_def_base = base.LookupStruct(qualified_name);
3125 if (!struct_def_base) continue;
3126 for (auto fit = struct_def.fields.vec.begin();
3127 fit != struct_def.fields.vec.end(); ++fit) {
3128 auto &field = **fit;
3129 auto field_base = struct_def_base->fields.Lookup(field.name);
3130 if (field_base) {
3131 if (field.value.offset != field_base->value.offset)
3132 return "offsets differ for field: " + field.name;
3133 if (field.value.constant != field_base->value.constant)
3134 return "defaults differ for field: " + field.name;
3135 if (!EqualByName(field.value.type, field_base->value.type))
3136 return "types differ for field: " + field.name;
3137 } else {
3138 // Doesn't have to exist, deleting fields is fine.
3139 // But we should check if there is a field that has the same offset
3140 // but is incompatible (in the case of field renaming).
3141 for (auto fbit = struct_def_base->fields.vec.begin();
3142 fbit != struct_def_base->fields.vec.end(); ++fbit) {
3143 field_base = *fbit;
3144 if (field.value.offset == field_base->value.offset) {
3145 if (!EqualByName(field.value.type, field_base->value.type))
3146 return "field renamed to different type: " + field.name;
3147 break;
3148 }
3149 }
3150 }
3151 }
3152 }
3153 for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
3154 auto &enum_def = **eit;
3155 auto qualified_name =
3156 enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
3157 auto enum_def_base = base.enums_.Lookup(qualified_name);
3158 if (!enum_def_base) continue;
3159 for (auto evit = enum_def.vals.vec.begin(); evit != enum_def.vals.vec.end();
3160 ++evit) {
3161 auto &enum_val = **evit;
3162 auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name);
3163 if (enum_val_base) {
3164 if (enum_val.value != enum_val_base->value)
3165 return "values differ for enum: " + enum_val.name;
3166 }
3167 }
3168 }
3169 return "";
3170 }
3171
3172 } // namespace flatbuffers
3173