Coverage Report

Created: 2026-06-02 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flatbuffers/src/idl_parser.cpp
Line
Count
Source
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 <cmath>
19
#include <iostream>
20
#include <list>
21
#include <string>
22
#include <utility>
23
24
#include "flatbuffers/base.h"
25
#include "flatbuffers/buffer.h"
26
#include "flatbuffers/idl.h"
27
#include "flatbuffers/reflection_generated.h"
28
#include "flatbuffers/util.h"
29
30
namespace flatbuffers {
31
32
// Reflects the version at the compiling time of binary(lib/dll/so).
33
0
const char* FLATBUFFERS_VERSION() {
34
  // clang-format off
35
0
  return
36
0
      FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
37
0
      FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
38
0
      FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
39
  // clang-format on
40
0
}
41
42
namespace {
43
44
static const double kPi = 3.14159265358979323846;
45
46
// The enums in the reflection schema should match the ones we use internally.
47
// Compare the last element to check if these go out of sync.
48
static_assert(BASE_TYPE_VECTOR64 ==
49
                  static_cast<BaseType>(reflection::MaxBaseType - 1),
50
              "enums don't match");
51
52
// Any parsing calls have to be wrapped in this macro, which automates
53
// handling of recursive error checking a bit. It will check the received
54
// CheckedError object, and return straight away on error.
55
#define ECHECK(call)           \
56
64.9M
  {                            \
57
64.9M
    auto ce = (call);          \
58
64.9M
    if (ce.Check()) return ce; \
59
64.9M
  }
60
61
// These two functions are called hundreds of times below, so define a short
62
// form:
63
20.5M
#define NEXT() ECHECK(Next())
64
13.0M
#define EXPECT(tok) ECHECK(Expect(tok))
65
66
53.3k
static bool ValidateUTF8(const std::string& str) {
67
53.3k
  const char* s = &str[0];
68
53.3k
  const char* const sEnd = s + str.length();
69
2.42M
  while (s < sEnd) {
70
2.39M
    if (FromUTF8(&s) < 0) {
71
21.6k
      return false;
72
21.6k
    }
73
2.39M
  }
74
31.6k
  return true;
75
53.3k
}
76
77
162k
static bool IsLowerSnakeCase(const std::string& str) {
78
310k
  for (size_t i = 0; i < str.length(); i++) {
79
275k
    char c = str[i];
80
275k
    if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') {
81
126k
      return false;
82
126k
    }
83
275k
  }
84
35.6k
  return true;
85
162k
}
86
87
static void DeserializeDoc(std::vector<std::string>& doc,
88
292
                           const Vector<Offset<String>>* documentation) {
89
292
  if (documentation == nullptr) return;
90
24
  for (uoffset_t index = 0; index < documentation->size(); index++)
91
14
    doc.push_back(documentation->Get(index)->str());
92
10
}
93
94
58.9M
static CheckedError NoError() { return CheckedError(false); }
95
96
template <typename T>
97
121k
static std::string TypeToIntervalString() {
98
121k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
121k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
121k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned char>()
Line
Count
Source
97
21.9k
static std::string TypeToIntervalString() {
98
21.9k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
21.9k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
21.9k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<signed char>()
Line
Count
Source
97
22.6k
static std::string TypeToIntervalString() {
98
22.6k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
22.6k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
22.6k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<short>()
Line
Count
Source
97
14.5k
static std::string TypeToIntervalString() {
98
14.5k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
14.5k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
14.5k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned short>()
Line
Count
Source
97
16.6k
static std::string TypeToIntervalString() {
98
16.6k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
16.6k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
16.6k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<int>()
Line
Count
Source
97
13.7k
static std::string TypeToIntervalString() {
98
13.7k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
13.7k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
13.7k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned int>()
Line
Count
Source
97
16.6k
static std::string TypeToIntervalString() {
98
16.6k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
16.6k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
16.6k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<long>()
Line
Count
Source
97
5.35k
static std::string TypeToIntervalString() {
98
5.35k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
5.35k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
5.35k
}
idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<unsigned long>()
Line
Count
Source
97
9.88k
static std::string TypeToIntervalString() {
98
9.88k
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
9.88k
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
9.88k
}
Unexecuted instantiation: idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<float>()
Unexecuted instantiation: idl_parser.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > flatbuffers::(anonymous namespace)::TypeToIntervalString<double>()
101
102
// atot: template version of atoi/atof: convert a string to an instance of T.
103
template <typename T>
104
1.18M
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
1.18M
  return StringToNumber(s, val);
106
1.18M
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned short>(char const*, unsigned short*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
178k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
178k
  return StringToNumber(s, val);
106
178k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned int>(char const*, unsigned int*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
140k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
140k
  return StringToNumber(s, val);
106
140k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned char>(char const*, unsigned char*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
228k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
228k
  return StringToNumber(s, val);
106
228k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<signed char>(char const*, signed char*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
91.4k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
91.4k
  return StringToNumber(s, val);
106
91.4k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<short>(char const*, short*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
78.3k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
78.3k
  return StringToNumber(s, val);
106
78.3k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<int>(char const*, int*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
118k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
118k
  return StringToNumber(s, val);
106
118k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<long>(char const*, long*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
121k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
121k
  return StringToNumber(s, val);
106
121k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<unsigned long>(char const*, unsigned long*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
227k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
227k
  return StringToNumber(s, val);
106
227k
}
107
108
template <typename T>
109
294k
static bool atot_scalar(const char* s, T* val, bool_constant<true>) {
110
  // Normalize NaN parsed from fbs or json to unsigned NaN.
111
294k
  if (false == StringToNumber(s, val)) return false;
112
259k
  *val = (*val != *val) ? std::fabs(*val) : *val;
113
259k
  return true;
114
294k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<float>(char const*, float*, std::__1::integral_constant<bool, true>)
Line
Count
Source
109
128k
static bool atot_scalar(const char* s, T* val, bool_constant<true>) {
110
  // Normalize NaN parsed from fbs or json to unsigned NaN.
111
128k
  if (false == StringToNumber(s, val)) return false;
112
106k
  *val = (*val != *val) ? std::fabs(*val) : *val;
113
106k
  return true;
114
128k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<double>(char const*, double*, std::__1::integral_constant<bool, true>)
Line
Count
Source
109
166k
static bool atot_scalar(const char* s, T* val, bool_constant<true>) {
110
  // Normalize NaN parsed from fbs or json to unsigned NaN.
111
166k
  if (false == StringToNumber(s, val)) return false;
112
153k
  *val = (*val != *val) ? std::fabs(*val) : *val;
113
153k
  return true;
114
166k
}
115
116
template <typename T>
117
1.48M
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
1.48M
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
1.48M
  if (done) return NoError();
120
220k
  if (0 == *val)
121
100k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
120k
  else
123
120k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
120k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
220k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned short>(char const*, flatbuffers::Parser&, unsigned short*)
Line
Count
Source
117
178k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
178k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
178k
  if (done) return NoError();
120
23.4k
  if (0 == *val)
121
6.99k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
16.4k
  else
123
16.4k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
16.4k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
23.4k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned int>(char const*, flatbuffers::Parser&, unsigned int*)
Line
Count
Source
117
140k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
140k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
140k
  if (done) return NoError();
120
23.9k
  if (0 == *val)
121
7.42k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
16.5k
  else
123
16.5k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
16.5k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
23.9k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned char>(char const*, flatbuffers::Parser&, unsigned char*)
Line
Count
Source
117
228k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
228k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
228k
  if (done) return NoError();
120
33.7k
  if (0 == *val)
121
12.1k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
21.6k
  else
123
21.6k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
21.6k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
33.7k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<signed char>(char const*, flatbuffers::Parser&, signed char*)
Line
Count
Source
117
91.4k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
91.4k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
91.4k
  if (done) return NoError();
120
29.9k
  if (0 == *val)
121
7.39k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
22.5k
  else
123
22.5k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
22.5k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
29.9k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<short>(char const*, flatbuffers::Parser&, short*)
Line
Count
Source
117
78.3k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
78.3k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
78.3k
  if (done) return NoError();
120
21.6k
  if (0 == *val)
121
7.19k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
14.4k
  else
123
14.4k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
14.4k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
21.6k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<int>(char const*, flatbuffers::Parser&, int*)
Line
Count
Source
117
118k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
118k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
118k
  if (done) return NoError();
120
20.8k
  if (0 == *val)
121
7.14k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
13.6k
  else
123
13.6k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
13.6k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
20.8k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<long>(char const*, flatbuffers::Parser&, long*)
Line
Count
Source
117
121k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
121k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
121k
  if (done) return NoError();
120
14.2k
  if (0 == *val)
121
8.88k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
5.35k
  else
123
5.35k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
5.35k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
14.2k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned long>(char const*, flatbuffers::Parser&, unsigned long*)
Line
Count
Source
117
227k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
227k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
227k
  if (done) return NoError();
120
17.7k
  if (0 == *val)
121
7.83k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
9.88k
  else
123
9.88k
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
9.88k
                        ", constant does not fit " + TypeToIntervalString<T>());
125
17.7k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<float>(char const*, flatbuffers::Parser&, float*)
Line
Count
Source
117
128k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
128k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
128k
  if (done) return NoError();
120
22.1k
  if (0 == *val)
121
22.1k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
0
  else
123
0
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
0
                        ", constant does not fit " + TypeToIntervalString<T>());
125
22.1k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<double>(char const*, flatbuffers::Parser&, double*)
Line
Count
Source
117
166k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
166k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
166k
  if (done) return NoError();
120
13.0k
  if (0 == *val)
121
13.0k
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
0
  else
123
0
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
0
                        ", constant does not fit " + TypeToIntervalString<T>());
125
13.0k
}
126
template <>
127
CheckedError atot<Offset<void>>(const char* s, Parser& parser,
128
476k
                                Offset<void>* val) {
129
476k
  (void)parser;
130
476k
  *val = Offset<void>(atoi(s));
131
476k
  return NoError();
132
476k
}
133
134
template <>
135
CheckedError atot<Offset64<void>>(const char* s, Parser& parser,
136
11.2k
                                  Offset64<void>* val) {
137
11.2k
  (void)parser;
138
11.2k
  *val = Offset64<void>(atoi(s));
139
11.2k
  return NoError();
140
11.2k
}
141
142
template <typename T>
143
static T* LookupTableByName(const SymbolTable<T>& table,
144
                            const std::string& name,
145
                            const Namespace& current_namespace,
146
402k
                            size_t skip_top) {
147
402k
  const auto& components = current_namespace.components;
148
402k
  if (table.dict.empty()) return nullptr;
149
368k
  if (components.size() < skip_top) return nullptr;
150
107k
  const auto N = components.size() - skip_top;
151
107k
  std::string full_name;
152
786k
  for (size_t i = 0; i < N; i++) {
153
678k
    full_name += components[i];
154
678k
    full_name += '.';
155
678k
  }
156
779k
  for (size_t i = N; i > 0; i--) {
157
675k
    full_name += name;
158
675k
    auto obj = table.Lookup(full_name);
159
675k
    if (obj) return obj;
160
672k
    auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
161
672k
    full_name.resize(len);
162
672k
  }
163
103k
  FLATBUFFERS_ASSERT(full_name.empty());
164
103k
  return table.Lookup(name);  // lookup in global namespace
165
103k
}
idl_parser.cpp:flatbuffers::EnumDef* flatbuffers::(anonymous namespace)::LookupTableByName<flatbuffers::EnumDef>(flatbuffers::SymbolTable<flatbuffers::EnumDef> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, flatbuffers::Namespace const&, unsigned long)
Line
Count
Source
146
79.2k
                            size_t skip_top) {
147
79.2k
  const auto& components = current_namespace.components;
148
79.2k
  if (table.dict.empty()) return nullptr;
149
51.3k
  if (components.size() < skip_top) return nullptr;
150
51.3k
  const auto N = components.size() - skip_top;
151
51.3k
  std::string full_name;
152
114k
  for (size_t i = 0; i < N; i++) {
153
63.4k
    full_name += components[i];
154
63.4k
    full_name += '.';
155
63.4k
  }
156
108k
  for (size_t i = N; i > 0; i--) {
157
60.5k
    full_name += name;
158
60.5k
    auto obj = table.Lookup(full_name);
159
60.5k
    if (obj) return obj;
160
57.4k
    auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
161
57.4k
    full_name.resize(len);
162
57.4k
  }
163
48.2k
  FLATBUFFERS_ASSERT(full_name.empty());
164
48.2k
  return table.Lookup(name);  // lookup in global namespace
165
48.2k
}
idl_parser.cpp:flatbuffers::StructDef* flatbuffers::(anonymous namespace)::LookupTableByName<flatbuffers::StructDef>(flatbuffers::SymbolTable<flatbuffers::StructDef> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, flatbuffers::Namespace const&, unsigned long)
Line
Count
Source
146
323k
                            size_t skip_top) {
147
323k
  const auto& components = current_namespace.components;
148
323k
  if (table.dict.empty()) return nullptr;
149
317k
  if (components.size() < skip_top) return nullptr;
150
55.9k
  const auto N = components.size() - skip_top;
151
55.9k
  std::string full_name;
152
671k
  for (size_t i = 0; i < N; i++) {
153
615k
    full_name += components[i];
154
615k
    full_name += '.';
155
615k
  }
156
671k
  for (size_t i = N; i > 0; i--) {
157
615k
    full_name += name;
158
615k
    auto obj = table.Lookup(full_name);
159
615k
    if (obj) return obj;
160
615k
    auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
161
615k
    full_name.resize(len);
162
615k
  }
163
55.7k
  FLATBUFFERS_ASSERT(full_name.empty());
164
55.7k
  return table.Lookup(name);  // lookup in global namespace
165
55.7k
}
166
167
// Declare tokens we'll use. Single character tokens are represented by their
168
// ascii character code (e.g. '{'), others above 256.
169
// clang-format off
170
#define FLATBUFFERS_GEN_TOKENS(TD) \
171
100k
  TD(Eof, 256, "end of file") \
172
100k
  TD(StringConstant, 257, "string constant") \
173
100k
  TD(IntegerConstant, 258, "integer constant") \
174
100k
  TD(FloatConstant, 259, "float constant") \
175
100k
  TD(Identifier, 260, "identifier")
176
#ifdef __GNUC__
177
__extension__  // Stop GCC complaining about trailing comma with -Wpendantic.
178
#endif
179
enum {
180
  #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
181
    FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
182
  #undef FLATBUFFERS_TOKEN
183
};
184
185
100k
static std::string TokenToString(int t) {
186
100k
  static const char * const tokens[] = {
187
500k
    #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
188
500k
      FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
189
100k
    #undef FLATBUFFERS_TOKEN
190
100k
    #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
191
1.90M
      IDLTYPE,
192
1.90M
      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
193
100k
    #undef FLATBUFFERS_TD
194
100k
  };
195
100k
  if (t < 256) {  // A single ascii char token.
196
70.0k
    std::string s;
197
70.0k
    s.append(1, static_cast<char>(t));
198
70.0k
    return s;
199
70.0k
  } else {       // Other tokens.
200
30.1k
    return tokens[t - 256];
201
30.1k
  }
202
100k
}
203
// clang-format on
204
205
24.7M
static bool IsIdentifierStart(char c) { return is_alpha(c) || (c == '_'); }
206
207
static bool CompareSerializedScalars(const uint8_t* a, const uint8_t* b,
208
296M
                                     const FieldDef& key) {
209
296M
  switch (key.value.type.base_type) {
210
0
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...)       \
211
296M
  case BASE_TYPE_##ENUM: {                              \
212
296M
    CTYPE def = static_cast<CTYPE>(0);                  \
213
296M
    if (!a || !b) {                                     \
214
275M
      StringToNumber(key.value.constant.c_str(), &def); \
215
275M
    }                                                   \
216
296M
    const auto av = a ? ReadScalar<CTYPE>(a) : def;     \
217
296M
    const auto bv = b ? ReadScalar<CTYPE>(b) : def;     \
218
296M
    return av < bv;                                     \
219
296M
  }
220
296M
    FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
221
0
#undef FLATBUFFERS_TD
222
0
    default: {
223
0
      FLATBUFFERS_ASSERT(false && "scalar type expected");
224
0
      return false;
225
0
    }
226
296M
  }
227
296M
}
228
229
static bool CompareTablesByScalarKey(const Offset<Table>* _a,
230
                                     const Offset<Table>* _b,
231
283M
                                     const FieldDef& key) {
232
283M
  const voffset_t offset = key.value.offset;
233
  // Indirect offset pointer to table pointer.
234
283M
  auto a = reinterpret_cast<const uint8_t*>(_a) + ReadScalar<uoffset_t>(_a);
235
283M
  auto b = reinterpret_cast<const uint8_t*>(_b) + ReadScalar<uoffset_t>(_b);
236
  // Fetch field address from table.
237
283M
  a = reinterpret_cast<const Table*>(a)->GetAddressOf(offset);
238
283M
  b = reinterpret_cast<const Table*>(b)->GetAddressOf(offset);
239
283M
  return CompareSerializedScalars(a, b, key);
240
283M
}
241
242
static bool CompareTablesByStringKey(const Offset<Table>* _a,
243
                                     const Offset<Table>* _b,
244
2.00M
                                     const FieldDef& key) {
245
2.00M
  const voffset_t offset = key.value.offset;
246
  // Indirect offset pointer to table pointer.
247
2.00M
  auto a = reinterpret_cast<const uint8_t*>(_a) + ReadScalar<uoffset_t>(_a);
248
2.00M
  auto b = reinterpret_cast<const uint8_t*>(_b) + ReadScalar<uoffset_t>(_b);
249
  // Fetch field address from table.
250
2.00M
  a = reinterpret_cast<const Table*>(a)->GetAddressOf(offset);
251
2.00M
  b = reinterpret_cast<const Table*>(b)->GetAddressOf(offset);
252
2.00M
  if (a && b) {
253
    // Indirect offset pointer to string pointer.
254
2.00M
    a += ReadScalar<uoffset_t>(a);
255
2.00M
    b += ReadScalar<uoffset_t>(b);
256
2.00M
    return *reinterpret_cast<const String*>(a) <
257
2.00M
           *reinterpret_cast<const String*>(b);
258
2.00M
  } else {
259
0
    return a ? true : false;
260
0
  }
261
2.00M
}
262
263
355k
static void SwapSerializedTables(Offset<Table>* a, Offset<Table>* b) {
264
  // These are serialized offsets, so are relative where they are
265
  // stored in memory, so compute the distance between these pointers:
266
355k
  ptrdiff_t diff = (b - a) * sizeof(Offset<Table>);
267
355k
  FLATBUFFERS_ASSERT(diff >= 0);  // Guaranteed by SimpleQsort.
268
355k
  auto udiff = static_cast<uoffset_t>(diff);
269
355k
  a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff);
270
355k
  b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff);
271
355k
  std::swap(*a, *b);
272
355k
}
273
274
// See below for why we need our own sort :(
275
template <typename T, typename F, typename S>
276
static void SimpleQsort(T* begin, T* end, size_t width, F comparator,
277
591k
                        S swapper) {
278
591k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
292k
  auto l = begin + width;
280
292k
  auto r = end;
281
298M
  while (l < r) {
282
298M
    if (comparator(begin, l)) {
283
92.6k
      r -= width;
284
92.6k
      swapper(l, r);
285
298M
    } else {
286
298M
      l += width;
287
298M
    }
288
298M
  }
289
292k
  l -= width;
290
292k
  swapper(begin, l);
291
292k
  SimpleQsort(begin, l, width, comparator, swapper);
292
292k
  SimpleQsort(r, end, width, comparator, swapper);
293
292k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SimpleQsort<unsigned char, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_1, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_2>(unsigned char*, unsigned char*, unsigned long, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_1, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_2)
Line
Count
Source
277
48.4k
                        S swapper) {
278
48.4k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
23.9k
  auto l = begin + width;
280
23.9k
  auto r = end;
281
13.6M
  while (l < r) {
282
13.5M
    if (comparator(begin, l)) {
283
5.85k
      r -= width;
284
5.85k
      swapper(l, r);
285
13.5M
    } else {
286
13.5M
      l += width;
287
13.5M
    }
288
13.5M
  }
289
23.9k
  l -= width;
290
23.9k
  swapper(begin, l);
291
23.9k
  SimpleQsort(begin, l, width, comparator, swapper);
292
23.9k
  SimpleQsort(r, end, width, comparator, swapper);
293
23.9k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SimpleQsort<flatbuffers::Offset<flatbuffers::Table>, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_3, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*)>(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*, unsigned long, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_3, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*))
Line
Count
Source
277
92.0k
                        S swapper) {
278
92.0k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
44.3k
  auto l = begin + width;
280
44.3k
  auto r = end;
281
2.05M
  while (l < r) {
282
2.00M
    if (comparator(begin, l)) {
283
46.4k
      r -= width;
284
46.4k
      swapper(l, r);
285
1.96M
    } else {
286
1.96M
      l += width;
287
1.96M
    }
288
2.00M
  }
289
44.3k
  l -= width;
290
44.3k
  swapper(begin, l);
291
44.3k
  SimpleQsort(begin, l, width, comparator, swapper);
292
44.3k
  SimpleQsort(r, end, width, comparator, swapper);
293
44.3k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SimpleQsort<flatbuffers::Offset<flatbuffers::Table>, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_4, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*)>(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*, unsigned long, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_4, void (*)(flatbuffers::Offset<flatbuffers::Table>*, flatbuffers::Offset<flatbuffers::Table>*))
Line
Count
Source
277
451k
                        S swapper) {
278
451k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
224k
  auto l = begin + width;
280
224k
  auto r = end;
281
283M
  while (l < r) {
282
283M
    if (comparator(begin, l)) {
283
40.3k
      r -= width;
284
40.3k
      swapper(l, r);
285
282M
    } else {
286
282M
      l += width;
287
282M
    }
288
283M
  }
289
224k
  l -= width;
290
224k
  swapper(begin, l);
291
224k
  SimpleQsort(begin, l, width, comparator, swapper);
292
224k
  SimpleQsort(r, end, width, comparator, swapper);
293
224k
}
294
295
template <typename T>
296
87.7k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
87.7k
  if (IsInteger(e.type.base_type)) {
299
87.7k
    e.constant = NumToString(val);
300
87.7k
  }
301
87.7k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned char>(flatbuffers::Value&, unsigned char)
Line
Count
Source
296
9.12k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
9.12k
  if (IsInteger(e.type.base_type)) {
299
9.12k
    e.constant = NumToString(val);
300
9.12k
  }
301
9.12k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<signed char>(flatbuffers::Value&, signed char)
Line
Count
Source
296
6.53k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
6.53k
  if (IsInteger(e.type.base_type)) {
299
6.53k
    e.constant = NumToString(val);
300
6.53k
  }
301
6.53k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<short>(flatbuffers::Value&, short)
Line
Count
Source
296
6.62k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
6.62k
  if (IsInteger(e.type.base_type)) {
299
6.62k
    e.constant = NumToString(val);
300
6.62k
  }
301
6.62k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned short>(flatbuffers::Value&, unsigned short)
Line
Count
Source
296
7.10k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
7.10k
  if (IsInteger(e.type.base_type)) {
299
7.10k
    e.constant = NumToString(val);
300
7.10k
  }
301
7.10k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<int>(flatbuffers::Value&, int)
Line
Count
Source
296
17.6k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
17.6k
  if (IsInteger(e.type.base_type)) {
299
17.6k
    e.constant = NumToString(val);
300
17.6k
  }
301
17.6k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned int>(flatbuffers::Value&, unsigned int)
Line
Count
Source
296
11.0k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
11.0k
  if (IsInteger(e.type.base_type)) {
299
11.0k
    e.constant = NumToString(val);
300
11.0k
  }
301
11.0k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<long>(flatbuffers::Value&, long)
Line
Count
Source
296
11.3k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
11.3k
  if (IsInteger(e.type.base_type)) {
299
11.3k
    e.constant = NumToString(val);
300
11.3k
  }
301
11.3k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned long>(flatbuffers::Value&, unsigned long)
Line
Count
Source
296
18.3k
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
18.3k
  if (IsInteger(e.type.base_type)) {
299
18.3k
    e.constant = NumToString(val);
300
18.3k
  }
301
18.3k
}
302
303
#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
304
// Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from
305
// hex-float literal.
306
13.9k
static void SingleValueRepack(Value& e, float val) {
307
13.9k
  if (val != val) e.constant = "nan";
308
13.9k
}
309
10.5k
static void SingleValueRepack(Value& e, double val) {
310
10.5k
  if (val != val) e.constant = "nan";
311
10.5k
}
312
#endif
313
314
template <typename T>
315
0
static uint64_t EnumDistanceImpl(T e1, T e2) {
316
0
  if (e1 < e2) {
317
0
    std::swap(e1, e2);
318
0
  }  // use std for scalars
319
  // Signed overflow may occur, use unsigned calculation.
320
  // The unsigned overflow is well-defined by C++ standard (modulo 2^n).
321
0
  return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2);
322
0
}
Unexecuted instantiation: idl_parser.cpp:unsigned long flatbuffers::(anonymous namespace)::EnumDistanceImpl<unsigned long>(unsigned long, unsigned long)
Unexecuted instantiation: idl_parser.cpp:unsigned long flatbuffers::(anonymous namespace)::EnumDistanceImpl<long>(long, long)
323
324
65.1k
static bool compareFieldDefs(const FieldDef* a, const FieldDef* b) {
325
65.1k
  auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
326
65.1k
  auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
327
65.1k
  return a_id < b_id;
328
65.1k
}
329
330
static Namespace* GetNamespace(
331
    const std::string& qualified_name, std::vector<Namespace*>& namespaces,
332
46
    std::map<std::string, Namespace*>& namespaces_index) {
333
46
  size_t dot = qualified_name.find_last_of('.');
334
46
  std::string namespace_name = (dot != std::string::npos)
335
46
                                   ? std::string(qualified_name.c_str(), dot)
336
46
                                   : "";
337
46
  Namespace*& ns = namespaces_index[namespace_name];
338
339
46
  if (!ns) {
340
10
    ns = new Namespace();
341
10
    namespaces.push_back(ns);
342
343
10
    size_t pos = 0;
344
345
24
    for (;;) {
346
24
      dot = qualified_name.find('.', pos);
347
24
      if (dot == std::string::npos) {
348
10
        break;
349
10
      }
350
14
      ns->components.push_back(qualified_name.substr(pos, dot - pos));
351
14
      pos = dot + 1;
352
14
    }
353
10
  }
354
355
46
  return ns;
356
46
}
357
358
// Generate a unique hash for a file based on its name and contents (if any).
359
159
static uint64_t HashFile(const char* source_filename, const char* source) {
360
159
  uint64_t hash = 0;
361
362
159
  if (source_filename)
363
159
    hash = HashFnv1a<uint64_t>(StripPath(source_filename).c_str());
364
365
159
  if (source && *source) hash ^= HashFnv1a<uint64_t>(source);
366
367
159
  return hash;
368
159
}
369
370
template <typename T>
371
951k
static bool compareName(const T* a, const T* b) {
372
951k
  return a->defined_namespace->GetFullyQualifiedName(a->name) <
373
951k
         b->defined_namespace->GetFullyQualifiedName(b->name);
374
951k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::compareName<flatbuffers::StructDef>(flatbuffers::StructDef const*, flatbuffers::StructDef const*)
Line
Count
Source
371
357k
static bool compareName(const T* a, const T* b) {
372
357k
  return a->defined_namespace->GetFullyQualifiedName(a->name) <
373
357k
         b->defined_namespace->GetFullyQualifiedName(b->name);
374
357k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::compareName<flatbuffers::EnumDef>(flatbuffers::EnumDef const*, flatbuffers::EnumDef const*)
Line
Count
Source
371
594k
static bool compareName(const T* a, const T* b) {
372
594k
  return a->defined_namespace->GetFullyQualifiedName(a->name) <
373
594k
         b->defined_namespace->GetFullyQualifiedName(b->name);
374
594k
}
375
376
template <typename T>
377
9.41k
static void AssignIndices(const std::vector<T*>& defvec) {
378
  // Pre-sort these vectors, such that we can set the correct indices for them.
379
9.41k
  auto vec = defvec;
380
9.41k
  std::sort(vec.begin(), vec.end(), compareName<T>);
381
124k
  for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
382
9.41k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::AssignIndices<flatbuffers::StructDef>(std::__1::vector<flatbuffers::StructDef*, std::__1::allocator<flatbuffers::StructDef*> > const&)
Line
Count
Source
377
4.70k
static void AssignIndices(const std::vector<T*>& defvec) {
378
  // Pre-sort these vectors, such that we can set the correct indices for them.
379
4.70k
  auto vec = defvec;
380
4.70k
  std::sort(vec.begin(), vec.end(), compareName<T>);
381
50.9k
  for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
382
4.70k
}
idl_parser.cpp:void flatbuffers::(anonymous namespace)::AssignIndices<flatbuffers::EnumDef>(std::__1::vector<flatbuffers::EnumDef*, std::__1::allocator<flatbuffers::EnumDef*> > const&)
Line
Count
Source
377
4.70k
static void AssignIndices(const std::vector<T*>& defvec) {
378
  // Pre-sort these vectors, such that we can set the correct indices for them.
379
4.70k
  auto vec = defvec;
380
4.70k
  std::sort(vec.begin(), vec.end(), compareName<T>);
381
73.9k
  for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
382
4.70k
}
383
384
}  // namespace
385
386
642k
void Parser::Message(const std::string& msg) {
387
642k
  if (!error_.empty()) error_ += "\n";  // log all warnings and errors
388
642k
  error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
389
  // clang-format off
390
391
  #ifdef _WIN32  // MSVC alike
392
    error_ +=
393
        "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")";
394
  #else  // gcc alike
395
642k
    if (file_being_parsed_.length()) error_ += ":";
396
642k
    error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
397
642k
  #endif
398
  // clang-format on
399
642k
  error_ += ": " + msg;
400
642k
}
401
402
130k
void Parser::Warning(const std::string& msg) {
403
130k
  if (!opts.no_warnings) {
404
130k
    Message("warning: " + msg);
405
130k
    has_warning_ = true;  // for opts.warnings_as_errors
406
130k
  }
407
130k
}
408
409
511k
CheckedError Parser::Error(const std::string& msg) {
410
511k
  Message("error: " + msg);
411
511k
  return CheckedError(true);
412
511k
}
413
414
469
CheckedError Parser::RecurseError() {
415
469
  return Error("maximum parsing depth " + NumToString(parse_depth_counter_) +
416
469
               " reached");
417
469
}
418
419
0
const std::string& Parser::GetPooledString(const std::string& s) const {
420
0
  return *(string_cache_.insert(s).first);
421
0
}
422
423
class Parser::ParseDepthGuard {
424
 public:
425
  explicit ParseDepthGuard(Parser* parser_not_null)
426
5.11M
      : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) {
427
5.11M
    FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) &&
428
5.11M
                       "Check() must be called to prevent stack overflow");
429
5.11M
    parser_.parse_depth_counter_ += 1;
430
5.11M
  }
431
432
5.11M
  ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; }
433
434
5.11M
  CheckedError Check() {
435
5.11M
    return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH)
436
5.11M
               ? parser_.RecurseError()
437
5.11M
               : CheckedError(false);
438
5.11M
  }
439
440
  FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard&));
441
  FLATBUFFERS_DELETE_FUNC(ParseDepthGuard& operator=(const ParseDepthGuard&));
442
443
 private:
444
  Parser& parser_;
445
  const int caller_depth_;
446
};
447
448
std::string Namespace::GetFullyQualifiedName(const std::string& name,
449
3.05M
                                             size_t max_components) const {
450
  // Early exit if we don't have a defined namespace.
451
3.05M
  if (components.empty() || !max_components) {
452
715k
    return name;
453
715k
  }
454
2.33M
  std::string stream_str;
455
5.83M
  for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
456
3.49M
    stream_str += components[i];
457
3.49M
    stream_str += '.';
458
3.49M
  }
459
2.33M
  if (!stream_str.empty()) stream_str.pop_back();
460
2.33M
  if (name.length()) {
461
2.33M
    stream_str += '.';
462
2.33M
    stream_str += name;
463
2.33M
  }
464
2.33M
  return stream_str;
465
3.05M
}
466
467
67.1k
std::string Parser::TokenToStringId(int t) const {
468
67.1k
  return t == kTokenIdentifier ? attribute_ : TokenToString(t);
469
67.1k
}
470
471
// Parses exactly nibbles worth of hex digits into a number, or error.
472
336k
CheckedError Parser::ParseHexNum(int nibbles, uint64_t* val) {
473
336k
  FLATBUFFERS_ASSERT(nibbles > 0);
474
1.08M
  for (int i = 0; i < nibbles; i++)
475
755k
    if (!is_xdigit(cursor_[i]))
476
4.51k
      return Error("escape code must be followed by " + NumToString(nibbles) +
477
4.51k
                   " hex digits");
478
331k
  std::string target(cursor_, cursor_ + nibbles);
479
331k
  *val = StringToUInt(target.c_str(), 16);
480
331k
  cursor_ += nibbles;
481
331k
  return NoError();
482
336k
}
483
484
849k
CheckedError Parser::SkipByteOrderMark() {
485
849k
  if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
486
42
  cursor_++;
487
42
  if (static_cast<unsigned char>(*cursor_) != 0xbb)
488
19
    return Error("invalid utf-8 byte order mark");
489
23
  cursor_++;
490
23
  if (static_cast<unsigned char>(*cursor_) != 0xbf)
491
20
    return Error("invalid utf-8 byte order mark");
492
3
  cursor_++;
493
3
  return NoError();
494
23
}
495
496
20.5M
CheckedError Parser::Next() {
497
20.5M
  doc_comment_.clear();
498
20.5M
  prev_cursor_ = cursor_;
499
20.5M
  bool seen_newline = cursor_ == source_;
500
20.5M
  attribute_.clear();
501
20.5M
  attr_is_trivial_ascii_string_ = true;
502
30.9M
  for (;;) {
503
30.9M
    char c = *cursor_++;
504
30.9M
    token_ = c;
505
30.9M
    switch (c) {
506
918k
      case '\0':
507
918k
        cursor_--;
508
918k
        token_ = kTokenEof;
509
918k
        return NoError();
510
9.31M
      case ' ':
511
9.33M
      case '\r':
512
9.47M
      case '\t':
513
9.47M
        break;
514
868k
      case '\n':
515
868k
        MarkNewLine();
516
868k
        seen_newline = true;
517
868k
        break;
518
1.57M
      case '{':
519
2.88M
      case '}':
520
2.98M
      case '(':
521
3.01M
      case ')':
522
4.33M
      case '[':
523
5.64M
      case ']':
524
5.64M
      case '<':
525
5.65M
      case '>':
526
9.49M
      case ',':
527
11.3M
      case ':':
528
11.7M
      case ';':
529
11.9M
      case '=':
530
11.9M
        return NoError();
531
1.18M
      case '\"':
532
1.45M
      case '\'': {
533
1.45M
        int unicode_high_surrogate = -1;
534
535
30.8M
        while (*cursor_ != c) {
536
29.4M
          if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
537
24.3k
            return Error("illegal character in string constant");
538
29.4M
          if (*cursor_ == '\\') {
539
367k
            attr_is_trivial_ascii_string_ = false;  // has escape sequence
540
367k
            cursor_++;
541
367k
            if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
542
1.22k
              return Error(
543
1.22k
                  "illegal Unicode sequence (unpaired high surrogate)");
544
1.22k
            }
545
366k
            switch (*cursor_) {
546
2.58k
              case 'n':
547
2.58k
                attribute_ += '\n';
548
2.58k
                cursor_++;
549
2.58k
                break;
550
3.55k
              case 't':
551
3.55k
                attribute_ += '\t';
552
3.55k
                cursor_++;
553
3.55k
                break;
554
3.57k
              case 'r':
555
3.57k
                attribute_ += '\r';
556
3.57k
                cursor_++;
557
3.57k
                break;
558
2.91k
              case 'b':
559
2.91k
                attribute_ += '\b';
560
2.91k
                cursor_++;
561
2.91k
                break;
562
2.99k
              case 'f':
563
2.99k
                attribute_ += '\f';
564
2.99k
                cursor_++;
565
2.99k
                break;
566
4.89k
              case '\"':
567
4.89k
                attribute_ += '\"';
568
4.89k
                cursor_++;
569
4.89k
                break;
570
3.92k
              case '\'':
571
3.92k
                attribute_ += '\'';
572
3.92k
                cursor_++;
573
3.92k
                break;
574
2.45k
              case '\\':
575
2.45k
                attribute_ += '\\';
576
2.45k
                cursor_++;
577
2.45k
                break;
578
1.99k
              case '/':
579
1.99k
                attribute_ += '/';
580
1.99k
                cursor_++;
581
1.99k
                break;
582
290k
              case 'x': {  // Not in the JSON standard
583
290k
                cursor_++;
584
290k
                uint64_t val;
585
290k
                ECHECK(ParseHexNum(2, &val));
586
289k
                attribute_ += static_cast<char>(val);
587
289k
                break;
588
290k
              }
589
45.6k
              case 'u': {
590
45.6k
                cursor_++;
591
45.6k
                uint64_t val;
592
45.6k
                ECHECK(ParseHexNum(4, &val));
593
42.2k
                if (val >= 0xD800 && val <= 0xDBFF) {
594
10.9k
                  if (unicode_high_surrogate != -1) {
595
762
                    return Error(
596
762
                        "illegal Unicode sequence (multiple high surrogates)");
597
10.2k
                  } else {
598
10.2k
                    unicode_high_surrogate = static_cast<int>(val);
599
10.2k
                  }
600
31.3k
                } else if (val >= 0xDC00 && val <= 0xDFFF) {
601
6.47k
                  if (unicode_high_surrogate == -1) {
602
1.30k
                    return Error(
603
1.30k
                        "illegal Unicode sequence (unpaired low surrogate)");
604
5.16k
                  } else {
605
5.16k
                    int code_point = 0x10000 +
606
5.16k
                                     ((unicode_high_surrogate & 0x03FF) << 10) +
607
5.16k
                                     (val & 0x03FF);
608
5.16k
                    ToUTF8(code_point, &attribute_);
609
5.16k
                    unicode_high_surrogate = -1;
610
5.16k
                  }
611
24.8k
                } else {
612
24.8k
                  if (unicode_high_surrogate != -1) {
613
573
                    return Error(
614
573
                        "illegal Unicode sequence (unpaired high surrogate)");
615
573
                  }
616
24.2k
                  ToUTF8(static_cast<int>(val), &attribute_);
617
24.2k
                }
618
39.6k
                break;
619
42.2k
              }
620
39.6k
              default:
621
1.31k
                return Error("unknown escape code in string constant");
622
366k
            }
623
29.0M
          } else {  // printable chars + UTF-8 bytes
624
29.0M
            if (unicode_high_surrogate != -1) {
625
799
              return Error(
626
799
                  "illegal Unicode sequence (unpaired high surrogate)");
627
799
            }
628
            // reset if non-printable
629
29.0M
            attr_is_trivial_ascii_string_ &=
630
29.0M
                check_ascii_range(*cursor_, ' ', '~');
631
632
29.0M
            attribute_ += *cursor_++;
633
29.0M
          }
634
29.4M
        }
635
1.41M
        if (unicode_high_surrogate != -1) {
636
850
          return Error("illegal Unicode sequence (unpaired high surrogate)");
637
850
        }
638
1.41M
        cursor_++;
639
1.41M
        if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
640
53.3k
            !ValidateUTF8(attribute_)) {
641
21.6k
          return Error("illegal UTF-8 sequence");
642
21.6k
        }
643
1.39M
        token_ = kTokenStringConstant;
644
1.39M
        return NoError();
645
1.41M
      }
646
62.4k
      case '/':
647
62.4k
        if (*cursor_ == '/') {
648
57.3k
          const char* start = ++cursor_;
649
562k
          while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
650
57.3k
          if (*start == '/') {  // documentation comment
651
38.3k
            if (!seen_newline)
652
4
              return Error(
653
4
                  "a documentation comment should be on a line on its own");
654
38.3k
            doc_comment_.push_back(std::string(start + 1, cursor_));
655
38.3k
          }
656
57.3k
          break;
657
57.3k
        } else if (*cursor_ == '*') {
658
785
          cursor_++;
659
          // TODO: make nested.
660
39.1k
          while (*cursor_ != '*' || cursor_[1] != '/') {
661
38.4k
            if (*cursor_ == '\n') MarkNewLine();
662
38.4k
            if (!*cursor_) return Error("end of file in comment");
663
38.3k
            cursor_++;
664
38.3k
          }
665
698
          cursor_ += 2;
666
698
          break;
667
785
        }
668
4.33k
        FLATBUFFERS_FALLTHROUGH();  // else fall thru
669
6.26M
      default:
670
6.26M
        if (IsIdentifierStart(c)) {
671
          // Collect all chars of an identifier:
672
2.85M
          const char* start = cursor_ - 1;
673
18.0M
          while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
674
2.85M
          attribute_.append(start, cursor_);
675
2.85M
          token_ = kTokenIdentifier;
676
2.85M
          return NoError();
677
2.85M
        }
678
679
3.40M
        const auto has_sign = (c == '+') || (c == '-');
680
3.40M
        if (has_sign) {
681
          // Check for +/-inf which is considered a float constant.
682
142k
          if (strncmp(cursor_, "inf", 3) == 0 &&
683
17.6k
              !(IsIdentifierStart(cursor_[3]) || is_digit(cursor_[3]))) {
684
5.81k
            attribute_.assign(cursor_ - 1, cursor_ + 3);
685
5.81k
            token_ = kTokenFloatConstant;
686
5.81k
            cursor_ += 3;
687
5.81k
            return NoError();
688
5.81k
          }
689
690
136k
          if (IsIdentifierStart(*cursor_)) {
691
            // '-'/'+' and following identifier - it could be a predefined
692
            // constant. Return the sign in token_, see ParseSingleValue.
693
36.1k
            return NoError();
694
36.1k
          }
695
136k
        }
696
697
3.36M
        auto dot_lvl =
698
3.36M
            (c == '.') ? 0 : 1;  // dot_lvl==0 <=> exactly one '.' seen
699
3.36M
        if (!dot_lvl && !is_digit(*cursor_)) return NoError();  // enum?
700
        // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
701
3.32M
        if (is_digit(c) || has_sign || !dot_lvl) {
702
3.26M
          const auto start = cursor_ - 1;
703
3.26M
          auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
704
3.26M
          if (!is_digit(c) && is_digit(*cursor_)) {
705
680k
            start_digits = cursor_;  // see digit in cursor_ position
706
680k
            c = *cursor_++;
707
680k
          }
708
          // hex-float can't begind with '.'
709
3.26M
          auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
710
3.26M
          if (use_hex) start_digits = ++cursor_;  // '0x' is the prefix, skip it
711
          // Read an integer number or mantisa of float-point number.
712
3.86M
          do {
713
3.86M
            if (use_hex) {
714
2.71M
              while (is_xdigit(*cursor_)) cursor_++;
715
3.78M
            } else {
716
21.6M
              while (is_digit(*cursor_)) cursor_++;
717
3.78M
            }
718
3.86M
          } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
719
          // Exponent of float-point number.
720
3.26M
          if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
721
            // The exponent suffix of hexadecimal float number is mandatory.
722
3.25M
            if (use_hex && !dot_lvl) start_digits = cursor_;
723
3.25M
            if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
724
3.25M
                is_alpha_char(*cursor_, 'E')) {
725
47.9k
              dot_lvl = 0;  // Emulate dot to signal about float-point number.
726
47.9k
              cursor_++;
727
47.9k
              if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
728
47.9k
              start_digits = cursor_;  // the exponent-part has to have digits
729
              // Exponent is decimal integer number
730
202k
              while (is_digit(*cursor_)) cursor_++;
731
47.9k
              if (*cursor_ == '.') {
732
596
                cursor_++;  // If see a dot treat it as part of invalid number.
733
596
                dot_lvl = -1;  // Fall thru to Error().
734
596
              }
735
47.9k
            }
736
3.25M
          }
737
          // Finalize.
738
3.26M
          if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
739
3.24M
            attribute_.append(start, cursor_);
740
3.24M
            token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
741
3.24M
            return NoError();
742
3.24M
          } else {
743
20.3k
            return Error("invalid number: " + std::string(start, cursor_));
744
20.3k
          }
745
3.26M
        }
746
55.1k
        std::string ch;
747
55.1k
        ch = c;
748
55.1k
        if (false == check_ascii_range(c, ' ', '~'))
749
23.8k
          ch = "code: " + NumToString(c);
750
55.1k
        return Error("illegal character: " + ch);
751
30.9M
    }
752
30.9M
  }
753
20.5M
}
754
755
// Check if a given token is next.
756
18.4M
bool Parser::Is(int t) const { return t == token_; }
757
758
7.26M
bool Parser::IsIdent(const char* id) const {
759
7.26M
  return token_ == kTokenIdentifier && attribute_ == id;
760
7.26M
}
761
762
// Expect a given token to be next, consume it, or error if not present.
763
13.0M
CheckedError Parser::Expect(int t) {
764
13.0M
  if (t != token_) {
765
48.5k
    return Error("expecting: " + TokenToString(t) +
766
48.5k
                 " instead got: " + TokenToStringId(token_));
767
48.5k
  }
768
13.0M
  NEXT();
769
12.9M
  return NoError();
770
13.0M
}
771
772
488k
CheckedError Parser::ParseNamespacing(std::string* id, std::string* last) {
773
498k
  while (Is('.')) {
774
10.1k
    NEXT();
775
10.1k
    *id += ".";
776
10.1k
    *id += attribute_;
777
10.1k
    if (last) *last = attribute_;
778
10.1k
    EXPECT(kTokenIdentifier);
779
10.1k
  }
780
488k
  return NoError();
781
488k
}
782
783
79.2k
EnumDef* Parser::LookupEnum(const std::string& id) {
784
  // Search thru parent namespaces.
785
79.2k
  return LookupTableByName(enums_, id, *current_namespace_, 0);
786
79.2k
}
787
788
1.28M
StructDef* Parser::LookupStruct(const std::string& id) const {
789
1.28M
  auto sd = structs_.Lookup(id);
790
1.28M
  if (sd) sd->refcount++;
791
1.28M
  return sd;
792
1.28M
}
793
794
StructDef* Parser::LookupStructThruParentNamespaces(
795
323k
    const std::string& id) const {
796
323k
  auto sd = LookupTableByName(structs_, id, *current_namespace_, 1);
797
323k
  if (sd) sd->refcount++;
798
323k
  return sd;
799
323k
}
800
801
71.5k
CheckedError Parser::ParseTypeIdent(Type& type) {
802
71.5k
  std::string id = attribute_;
803
71.5k
  EXPECT(kTokenIdentifier);
804
71.5k
  ECHECK(ParseNamespacing(&id, nullptr));
805
71.4k
  auto enum_def = LookupEnum(id);
806
71.4k
  if (enum_def) {
807
35.0k
    type = enum_def->underlying_type;
808
35.0k
    if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
809
36.4k
  } else {
810
36.4k
    type.base_type = BASE_TYPE_STRUCT;
811
36.4k
    type.struct_def = LookupCreateStruct(id);
812
36.4k
  }
813
71.4k
  return NoError();
814
71.5k
}
815
816
// Parse any IDL type.
817
197k
CheckedError Parser::ParseType(Type& type) {
818
197k
  if (token_ == kTokenIdentifier) {
819
185k
    if (IsIdent("bool")) {
820
6.10k
      type.base_type = BASE_TYPE_BOOL;
821
6.10k
      NEXT();
822
179k
    } else if (IsIdent("byte") || IsIdent("int8")) {
823
7.76k
      type.base_type = BASE_TYPE_CHAR;
824
7.76k
      NEXT();
825
171k
    } else if (IsIdent("ubyte") || IsIdent("uint8")) {
826
8.52k
      type.base_type = BASE_TYPE_UCHAR;
827
8.52k
      NEXT();
828
163k
    } else if (IsIdent("short") || IsIdent("int16")) {
829
7.65k
      type.base_type = BASE_TYPE_SHORT;
830
7.65k
      NEXT();
831
155k
    } else if (IsIdent("ushort") || IsIdent("uint16")) {
832
8.11k
      type.base_type = BASE_TYPE_USHORT;
833
8.11k
      NEXT();
834
147k
    } else if (IsIdent("int") || IsIdent("int32")) {
835
14.4k
      type.base_type = BASE_TYPE_INT;
836
14.4k
      NEXT();
837
132k
    } else if (IsIdent("uint") || IsIdent("uint32")) {
838
12.5k
      type.base_type = BASE_TYPE_UINT;
839
12.5k
      NEXT();
840
120k
    } else if (IsIdent("long") || IsIdent("int64")) {
841
13.6k
      type.base_type = BASE_TYPE_LONG;
842
13.6k
      NEXT();
843
106k
    } else if (IsIdent("ulong") || IsIdent("uint64")) {
844
23.1k
      type.base_type = BASE_TYPE_ULONG;
845
23.1k
      NEXT();
846
83.4k
    } else if (IsIdent("float") || IsIdent("float32")) {
847
15.5k
      type.base_type = BASE_TYPE_FLOAT;
848
15.5k
      NEXT();
849
67.9k
    } else if (IsIdent("double") || IsIdent("float64")) {
850
11.3k
      type.base_type = BASE_TYPE_DOUBLE;
851
11.3k
      NEXT();
852
56.5k
    } else if (IsIdent("string")) {
853
462
      type.base_type = BASE_TYPE_STRING;
854
462
      NEXT();
855
56.0k
    } else {
856
56.0k
      ECHECK(ParseTypeIdent(type));
857
56.0k
    }
858
185k
  } else if (token_ == '[') {
859
11.6k
    ParseDepthGuard depth_guard(this);
860
11.6k
    ECHECK(depth_guard.Check());
861
11.6k
    NEXT();
862
11.6k
    Type subtype;
863
11.6k
    ECHECK(ParseType(subtype));
864
11.4k
    if (IsSeries(subtype)) {
865
      // We could support this, but it will complicate things, and it's
866
      // easier to work around with a struct around the inner vector.
867
2
      return Error("nested vector types not supported (wrap in table first)");
868
2
    }
869
11.4k
    if (token_ == ':') {
870
1.10k
      NEXT();
871
1.10k
      if (token_ != kTokenIntegerConstant) {
872
9
        return Error("length of fixed-length array must be an integer value");
873
9
      }
874
1.09k
      uint16_t fixed_length = 0;
875
1.09k
      bool check = StringToNumber(attribute_.c_str(), &fixed_length);
876
1.09k
      if (!check || fixed_length < 1) {
877
92
        return Error(
878
92
            "length of fixed-length array must be positive and fit to "
879
92
            "uint16_t type");
880
92
      }
881
1.00k
      type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
882
1.00k
                  fixed_length);
883
1.00k
      NEXT();
884
10.3k
    } else {
885
10.3k
      type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
886
10.3k
    }
887
11.3k
    type.element = subtype.base_type;
888
11.3k
    EXPECT(']');
889
11.2k
  } else {
890
42
    return Error("illegal type syntax");
891
42
  }
892
196k
  return NoError();
893
197k
}
894
895
CheckedError Parser::AddField(StructDef& struct_def, const std::string& name,
896
182k
                              const Type& type, FieldDef** dest) {
897
182k
  auto& field = *new FieldDef();
898
182k
  field.value.offset =
899
182k
      FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
900
182k
  field.name = name;
901
182k
  field.file = struct_def.file;
902
182k
  field.value.type = type;
903
182k
  if (struct_def.fixed) {  // statically compute the field offset
904
2.74k
    auto size = InlineSize(type);
905
2.74k
    auto alignment = InlineAlignment(type);
906
    // structs_ need to have a predictable format, so we need to align to
907
    // the largest scalar
908
2.74k
    struct_def.minalign = std::max(struct_def.minalign, alignment);
909
2.74k
    struct_def.PadLastField(alignment);
910
2.74k
    field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
911
2.74k
    struct_def.bytesize += size;
912
2.74k
  }
913
182k
  if (struct_def.fields.Add(name, &field))
914
58
    return Error("field already exists: " + name);
915
182k
  *dest = &field;
916
182k
  return NoError();
917
182k
}
918
919
162k
CheckedError Parser::ParseField(StructDef& struct_def) {
920
162k
  std::string name = attribute_;
921
922
162k
  if (LookupCreateStruct(name, false, false))
923
22
    return Error("field name can not be the same as table/struct name");
924
925
162k
  if (!IsLowerSnakeCase(name)) {
926
126k
    Warning("field names should be lowercase snake_case, got: " + name);
927
126k
  }
928
929
162k
  std::vector<std::string> dc = doc_comment_;
930
162k
  EXPECT(kTokenIdentifier);
931
162k
  EXPECT(':');
932
161k
  Type type;
933
161k
  ECHECK(ParseType(type));
934
935
161k
  if (struct_def.fixed) {
936
2.75k
    if (IsIncompleteStruct(type) ||
937
2.75k
        (IsArray(type) && IsIncompleteStruct(type.VectorType()))) {
938
4
      std::string type_name = IsArray(type) ? type.VectorType().struct_def->name
939
4
                                            : type.struct_def->name;
940
4
      return Error(
941
4
          std::string("Incomplete type in struct is not allowed, type name: ") +
942
4
          type_name);
943
4
    }
944
945
2.75k
    auto valid = IsScalar(type.base_type) || IsStruct(type);
946
2.75k
    if (!valid && IsArray(type)) {
947
956
      const auto& elem_type = type.VectorType();
948
956
      valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type);
949
956
    }
950
2.75k
    if (!valid)
951
4
      return Error("structs may contain only scalar or struct fields");
952
2.75k
  }
953
954
161k
  if (!struct_def.fixed && IsArray(type))
955
1
    return Error("fixed-length array in table must be wrapped in struct");
956
957
161k
  if (IsArray(type)) {
958
955
    advanced_features_ |= reflection::AdvancedArrayFeatures;
959
955
    if (!SupportsAdvancedArrayFeatures()) {
960
0
      return Error(
961
0
          "Arrays are not yet supported in all "
962
0
          "the specified programming languages.");
963
0
    }
964
955
  }
965
966
161k
  FieldDef* typefield = nullptr;
967
161k
  if (type.base_type == BASE_TYPE_UNION) {
968
    // For union fields, add a second auto-generated field to hold the type,
969
    // with a special suffix.
970
971
    // To ensure compatibility with many codes that rely on the BASE_TYPE_UTYPE
972
    // value to identify union type fields.
973
18.5k
    Type union_type(type.enum_def->underlying_type);
974
18.5k
    union_type.base_type = BASE_TYPE_UTYPE;
975
18.5k
    ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_type,
976
18.5k
                    &typefield));
977
978
143k
  } else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
979
1.79k
    advanced_features_ |= reflection::AdvancedUnionFeatures;
980
    // Only cpp, js and ts supports the union vector feature so far.
981
1.79k
    if (!SupportsAdvancedUnionFeatures()) {
982
0
      return Error(
983
0
          "Vectors of unions are not yet supported in at least one of "
984
0
          "the specified programming languages.");
985
0
    }
986
    // For vector of union fields, add a second auto-generated vector field to
987
    // hold the types, with a special suffix.
988
1.79k
    Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
989
1.79k
    union_vector.element = BASE_TYPE_UTYPE;
990
1.79k
    ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
991
1.79k
                    &typefield));
992
1.79k
  }
993
994
161k
  FieldDef* field;
995
161k
  ECHECK(AddField(struct_def, name, type, &field));
996
997
161k
  if (typefield) {
998
    // We preserve the relation between the typefield
999
    // and field, so we can easily map it in the code
1000
    // generators.
1001
20.3k
    typefield->sibling_union_field = field;
1002
20.3k
    field->sibling_union_field = typefield;
1003
20.3k
  }
1004
1005
161k
  if (token_ == '=') {
1006
109k
    NEXT();
1007
109k
    ECHECK(ParseSingleValue(&field->name, field->value, true));
1008
108k
    if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
1009
10
      return Error(
1010
10
          "default values are not supported for struct fields, table fields, "
1011
10
          "or in structs.");
1012
108k
    if (IsString(type) || IsVector(type)) {
1013
107
      advanced_features_ |= reflection::DefaultVectorsAndStrings;
1014
107
      if (field->value.constant != "0" && !SupportsDefaultVectorsAndStrings()) {
1015
0
        return Error(
1016
0
            "Default values for strings and vectors are not supported in one "
1017
0
            "of the specified programming languages");
1018
0
      }
1019
107
    }
1020
1021
108k
    if (IsVector(type) && field->value.constant != "0" &&
1022
36
        field->value.constant != "[]") {
1023
0
      return Error("The only supported default for vectors is `[]`.");
1024
0
    }
1025
108k
  }
1026
1027
  // Append .0 if the value has not it (skip hex and scientific floats).
1028
  // This suffix needed for generated C++ code.
1029
160k
  if (IsFloat(type.base_type)) {
1030
26.4k
    auto& text = field->value.constant;
1031
26.4k
    FLATBUFFERS_ASSERT(false == text.empty());
1032
26.4k
    auto s = text.c_str();
1033
28.2k
    while (*s == ' ') s++;
1034
26.4k
    if (*s == '-' || *s == '+') s++;
1035
    // 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
1036
    // 2) A float number needn't ".0" at the end if it has exponent.
1037
26.4k
    if ((false == IsIdentifierStart(*s)) &&
1038
22.9k
        (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
1039
15.8k
      field->value.constant += ".0";
1040
15.8k
    }
1041
26.4k
  }
1042
1043
160k
  field->doc_comment = dc;
1044
160k
  ECHECK(ParseMetaData(&field->attributes));
1045
160k
  field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
1046
160k
  auto hash_name = field->attributes.Lookup("hash");
1047
160k
  if (hash_name) {
1048
374
    switch ((IsVector(type)) ? type.element : type.base_type) {
1049
55
      case BASE_TYPE_SHORT:
1050
57
      case BASE_TYPE_USHORT: {
1051
57
        if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
1052
40
          return Error("Unknown hashing algorithm for 16 bit types: " +
1053
40
                       hash_name->constant);
1054
17
        break;
1055
57
      }
1056
109
      case BASE_TYPE_INT:
1057
152
      case BASE_TYPE_UINT: {
1058
152
        if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
1059
60
          return Error("Unknown hashing algorithm for 32 bit types: " +
1060
60
                       hash_name->constant);
1061
92
        break;
1062
152
      }
1063
124
      case BASE_TYPE_LONG:
1064
159
      case BASE_TYPE_ULONG: {
1065
159
        if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
1066
46
          return Error("Unknown hashing algorithm for 64 bit types: " +
1067
46
                       hash_name->constant);
1068
113
        break;
1069
159
      }
1070
113
      default:
1071
6
        return Error(
1072
6
            "only short, ushort, int, uint, long and ulong data types support "
1073
6
            "hashing.");
1074
374
    }
1075
374
  }
1076
1077
160k
  if (field->attributes.Lookup("vector64") != nullptr) {
1078
102
    if (!IsVector(type)) {
1079
4
      return Error("`vector64` attribute can only be applied on vectors.");
1080
4
    }
1081
1082
    // Upgrade the type to be a BASE_TYPE_VECTOR64, since the attributes are
1083
    // parsed after the type.
1084
98
    const BaseType element_base_type = type.element;
1085
98
    type = Type(BASE_TYPE_VECTOR64, type.struct_def, type.enum_def);
1086
98
    type.element = element_base_type;
1087
1088
    // Since the field was already added to the parent object, update the type
1089
    // in place.
1090
98
    field->value.type = type;
1091
1092
    // 64-bit vectors imply the offset64 attribute.
1093
98
    field->offset64 = true;
1094
98
  }
1095
1096
  // Record that this field uses 64-bit offsets.
1097
160k
  if (field->attributes.Lookup("offset64") != nullptr) {
1098
    // TODO(derekbailey): would be nice to have this be a recommendation or hint
1099
    // instead of a warning.
1100
214
    if (type.base_type == BASE_TYPE_VECTOR64) {
1101
1
      Warning("attribute `vector64` implies `offset64` and isn't required.");
1102
1
    }
1103
1104
214
    field->offset64 = true;
1105
214
  }
1106
1107
  // Check for common conditions with Offset64 fields.
1108
160k
  if (field->offset64) {
1109
    // TODO(derekbailey): this is where we can disable string support for
1110
    // offset64, as that is not a hard requirement to have.
1111
311
    if (!IsString(type) && !IsVector(type)) {
1112
6
      return Error(
1113
6
          "only string and vectors can have `offset64` attribute applied");
1114
6
    }
1115
1116
    // If this is a Vector, only scalar and scalar-like (structs) items are
1117
    // allowed.
1118
    // TODO(derekbailey): allow vector of strings, just require that the strings
1119
    // are Offset64<string>.
1120
305
    if (IsVector(type) &&
1121
281
        !((IsScalar(type.element) && !IsEnum(type.VectorType())) ||
1122
16
          IsStruct(type.VectorType()))) {
1123
11
      return Error("only vectors of scalars are allowed to be 64-bit.");
1124
11
    }
1125
1126
    // Lastly, check if it is supported by the specified generated languages. Do
1127
    // this last so the above checks can inform the user of schema errors to fix
1128
    // first.
1129
294
    if (!Supports64BitOffsets()) {
1130
0
      return Error(
1131
0
          "fields using 64-bit offsets are not yet supported in at least one "
1132
0
          "of the specified programming languages.");
1133
0
    }
1134
294
  }
1135
1136
160k
  field->key = field->attributes.Lookup("key") != nullptr;
1137
1138
160k
  if (!struct_def.fixed) {
1139
    // For historical convenience reasons, string keys are assumed required.
1140
    // Scalars are kDefault unless otherwise specified.
1141
    // Nonscalars are kOptional unless required;
1142
157k
    const bool required = field->attributes.Lookup("required") != nullptr ||
1143
157k
                          (IsString(type) && field->key);
1144
157k
    const bool default_str_or_vec =
1145
157k
        ((IsString(type) || IsVector(type)) && field->value.constant != "0");
1146
157k
    const bool optional = IsScalar(type.base_type)
1147
157k
                              ? (field->value.constant == "null")
1148
157k
                              : !(required || default_str_or_vec);
1149
157k
    if (required && optional) {
1150
0
      return Error("Fields cannot be both optional and required.");
1151
0
    }
1152
157k
    field->presence = FieldDef::MakeFieldPresence(optional, required);
1153
1154
157k
    if (required && IsScalar(type.base_type)) {
1155
1
      return Error("only non-scalar fields in tables may be 'required'");
1156
1
    }
1157
157k
  } else {
1158
    // all struct fields are required
1159
2.68k
    field->presence = FieldDef::kDefault;
1160
1161
    // setting required or optional on a struct field is meaningless
1162
2.68k
    if (field->attributes.Lookup("required") != nullptr ||
1163
2.68k
        field->attributes.Lookup("optional") != nullptr) {
1164
1
      return Error("struct fields are always required");
1165
1
    }
1166
2.68k
  }
1167
1168
160k
  if (field->key) {
1169
1.12k
    if (struct_def.has_key) return Error("only one field may be set as 'key'");
1170
1.11k
    struct_def.has_key = true;
1171
1.11k
    auto is_valid =
1172
1.11k
        IsScalar(type.base_type) || IsString(type) || IsStruct(type);
1173
1.11k
    if (IsArray(type)) {
1174
2
      is_valid |=
1175
2
          IsScalar(type.VectorType().base_type) || IsStruct(type.VectorType());
1176
2
    }
1177
1.11k
    if (!is_valid) {
1178
5
      return Error(
1179
5
          "'key' field must be string, scalar type or fixed size array of "
1180
5
          "scalars");
1181
5
    }
1182
1.11k
  }
1183
1184
160k
  if (field->IsScalarOptional()) {
1185
830
    advanced_features_ |= reflection::OptionalScalars;
1186
830
    if (type.enum_def && type.enum_def->Lookup("null")) {
1187
1
      FLATBUFFERS_ASSERT(IsInteger(type.base_type));
1188
1
      return Error(
1189
1
          "the default 'null' is reserved for declaring optional scalar "
1190
1
          "fields, it conflicts with declaration of enum '" +
1191
1
          type.enum_def->name + "'.");
1192
1
    }
1193
829
    if (field->attributes.Lookup("key")) {
1194
1
      return Error(
1195
1
          "only a non-optional scalar field can be used as a 'key' field");
1196
1
    }
1197
828
    if (!SupportsOptionalScalars()) {
1198
0
      return Error(
1199
0
          "Optional scalars are not yet supported in at least one of "
1200
0
          "the specified programming languages.");
1201
0
    }
1202
828
  }
1203
1204
160k
  auto check_enum = [this](const FieldDef* field, const Type& type,
1205
160k
                           const std::string& name,
1206
160k
                           const std::string& constant) -> CheckedError {
1207
    // Optional and bitflags enums may have default constants that are not
1208
    // their specified variants.
1209
1.48k
    if (!field->IsOptional() &&
1210
1.28k
        type.enum_def->attributes.Lookup("bit_flags") == nullptr) {
1211
1.21k
      if (type.enum_def->FindByValue(constant) == nullptr) {
1212
95
        return Error("default value of `" + constant + "` for " + "field `" +
1213
95
                     name + "` is not part of enum `" + type.enum_def->name +
1214
95
                     "`.");
1215
95
      }
1216
1.21k
    }
1217
1218
1.38k
    return NoError();
1219
1.48k
  };
1220
1221
160k
  if (type.enum_def) {
1222
    // Verify the enum's type and default value.
1223
21.8k
    const std::string& constant = field->value.constant;
1224
21.8k
    if (type.base_type == BASE_TYPE_UNION) {
1225
18.5k
      if (constant != "0") {
1226
0
        return Error("Union defaults must be NONE");
1227
0
      }
1228
18.5k
    } else if (IsVector(type)) {
1229
1.80k
      if (constant != "0" && constant != "[]") {
1230
0
        return Error("Vector defaults may only be `[]`.");
1231
0
      }
1232
1.80k
    } else if (IsArray(type)) {
1233
11
      if (constant != "0") {
1234
0
        return Error("Array defaults are not supported yet.");
1235
0
      }
1236
11
      CheckedError err = check_enum(field, type.VectorType(), name, constant);
1237
11
      if (err.Check()) {
1238
        // reset the check state of the error
1239
1
        return CheckedError{err};
1240
1
      }
1241
1.46k
    } else {
1242
1.46k
      if (!IsInteger(type.base_type)) {
1243
0
        return Error("Enums must have integer base types");
1244
0
      }
1245
1.46k
      CheckedError err = check_enum(field, type, name, constant);
1246
1.46k
      if (err.Check()) {
1247
        // reset the check state of the error
1248
94
        return CheckedError{err};
1249
94
      }
1250
1.46k
    }
1251
21.8k
  }
1252
1253
160k
  if (field->deprecated && struct_def.fixed)
1254
1
    return Error("can't deprecate fields in a struct");
1255
1256
160k
  auto cpp_type = field->attributes.Lookup("cpp_type");
1257
160k
  if (cpp_type) {
1258
2
    if (!hash_name)
1259
1
      return Error("cpp_type can only be used with a hashed field");
1260
    /// forcing cpp_ptr_type to 'naked' if unset
1261
1
    auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
1262
1
    if (!cpp_ptr_type) {
1263
1
      auto val = new Value();
1264
1
      val->type = cpp_type->type;
1265
1
      val->constant = "naked";
1266
1
      field->attributes.Add("cpp_ptr_type", val);
1267
1
    }
1268
1
  }
1269
1270
160k
  field->shared = field->attributes.Lookup("shared") != nullptr;
1271
160k
  if (field->shared && field->value.type.base_type != BASE_TYPE_STRING)
1272
2
    return Error("shared can only be defined on strings");
1273
1274
160k
  auto field_native_custom_alloc =
1275
160k
      field->attributes.Lookup("native_custom_alloc");
1276
160k
  if (field_native_custom_alloc)
1277
1
    return Error(
1278
1
        "native_custom_alloc can only be used with a table or struct "
1279
1
        "definition");
1280
1281
160k
  field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
1282
160k
  if (field->native_inline && !IsStruct(field->value.type) &&
1283
26
      !IsVectorOfStruct(field->value.type) &&
1284
23
      !IsVectorOfTable(field->value.type))
1285
5
    return Error(
1286
5
        "'native_inline' can only be defined on structs, vector of structs or "
1287
5
        "vector of tables");
1288
1289
160k
  auto nested = field->attributes.Lookup("nested_flatbuffer");
1290
160k
  if (nested) {
1291
4
    if (nested->type.base_type != BASE_TYPE_STRING)
1292
1
      return Error(
1293
1
          "nested_flatbuffer attribute must be a string (the root type)");
1294
3
    if (!IsVector(type.base_type) || type.element != BASE_TYPE_UCHAR)
1295
2
      return Error(
1296
2
          "nested_flatbuffer attribute may only apply to a vector of ubyte");
1297
    // This will cause an error if the root type of the nested flatbuffer
1298
    // wasn't defined elsewhere.
1299
1
    field->nested_flatbuffer = LookupCreateStruct(nested->constant);
1300
1
  }
1301
1302
160k
  if (field->attributes.Lookup("flexbuffer")) {
1303
3.86k
    field->flexbuffer = true;
1304
3.86k
    uses_flexbuffers_ = true;
1305
3.86k
    if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
1306
6
      return Error("flexbuffer attribute may only apply to a vector of ubyte");
1307
3.86k
  }
1308
1309
160k
  if (typefield) {
1310
20.3k
    if (!IsScalar(typefield->value.type.base_type)) {
1311
      // this is a union vector field
1312
1.79k
      typefield->presence = field->presence;
1313
1.79k
    }
1314
    // If this field is a union, and it has a manually assigned id,
1315
    // the automatically added type field should have an id as well (of N - 1).
1316
20.3k
    auto attr = field->attributes.Lookup("id");
1317
20.3k
    if (attr) {
1318
3.28k
      const auto& id_str = attr->constant;
1319
3.28k
      voffset_t id = 0;
1320
3.28k
      const auto done = !atot(id_str.c_str(), *this, &id).Check();
1321
3.28k
      if (done && id > 0) {
1322
3.27k
        auto val = new Value();
1323
3.27k
        val->type = attr->type;
1324
3.27k
        val->constant = NumToString(id - 1);
1325
3.27k
        typefield->attributes.Add("id", val);
1326
3.27k
      } else {
1327
6
        return Error(
1328
6
            "a union type effectively adds two fields with non-negative ids, "
1329
6
            "its id must be that of the second field (the first field is "
1330
6
            "the type field and not explicitly declared in the schema);\n"
1331
6
            "field: " +
1332
6
            field->name + ", id: " + id_str);
1333
6
      }
1334
3.28k
    }
1335
    // if this field is a union that is deprecated,
1336
    // the automatically added type field should be deprecated as well
1337
20.3k
    if (field->deprecated) {
1338
7
      typefield->deprecated = true;
1339
7
    }
1340
20.3k
  }
1341
1342
160k
  EXPECT(';');
1343
159k
  return NoError();
1344
160k
}
1345
1346
123k
CheckedError Parser::ParseString(Value& val, bool use_string_pooling) {
1347
123k
  auto s = attribute_;
1348
123k
  EXPECT(kTokenStringConstant);
1349
123k
  if (use_string_pooling) {
1350
1.92k
    val.constant = NumToString(builder_.CreateSharedString(s).o);
1351
121k
  } else {
1352
121k
    val.constant = NumToString(builder_.CreateString(s).o);
1353
121k
  }
1354
123k
  return NoError();
1355
123k
}
1356
1357
3.46M
CheckedError Parser::ParseComma() {
1358
3.46M
  if (!opts.protobuf_ascii_alike) EXPECT(',');
1359
3.42M
  return NoError();
1360
3.46M
}
1361
1362
CheckedError Parser::ParseAnyValue(Value& val, FieldDef* field,
1363
                                   size_t parent_fieldn,
1364
                                   const StructDef* parent_struct_def,
1365
1.77M
                                   size_t count, bool inside_vector) {
1366
1.77M
  switch (val.type.base_type) {
1367
3.88k
    case BASE_TYPE_UNION: {
1368
3.88k
      FLATBUFFERS_ASSERT(field);
1369
3.88k
      std::string constant;
1370
3.88k
      Vector<uint8_t>* vector_of_union_types = nullptr;
1371
      // Find corresponding type field we may have already parsed.
1372
3.88k
      for (auto elem = field_stack_.rbegin() + count;
1373
4.25k
           elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) {
1374
2.42k
        auto& type = elem->second->value.type;
1375
2.42k
        if (type.enum_def == val.type.enum_def) {
1376
2.21k
          if (inside_vector) {
1377
204
            if (IsVector(type) && type.element == BASE_TYPE_UTYPE) {
1378
              // Vector of union type field.
1379
141
              uoffset_t offset;
1380
141
              ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
1381
141
              vector_of_union_types = reinterpret_cast<Vector<uint8_t>*>(
1382
141
                  builder_.GetCurrentBufferPointer() + builder_.GetSize() -
1383
141
                  offset);
1384
141
              break;
1385
141
            }
1386
2.01k
          } else {
1387
2.01k
            if (type.base_type == BASE_TYPE_UTYPE) {
1388
              // Union type field.
1389
1.91k
              constant = elem->first.constant;
1390
1.91k
              break;
1391
1.91k
            }
1392
2.01k
          }
1393
2.21k
        }
1394
2.42k
      }
1395
3.88k
      if (constant.empty() && !inside_vector) {
1396
        // We haven't seen the type field yet. Sadly a lot of JSON writers
1397
        // output these in alphabetical order, meaning it comes after this
1398
        // value. So we scan past the value to find it, then come back here.
1399
        // We currently don't do this for vectors of unions because the
1400
        // scanning/serialization logic would get very complicated.
1401
1.83k
        auto type_name = field->name + UnionTypeFieldSuffix();
1402
1.83k
        FLATBUFFERS_ASSERT(parent_struct_def);
1403
1.83k
        auto type_field = parent_struct_def->fields.Lookup(type_name);
1404
1.83k
        FLATBUFFERS_ASSERT(type_field);  // Guaranteed by ParseField().
1405
        // Remember where we are in the source file, so we can come back here.
1406
1.83k
        auto backup = *static_cast<ParserState*>(this);
1407
1.83k
        ECHECK(SkipAnyJsonValue());  // The table.
1408
1.79k
        ECHECK(ParseComma());
1409
1.78k
        auto next_name = attribute_;
1410
1.78k
        if (Is(kTokenStringConstant)) {
1411
43
          NEXT();
1412
1.74k
        } else {
1413
1.74k
          EXPECT(kTokenIdentifier);
1414
1.73k
        }
1415
1.77k
        if (next_name == type_name) {
1416
1.73k
          EXPECT(':');
1417
1.73k
          ParseDepthGuard depth_guard(this);
1418
1.73k
          ECHECK(depth_guard.Check());
1419
1.73k
          Value type_val = type_field->value;
1420
1.73k
          ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0));
1421
1.72k
          constant = type_val.constant;
1422
          // Got the information we needed, now rewind:
1423
1.72k
          *static_cast<ParserState*>(this) = backup;
1424
1.72k
        }
1425
1.77k
      }
1426
3.81k
      if (constant.empty() && !vector_of_union_types) {
1427
40
        return Error("missing type field for this union value: " + field->name);
1428
40
      }
1429
3.77k
      uint8_t enum_idx;
1430
3.77k
      if (vector_of_union_types) {
1431
141
        if (vector_of_union_types->size() <= count)
1432
4
          return Error(
1433
4
              "union types vector smaller than union values vector for: " +
1434
4
              field->name);
1435
137
        enum_idx = vector_of_union_types->Get(static_cast<uoffset_t>(count));
1436
3.63k
      } else {
1437
3.63k
        ECHECK(atot(constant.c_str(), *this, &enum_idx));
1438
3.60k
      }
1439
3.74k
      auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true);
1440
3.74k
      if (!enum_val) return Error("illegal type id for: " + field->name);
1441
3.69k
      if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
1442
3.69k
        ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
1443
3.69k
                          nullptr));
1444
3.34k
        if (enum_val->union_type.struct_def->fixed) {
1445
          // All BASE_TYPE_UNION values are offsets, so turn this into one.
1446
0
          SerializeStruct(*enum_val->union_type.struct_def, val);
1447
0
          builder_.ClearOffsets();
1448
0
          val.constant = NumToString(builder_.GetSize());
1449
0
        }
1450
3.34k
      } else if (IsString(enum_val->union_type)) {
1451
0
        ECHECK(ParseString(val, field->shared));
1452
0
      } else {
1453
0
        FLATBUFFERS_ASSERT(false);
1454
0
      }
1455
3.34k
      break;
1456
3.69k
    }
1457
427k
    case BASE_TYPE_STRUCT:
1458
427k
      ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
1459
421k
      break;
1460
123k
    case BASE_TYPE_STRING: {
1461
123k
      ECHECK(ParseString(val, field->shared));
1462
123k
      break;
1463
123k
    }
1464
7.24k
    case BASE_TYPE_VECTOR64:
1465
51.9k
    case BASE_TYPE_VECTOR: {
1466
51.9k
      uoffset_t off;
1467
51.9k
      ECHECK(ParseVector(val.type, &off, field, parent_fieldn));
1468
46.1k
      val.constant = NumToString(off);
1469
46.1k
      break;
1470
51.9k
    }
1471
5.71k
    case BASE_TYPE_ARRAY: {
1472
5.71k
      ECHECK(ParseArray(val));
1473
5.47k
      break;
1474
5.71k
    }
1475
79.8k
    case BASE_TYPE_INT:
1476
191k
    case BASE_TYPE_UINT:
1477
281k
    case BASE_TYPE_LONG:
1478
434k
    case BASE_TYPE_ULONG: {
1479
434k
      if (field && field->attributes.Lookup("hash") &&
1480
82.0k
          (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
1481
8.24k
        ECHECK(ParseHash(val, field));
1482
425k
      } else {
1483
425k
        ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
1484
398k
      }
1485
407k
      break;
1486
434k
    }
1487
725k
    default:
1488
725k
      ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
1489
641k
      break;
1490
1.77M
  }
1491
1.64M
  return NoError();
1492
1.77M
}
1493
1494
57.6k
void Parser::SerializeStruct(const StructDef& struct_def, const Value& val) {
1495
57.6k
  SerializeStruct(builder_, struct_def, val);
1496
57.6k
}
1497
1498
void Parser::SerializeStruct(FlatBufferBuilder& builder,
1499
57.6k
                             const StructDef& struct_def, const Value& val) {
1500
57.6k
  FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
1501
57.6k
  builder.Align(struct_def.minalign);
1502
57.6k
  builder.PushBytes(reinterpret_cast<const uint8_t*>(val.constant.c_str()),
1503
57.6k
                    struct_def.bytesize);
1504
57.6k
  builder.AddStructOffset(val.offset, builder.GetSize());
1505
57.6k
}
1506
1507
template <typename F>
1508
CheckedError Parser::ParseTableDelimiters(size_t& fieldn,
1509
1.44M
                                          const StructDef* struct_def, F body) {
1510
  // We allow tables both as JSON object{ .. } with field names
1511
  // or vector[..] with all fields in order
1512
1.44M
  char terminator = '}';
1513
1.44M
  bool is_nested_vector = struct_def && Is('[');
1514
1.44M
  if (is_nested_vector) {
1515
142k
    NEXT();
1516
142k
    terminator = ']';
1517
1.29M
  } else {
1518
1.29M
    EXPECT('{');
1519
1.29M
  }
1520
2.23M
  for (;;) {
1521
2.23M
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
1.91M
    std::string name;
1523
1.91M
    if (is_nested_vector) {
1524
221k
      if (fieldn >= struct_def->fields.vec.size()) {
1525
32
        return Error("too many unnamed fields in nested array");
1526
32
      }
1527
221k
      name = struct_def->fields.vec[fieldn]->name;
1528
1.69M
    } else {
1529
1.69M
      name = attribute_;
1530
1.69M
      if (Is(kTokenStringConstant)) {
1531
767k
        NEXT();
1532
927k
      } else {
1533
927k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
923k
      }
1535
1.68M
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
1.58M
    }
1537
1.80M
    ECHECK(body(name, fieldn, struct_def));
1538
1.66M
    if (Is(terminator)) break;
1539
823k
    ECHECK(ParseComma());
1540
791k
  }
1541
1.15M
  NEXT();
1542
1.15M
  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1543
41
    return Error("wrong number of unnamed fields in table vector");
1544
41
  }
1545
1.15M
  return NoError();
1546
1.15M
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseTableDelimiters<flatbuffers::Parser::ParseTable(flatbuffers::StructDef const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, unsigned int*)::$_0>(unsigned long&, flatbuffers::StructDef const*, flatbuffers::Parser::ParseTable(flatbuffers::StructDef const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, unsigned int*)::$_0)
Line
Count
Source
1509
1.25M
                                          const StructDef* struct_def, F body) {
1510
  // We allow tables both as JSON object{ .. } with field names
1511
  // or vector[..] with all fields in order
1512
1.25M
  char terminator = '}';
1513
1.25M
  bool is_nested_vector = struct_def && Is('[');
1514
1.25M
  if (is_nested_vector) {
1515
142k
    NEXT();
1516
142k
    terminator = ']';
1517
1.11M
  } else {
1518
1.11M
    EXPECT('{');
1519
1.11M
  }
1520
1.50M
  for (;;) {
1521
1.50M
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
1.25M
    std::string name;
1523
1.25M
    if (is_nested_vector) {
1524
221k
      if (fieldn >= struct_def->fields.vec.size()) {
1525
32
        return Error("too many unnamed fields in nested array");
1526
32
      }
1527
221k
      name = struct_def->fields.vec[fieldn]->name;
1528
1.02M
    } else {
1529
1.02M
      name = attribute_;
1530
1.02M
      if (Is(kTokenStringConstant)) {
1531
710k
        NEXT();
1532
709k
      } else {
1533
319k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
315k
      }
1535
1.02M
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
921k
    }
1537
1.14M
    ECHECK(body(name, fieldn, struct_def));
1538
1.00M
    if (Is(terminator)) break;
1539
281k
    ECHECK(ParseComma());
1540
248k
  }
1541
974k
  NEXT();
1542
974k
  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1543
41
    return Error("wrong number of unnamed fields in table vector");
1544
41
  }
1545
974k
  return NoError();
1546
974k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseTableDelimiters<flatbuffers::Parser::SkipAnyJsonValue()::$_0>(unsigned long&, flatbuffers::StructDef const*, flatbuffers::Parser::SkipAnyJsonValue()::$_0)
Line
Count
Source
1509
75.3k
                                          const StructDef* struct_def, F body) {
1510
  // We allow tables both as JSON object{ .. } with field names
1511
  // or vector[..] with all fields in order
1512
75.3k
  char terminator = '}';
1513
75.3k
  bool is_nested_vector = struct_def && Is('[');
1514
75.3k
  if (is_nested_vector) {
1515
0
    NEXT();
1516
0
    terminator = ']';
1517
75.3k
  } else {
1518
75.3k
    EXPECT('{');
1519
75.3k
  }
1520
190k
  for (;;) {
1521
190k
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
185k
    std::string name;
1523
185k
    if (is_nested_vector) {
1524
0
      if (fieldn >= struct_def->fields.vec.size()) {
1525
0
        return Error("too many unnamed fields in nested array");
1526
0
      }
1527
0
      name = struct_def->fields.vec[fieldn]->name;
1528
185k
    } else {
1529
185k
      name = attribute_;
1530
185k
      if (Is(kTokenStringConstant)) {
1531
2.75k
        NEXT();
1532
182k
      } else {
1533
182k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
182k
      }
1535
185k
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
185k
    }
1537
185k
    ECHECK(body(name, fieldn, struct_def));
1538
185k
    if (Is(terminator)) break;
1539
114k
    ECHECK(ParseComma());
1540
114k
  }
1541
74.9k
  NEXT();
1542
74.9k
  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1543
0
    return Error("wrong number of unnamed fields in table vector");
1544
0
  }
1545
74.9k
  return NoError();
1546
74.9k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseTableDelimiters<flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_0>(unsigned long&, flatbuffers::StructDef const*, flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_0)
Line
Count
Source
1509
111k
                                          const StructDef* struct_def, F body) {
1510
  // We allow tables both as JSON object{ .. } with field names
1511
  // or vector[..] with all fields in order
1512
111k
  char terminator = '}';
1513
111k
  bool is_nested_vector = struct_def && Is('[');
1514
111k
  if (is_nested_vector) {
1515
0
    NEXT();
1516
0
    terminator = ']';
1517
111k
  } else {
1518
111k
    EXPECT('{');
1519
111k
  }
1520
538k
  for (;;) {
1521
538k
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
479k
    std::string name;
1523
479k
    if (is_nested_vector) {
1524
0
      if (fieldn >= struct_def->fields.vec.size()) {
1525
0
        return Error("too many unnamed fields in nested array");
1526
0
      }
1527
0
      name = struct_def->fields.vec[fieldn]->name;
1528
479k
    } else {
1529
479k
      name = attribute_;
1530
479k
      if (Is(kTokenStringConstant)) {
1531
54.2k
        NEXT();
1532
425k
      } else {
1533
425k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
425k
      }
1535
479k
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
479k
    }
1537
479k
    ECHECK(body(name, fieldn, struct_def));
1538
478k
    if (Is(terminator)) break;
1539
427k
    ECHECK(ParseComma());
1540
427k
  }
1541
109k
  NEXT();
1542
109k
  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1543
0
    return Error("wrong number of unnamed fields in table vector");
1544
0
  }
1545
109k
  return NoError();
1546
109k
}
1547
1548
CheckedError Parser::ParseTable(const StructDef& struct_def, std::string* value,
1549
1.25M
                                uoffset_t* ovalue) {
1550
1.25M
  ParseDepthGuard depth_guard(this);
1551
1.25M
  ECHECK(depth_guard.Check());
1552
1553
1.25M
  size_t fieldn_outer = 0;
1554
1.25M
  auto err = ParseTableDelimiters(
1555
1.25M
      fieldn_outer, &struct_def,
1556
1.25M
      [&](const std::string& name, size_t& fieldn,
1557
1.25M
          const StructDef* struct_def_inner) -> CheckedError {
1558
1.14M
        if (name == "$schema") {
1559
4.51k
          ECHECK(Expect(kTokenStringConstant));
1560
4.24k
          return NoError();
1561
4.51k
        }
1562
1.13M
        auto field = struct_def_inner->fields.Lookup(name);
1563
1.13M
        if (!field) {
1564
38.4k
          if (!opts.skip_unexpected_fields_in_json) {
1565
8.69k
            return Error("unknown field: " + name);
1566
29.7k
          } else {
1567
29.7k
            ECHECK(SkipAnyJsonValue());
1568
29.2k
          }
1569
1.10M
        } else {
1570
1.10M
          if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
1571
419
            ECHECK(Next());  // Ignore this field.
1572
1.09M
          } else {
1573
1.09M
            Value val = field->value;
1574
1.09M
            if (field->flexbuffer) {
1575
24.0k
              flexbuffers::Builder builder(1024,
1576
24.0k
                                           flexbuffers::BUILDER_FLAG_SHARE_ALL);
1577
24.0k
              ECHECK(ParseFlexBufferValue(&builder));
1578
17.8k
              builder.Finish();
1579
              // Force alignment for nested flexbuffer
1580
17.8k
              builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
1581
17.8k
                                            sizeof(largest_scalar_t));
1582
17.8k
              auto off = builder_.CreateVector(builder.GetBuffer());
1583
17.8k
              val.constant = NumToString(off.o);
1584
1.07M
            } else if (field->nested_flatbuffer) {
1585
11.2k
              ECHECK(
1586
11.2k
                  ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
1587
1.06M
            } else {
1588
1.06M
              ECHECK(ParseAnyValue(val, field, fieldn, struct_def_inner, 0));
1589
946k
            }
1590
            // Hardcoded insertion-sort with error-check.
1591
            // If fields are specified in order, then this loop exits
1592
            // immediately.
1593
974k
            auto elem = field_stack_.rbegin();
1594
1.02M
            for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
1595
204k
              auto existing_field = elem->second;
1596
204k
              if (existing_field == field)
1597
4.63k
                return Error("field set more than once: " + field->name);
1598
199k
              if (existing_field->value.offset < field->value.offset) break;
1599
199k
            }
1600
            // Note: elem points to before the insertion point, thus .base()
1601
            // points to the correct spot.
1602
969k
            field_stack_.insert(elem.base(), std::make_pair(val, field));
1603
969k
            fieldn++;
1604
969k
          }
1605
1.10M
        }
1606
999k
        return NoError();
1607
1.13M
      });
1608
1.25M
  ECHECK(err);
1609
1610
  // Check if all required fields are parsed.
1611
974k
  for (auto field_it = struct_def.fields.vec.begin();
1612
6.88M
       field_it != struct_def.fields.vec.end(); ++field_it) {
1613
5.90M
    auto required_field = *field_it;
1614
5.90M
    if (!required_field->IsRequired()) {
1615
5.83M
      continue;
1616
5.83M
    }
1617
75.8k
    bool found = false;
1618
75.8k
    for (auto pf_it = field_stack_.end() - fieldn_outer;
1619
85.6k
         pf_it != field_stack_.end(); ++pf_it) {
1620
85.4k
      auto parsed_field = pf_it->second;
1621
85.4k
      if (parsed_field == required_field) {
1622
75.6k
        found = true;
1623
75.6k
        break;
1624
75.6k
      }
1625
85.4k
    }
1626
75.8k
    if (!found) {
1627
176
      return Error("required field is missing: " + required_field->name +
1628
176
                   " in " + struct_def.name);
1629
176
    }
1630
75.8k
  }
1631
1632
973k
  if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
1633
4
    return Error("struct: wrong number of initializers: " + struct_def.name);
1634
1635
973k
  auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
1636
973k
                                : builder_.StartTable();
1637
1638
4.10M
  for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
1639
3.35M
       size /= 2) {
1640
    // Go through elements in reverse, since we're building the data backwards.
1641
    // TODO(derekbailey): this doesn't work when there are Offset64 fields, as
1642
    // those have to be built first. So this needs to be changed to iterate over
1643
    // Offset64 then Offset32 fields.
1644
3.35M
    for (auto it = field_stack_.rbegin();
1645
6.00M
         it != field_stack_.rbegin() + fieldn_outer; ++it) {
1646
2.86M
      auto& field_value = it->first;
1647
2.86M
      auto field = it->second;
1648
2.86M
      if (!struct_def.sortbysize ||
1649
2.71M
          size == SizeOf(field_value.type.base_type)) {
1650
909k
        switch (field_value.type.base_type) {
1651
          // clang-format off
1652
0
          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1653
738k
            case BASE_TYPE_ ## ENUM: \
1654
519k
              builder_.Pad(field->padding); \
1655
738k
              if (struct_def.fixed) { \
1656
122k
                CTYPE val; \
1657
122k
                ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1658
121k
                builder_.PushElement(val); \
1659
616k
              } else { \
1660
616k
                if (field->IsScalarOptional()) { \
1661
26.4k
                  if (field_value.constant != "null") { \
1662
24.2k
                    CTYPE val; \
1663
24.2k
                    ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1664
24.2k
                    builder_.AddElement(field_value.offset, val); \
1665
24.2k
                  } \
1666
589k
                } else { \
1667
589k
                  CTYPE val, valdef; \
1668
589k
                  ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1669
371k
                  ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1670
371k
                  builder_.AddElement(field_value.offset, val, valdef); \
1671
371k
                } \
1672
616k
              } \
1673
519k
              break;
1674
738k
            FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
1675
40.3k
          #undef FLATBUFFERS_TD
1676
40.3k
          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1677
165k
            case BASE_TYPE_ ## ENUM: \
1678
165k
              builder_.Pad(field->padding); \
1679
165k
              if (IsStruct(field->value.type)) { \
1680
10.9k
                SerializeStruct(*field->value.type.struct_def, field_value); \
1681
154k
              } else { \
1682
                /* Special case for fields that use 64-bit addressing */ \
1683
154k
                if(field->offset64) { \
1684
11.2k
                  Offset64<void> offset; \
1685
11.2k
                  ECHECK(atot(field_value.constant.c_str(), *this, &offset)); \
1686
11.2k
                  builder_.AddOffset(field_value.offset, offset); \
1687
143k
                } else { \
1688
143k
                  CTYPE val; \
1689
143k
                  ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1690
143k
                  builder_.AddOffset(field_value.offset, val); \
1691
143k
                } \
1692
154k
              } \
1693
165k
              break;
1694
165k
            FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
1695
2.85k
          #undef FLATBUFFERS_TD
1696
5.32k
            case BASE_TYPE_ARRAY:
1697
5.32k
              builder_.Pad(field->padding);
1698
5.32k
              builder_.PushBytes(
1699
5.32k
                reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
1700
5.32k
                InlineSize(field_value.type));
1701
5.32k
              break;
1702
            // clang-format on
1703
909k
        }
1704
909k
      }
1705
2.86M
    }
1706
3.35M
  }
1707
1.44M
  for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
1708
1709
754k
  if (struct_def.fixed) {
1710
70.0k
    builder_.ClearOffsets();
1711
70.0k
    builder_.EndStruct();
1712
70.0k
    FLATBUFFERS_ASSERT(value);
1713
    // Temporarily store this struct in the value string, since it is to
1714
    // be serialized in-place elsewhere.
1715
70.0k
    value->assign(
1716
70.0k
        reinterpret_cast<const char*>(builder_.GetCurrentBufferPointer()),
1717
70.0k
        struct_def.bytesize);
1718
70.0k
    builder_.PopBytes(struct_def.bytesize);
1719
70.0k
    FLATBUFFERS_ASSERT(!ovalue);
1720
684k
  } else {
1721
684k
    auto val = builder_.EndTable(start);
1722
684k
    if (ovalue) *ovalue = val;
1723
684k
    if (value) *value = NumToString(val);
1724
684k
  }
1725
754k
  return NoError();
1726
754k
}
1727
1728
template <typename F>
1729
1.16M
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
1.16M
  EXPECT('[');
1731
3.80M
  for (;;) {
1732
3.80M
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
3.76M
    ECHECK(body(count));
1734
3.75M
    count++;
1735
3.75M
    if (Is(']')) break;
1736
2.63M
    ECHECK(ParseComma());
1737
2.63M
  }
1738
1.16M
  NEXT();
1739
1.16M
  return NoError();
1740
1.16M
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_0>(unsigned long&, flatbuffers::Parser::ParseVector(flatbuffers::Type const&, unsigned int*, flatbuffers::FieldDef*, unsigned long)::$_0)
Line
Count
Source
1729
51.9k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
51.9k
  EXPECT('[');
1731
724k
  for (;;) {
1732
724k
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
705k
    ECHECK(body(count));
1734
701k
    count++;
1735
701k
    if (Is(']')) break;
1736
674k
    ECHECK(ParseComma());
1737
673k
  }
1738
46.4k
  NEXT();
1739
46.4k
  return NoError();
1740
46.4k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseArray(flatbuffers::Value&)::$_0>(unsigned long&, flatbuffers::Parser::ParseArray(flatbuffers::Value&)::$_0)
Line
Count
Source
1729
5.71k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
5.71k
  EXPECT('[');
1731
17.8k
  for (;;) {
1732
17.8k
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
17.4k
    ECHECK(body(count));
1734
17.3k
    count++;
1735
17.3k
    if (Is(']')) break;
1736
12.1k
    ECHECK(ParseComma());
1737
12.1k
  }
1738
5.53k
  NEXT();
1739
5.53k
  return NoError();
1740
5.53k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::SkipAnyJsonValue()::$_1>(unsigned long&, flatbuffers::Parser::SkipAnyJsonValue()::$_1)
Line
Count
Source
1729
428k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
428k
  EXPECT('[');
1731
1.10M
  for (;;) {
1732
1.10M
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
1.10M
    ECHECK(body(count));
1734
1.10M
    count++;
1735
1.10M
    if (Is(']')) break;
1736
678k
    ECHECK(ParseComma());
1737
678k
  }
1738
428k
  NEXT();
1739
428k
  return NoError();
1740
428k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_1>(unsigned long&, flatbuffers::Parser::ParseFlexBufferValue(flexbuffers::Builder*)::$_1)
Line
Count
Source
1729
681k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
681k
  EXPECT('[');
1731
1.95M
  for (;;) {
1732
1.95M
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
1.93M
    ECHECK(body(count));
1734
1.93M
    count++;
1735
1.93M
    if (Is(']')) break;
1736
1.27M
    ECHECK(ParseComma());
1737
1.26M
  }
1738
679k
  NEXT();
1739
679k
  return NoError();
1740
679k
}
1741
1742
CheckedError Parser::ParseAlignAttribute(const std::string& align_constant,
1743
4.96k
                                         size_t min_align, size_t* align) {
1744
  // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64.
1745
4.96k
  uint8_t align_value;
1746
4.96k
  if (StringToNumber(align_constant.c_str(), &align_value) &&
1747
4.85k
      VerifyAlignmentRequirements(static_cast<size_t>(align_value),
1748
4.85k
                                  min_align)) {
1749
4.84k
    *align = align_value;
1750
4.84k
    return NoError();
1751
4.84k
  }
1752
118
  return Error("unexpected force_align value '" + align_constant +
1753
118
               "', alignment must be a power of two integer ranging from the "
1754
118
               "type\'s natural alignment " +
1755
118
               NumToString(min_align) + " to " +
1756
118
               NumToString(FLATBUFFERS_MAX_ALIGNMENT));
1757
4.96k
}
1758
1759
CheckedError Parser::ParseVector(const Type& vector_type, uoffset_t* ovalue,
1760
51.9k
                                 FieldDef* field, size_t fieldn) {
1761
51.9k
  Type type = vector_type.VectorType();
1762
51.9k
  size_t count = 0;
1763
705k
  auto err = ParseVectorDelimiters(count, [&](size_t&) -> CheckedError {
1764
705k
    Value val;
1765
705k
    val.type = type;
1766
705k
    ECHECK(ParseAnyValue(val, field, fieldn, nullptr, count, true));
1767
701k
    field_stack_.push_back(std::make_pair(val, nullptr));
1768
701k
    return NoError();
1769
705k
  });
1770
51.9k
  ECHECK(err);
1771
1772
46.4k
  const size_t alignment = InlineAlignment(type);
1773
46.4k
  const size_t len = count * InlineSize(type) / InlineAlignment(type);
1774
46.4k
  const size_t elemsize = InlineAlignment(type);
1775
46.4k
  const auto force_align = field->attributes.Lookup("force_align");
1776
46.4k
  if (force_align) {
1777
4.64k
    size_t align;
1778
4.64k
    ECHECK(ParseAlignAttribute(force_align->constant, 1, &align));
1779
4.64k
    if (align > 1) {
1780
4.44k
      builder_.ForceVectorAlignment(len, elemsize, align);
1781
4.44k
    }
1782
4.64k
  }
1783
1784
  // TODO Fix using element alignment as size (`elemsize`)!
1785
46.4k
  if (vector_type.base_type == BASE_TYPE_VECTOR64) {
1786
    // TODO(derekbailey): this requires a 64-bit builder.
1787
    // builder_.StartVector<Offset64, uoffset64_t>(len, elemsize, alignment);
1788
7.23k
    builder_.StartVector(len, elemsize, alignment);
1789
39.2k
  } else {
1790
39.2k
    builder_.StartVector(len, elemsize, alignment);
1791
39.2k
  }
1792
658k
  for (size_t i = 0; i < count; i++) {
1793
    // start at the back, since we're building the data backwards.
1794
612k
    auto& val = field_stack_.back().first;
1795
612k
    switch (val.type.base_type) {
1796
      // clang-format off
1797
0
      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
1798
612k
        case BASE_TYPE_ ## ENUM: \
1799
612k
          if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
1800
611k
          else { \
1801
565k
             CTYPE elem; \
1802
565k
             ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1803
565k
             builder_.PushElement(elem); \
1804
565k
          } \
1805
611k
          break;
1806
612k
        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1807
612k
      #undef FLATBUFFERS_TD
1808
      // clang-format on
1809
612k
    }
1810
611k
    field_stack_.pop_back();
1811
611k
  }
1812
1813
46.1k
  builder_.ClearOffsets();
1814
46.1k
  if (vector_type.base_type == BASE_TYPE_VECTOR64) {
1815
7.23k
    *ovalue = builder_.EndVector<uoffset64_t>(count);
1816
38.9k
  } else {
1817
38.9k
    *ovalue = builder_.EndVector(count);
1818
38.9k
  }
1819
1820
46.1k
  if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) {
1821
    // We should sort this vector. Find the key first.
1822
6.40k
    const FieldDef* key = nullptr;
1823
6.40k
    for (auto it = type.struct_def->fields.vec.begin();
1824
16.9k
         it != type.struct_def->fields.vec.end(); ++it) {
1825
16.9k
      if ((*it)->key) {
1826
6.40k
        key = (*it);
1827
6.40k
        break;
1828
6.40k
      }
1829
16.9k
    }
1830
6.40k
    FLATBUFFERS_ASSERT(key);
1831
    // Now sort it.
1832
    // We can't use std::sort because for structs the size is not known at
1833
    // compile time, and for tables our iterators dereference offsets, so can't
1834
    // be used to swap elements.
1835
    // And we can't use C qsort either, since that would force use to use
1836
    // globals, making parsing thread-unsafe.
1837
    // So for now, we use SimpleQsort above.
1838
    // TODO: replace with something better, preferably not recursive.
1839
1840
6.40k
    if (type.struct_def->fixed) {
1841
505
      const voffset_t offset = key->value.offset;
1842
505
      const size_t struct_size = type.struct_def->bytesize;
1843
505
      auto v =
1844
505
          reinterpret_cast<VectorOfAny*>(builder_.GetCurrentBufferPointer());
1845
505
      SimpleQsort<uint8_t>(
1846
505
          v->Data(), v->Data() + v->size() * type.struct_def->bytesize,
1847
505
          type.struct_def->bytesize,
1848
13.5M
          [offset, key](const uint8_t* a, const uint8_t* b) -> bool {
1849
13.5M
            return CompareSerializedScalars(a + offset, b + offset, *key);
1850
13.5M
          },
1851
29.8k
          [struct_size](uint8_t* a, uint8_t* b) {
1852
            // FIXME: faster?
1853
266k
            for (size_t i = 0; i < struct_size; i++) {
1854
236k
              std::swap(a[i], b[i]);
1855
236k
            }
1856
29.8k
          });
1857
5.89k
    } else {
1858
5.89k
      auto v = reinterpret_cast<Vector<Offset<Table>>*>(
1859
5.89k
          builder_.GetCurrentBufferPointer());
1860
      // Here also can't use std::sort. We do have an iterator type for it,
1861
      // but it is non-standard as it will dereference the offsets, and thus
1862
      // can't be used to swap elements.
1863
5.89k
      if (key->value.type.base_type == BASE_TYPE_STRING) {
1864
3.35k
        SimpleQsort<Offset<Table>>(
1865
3.35k
            v->data(), v->data() + v->size(), 1,
1866
2.00M
            [key](const Offset<Table>* _a, const Offset<Table>* _b) -> bool {
1867
2.00M
              return CompareTablesByStringKey(_a, _b, *key);
1868
2.00M
            },
1869
3.35k
            SwapSerializedTables);
1870
3.35k
      } else {
1871
2.53k
        SimpleQsort<Offset<Table>>(
1872
2.53k
            v->data(), v->data() + v->size(), 1,
1873
283M
            [key](const Offset<Table>* _a, const Offset<Table>* _b) -> bool {
1874
283M
              return CompareTablesByScalarKey(_a, _b, *key);
1875
283M
            },
1876
2.53k
            SwapSerializedTables);
1877
2.53k
      }
1878
5.89k
    }
1879
6.40k
  }
1880
46.1k
  return NoError();
1881
46.1k
}
1882
1883
5.71k
CheckedError Parser::ParseArray(Value& array) {
1884
5.71k
  std::vector<Value> stack;
1885
5.71k
  FlatBufferBuilder builder;
1886
5.71k
  const auto& type = array.type.VectorType();
1887
5.71k
  auto length = array.type.fixed_length;
1888
5.71k
  size_t count = 0;
1889
17.4k
  auto err = ParseVectorDelimiters(count, [&](size_t&) -> CheckedError {
1890
17.4k
    stack.emplace_back(Value());
1891
17.4k
    auto& val = stack.back();
1892
17.4k
    val.type = type;
1893
17.4k
    if (IsStruct(type)) {
1894
115
      ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
1895
17.3k
    } else {
1896
17.3k
      ECHECK(ParseSingleValue(nullptr, val, false));
1897
17.3k
    }
1898
17.3k
    return NoError();
1899
17.4k
  });
1900
5.71k
  ECHECK(err);
1901
5.53k
  if (length != count) return Error("Fixed-length array size is incorrect.");
1902
1903
13.6k
  for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
1904
8.20k
    auto& val = *it;
1905
    // clang-format off
1906
8.20k
    switch (val.type.base_type) {
1907
0
      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1908
8.20k
        case BASE_TYPE_ ## ENUM: \
1909
8.20k
          if (IsStruct(val.type)) { \
1910
0
            SerializeStruct(builder, *val.type.struct_def, val); \
1911
8.20k
          } else { \
1912
8.20k
            CTYPE elem; \
1913
8.20k
            ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1914
8.17k
            builder.PushElement(elem); \
1915
8.17k
          } \
1916
8.17k
        break;
1917
8.20k
        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1918
0
      #undef FLATBUFFERS_TD
1919
0
      default: FLATBUFFERS_ASSERT(0);
1920
8.20k
    }
1921
    // clang-format on
1922
8.20k
  }
1923
1924
5.47k
  array.constant.assign(
1925
5.47k
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
1926
5.47k
      InlineSize(array.type));
1927
5.47k
  return NoError();
1928
5.50k
}
1929
1930
CheckedError Parser::ParseNestedFlatbuffer(Value& val, FieldDef* field,
1931
                                           size_t fieldn,
1932
11.2k
                                           const StructDef* parent_struct_def) {
1933
11.2k
  if (token_ == '[') {  // backwards compat for 'legacy' ubyte buffers
1934
7
    if (opts.json_nested_legacy_flatbuffers) {
1935
0
      ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0));
1936
7
    } else {
1937
7
      return Error(
1938
7
          "cannot parse nested_flatbuffer as bytes unless"
1939
7
          " --json-nested-bytes is set");
1940
7
    }
1941
11.2k
  } else {
1942
11.2k
    auto cursor_at_value_begin = cursor_;
1943
11.2k
    ECHECK(SkipAnyJsonValue());
1944
11.2k
    std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
1945
1946
    // Create and initialize new parser
1947
11.2k
    Parser nested_parser;
1948
11.2k
    FLATBUFFERS_ASSERT(field->nested_flatbuffer);
1949
11.2k
    nested_parser.root_struct_def_ = field->nested_flatbuffer;
1950
11.2k
    nested_parser.enums_ = enums_;
1951
11.2k
    nested_parser.opts = opts;
1952
11.2k
    nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1953
11.2k
    nested_parser.parse_depth_counter_ = parse_depth_counter_;
1954
    // Parse JSON substring into new flatbuffer builder using nested_parser
1955
11.2k
    bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr);
1956
1957
    // Clean nested_parser to avoid deleting the elements in
1958
    // the SymbolTables on destruction
1959
11.2k
    nested_parser.enums_.dict.clear();
1960
11.2k
    nested_parser.enums_.vec.clear();
1961
1962
11.2k
    if (!ok) {
1963
859
      ECHECK(Error(nested_parser.error_));
1964
0
    }
1965
    // Force alignment for nested flatbuffer
1966
10.3k
    builder_.ForceVectorAlignment(
1967
10.3k
        nested_parser.builder_.GetSize(), sizeof(uint8_t),
1968
10.3k
        nested_parser.builder_.GetBufferMinAlignment());
1969
1970
10.3k
    auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
1971
10.3k
                                     nested_parser.builder_.GetSize());
1972
10.3k
    val.constant = NumToString(off.o);
1973
10.3k
  }
1974
10.3k
  return NoError();
1975
11.2k
}
1976
1977
878k
CheckedError Parser::ParseMetaData(SymbolTable<Value>* attributes) {
1978
878k
  if (Is('(')) {
1979
12.5k
    NEXT();
1980
16.6k
    for (;;) {
1981
16.6k
      auto name = attribute_;
1982
16.6k
      if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
1983
59
        return Error("attribute name must be either identifier or string: " +
1984
59
                     name);
1985
16.5k
      if (known_attributes_.find(name) == known_attributes_.end())
1986
102
        return Error("user define attributes must be declared before use: " +
1987
102
                     name);
1988
16.4k
      NEXT();
1989
16.4k
      auto e = new Value();
1990
16.4k
      if (attributes->Add(name, e)) Warning("attribute already found: " + name);
1991
16.4k
      if (Is(':')) {
1992
6.16k
        NEXT();
1993
6.15k
        ECHECK(ParseSingleValue(&name, *e, true));
1994
6.08k
      }
1995
16.3k
      if (Is(')')) {
1996
12.0k
        NEXT();
1997
12.0k
        break;
1998
12.0k
      }
1999
4.30k
      EXPECT(',');
2000
4.09k
    }
2001
12.5k
  }
2002
878k
  return NoError();
2003
878k
}
2004
2005
CheckedError Parser::ParseEnumFromString(const Type& type,
2006
50.0k
                                         std::string* result) {
2007
50.0k
  const auto base_type =
2008
50.0k
      type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type;
2009
50.0k
  if (!IsInteger(base_type)) return Error("not a valid value for this field");
2010
50.0k
  uint64_t u64 = 0;
2011
86.7k
  for (size_t pos = 0; pos != std::string::npos;) {
2012
58.8k
    const auto delim = attribute_.find_first_of(' ', pos);
2013
58.8k
    const auto last = (std::string::npos == delim);
2014
58.8k
    auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos);
2015
58.8k
    pos = !last ? delim + 1 : std::string::npos;
2016
58.8k
    const EnumVal* ev = nullptr;
2017
58.8k
    if (type.enum_def) {
2018
33.9k
      ev = type.enum_def->Lookup(word);
2019
33.9k
    } else {
2020
24.9k
      auto dot = word.find_first_of('.');
2021
24.9k
      if (std::string::npos == dot)
2022
17.1k
        return Error("enum values need to be qualified by an enum type");
2023
7.75k
      auto enum_def_str = word.substr(0, dot);
2024
7.75k
      const auto enum_def = LookupEnum(enum_def_str);
2025
7.75k
      if (!enum_def) return Error("unknown enum: " + enum_def_str);
2026
3.13k
      auto enum_val_str = word.substr(dot + 1);
2027
3.13k
      ev = enum_def->Lookup(enum_val_str);
2028
3.13k
    }
2029
37.0k
    if (!ev) return Error("unknown enum value: " + word);
2030
36.7k
    u64 |= ev->GetAsUInt64();
2031
36.7k
  }
2032
27.9k
  *result = IsUnsigned(base_type) ? NumToString(u64)
2033
27.9k
                                  : NumToString(static_cast<int64_t>(u64));
2034
27.9k
  return NoError();
2035
50.0k
}
2036
2037
8.24k
CheckedError Parser::ParseHash(Value& e, FieldDef* field) {
2038
8.24k
  FLATBUFFERS_ASSERT(field);
2039
8.24k
  Value* hash_name = field->attributes.Lookup("hash");
2040
8.24k
  switch (e.type.base_type) {
2041
0
    case BASE_TYPE_SHORT: {
2042
0
      auto hash = FindHashFunction16(hash_name->constant.c_str());
2043
0
      int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str()));
2044
0
      e.constant = NumToString(hashed_value);
2045
0
      break;
2046
0
    }
2047
0
    case BASE_TYPE_USHORT: {
2048
0
      auto hash = FindHashFunction16(hash_name->constant.c_str());
2049
0
      uint16_t hashed_value = hash(attribute_.c_str());
2050
0
      e.constant = NumToString(hashed_value);
2051
0
      break;
2052
0
    }
2053
1.43k
    case BASE_TYPE_INT: {
2054
1.43k
      auto hash = FindHashFunction32(hash_name->constant.c_str());
2055
1.43k
      int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
2056
1.43k
      e.constant = NumToString(hashed_value);
2057
1.43k
      break;
2058
0
    }
2059
1.68k
    case BASE_TYPE_UINT: {
2060
1.68k
      auto hash = FindHashFunction32(hash_name->constant.c_str());
2061
1.68k
      uint32_t hashed_value = hash(attribute_.c_str());
2062
1.68k
      e.constant = NumToString(hashed_value);
2063
1.68k
      break;
2064
0
    }
2065
2.68k
    case BASE_TYPE_LONG: {
2066
2.68k
      auto hash = FindHashFunction64(hash_name->constant.c_str());
2067
2.68k
      int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
2068
2.68k
      e.constant = NumToString(hashed_value);
2069
2.68k
      break;
2070
0
    }
2071
2.44k
    case BASE_TYPE_ULONG: {
2072
2.44k
      auto hash = FindHashFunction64(hash_name->constant.c_str());
2073
2.44k
      uint64_t hashed_value = hash(attribute_.c_str());
2074
2.44k
      e.constant = NumToString(hashed_value);
2075
2.44k
      break;
2076
0
    }
2077
0
    default:
2078
0
      FLATBUFFERS_ASSERT(0);
2079
8.24k
  }
2080
8.24k
  NEXT();
2081
8.24k
  return NoError();
2082
8.24k
}
2083
2084
764
CheckedError Parser::TokenError() {
2085
764
  return Error("cannot parse value starting with: " + TokenToStringId(token_));
2086
764
}
2087
2088
75.5k
CheckedError Parser::ParseFunction(const std::string* name, Value& e) {
2089
75.5k
  ParseDepthGuard depth_guard(this);
2090
75.5k
  ECHECK(depth_guard.Check());
2091
2092
  // Copy name, attribute will be changed on NEXT().
2093
75.1k
  const auto functionname = attribute_;
2094
75.1k
  if (!IsFloat(e.type.base_type)) {
2095
2.85k
    return Error(functionname + ": type of argument mismatch, expecting: " +
2096
2.85k
                 TypeName(BASE_TYPE_DOUBLE) +
2097
2.85k
                 ", found: " + TypeName(e.type.base_type) +
2098
2.85k
                 ", name: " + (name ? *name : "") + ", value: " + e.constant);
2099
2.85k
  }
2100
72.2k
  NEXT();
2101
72.2k
  EXPECT('(');
2102
69.4k
  ECHECK(ParseSingleValue(name, e, false));
2103
14.9k
  EXPECT(')');
2104
  // calculate with double precision
2105
11.8k
  double x, y = 0.0;
2106
11.8k
  ECHECK(atot(e.constant.c_str(), *this, &x));
2107
  // clang-format off
2108
11.3k
  auto func_match = false;
2109
11.3k
  #define FLATBUFFERS_FN_DOUBLE(name, op) \
2110
90.7k
    if (!func_match && functionname == name) { y = op; func_match = true; }
2111
11.3k
  FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
2112
11.3k
  FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
2113
11.3k
  FLATBUFFERS_FN_DOUBLE("sin", sin(x));
2114
11.3k
  FLATBUFFERS_FN_DOUBLE("cos", cos(x));
2115
11.3k
  FLATBUFFERS_FN_DOUBLE("tan", tan(x));
2116
11.3k
  FLATBUFFERS_FN_DOUBLE("asin", asin(x));
2117
11.3k
  FLATBUFFERS_FN_DOUBLE("acos", acos(x));
2118
11.3k
  FLATBUFFERS_FN_DOUBLE("atan", atan(x));
2119
  // TODO(wvo): add more useful conversion functions here.
2120
11.3k
  #undef FLATBUFFERS_FN_DOUBLE
2121
  // clang-format on
2122
11.3k
  if (true != func_match) {
2123
3.21k
    return Error(std::string("Unknown conversion function: ") + functionname +
2124
3.21k
                 ", field name: " + (name ? *name : "") +
2125
3.21k
                 ", value: " + e.constant);
2126
3.21k
  }
2127
8.12k
  e.constant = NumToString(y);
2128
8.12k
  return NoError();
2129
11.3k
}
2130
2131
CheckedError Parser::TryTypedValue(const std::string* name, int dtoken,
2132
                                   bool check, Value& e, BaseType req,
2133
1.17M
                                   bool* destmatch) {
2134
1.17M
  FLATBUFFERS_ASSERT(*destmatch == false && dtoken == token_);
2135
1.17M
  *destmatch = true;
2136
1.17M
  e.constant = attribute_;
2137
  // Check token match
2138
1.17M
  if (!check) {
2139
6.14k
    if (e.type.base_type == BASE_TYPE_NONE) {
2140
6.14k
      e.type.base_type = req;
2141
6.14k
    } else {
2142
7
      return Error(std::string("type mismatch: expecting: ") +
2143
7
                   TypeName(e.type.base_type) + ", found: " + TypeName(req) +
2144
7
                   ", name: " + (name ? *name : "") + ", value: " + e.constant);
2145
7
    }
2146
6.14k
  }
2147
  // The exponent suffix of hexadecimal float-point number is mandatory.
2148
  // A hex-integer constant is forbidden as an initializer of float number.
2149
1.17M
  if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
2150
226k
    const auto& s = e.constant;
2151
226k
    const auto k = s.find_first_of("0123456789.");
2152
226k
    if ((std::string::npos != k) && (s.length() > (k + 1)) &&
2153
64.7k
        (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
2154
11.6k
        (std::string::npos == s.find_first_of("pP", k + 2))) {
2155
6.96k
      return Error(
2156
6.96k
          "invalid number, the exponent suffix of hexadecimal "
2157
6.96k
          "floating-point literals is mandatory: \"" +
2158
6.96k
          s + "\"");
2159
6.96k
    }
2160
226k
  }
2161
1.16M
  NEXT();
2162
1.14M
  return NoError();
2163
1.16M
}
2164
2165
CheckedError Parser::ParseSingleValue(const std::string* name, Value& e,
2166
1.35M
                                      bool check_now) {
2167
1.35M
  if (token_ == '+' || token_ == '-') {
2168
31.9k
    const char sign = static_cast<char>(token_);
2169
    // Get an indentifier: NAN, INF, or function name like cos/sin/deg.
2170
31.9k
    NEXT();
2171
31.9k
    if (token_ != kTokenIdentifier) return Error("constant name expected");
2172
31.9k
    attribute_.insert(size_t(0), size_t(1), sign);
2173
31.9k
  }
2174
2175
1.35M
  const auto in_type = e.type.base_type;
2176
1.35M
  const auto is_tok_ident = (token_ == kTokenIdentifier);
2177
1.35M
  const auto is_tok_string = (token_ == kTokenStringConstant);
2178
2179
  // First see if this could be a conversion function.
2180
1.35M
  if (is_tok_ident && *cursor_ == '(') {
2181
75.5k
    return ParseFunction(name, e);
2182
75.5k
  }
2183
2184
  // clang-format off
2185
1.27M
  auto match = false;
2186
2187
1.27M
  #define IF_ECHECK_(force, dtoken, check, req)    \
2188
3.29M
    if (!match && ((dtoken) == token_) && ((check) || flatbuffers::IsConstTrue(force))) \
2189
3.29M
      ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
2190
2.08M
  #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req)
2191
1.27M
  #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
2192
  // clang-format on
2193
2194
1.27M
  if (is_tok_ident || is_tok_string) {
2195
450k
    const auto kTokenStringOrIdent = token_;
2196
    // The string type is a most probable type, check it first.
2197
450k
    TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
2198
450k
               BASE_TYPE_STRING);
2199
2200
    // avoid escaped and non-ascii in the string
2201
450k
    if (!match && is_tok_string && IsScalar(in_type) &&
2202
359k
        !attr_is_trivial_ascii_string_) {
2203
21.2k
      return Error(
2204
21.2k
          std::string("type mismatch or invalid value, an initializer of "
2205
21.2k
                      "non-string field must be trivial ASCII string: type: ") +
2206
21.2k
          TypeName(in_type) + ", name: " + (name ? *name : "") +
2207
21.2k
          ", value: " + attribute_);
2208
21.2k
    }
2209
2210
    // A boolean as true/false. Boolean as Integer check below.
2211
429k
    if (!match && IsBool(in_type)) {
2212
56.6k
      auto is_true = attribute_ == "true";
2213
56.6k
      if (is_true || attribute_ == "false") {
2214
20.0k
        attribute_ = is_true ? "1" : "0";
2215
        // accepts both kTokenStringConstant and kTokenIdentifier
2216
20.0k
        TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
2217
19.4k
      }
2218
56.6k
    }
2219
    // Check for optional scalars.
2220
428k
    if (!match && IsScalar(in_type) && attribute_ == "null") {
2221
7.08k
      e.constant = "null";
2222
7.08k
      NEXT();
2223
6.15k
      match = true;
2224
6.15k
    }
2225
    // Check if this could be a string/identifier enum value.
2226
    // Enum can have only true integer base type.
2227
428k
    if (!match && IsInteger(in_type) && !IsBool(in_type) &&
2228
252k
        IsIdentifierStart(*attribute_.c_str())) {
2229
50.0k
      ECHECK(ParseEnumFromString(e.type, &e.constant));
2230
27.9k
      NEXT();
2231
27.9k
      match = true;
2232
27.9k
    }
2233
    // Parse a float/integer number from the string.
2234
    // A "scalar-in-string" value needs extra checks.
2235
405k
    if (!match && is_tok_string && IsScalar(in_type)) {
2236
      // Strip trailing whitespaces from attribute_.
2237
296k
      auto last_non_ws = attribute_.find_last_not_of(' ');
2238
296k
      if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1);
2239
296k
      if (IsFloat(e.type.base_type)) {
2240
        // The functions strtod() and strtof() accept both 'nan' and
2241
        // 'nan(number)' literals. While 'nan(number)' is rejected by the parser
2242
        // as an unsupported function if is_tok_ident is true.
2243
83.1k
        if (attribute_.find_last_of(')') != std::string::npos) {
2244
5.10k
          return Error("invalid number: " + attribute_);
2245
5.10k
        }
2246
83.1k
      }
2247
296k
    }
2248
    // Float numbers or nan, inf, pi, etc.
2249
400k
    TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
2250
    // An integer constant in string.
2251
387k
    TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT);
2252
    // Unknown tokens will be interpreted as string type.
2253
    // An attribute value may be a scalar or string constant.
2254
381k
    FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
2255
381k
                 BASE_TYPE_STRING);
2256
826k
  } else {
2257
    // Try a float number.
2258
826k
    TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
2259
    // Integer token can init any scalar (integer of float).
2260
824k
    FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
2261
816k
  }
2262
  // Match empty vectors for default-empty-vectors.
2263
1.19M
  if (!match && IsVector(e.type) && token_ == '[') {
2264
42
    NEXT();
2265
41
    if (token_ != ']') {
2266
4
      return Error("Expected `]` in vector default");
2267
4
    }
2268
37
    NEXT();
2269
36
    match = true;
2270
36
    e.constant = "[]";
2271
36
  }
2272
2273
1.19M
#undef FORCE_ECHECK
2274
1.19M
#undef TRY_ECHECK
2275
1.19M
#undef IF_ECHECK_
2276
2277
1.19M
  if (!match) {
2278
17.8k
    std::string msg;
2279
17.8k
    msg += "Cannot assign token starting with '" + TokenToStringId(token_) +
2280
17.8k
           "' to value of <" + std::string(TypeName(in_type)) + "> type.";
2281
17.8k
    return Error(msg);
2282
17.8k
  }
2283
1.17M
  const auto match_type = e.type.base_type;  // may differ from in_type
2284
  // The check_now flag must be true when parse a fbs-schema.
2285
  // This flag forces to check default scalar values or metadata of field.
2286
  // For JSON parser the flag should be false.
2287
  // If it is set for JSON each value will be checked twice (see ParseTable).
2288
  // Special case 'null' since atot can't handle that.
2289
1.17M
  if (check_now && IsScalar(match_type) && e.constant != "null") {
2290
    // clang-format off
2291
112k
    switch (match_type) {
2292
0
    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
2293
112k
      case BASE_TYPE_ ## ENUM: {\
2294
112k
          CTYPE val; \
2295
112k
          ECHECK(atot(e.constant.c_str(), *this, &val)); \
2296
112k
          SingleValueRepack(e, val); \
2297
112k
        break; }
2298
112k
    FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
2299
0
    #undef FLATBUFFERS_TD
2300
0
    default: break;
2301
112k
    }
2302
    // clang-format on
2303
112k
  }
2304
1.17M
  return NoError();
2305
1.17M
}
2306
2307
StructDef* Parser::LookupCreateStruct(const std::string& name,
2308
670k
                                      bool create_if_new, bool definition) {
2309
670k
  std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
2310
  // See if it exists pre-declared by an unqualified use.
2311
670k
  auto struct_def = LookupStruct(name);
2312
670k
  if (struct_def && struct_def->predecl) {
2313
171k
    if (definition) {
2314
      // Make sure it has the current namespace, and is registered under its
2315
      // qualified name.
2316
8.31k
      struct_def->defined_namespace = current_namespace_;
2317
8.31k
      structs_.Move(name, qualified_name);
2318
8.31k
    }
2319
171k
    return struct_def;
2320
171k
  }
2321
  // See if it exists pre-declared by an qualified use.
2322
498k
  struct_def = LookupStruct(qualified_name);
2323
498k
  if (struct_def && struct_def->predecl) {
2324
69
    if (definition) {
2325
      // Make sure it has the current namespace.
2326
6
      struct_def->defined_namespace = current_namespace_;
2327
6
    }
2328
69
    return struct_def;
2329
69
  }
2330
498k
  if (!definition && !struct_def) {
2331
323k
    struct_def = LookupStructThruParentNamespaces(name);
2332
323k
  }
2333
498k
  if (!struct_def && create_if_new) {
2334
327k
    struct_def = new StructDef();
2335
327k
    if (definition) {
2336
168k
      structs_.Add(qualified_name, struct_def);
2337
168k
      struct_def->name = name;
2338
168k
      struct_def->defined_namespace = current_namespace_;
2339
168k
    } else {
2340
      // Not a definition.
2341
      // Rather than failing, we create a "pre declared" StructDef, due to
2342
      // circular references, and check for errors at the end of parsing.
2343
      // It is defined in the current namespace, as the best guess what the
2344
      // final namespace will be.
2345
158k
      structs_.Add(name, struct_def);
2346
158k
      struct_def->name = name;
2347
158k
      struct_def->defined_namespace = current_namespace_;
2348
158k
      struct_def->original_location.reset(
2349
158k
          new std::string(file_being_parsed_ + ":" + NumToString(line_)));
2350
158k
    }
2351
327k
  }
2352
498k
  return struct_def;
2353
498k
}
2354
2355
0
const EnumVal* EnumDef::MinValue() const {
2356
0
  return vals.vec.empty() ? nullptr : vals.vec.front();
2357
0
}
2358
0
const EnumVal* EnumDef::MaxValue() const {
2359
0
  return vals.vec.empty() ? nullptr : vals.vec.back();
2360
0
}
2361
2362
0
uint64_t EnumDef::Distance(const EnumVal* v1, const EnumVal* v2) const {
2363
0
  return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64())
2364
0
                    : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64());
2365
0
}
2366
2367
0
std::string EnumDef::AllFlags() const {
2368
0
  FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags"));
2369
0
  uint64_t u64 = 0;
2370
0
  for (auto it = Vals().begin(); it != Vals().end(); ++it) {
2371
0
    u64 |= (*it)->GetAsUInt64();
2372
0
  }
2373
0
  return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64));
2374
0
}
2375
2376
EnumVal* EnumDef::ReverseLookup(int64_t enum_idx,
2377
72.3k
                                bool skip_union_default) const {
2378
72.3k
  auto skip_first = static_cast<int>(is_union && skip_union_default);
2379
224k
  for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) {
2380
206k
    if ((*it)->GetAsInt64() == enum_idx) {
2381
54.1k
      return *it;
2382
54.1k
    }
2383
206k
  }
2384
18.2k
  return nullptr;
2385
72.3k
}
2386
2387
1.21k
EnumVal* EnumDef::FindByValue(const std::string& constant) const {
2388
1.21k
  int64_t i64;
2389
1.21k
  auto done = false;
2390
1.21k
  if (IsUInt64()) {
2391
317
    uint64_t u64;  // avoid reinterpret_cast of pointers
2392
317
    done = StringToNumber(constant.c_str(), &u64);
2393
317
    i64 = static_cast<int64_t>(u64);
2394
901
  } else {
2395
901
    done = StringToNumber(constant.c_str(), &i64);
2396
901
  }
2397
1.21k
  FLATBUFFERS_ASSERT(done);
2398
1.21k
  if (!done) return nullptr;
2399
1.21k
  return ReverseLookup(i64, false);
2400
1.21k
}
2401
2402
93.2k
void EnumDef::SortByValue() {
2403
93.2k
  auto& v = vals.vec;
2404
93.2k
  if (IsUInt64())
2405
1.75M
    std::sort(v.begin(), v.end(), [](const EnumVal* e1, const EnumVal* e2) {
2406
1.75M
      if (e1->GetAsUInt64() == e2->GetAsUInt64()) {
2407
278k
        return e1->name < e2->name;
2408
278k
      }
2409
1.47M
      return e1->GetAsUInt64() < e2->GetAsUInt64();
2410
1.75M
    });
2411
82.9k
  else
2412
1.59M
    std::sort(v.begin(), v.end(), [](const EnumVal* e1, const EnumVal* e2) {
2413
1.59M
      if (e1->GetAsInt64() == e2->GetAsInt64()) {
2414
267k
        return e1->name < e2->name;
2415
267k
      }
2416
1.32M
      return e1->GetAsInt64() < e2->GetAsInt64();
2417
1.59M
    });
2418
93.2k
}
2419
2420
0
void EnumDef::RemoveDuplicates() {
2421
  // This method depends form SymbolTable implementation!
2422
  // 1) vals.vec - owner (raw pointer)
2423
  // 2) vals.dict - access map
2424
0
  auto first = vals.vec.begin();
2425
0
  auto last = vals.vec.end();
2426
0
  if (first == last) return;
2427
0
  auto result = first;
2428
0
  while (++first != last) {
2429
0
    if ((*result)->value != (*first)->value) {
2430
0
      *(++result) = *first;
2431
0
    } else {
2432
0
      auto ev = *first;
2433
0
      for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) {
2434
0
        if (it->second == ev) it->second = *result;  // reassign
2435
0
      }
2436
0
      delete ev;  // delete enum value
2437
0
      *first = nullptr;
2438
0
    }
2439
0
  }
2440
0
  vals.vec.erase(++result, last);
2441
0
}
2442
2443
template <typename T>
2444
2.15k
void EnumDef::ChangeEnumValue(EnumVal* ev, T new_value) {
2445
2.15k
  ev->value = static_cast<int64_t>(new_value);
2446
2.15k
}
2447
2448
namespace EnumHelper {
2449
template <BaseType E>
2450
struct EnumValType {
2451
  typedef int64_t type;
2452
};
2453
template <>
2454
struct EnumValType<BASE_TYPE_ULONG> {
2455
  typedef uint64_t type;
2456
};
2457
}  // namespace EnumHelper
2458
2459
struct EnumValBuilder {
2460
520k
  EnumVal* CreateEnumerator(const std::string& ev_name) {
2461
520k
    FLATBUFFERS_ASSERT(!temp);
2462
520k
    auto first = enum_def.vals.vec.empty();
2463
520k
    user_value = first;
2464
520k
    temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value);
2465
520k
    return temp;
2466
520k
  }
2467
2468
0
  EnumVal* CreateEnumerator(const std::string& ev_name, int64_t val) {
2469
0
    FLATBUFFERS_ASSERT(!temp);
2470
0
    user_value = true;
2471
0
    temp = new EnumVal(ev_name, val);
2472
0
    return temp;
2473
0
  }
2474
2475
519k
  FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string& name) {
2476
519k
    FLATBUFFERS_ASSERT(temp);
2477
519k
    ECHECK(ValidateValue(&temp->value, false == user_value));
2478
518k
    FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) ||
2479
518k
                       (temp->union_type.enum_def == &enum_def));
2480
518k
    auto not_unique = enum_def.vals.Add(name, temp);
2481
518k
    temp = nullptr;
2482
518k
    if (not_unique) return parser.Error("enum value already exists: " + name);
2483
518k
    return NoError();
2484
518k
  }
2485
2486
519k
  FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() {
2487
519k
    return AcceptEnumerator(temp->name);
2488
519k
  }
2489
2490
118k
  FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string& value) {
2491
118k
    user_value = true;
2492
118k
    auto fit = false;
2493
118k
    if (enum_def.IsUInt64()) {
2494
60.6k
      uint64_t u64;
2495
60.6k
      fit = StringToNumber(value.c_str(), &u64);
2496
60.6k
      temp->value = static_cast<int64_t>(u64);  // well-defined since C++20.
2497
60.6k
    } else {
2498
57.4k
      int64_t i64;
2499
57.4k
      fit = StringToNumber(value.c_str(), &i64);
2500
57.4k
      temp->value = i64;
2501
57.4k
    }
2502
118k
    if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
2503
118k
    return NoError();
2504
118k
  }
2505
2506
  template <BaseType E, typename CTYPE>
2507
519k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
519k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
519k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
519k
    const auto v = static_cast<T>(*ev);
2511
519k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
519k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
519k
    if (v < dn || v > (up - m)) {
2514
819
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
819
                          (m ? " + 1\"" : "\"") + " out of " +
2516
819
                          TypeToIntervalString<CTYPE>());
2517
819
    }
2518
518k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
518k
    return NoError();
2520
519k
  }
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)0, unsigned char>(long*, int)
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)1, unsigned char>(long*, int)
Line
Count
Source
2507
116k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
116k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
116k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
116k
    const auto v = static_cast<T>(*ev);
2511
116k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
116k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
116k
    if (v < dn || v > (up - m)) {
2514
143
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
143
                          (m ? " + 1\"" : "\"") + " out of " +
2516
143
                          TypeToIntervalString<CTYPE>());
2517
143
    }
2518
116k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
116k
    return NoError();
2520
116k
  }
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)2, unsigned char>(long*, int)
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)3, signed char>(long*, int)
Line
Count
Source
2507
597
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
597
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
597
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
597
    const auto v = static_cast<T>(*ev);
2511
597
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
597
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
597
    if (v < dn || v > (up - m)) {
2514
134
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
134
                          (m ? " + 1\"" : "\"") + " out of " +
2516
134
                          TypeToIntervalString<CTYPE>());
2517
134
    }
2518
463
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
463
    return NoError();
2520
597
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)4, unsigned char>(long*, int)
Line
Count
Source
2507
1.20k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
1.20k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
1.20k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
1.20k
    const auto v = static_cast<T>(*ev);
2511
1.20k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
1.20k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
1.20k
    if (v < dn || v > (up - m)) {
2514
139
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
139
                          (m ? " + 1\"" : "\"") + " out of " +
2516
139
                          TypeToIntervalString<CTYPE>());
2517
139
    }
2518
1.06k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
1.06k
    return NoError();
2520
1.20k
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)5, short>(long*, int)
Line
Count
Source
2507
3.79k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
3.79k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
3.79k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
3.79k
    const auto v = static_cast<T>(*ev);
2511
3.79k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
3.79k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
3.79k
    if (v < dn || v > (up - m)) {
2514
95
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
95
                          (m ? " + 1\"" : "\"") + " out of " +
2516
95
                          TypeToIntervalString<CTYPE>());
2517
95
    }
2518
3.70k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
3.70k
    return NoError();
2520
3.79k
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)6, unsigned short>(long*, int)
Line
Count
Source
2507
32.0k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
32.0k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
32.0k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
32.0k
    const auto v = static_cast<T>(*ev);
2511
32.0k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
32.0k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
32.0k
    if (v < dn || v > (up - m)) {
2514
130
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
130
                          (m ? " + 1\"" : "\"") + " out of " +
2516
130
                          TypeToIntervalString<CTYPE>());
2517
130
    }
2518
31.9k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
31.9k
    return NoError();
2520
32.0k
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)7, int>(long*, int)
Line
Count
Source
2507
16.0k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
16.0k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
16.0k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
16.0k
    const auto v = static_cast<T>(*ev);
2511
16.0k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
16.0k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
16.0k
    if (v < dn || v > (up - m)) {
2514
90
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
90
                          (m ? " + 1\"" : "\"") + " out of " +
2516
90
                          TypeToIntervalString<CTYPE>());
2517
90
    }
2518
15.9k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
15.9k
    return NoError();
2520
16.0k
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)8, unsigned int>(long*, int)
Line
Count
Source
2507
100k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
100k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
100k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
100k
    const auto v = static_cast<T>(*ev);
2511
100k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
100k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
100k
    if (v < dn || v > (up - m)) {
2514
86
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
86
                          (m ? " + 1\"" : "\"") + " out of " +
2516
86
                          TypeToIntervalString<CTYPE>());
2517
86
    }
2518
100k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
100k
    return NoError();
2520
100k
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)9, long>(long*, int)
Line
Count
Source
2507
21.3k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
21.3k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
21.3k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
21.3k
    const auto v = static_cast<T>(*ev);
2511
21.3k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
21.3k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
21.3k
    if (v < dn || v > (up - m)) {
2514
1
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
1
                          (m ? " + 1\"" : "\"") + " out of " +
2516
1
                          TypeToIntervalString<CTYPE>());
2517
1
    }
2518
21.3k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
21.3k
    return NoError();
2520
21.3k
  }
flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)10, unsigned long>(long*, int)
Line
Count
Source
2507
227k
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
227k
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
227k
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
227k
    const auto v = static_cast<T>(*ev);
2511
227k
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
227k
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
227k
    if (v < dn || v > (up - m)) {
2514
1
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
1
                          (m ? " + 1\"" : "\"") + " out of " +
2516
1
                          TypeToIntervalString<CTYPE>());
2517
1
    }
2518
227k
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
227k
    return NoError();
2520
227k
  }
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)11, float>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)12, double>(long*, int)
2521
2522
519k
  FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t* ev, bool next) {
2523
    // clang-format off
2524
519k
    switch (enum_def.underlying_type.base_type) {
2525
0
    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...)                   \
2526
519k
      case BASE_TYPE_##ENUM: {                                          \
2527
519k
        if (!IsInteger(BASE_TYPE_##ENUM)) break;                        \
2528
519k
        return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
2529
519k
      }
2530
519k
      FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
2531
0
    #undef FLATBUFFERS_TD
2532
0
    default: break;
2533
519k
    }
2534
    // clang-format on
2535
0
    return parser.Error("fatal: invalid enum underlying type");
2536
519k
  }
2537
2538
  EnumValBuilder(Parser& _parser, EnumDef& _enum_def)
2539
95.3k
      : parser(_parser),
2540
95.3k
        enum_def(_enum_def),
2541
95.3k
        temp(nullptr),
2542
95.3k
        user_value(false) {}
2543
2544
95.3k
  ~EnumValBuilder() { delete temp; }
2545
2546
  Parser& parser;
2547
  EnumDef& enum_def;
2548
  EnumVal* temp;
2549
  bool user_value;
2550
};
2551
2552
CheckedError Parser::ParseEnum(const bool is_union, EnumDef** dest,
2553
96.1k
                               const char* filename) {
2554
96.1k
  std::vector<std::string> enum_comment = doc_comment_;
2555
96.1k
  NEXT();
2556
96.1k
  std::string enum_name = attribute_;
2557
96.1k
  EXPECT(kTokenIdentifier);
2558
96.0k
  EnumDef* enum_def;
2559
96.0k
  ECHECK(StartEnum(enum_name, is_union, &enum_def));
2560
95.9k
  if (filename != nullptr && !opts.project_root.empty()) {
2561
0
    enum_def->declaration_file = &GetPooledString(FilePath(
2562
0
        opts.project_root, filename, opts.binary_schema_absolute_paths));
2563
0
  }
2564
95.9k
  enum_def->doc_comment = enum_comment;
2565
95.9k
  if (!opts.proto_mode) {
2566
    // Give specialized error message, since this type spec used to
2567
    // be optional in the first FlatBuffers release.
2568
95.9k
    bool explicit_underlying_type = false;
2569
95.9k
    if (!Is(':')) {
2570
      // Enum is forced to have an explicit underlying type in declaration.
2571
75.6k
      if (!is_union) {
2572
146
        return Error(
2573
146
            "must specify the underlying integer type for this"
2574
146
            " enum (e.g. \': short\', which was the default).");
2575
146
      }
2576
75.6k
    } else {
2577
      // Union underlying type is only supported for cpp
2578
20.2k
      if (is_union && !SupportsUnionUnderlyingType()) {
2579
0
        return Error(
2580
0
            "Underlying type for union is not yet supported in at least one of "
2581
0
            "the specified programming languages.");
2582
0
      }
2583
20.2k
      NEXT();
2584
20.2k
      explicit_underlying_type = true;
2585
20.2k
    }
2586
2587
95.8k
    if (explicit_underlying_type) {
2588
      // Specify the integer type underlying this enum.
2589
20.2k
      ECHECK(ParseType(enum_def->underlying_type));
2590
20.0k
      if (!IsInteger(enum_def->underlying_type.base_type) ||
2591
19.9k
          IsBool(enum_def->underlying_type.base_type)) {
2592
154
        return Error("underlying " + std::string(is_union ? "union" : "enum") +
2593
154
                     "type must be integral");
2594
154
      }
2595
2596
      // Make this type refer back to the enum it was derived from.
2597
19.9k
      enum_def->underlying_type.enum_def = enum_def;
2598
19.9k
    }
2599
95.8k
  }
2600
95.4k
  ECHECK(ParseMetaData(&enum_def->attributes));
2601
95.3k
  const auto underlying_type = enum_def->underlying_type.base_type;
2602
95.3k
  if (enum_def->attributes.Lookup("bit_flags") &&
2603
562
      !IsUnsigned(underlying_type)) {
2604
    // todo: Convert to the Error in the future?
2605
269
    Warning("underlying type of bit_flags enum must be unsigned");
2606
269
  }
2607
95.3k
  if (enum_def->attributes.Lookup("force_align")) {
2608
1
    return Error("`force_align` is not a valid attribute for Enums. ");
2609
1
  }
2610
95.3k
  EnumValBuilder evb(*this, *enum_def);
2611
95.3k
  EXPECT('{');
2612
  // A lot of code generatos expect that an enum is not-empty.
2613
95.0k
  if ((is_union || Is('}')) && !opts.proto_mode) {
2614
84.2k
    evb.CreateEnumerator("NONE");
2615
84.2k
    ECHECK(evb.AcceptEnumerator());
2616
84.2k
  }
2617
95.0k
  std::set<std::pair<BaseType, StructDef*>> union_types;
2618
508k
  while (!Is('}')) {
2619
435k
    if (opts.proto_mode && attribute_ == "option") {
2620
0
      ECHECK(ParseProtoOption());
2621
435k
    } else {
2622
435k
      auto& ev = *evb.CreateEnumerator(attribute_);
2623
435k
      auto full_name = ev.name;
2624
435k
      ev.doc_comment = doc_comment_;
2625
435k
      EXPECT(kTokenIdentifier);
2626
435k
      if (is_union) {
2627
298k
        ECHECK(ParseNamespacing(&full_name, &ev.name));
2628
298k
        if (opts.union_value_namespacing) {
2629
          // Since we can't namespace the actual enum identifiers, turn
2630
          // namespace parts into part of the identifier.
2631
298k
          ev.name = full_name;
2632
298k
          std::replace(ev.name.begin(), ev.name.end(), '.', '_');
2633
298k
        }
2634
298k
        if (Is(':')) {
2635
3.35k
          NEXT();
2636
3.35k
          ECHECK(ParseType(ev.union_type));
2637
3.34k
          if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
2638
62
              ev.union_type.base_type != BASE_TYPE_STRING)
2639
27
            return Error("union value type may only be table/struct/string");
2640
294k
        } else {
2641
294k
          ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
2642
294k
        }
2643
298k
        if (!enum_def->uses_multiple_type_instances) {
2644
296k
          auto ins = union_types.insert(std::make_pair(
2645
296k
              ev.union_type.base_type, ev.union_type.struct_def));
2646
296k
          enum_def->uses_multiple_type_instances = (false == ins.second);
2647
296k
        }
2648
298k
      }
2649
2650
435k
      if (Is('=')) {
2651
118k
        NEXT();
2652
118k
        ECHECK(evb.AssignEnumeratorValue(attribute_));
2653
118k
        EXPECT(kTokenIntegerConstant);
2654
118k
      }
2655
2656
435k
      if (opts.proto_mode && Is('[')) {
2657
0
        NEXT();
2658
        // ignore attributes on enums.
2659
0
        while (token_ != ']') NEXT();
2660
0
        NEXT();
2661
435k
      } else {
2662
        // parse attributes in fbs schema
2663
435k
        ECHECK(ParseMetaData(&ev.attributes));
2664
435k
      }
2665
2666
435k
      ECHECK(evb.AcceptEnumerator());
2667
434k
    }
2668
434k
    if (!Is(opts.proto_mode ? ';' : ',')) break;
2669
413k
    NEXT();
2670
413k
  }
2671
93.9k
  EXPECT('}');
2672
2673
  // At this point, the enum can be empty if input is invalid proto-file.
2674
93.2k
  if (!enum_def->size())
2675
0
    return Error("incomplete enum declaration, values not found");
2676
2677
93.2k
  if (enum_def->attributes.Lookup("bit_flags")) {
2678
539
    const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type));
2679
2.69k
    for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
2680
2.22k
         ++it) {
2681
2.22k
      auto ev = *it;
2682
2.22k
      const auto u = ev->GetAsUInt64();
2683
      // Stop manipulations with the sign.
2684
2.22k
      if (!IsUnsigned(underlying_type) && u == (base_width - 1))
2685
2
        return Error("underlying type of bit_flags enum must be unsigned");
2686
2.22k
      if (u >= base_width)
2687
68
        return Error("bit flag out of range of underlying integral type");
2688
2.15k
      enum_def->ChangeEnumValue(ev, 1ULL << u);
2689
2.15k
    }
2690
539
  }
2691
2692
93.2k
  enum_def->SortByValue();  // Must be sorted to use MinValue/MaxValue.
2693
2694
  // Ensure enum value uniqueness.
2695
93.2k
  auto prev_it = enum_def->Vals().begin();
2696
449k
  for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) {
2697
359k
    auto prev_ev = *prev_it;
2698
359k
    auto ev = *it;
2699
359k
    if (prev_ev->GetAsUInt64() == ev->GetAsUInt64())
2700
2.38k
      return Error("all enum values must be unique: " + prev_ev->name +
2701
2.38k
                   " and " + ev->name + " are both " +
2702
2.38k
                   NumToString(ev->GetAsInt64()));
2703
359k
  }
2704
2705
90.8k
  if (dest) *dest = enum_def;
2706
90.8k
  const auto qualified_name =
2707
90.8k
      current_namespace_->GetFullyQualifiedName(enum_def->name);
2708
90.8k
  if (types_.Add(qualified_name, new Type(BASE_TYPE_UNION, nullptr, enum_def)))
2709
1
    return Error("datatype already exists: " + qualified_name);
2710
90.8k
  return NoError();
2711
90.8k
}
2712
2713
176k
CheckedError Parser::StartStruct(const std::string& name, StructDef** dest) {
2714
176k
  auto& struct_def = *LookupCreateStruct(name, true, true);
2715
176k
  if (!struct_def.predecl)
2716
7
    return Error("datatype already exists: " +
2717
7
                 current_namespace_->GetFullyQualifiedName(name));
2718
176k
  struct_def.predecl = false;
2719
176k
  struct_def.name = name;
2720
176k
  struct_def.file = file_being_parsed_;
2721
  // Move this struct to the back of the vector just in case it was predeclared,
2722
  // to preserve declaration order.
2723
176k
  *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
2724
176k
      &struct_def;
2725
176k
  *dest = &struct_def;
2726
176k
  return NoError();
2727
176k
}
2728
2729
CheckedError Parser::CheckClash(std::vector<FieldDef*>& fields,
2730
                                StructDef* struct_def, const char* suffix,
2731
1.04M
                                BaseType basetype) {
2732
1.04M
  auto len = strlen(suffix);
2733
2.05M
  for (auto it = fields.begin(); it != fields.end(); ++it) {
2734
1.01M
    auto& fname = (*it)->name;
2735
1.01M
    if (fname.length() > len &&
2736
67.5k
        fname.compare(fname.length() - len, len, suffix) == 0 &&
2737
16.9k
        (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
2738
2.17k
      auto field =
2739
2.17k
          struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
2740
2.17k
      if (field && field->value.type.base_type == basetype)
2741
10
        return Error("Field " + fname +
2742
10
                     " would clash with generated functions for field " +
2743
10
                     field->name);
2744
2.17k
    }
2745
1.01M
  }
2746
1.04M
  return NoError();
2747
1.04M
}
2748
2749
0
std::vector<IncludedFile> Parser::GetIncludedFiles() const {
2750
0
  const auto it = files_included_per_file_.find(file_being_parsed_);
2751
0
  if (it == files_included_per_file_.end()) {
2752
0
    return {};
2753
0
  }
2754
2755
0
  return {it->second.cbegin(), it->second.cend()};
2756
0
}
2757
2758
0
bool Parser::HasCircularStructDependency() {
2759
0
  std::function<bool(StructDef*)> visit =
2760
0
      [&](StructDef* struct_def) {
2761
        // Only consider fixed structs and structs we have yet to check
2762
0
        if (!struct_def->fixed || struct_def->cycle_status == StructDef::CycleStatus::Checked) {
2763
0
          return false;
2764
0
        }
2765
2766
0
        if (struct_def->cycle_status == StructDef::CycleStatus::InProgress) {
2767
          // cycle found
2768
0
          return true;
2769
0
        }
2770
2771
0
        struct_def->cycle_status = StructDef::CycleStatus::InProgress;
2772
2773
0
        for (const auto& field : struct_def->fields.vec) {
2774
0
          if (field->value.type.base_type == BASE_TYPE_STRUCT) {
2775
0
            if (visit(field->value.type.struct_def)) {
2776
0
              return true;  // Cycle detected in recursion.
2777
0
            }
2778
0
          }
2779
0
        }
2780
2781
0
        struct_def->cycle_status = StructDef::CycleStatus::Checked;
2782
0
        return false;  // No cycle detected.
2783
0
      };
2784
2785
0
  for (const auto& struct_def : structs_.vec) {
2786
0
    if (visit(struct_def)) {
2787
0
      return true;  // Cycle detected.
2788
0
    }
2789
0
  }
2790
2791
0
  return false;  // No cycle detected.
2792
0
}
2793
2794
0
bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions& opts) {
2795
0
  static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
2796
0
      IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
2797
0
      IDLOptions::kKotlin | IDLOptions::kKotlinKmp | IDLOptions::kCpp |
2798
0
      IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kTs |
2799
0
      IDLOptions::kBinary | IDLOptions::kGo | IDLOptions::kPython |
2800
0
      IDLOptions::kJson | IDLOptions::kNim;
2801
0
  unsigned long langs = opts.lang_to_generate;
2802
0
  return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
2803
0
}
2804
828
bool Parser::SupportsOptionalScalars() const {
2805
  // Check in general if a language isn't specified.
2806
828
  return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
2807
828
}
2808
2809
89
bool Parser::SupportsDefaultVectorsAndStrings() const {
2810
89
  static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
2811
89
      IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim |
2812
89
      IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson |
2813
89
      IDLOptions::kTs;
2814
89
  return !(opts.lang_to_generate & ~supported_langs);
2815
89
}
2816
2817
1.79k
bool Parser::SupportsAdvancedUnionFeatures() const {
2818
1.79k
  return (opts.lang_to_generate &
2819
1.79k
          ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp |
2820
1.79k
            IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin |
2821
1.79k
            IDLOptions::kBinary | IDLOptions::kSwift | IDLOptions::kNim |
2822
1.79k
            IDLOptions::kJson | IDLOptions::kKotlinKmp)) == 0;
2823
1.79k
}
2824
2825
955
bool Parser::SupportsAdvancedArrayFeatures() const {
2826
955
  return (opts.lang_to_generate &
2827
955
          ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
2828
955
            IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
2829
955
            IDLOptions::kBinary | IDLOptions::kRust | IDLOptions::kTs |
2830
955
            IDLOptions::kSwift)) == 0;
2831
955
}
2832
2833
294
bool Parser::Supports64BitOffsets() const {
2834
294
  return (opts.lang_to_generate &
2835
294
          ~(IDLOptions::kCpp | IDLOptions::kJson | IDLOptions::kBinary)) == 0;
2836
294
}
2837
2838
8.75k
bool Parser::SupportsUnionUnderlyingType() const {
2839
8.75k
  return (opts.lang_to_generate &
2840
8.75k
          ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kBinary)) == 0;
2841
8.75k
}
2842
2843
18.1k
Namespace* Parser::UniqueNamespace(Namespace* ns) {
2844
228k
  for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
2845
211k
    if (ns->components == (*it)->components) {
2846
963
      delete ns;
2847
963
      return *it;
2848
963
    }
2849
211k
  }
2850
17.1k
  namespaces_.push_back(ns);
2851
17.1k
  return ns;
2852
18.1k
}
2853
2854
46
std::string Parser::UnqualifiedName(const std::string& full_qualified_name) {
2855
46
  Namespace* ns = new Namespace();
2856
2857
46
  std::size_t current, previous = 0;
2858
46
  current = full_qualified_name.find('.');
2859
132
  while (current != std::string::npos) {
2860
86
    ns->components.push_back(
2861
86
        full_qualified_name.substr(previous, current - previous));
2862
86
    previous = current + 1;
2863
86
    current = full_qualified_name.find('.', previous);
2864
86
  }
2865
46
  current_namespace_ = UniqueNamespace(ns);
2866
46
  return full_qualified_name.substr(previous, current - previous);
2867
46
}
2868
2869
178k
CheckedError Parser::ParseDecl(const char* filename) {
2870
178k
  std::vector<std::string> dc = doc_comment_;
2871
178k
  bool fixed = IsIdent("struct");
2872
178k
  if (!fixed && !IsIdent("table")) return Error("declaration expected");
2873
176k
  NEXT();
2874
176k
  std::string name = attribute_;
2875
176k
  EXPECT(kTokenIdentifier);
2876
176k
  StructDef* struct_def;
2877
176k
  ECHECK(StartStruct(name, &struct_def));
2878
176k
  struct_def->doc_comment = dc;
2879
176k
  struct_def->fixed = fixed;
2880
176k
  if (filename && !opts.project_root.empty()) {
2881
0
    struct_def->declaration_file = &GetPooledString(FilePath(
2882
0
        opts.project_root, filename, opts.binary_schema_absolute_paths));
2883
0
  }
2884
176k
  ECHECK(ParseMetaData(&struct_def->attributes));
2885
176k
  struct_def->sortbysize =
2886
176k
      struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
2887
176k
  EXPECT('{');
2888
336k
  while (token_ != '}') ECHECK(ParseField(*struct_def));
2889
173k
  if (fixed) {
2890
999
    const auto force_align = struct_def->attributes.Lookup("force_align");
2891
999
    if (force_align) {
2892
319
      size_t align;
2893
319
      ECHECK(ParseAlignAttribute(force_align->constant, struct_def->minalign,
2894
319
                                 &align));
2895
204
      struct_def->minalign = align;
2896
204
    }
2897
884
    if (!struct_def->bytesize) return Error("size 0 structs not allowed");
2898
884
  }
2899
173k
  struct_def->PadLastField(struct_def->minalign);
2900
  // Check if this is a table that has manual id assignments
2901
173k
  auto& fields = struct_def->fields.vec;
2902
173k
  if (!fixed && fields.size()) {
2903
133k
    size_t num_id_fields = 0;
2904
307k
    for (auto it = fields.begin(); it != fields.end(); ++it) {
2905
174k
      if ((*it)->attributes.Lookup("id")) num_id_fields++;
2906
174k
    }
2907
    // If any fields have ids..
2908
133k
    if (num_id_fields || opts.require_explicit_ids) {
2909
      // Then all fields must have them.
2910
330
      if (num_id_fields != fields.size()) {
2911
1
        if (opts.require_explicit_ids) {
2912
0
          return Error(
2913
0
              "all fields must have an 'id' attribute when "
2914
0
              "--require-explicit-ids is used");
2915
1
        } else {
2916
1
          return Error(
2917
1
              "either all fields or no fields must have an 'id' attribute");
2918
1
        }
2919
1
      }
2920
      // Simply sort by id, then the fields are the same as if no ids had
2921
      // been specified.
2922
329
      std::sort(fields.begin(), fields.end(), compareFieldDefs);
2923
      // Verify we have a contiguous set, and reassign vtable offsets.
2924
329
      FLATBUFFERS_ASSERT(fields.size() <=
2925
329
                         flatbuffers::numeric_limits<voffset_t>::max());
2926
765
      for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) {
2927
718
        auto& field = *fields[i];
2928
718
        const auto& id_str = field.attributes.Lookup("id")->constant;
2929
2930
        // Metadata values have a dynamic type, they can be `float`, 'int', or
2931
        // 'string`.
2932
        // The FieldIndexToOffset(i) expects the voffset_t so `id` is limited by
2933
        // this type.
2934
718
        voffset_t id = 0;
2935
718
        const auto done = !atot(id_str.c_str(), *this, &id).Check();
2936
718
        if (!done)
2937
38
          return Error("field id\'s must be non-negative number, field: " +
2938
38
                       field.name + ", id: " + id_str);
2939
680
        if (i != id)
2940
244
          return Error("field id\'s must be consecutive from 0, id " +
2941
244
                       NumToString(i) + " missing or set twice, field: " +
2942
244
                       field.name + ", id: " + id_str);
2943
436
        field.value.offset = FieldIndexToOffset(i);
2944
436
      }
2945
329
    }
2946
133k
  }
2947
2948
173k
  ECHECK(
2949
173k
      CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
2950
173k
  ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
2951
173k
  ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
2952
173k
  ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
2953
173k
  ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
2954
173k
  ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
2955
173k
  EXPECT('}');
2956
173k
  const auto qualified_name =
2957
173k
      current_namespace_->GetFullyQualifiedName(struct_def->name);
2958
173k
  if (types_.Add(qualified_name,
2959
173k
                 new Type(BASE_TYPE_STRUCT, struct_def, nullptr)))
2960
2
    return Error("datatype already exists: " + qualified_name);
2961
173k
  return NoError();
2962
173k
}
2963
2964
2.76k
CheckedError Parser::ParseService(const char* filename) {
2965
2.76k
  std::vector<std::string> service_comment = doc_comment_;
2966
2.76k
  NEXT();
2967
2.76k
  auto service_name = attribute_;
2968
2.76k
  EXPECT(kTokenIdentifier);
2969
2.76k
  auto& service_def = *new ServiceDef();
2970
2.76k
  service_def.name = service_name;
2971
2.76k
  service_def.file = file_being_parsed_;
2972
2.76k
  service_def.doc_comment = service_comment;
2973
2.76k
  service_def.defined_namespace = current_namespace_;
2974
2.76k
  if (filename != nullptr && !opts.project_root.empty()) {
2975
0
    service_def.declaration_file = &GetPooledString(FilePath(
2976
0
        opts.project_root, filename, opts.binary_schema_absolute_paths));
2977
0
  }
2978
2.76k
  if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
2979
2.76k
                    &service_def))
2980
5
    return Error("service already exists: " + service_name);
2981
2.76k
  ECHECK(ParseMetaData(&service_def.attributes));
2982
2.75k
  EXPECT('{');
2983
7.82k
  do {
2984
7.82k
    std::vector<std::string> doc_comment = doc_comment_;
2985
7.82k
    auto rpc_name = attribute_;
2986
7.82k
    EXPECT(kTokenIdentifier);
2987
7.79k
    EXPECT('(');
2988
7.74k
    Type reqtype, resptype;
2989
7.74k
    ECHECK(ParseTypeIdent(reqtype));
2990
7.73k
    EXPECT(')');
2991
7.73k
    EXPECT(':');
2992
7.72k
    ECHECK(ParseTypeIdent(resptype));
2993
7.72k
    if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
2994
7.72k
        resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
2995
5
      return Error("rpc request and response types must be tables");
2996
7.71k
    auto& rpc = *new RPCCall();
2997
7.71k
    rpc.name = rpc_name;
2998
7.71k
    rpc.request = reqtype.struct_def;
2999
7.71k
    rpc.response = resptype.struct_def;
3000
7.71k
    rpc.doc_comment = doc_comment;
3001
7.71k
    if (service_def.calls.Add(rpc_name, &rpc))
3002
17
      return Error("rpc already exists: " + rpc_name);
3003
7.70k
    ECHECK(ParseMetaData(&rpc.attributes));
3004
7.69k
    EXPECT(';');
3005
7.55k
  } while (token_ != '}');
3006
2.36k
  NEXT();
3007
2.36k
  return NoError();
3008
2.36k
}
3009
3010
119k
bool Parser::SetRootType(const char* name) {
3011
119k
  root_struct_def_ = LookupStruct(name);
3012
119k
  if (!root_struct_def_)
3013
412
    root_struct_def_ =
3014
412
        LookupStruct(current_namespace_->GetFullyQualifiedName(name));
3015
119k
  return root_struct_def_ != nullptr;
3016
119k
}
3017
3018
0
void Parser::MarkGenerated() {
3019
  // This function marks all existing definitions as having already
3020
  // been generated, which signals no code for included files should be
3021
  // generated.
3022
0
  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
3023
0
    (*it)->generated = true;
3024
0
  }
3025
0
  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
3026
0
    if (!(*it)->predecl) {
3027
0
      (*it)->generated = true;
3028
0
    }
3029
0
  }
3030
0
  for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
3031
0
    (*it)->generated = true;
3032
0
  }
3033
0
}
3034
3035
18.1k
CheckedError Parser::ParseNamespace() {
3036
18.1k
  NEXT();
3037
18.1k
  auto ns = new Namespace();
3038
18.1k
  namespaces_.push_back(ns);  // Store it here to not leak upon error.
3039
18.1k
  if (token_ != ';') {
3040
51.1k
    for (;;) {
3041
51.1k
      ns->components.push_back(attribute_);
3042
51.1k
      EXPECT(kTokenIdentifier);
3043
51.1k
      if (Is('.')) NEXT() else break;
3044
51.1k
    }
3045
17.7k
  }
3046
18.0k
  namespaces_.pop_back();
3047
18.0k
  current_namespace_ = UniqueNamespace(ns);
3048
18.0k
  EXPECT(';');
3049
17.9k
  return NoError();
3050
18.0k
}
3051
3052
// Best effort parsing of .proto declarations, with the aim to turn them
3053
// in the closest corresponding FlatBuffer equivalent.
3054
// We parse everything as identifiers instead of keywords, since we don't
3055
// want protobuf keywords to become invalid identifiers in FlatBuffers.
3056
0
CheckedError Parser::ParseProtoDecl() {
3057
0
  bool isextend = IsIdent("extend");
3058
0
  if (IsIdent("package")) {
3059
    // These are identical in syntax to FlatBuffer's namespace decl.
3060
0
    ECHECK(ParseNamespace());
3061
0
  } else if (IsIdent("message") || isextend) {
3062
0
    std::vector<std::string> struct_comment = doc_comment_;
3063
0
    NEXT();
3064
0
    StructDef* struct_def = nullptr;
3065
0
    Namespace* parent_namespace = nullptr;
3066
0
    if (isextend) {
3067
0
      if (Is('.')) NEXT();  // qualified names may start with a . ?
3068
0
      auto id = attribute_;
3069
0
      EXPECT(kTokenIdentifier);
3070
0
      ECHECK(ParseNamespacing(&id, nullptr));
3071
0
      struct_def = LookupCreateStruct(id, false);
3072
0
      if (!struct_def)
3073
0
        return Error("cannot extend unknown message type: " + id);
3074
0
    } else {
3075
0
      std::string name = attribute_;
3076
0
      EXPECT(kTokenIdentifier);
3077
0
      ECHECK(StartStruct(name, &struct_def));
3078
      // Since message definitions can be nested, we create a new namespace.
3079
0
      auto ns = new Namespace();
3080
      // Copy of current namespace.
3081
0
      *ns = *current_namespace_;
3082
      // But with current message name.
3083
0
      ns->components.push_back(name);
3084
0
      ns->from_table++;
3085
0
      parent_namespace = current_namespace_;
3086
0
      current_namespace_ = UniqueNamespace(ns);
3087
0
    }
3088
0
    struct_def->doc_comment = struct_comment;
3089
0
    ECHECK(ParseProtoFields(struct_def, isextend, false));
3090
0
    if (!isextend) {
3091
0
      current_namespace_ = parent_namespace;
3092
0
    }
3093
0
    if (Is(';')) NEXT();
3094
0
  } else if (IsIdent("enum")) {
3095
    // These are almost the same, just with different terminator:
3096
0
    EnumDef* enum_def;
3097
0
    ECHECK(ParseEnum(false, &enum_def, nullptr));
3098
0
    if (Is(';')) NEXT();
3099
    // Temp: remove any duplicates, as .fbs files can't handle them.
3100
0
    enum_def->RemoveDuplicates();
3101
0
  } else if (IsIdent("syntax")) {  // Skip these.
3102
0
    NEXT();
3103
0
    EXPECT('=');
3104
0
    EXPECT(kTokenStringConstant);
3105
0
    EXPECT(';');
3106
0
  } else if (IsIdent("option")) {  // Skip these.
3107
0
    ECHECK(ParseProtoOption());
3108
0
    EXPECT(';');
3109
0
  } else if (IsIdent("service")) {  // Skip these.
3110
0
    NEXT();
3111
0
    EXPECT(kTokenIdentifier);
3112
0
    ECHECK(ParseProtoCurliesOrIdent());
3113
0
  } else {
3114
0
    return Error("don\'t know how to parse .proto declaration starting with " +
3115
0
                 TokenToStringId(token_));
3116
0
  }
3117
0
  return NoError();
3118
0
}
3119
3120
CheckedError Parser::StartEnum(const std::string& name, bool is_union,
3121
96.0k
                               EnumDef** dest) {
3122
96.0k
  auto& enum_def = *new EnumDef();
3123
96.0k
  enum_def.name = name;
3124
96.0k
  enum_def.file = file_being_parsed_;
3125
96.0k
  enum_def.doc_comment = doc_comment_;
3126
96.0k
  enum_def.is_union = is_union;
3127
96.0k
  enum_def.defined_namespace = current_namespace_;
3128
96.0k
  const auto qualified_name = current_namespace_->GetFullyQualifiedName(name);
3129
96.0k
  if (enums_.Add(qualified_name, &enum_def))
3130
71
    return Error("enum already exists: " + qualified_name);
3131
95.9k
  enum_def.underlying_type.base_type =
3132
95.9k
      is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT;
3133
95.9k
  enum_def.underlying_type.enum_def = &enum_def;
3134
95.9k
  if (dest) *dest = &enum_def;
3135
95.9k
  return NoError();
3136
96.0k
}
3137
3138
CheckedError Parser::ParseProtoFields(StructDef* struct_def, bool isextend,
3139
0
                                      bool inside_oneof) {
3140
0
  EXPECT('{');
3141
0
  while (token_ != '}') {
3142
0
    if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
3143
      // Nested declarations.
3144
0
      ECHECK(ParseProtoDecl());
3145
0
    } else if (IsIdent("extensions")) {  // Skip these.
3146
0
      NEXT();
3147
0
      EXPECT(kTokenIntegerConstant);
3148
0
      if (Is(kTokenIdentifier)) {
3149
0
        NEXT();  // to
3150
0
        NEXT();  // num
3151
0
      }
3152
0
      EXPECT(';');
3153
0
    } else if (IsIdent("option")) {  // Skip these.
3154
0
      ECHECK(ParseProtoOption());
3155
0
      EXPECT(';');
3156
0
    } else if (IsIdent("reserved")) {  // Skip these.
3157
      /**
3158
       * Reserved proto ids can be comma seperated (e.g. 1,2,4,5;)
3159
       * or range based (e.g. 9 to 11;)
3160
       * or combination of them (e.g. 1,2,9 to 11,4,5;)
3161
       * It will be ended by a semicolon.
3162
       */
3163
0
      NEXT();
3164
0
      bool range = false;
3165
0
      voffset_t from = 0;
3166
3167
0
      while (!Is(';')) {
3168
0
        if (token_ == kTokenIntegerConstant) {
3169
0
          voffset_t attribute = 0;
3170
0
          bool done = StringToNumber(attribute_.c_str(), &attribute);
3171
0
          if (!done)
3172
0
            return Error("Protobuf has non positive number in reserved ids");
3173
3174
0
          if (range) {
3175
0
            for (uint32_t id = static_cast<uint32_t>(from) + 1;
3176
0
                 id <= static_cast<uint32_t>(attribute); id++) {
3177
0
              struct_def->reserved_ids.push_back(static_cast<voffset_t>(id));
3178
0
            }
3179
3180
0
            range = false;
3181
0
          } else {
3182
0
            struct_def->reserved_ids.push_back(attribute);
3183
0
          }
3184
3185
0
          from = attribute;
3186
0
        }
3187
3188
0
        if (attribute_ == "to") range = true;
3189
3190
0
        NEXT();
3191
0
      }  // A variety of formats, just skip.
3192
3193
0
      NEXT();
3194
0
    } else if (IsIdent("map")) {
3195
0
      ECHECK(ParseProtoMapField(struct_def));
3196
0
    } else {
3197
0
      std::vector<std::string> field_comment = doc_comment_;
3198
      // Parse the qualifier.
3199
0
      bool required = false;
3200
0
      bool repeated = false;
3201
0
      bool oneof = false;
3202
0
      if (!inside_oneof) {
3203
0
        if (IsIdent("optional")) {
3204
          // This is the default.
3205
0
          NEXT();
3206
0
        } else if (IsIdent("required")) {
3207
0
          required = true;
3208
0
          NEXT();
3209
0
        } else if (IsIdent("repeated")) {
3210
0
          repeated = true;
3211
0
          NEXT();
3212
0
        } else if (IsIdent("oneof")) {
3213
0
          oneof = true;
3214
0
          NEXT();
3215
0
        } else {
3216
          // can't error, proto3 allows decls without any of the above.
3217
0
        }
3218
0
      }
3219
0
      StructDef* anonymous_struct = nullptr;
3220
0
      EnumDef* oneof_union = nullptr;
3221
0
      Type type;
3222
0
      if (IsIdent("group") || oneof) {
3223
0
        if (!oneof) NEXT();
3224
0
        if (oneof && opts.proto_oneof_union) {
3225
0
          auto name = ConvertCase(attribute_, Case::kUpperCamel) + "Union";
3226
0
          ECHECK(StartEnum(name, true, &oneof_union));
3227
0
          type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
3228
0
        } else {
3229
0
          auto name = "Anonymous" + NumToString(anonymous_counter_++);
3230
0
          ECHECK(StartStruct(name, &anonymous_struct));
3231
0
          type = Type(BASE_TYPE_STRUCT, anonymous_struct);
3232
0
        }
3233
0
      } else {
3234
0
        ECHECK(ParseTypeFromProtoType(&type));
3235
0
      }
3236
      // Repeated elements get mapped to a vector.
3237
0
      if (repeated) {
3238
0
        type.element = type.base_type;
3239
0
        type.base_type = BASE_TYPE_VECTOR;
3240
0
        if (type.element == BASE_TYPE_VECTOR) {
3241
          // We have a vector or vectors, which FlatBuffers doesn't support.
3242
          // For now make it a vector of string (since the source is likely
3243
          // "repeated bytes").
3244
          // TODO(wvo): A better solution would be to wrap this in a table.
3245
0
          type.element = BASE_TYPE_STRING;
3246
0
        }
3247
0
      }
3248
0
      std::string name = attribute_;
3249
0
      EXPECT(kTokenIdentifier);
3250
0
      std::string proto_field_id;
3251
0
      if (!oneof) {
3252
        // Parse the field id. Since we're just translating schemas, not
3253
        // any kind of binary compatibility, we can safely ignore these, and
3254
        // assign our own.
3255
0
        EXPECT('=');
3256
0
        proto_field_id = attribute_;
3257
0
        EXPECT(kTokenIntegerConstant);
3258
0
      }
3259
0
      FieldDef* field = nullptr;
3260
0
      if (isextend) {
3261
        // We allow a field to be re-defined when extending.
3262
        // TODO: are there situations where that is problematic?
3263
0
        field = struct_def->fields.Lookup(name);
3264
0
      }
3265
0
      if (!field) ECHECK(AddField(*struct_def, name, type, &field));
3266
0
      field->doc_comment = field_comment;
3267
0
      if (!proto_field_id.empty() || oneof) {
3268
0
        auto val = new Value();
3269
0
        val->constant = proto_field_id;
3270
0
        field->attributes.Add("id", val);
3271
0
      }
3272
0
      if (!IsScalar(type.base_type) && required) {
3273
0
        field->presence = FieldDef::kRequired;
3274
0
      }
3275
      // See if there's a default specified.
3276
0
      if (Is('[')) {
3277
0
        NEXT();
3278
0
        for (;;) {
3279
0
          auto key = attribute_;
3280
0
          ECHECK(ParseProtoKey());
3281
0
          EXPECT('=');
3282
0
          auto val = attribute_;
3283
0
          ECHECK(ParseProtoCurliesOrIdent());
3284
0
          if (key == "default") {
3285
            // Temp: skip non-numeric and non-boolean defaults (enums).
3286
0
            auto numeric = strpbrk(val.c_str(), "0123456789-+.");
3287
0
            if (IsFloat(type.base_type) &&
3288
0
                (val == "inf" || val == "+inf" || val == "-inf")) {
3289
              // Prefer to be explicit with +inf.
3290
0
              field->value.constant = val == "inf" ? "+inf" : val;
3291
0
            } else if (IsScalar(type.base_type) && numeric == val.c_str()) {
3292
0
              field->value.constant = val;
3293
0
            } else if (val == "true") {
3294
0
              field->value.constant = val;
3295
0
            }  // "false" is default, no need to handle explicitly.
3296
0
          } else if (key == "deprecated") {
3297
0
            field->deprecated = val == "true";
3298
0
          }
3299
0
          if (!Is(',')) break;
3300
0
          NEXT();
3301
0
        }
3302
0
        EXPECT(']');
3303
0
      }
3304
0
      if (anonymous_struct) {
3305
0
        ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
3306
0
        if (Is(';')) NEXT();
3307
0
      } else if (oneof_union) {
3308
        // Parse into a temporary StructDef, then transfer fields into an
3309
        // EnumDef describing the oneof as a union.
3310
0
        StructDef oneof_struct;
3311
0
        ECHECK(ParseProtoFields(&oneof_struct, false, oneof));
3312
0
        if (Is(';')) NEXT();
3313
0
        for (auto field_it = oneof_struct.fields.vec.begin();
3314
0
             field_it != oneof_struct.fields.vec.end(); ++field_it) {
3315
0
          const auto& oneof_field = **field_it;
3316
0
          const auto& oneof_type = oneof_field.value.type;
3317
0
          if (oneof_type.base_type != BASE_TYPE_STRUCT ||
3318
0
              !oneof_type.struct_def || oneof_type.struct_def->fixed)
3319
0
            return Error("oneof '" + name +
3320
0
                         "' cannot be mapped to a union because member '" +
3321
0
                         oneof_field.name + "' is not a table type.");
3322
0
          EnumValBuilder evb(*this, *oneof_union);
3323
0
          auto ev = evb.CreateEnumerator(oneof_type.struct_def->name);
3324
0
          ev->union_type = oneof_type;
3325
0
          ev->doc_comment = oneof_field.doc_comment;
3326
0
          ECHECK(evb.AcceptEnumerator(oneof_field.name));
3327
0
        }
3328
0
      } else {
3329
0
        EXPECT(';');
3330
0
      }
3331
0
    }
3332
0
  }
3333
0
  NEXT();
3334
0
  return NoError();
3335
0
}
3336
3337
0
CheckedError Parser::ParseProtoMapField(StructDef* struct_def) {
3338
0
  NEXT();
3339
0
  EXPECT('<');
3340
0
  Type key_type;
3341
0
  ECHECK(ParseType(key_type));
3342
0
  EXPECT(',');
3343
0
  Type value_type;
3344
0
  ECHECK(ParseType(value_type));
3345
0
  EXPECT('>');
3346
0
  auto field_name = attribute_;
3347
0
  NEXT();
3348
0
  EXPECT('=');
3349
0
  std::string proto_field_id = attribute_;
3350
0
  EXPECT(kTokenIntegerConstant);
3351
0
  EXPECT(';');
3352
3353
0
  auto entry_table_name = ConvertCase(field_name, Case::kUpperCamel) + "Entry";
3354
0
  StructDef* entry_table;
3355
0
  ECHECK(StartStruct(entry_table_name, &entry_table));
3356
0
  entry_table->has_key = true;
3357
0
  FieldDef* key_field;
3358
0
  ECHECK(AddField(*entry_table, "key", key_type, &key_field));
3359
0
  key_field->key = true;
3360
0
  FieldDef* value_field;
3361
0
  ECHECK(AddField(*entry_table, "value", value_type, &value_field));
3362
3363
0
  Type field_type;
3364
0
  field_type.base_type = BASE_TYPE_VECTOR;
3365
0
  field_type.element = BASE_TYPE_STRUCT;
3366
0
  field_type.struct_def = entry_table;
3367
0
  FieldDef* field;
3368
0
  ECHECK(AddField(*struct_def, field_name, field_type, &field));
3369
0
  if (!proto_field_id.empty()) {
3370
0
    auto val = new Value();
3371
0
    val->constant = proto_field_id;
3372
0
    field->attributes.Add("id", val);
3373
0
  }
3374
3375
0
  return NoError();
3376
0
}
3377
3378
0
CheckedError Parser::ParseProtoKey() {
3379
0
  if (token_ == '(') {
3380
0
    NEXT();
3381
    // Skip "(a.b)" style custom attributes.
3382
0
    while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
3383
0
    EXPECT(')');
3384
0
    while (Is('.')) {
3385
0
      NEXT();
3386
0
      EXPECT(kTokenIdentifier);
3387
0
    }
3388
0
  } else {
3389
0
    EXPECT(kTokenIdentifier);
3390
0
  }
3391
0
  return NoError();
3392
0
}
3393
3394
0
CheckedError Parser::ParseProtoCurliesOrIdent() {
3395
0
  if (Is('{')) {
3396
0
    NEXT();
3397
0
    for (int nesting = 1; nesting;) {
3398
0
      if (token_ == '{')
3399
0
        nesting++;
3400
0
      else if (token_ == '}')
3401
0
        nesting--;
3402
0
      NEXT();
3403
0
    }
3404
0
  } else {
3405
0
    NEXT();  // Any single token.
3406
0
  }
3407
0
  return NoError();
3408
0
}
3409
3410
0
CheckedError Parser::ParseProtoOption() {
3411
0
  NEXT();
3412
0
  ECHECK(ParseProtoKey());
3413
0
  EXPECT('=');
3414
0
  ECHECK(ParseProtoCurliesOrIdent());
3415
0
  return NoError();
3416
0
}
3417
3418
// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
3419
0
CheckedError Parser::ParseTypeFromProtoType(Type* type) {
3420
0
  struct type_lookup {
3421
0
    const char* proto_type;
3422
0
    BaseType fb_type, element;
3423
0
  };
3424
0
  static type_lookup lookup[] = {{"float", BASE_TYPE_FLOAT, BASE_TYPE_NONE},
3425
0
                                 {"double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE},
3426
0
                                 {"int32", BASE_TYPE_INT, BASE_TYPE_NONE},
3427
0
                                 {"int64", BASE_TYPE_LONG, BASE_TYPE_NONE},
3428
0
                                 {"uint32", BASE_TYPE_UINT, BASE_TYPE_NONE},
3429
0
                                 {"uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE},
3430
0
                                 {"sint32", BASE_TYPE_INT, BASE_TYPE_NONE},
3431
0
                                 {"sint64", BASE_TYPE_LONG, BASE_TYPE_NONE},
3432
0
                                 {"fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE},
3433
0
                                 {"fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE},
3434
0
                                 {"sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE},
3435
0
                                 {"sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE},
3436
0
                                 {"bool", BASE_TYPE_BOOL, BASE_TYPE_NONE},
3437
0
                                 {"string", BASE_TYPE_STRING, BASE_TYPE_NONE},
3438
0
                                 {"bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR},
3439
0
                                 {nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE}};
3440
0
  for (auto tl = lookup; tl->proto_type; tl++) {
3441
0
    if (attribute_ == tl->proto_type) {
3442
0
      type->base_type = tl->fb_type;
3443
0
      type->element = tl->element;
3444
0
      NEXT();
3445
0
      return NoError();
3446
0
    }
3447
0
  }
3448
0
  if (Is('.')) NEXT();  // qualified names may start with a . ?
3449
0
  ECHECK(ParseTypeIdent(*type));
3450
0
  return NoError();
3451
0
}
3452
3453
1.32M
CheckedError Parser::SkipAnyJsonValue() {
3454
1.32M
  ParseDepthGuard depth_guard(this);
3455
1.32M
  ECHECK(depth_guard.Check());
3456
3457
1.32M
  switch (token_) {
3458
75.3k
    case '{': {
3459
75.3k
      size_t fieldn_outer = 0;
3460
75.3k
      return ParseTableDelimiters(fieldn_outer, nullptr,
3461
75.3k
                                  [&](const std::string&, size_t& fieldn,
3462
185k
                                      const StructDef*) -> CheckedError {
3463
185k
                                    ECHECK(SkipAnyJsonValue());
3464
185k
                                    fieldn++;
3465
185k
                                    return NoError();
3466
185k
                                  });
3467
0
    }
3468
428k
    case '[': {
3469
428k
      size_t count = 0;
3470
428k
      return ParseVectorDelimiters(
3471
1.10M
          count, [&](size_t&) -> CheckedError { return SkipAnyJsonValue(); });
3472
0
    }
3473
99.1k
    case kTokenStringConstant:
3474
357k
    case kTokenIntegerConstant:
3475
801k
    case kTokenFloatConstant:
3476
801k
      NEXT();
3477
801k
      break;
3478
23.4k
    default:
3479
23.4k
      if (IsIdent("true") || IsIdent("false") || IsIdent("null") ||
3480
23.1k
          IsIdent("inf")) {
3481
23.1k
        NEXT();
3482
23.1k
      } else
3483
329
        return TokenError();
3484
1.32M
  }
3485
824k
  return NoError();
3486
1.32M
}
3487
3488
CheckedError Parser::ParseFlexBufferNumericConstant(
3489
6.29k
    flexbuffers::Builder* builder) {
3490
6.29k
  double d;
3491
6.29k
  if (!StringToNumber(attribute_.c_str(), &d))
3492
34
    return Error("unexpected floating-point constant: " + attribute_);
3493
6.26k
  builder->Double(d);
3494
6.26k
  return NoError();
3495
6.29k
}
3496
3497
2.44M
CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder* builder) {
3498
2.44M
  ParseDepthGuard depth_guard(this);
3499
2.44M
  ECHECK(depth_guard.Check());
3500
3501
2.44M
  switch (token_) {
3502
111k
    case '{': {
3503
111k
      auto start = builder->StartMap();
3504
111k
      size_t fieldn_outer = 0;
3505
111k
      auto err =
3506
111k
          ParseTableDelimiters(fieldn_outer, nullptr,
3507
111k
                               [&](const std::string& name, size_t& fieldn,
3508
479k
                                   const StructDef*) -> CheckedError {
3509
479k
                                 builder->Key(name);
3510
479k
                                 ECHECK(ParseFlexBufferValue(builder));
3511
478k
                                 fieldn++;
3512
478k
                                 return NoError();
3513
479k
                               });
3514
111k
      ECHECK(err);
3515
109k
      builder->EndMap(start);
3516
109k
      if (builder->HasDuplicateKeys())
3517
4.62k
        return Error("FlexBuffers map has duplicate keys");
3518
104k
      break;
3519
109k
    }
3520
681k
    case '[': {
3521
681k
      auto start = builder->StartVector();
3522
681k
      size_t count = 0;
3523
681k
      ECHECK(ParseVectorDelimiters(count, [&](size_t&) -> CheckedError {
3524
681k
        return ParseFlexBufferValue(builder);
3525
681k
      }));
3526
679k
      builder->EndVector(start, false, false);
3527
679k
      break;
3528
681k
    }
3529
26.8k
    case kTokenStringConstant:
3530
26.8k
      builder->String(attribute_);
3531
26.8k
      EXPECT(kTokenStringConstant);
3532
26.8k
      break;
3533
889k
    case kTokenIntegerConstant:
3534
889k
      builder->Int(StringToInt(attribute_.c_str()));
3535
889k
      EXPECT(kTokenIntegerConstant);
3536
889k
      break;
3537
721k
    case kTokenFloatConstant: {
3538
721k
      double d;
3539
721k
      StringToNumber(attribute_.c_str(), &d);
3540
721k
      builder->Double(d);
3541
721k
      EXPECT(kTokenFloatConstant);
3542
721k
      break;
3543
721k
    }
3544
276
    case '-':
3545
1.88k
    case '+': {
3546
      // `[-+]?(nan|inf|infinity)`, see ParseSingleValue().
3547
1.88k
      const auto sign = static_cast<char>(token_);
3548
1.88k
      NEXT();
3549
1.88k
      if (token_ != kTokenIdentifier)
3550
0
        return Error("floating-point constant expected");
3551
1.88k
      attribute_.insert(size_t(0), size_t(1), sign);
3552
1.88k
      ECHECK(ParseFlexBufferNumericConstant(builder));
3553
1.85k
      NEXT();
3554
1.84k
      break;
3555
1.85k
    }
3556
10.2k
    default:
3557
10.2k
      if (IsIdent("true")) {
3558
2.10k
        builder->Bool(true);
3559
2.10k
        NEXT();
3560
8.09k
      } else if (IsIdent("false")) {
3561
1.45k
        builder->Bool(false);
3562
1.45k
        NEXT();
3563
6.64k
      } else if (IsIdent("null")) {
3564
1.80k
        builder->Null();
3565
1.80k
        NEXT();
3566
4.84k
      } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) {
3567
4.40k
        ECHECK(ParseFlexBufferNumericConstant(builder));
3568
4.40k
        NEXT();
3569
4.40k
      } else
3570
435
        return TokenError();
3571
2.44M
  }
3572
2.43M
  return NoError();
3573
2.44M
}
3574
3575
bool Parser::ParseFlexBuffer(const char* source, const char* source_filename,
3576
0
                             flexbuffers::Builder* builder) {
3577
0
  const auto initial_depth = parse_depth_counter_;
3578
0
  (void)initial_depth;
3579
0
  auto ok = !StartParseFile(source, source_filename).Check() &&
3580
0
            !ParseFlexBufferValue(builder).Check();
3581
0
  if (ok) builder->Finish();
3582
0
  FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3583
0
  return ok;
3584
0
}
3585
3586
bool Parser::Parse(const char* source, const char** include_paths,
3587
148k
                   const char* source_filename) {
3588
148k
  const auto initial_depth = parse_depth_counter_;
3589
148k
  (void)initial_depth;
3590
148k
  bool r;
3591
3592
148k
  if (opts.use_flexbuffers) {
3593
0
    r = ParseFlexBuffer(source, source_filename, &flex_builder_);
3594
148k
  } else {
3595
148k
    r = !ParseRoot(source, include_paths, source_filename).Check();
3596
148k
  }
3597
148k
  FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3598
148k
  return r;
3599
148k
}
3600
3601
700k
bool Parser::ParseJson(const char* json, const char* json_filename) {
3602
700k
  const auto initial_depth = parse_depth_counter_;
3603
700k
  (void)initial_depth;
3604
700k
  builder_.Clear();
3605
700k
  const auto done =
3606
700k
      !StartParseFile(json, json_filename).Check() && !DoParseJson().Check();
3607
700k
  FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3608
700k
  return done;
3609
700k
}
3610
3611
0
std::ptrdiff_t Parser::BytesConsumed() const {
3612
0
  return std::distance(source_, prev_cursor_);
3613
0
}
3614
3615
CheckedError Parser::StartParseFile(const char* source,
3616
849k
                                    const char* source_filename) {
3617
849k
  file_being_parsed_ = source_filename ? source_filename : "";
3618
849k
  source_ = source;
3619
849k
  ResetState(source_);
3620
849k
  error_.clear();
3621
849k
  ECHECK(SkipByteOrderMark());
3622
848k
  NEXT();
3623
848k
  if (Is(kTokenEof)) return Error("input file is empty");
3624
847k
  return NoError();
3625
848k
}
3626
3627
CheckedError Parser::ParseRoot(const char* source, const char** include_paths,
3628
148k
                               const char* source_filename) {
3629
148k
  ECHECK(DoParse(source, include_paths, source_filename, nullptr));
3630
3631
  // Check that all types were defined.
3632
303k
  for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
3633
169k
    auto& struct_def = **it;
3634
169k
    if (struct_def.predecl) {
3635
2.54k
      if (opts.proto_mode) {
3636
        // Protos allow enums to be used before declaration, so check if that
3637
        // is the case here.
3638
0
        EnumDef* enum_def = nullptr;
3639
0
        for (size_t components =
3640
0
                 struct_def.defined_namespace->components.size() + 1;
3641
0
             components && !enum_def; components--) {
3642
0
          auto qualified_name =
3643
0
              struct_def.defined_namespace->GetFullyQualifiedName(
3644
0
                  struct_def.name, components - 1);
3645
0
          enum_def = LookupEnum(qualified_name);
3646
0
        }
3647
0
        if (enum_def) {
3648
          // This is pretty slow, but a simple solution for now.
3649
0
          auto initial_count = struct_def.refcount;
3650
0
          for (auto struct_it = structs_.vec.begin();
3651
0
               struct_it != structs_.vec.end(); ++struct_it) {
3652
0
            auto& sd = **struct_it;
3653
0
            for (auto field_it = sd.fields.vec.begin();
3654
0
                 field_it != sd.fields.vec.end(); ++field_it) {
3655
0
              auto& field = **field_it;
3656
0
              if (field.value.type.struct_def == &struct_def) {
3657
0
                field.value.type.struct_def = nullptr;
3658
0
                field.value.type.enum_def = enum_def;
3659
0
                auto& bt = IsVector(field.value.type)
3660
0
                               ? field.value.type.element
3661
0
                               : field.value.type.base_type;
3662
0
                FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
3663
0
                bt = enum_def->underlying_type.base_type;
3664
0
                struct_def.refcount--;
3665
0
                enum_def->refcount++;
3666
0
              }
3667
0
            }
3668
0
          }
3669
0
          if (struct_def.refcount)
3670
0
            return Error("internal: " + NumToString(struct_def.refcount) + "/" +
3671
0
                         NumToString(initial_count) +
3672
0
                         " use(s) of pre-declaration enum not accounted for: " +
3673
0
                         enum_def->name);
3674
0
          structs_.dict.erase(structs_.dict.find(struct_def.name));
3675
0
          it = structs_.vec.erase(it);
3676
0
          delete &struct_def;
3677
0
          continue;  // Skip error.
3678
0
        }
3679
0
      }
3680
2.54k
      auto err = "type referenced but not defined (check namespace): " +
3681
2.54k
                 struct_def.name;
3682
2.54k
      if (struct_def.original_location)
3683
2.54k
        err += ", originally at: " + *struct_def.original_location;
3684
2.54k
      return Error(err);
3685
2.54k
    }
3686
166k
    ++it;
3687
166k
  }
3688
3689
  // This check has to happen here and not earlier, because only now do we
3690
  // know for sure what the type of these are.
3691
282k
  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
3692
147k
    auto& enum_def = **it;
3693
147k
    if (enum_def.is_union) {
3694
100k
      for (auto val_it = enum_def.Vals().begin();
3695
302k
           val_it != enum_def.Vals().end(); ++val_it) {
3696
201k
        auto& val = **val_it;
3697
3698
201k
        if (!(opts.lang_to_generate != 0 && SupportsAdvancedUnionFeatures()) &&
3699
201k
            (IsStruct(val.union_type) || IsString(val.union_type)))
3700
3701
2
          return Error(
3702
2
              "only tables can be union elements in the generated language: " +
3703
2
              val.name);
3704
201k
      }
3705
100k
    }
3706
147k
  }
3707
3708
134k
  auto err = CheckPrivateLeak();
3709
134k
  if (err.Check()) return err;
3710
3711
  // Parse JSON object only if the scheme has been parsed.
3712
134k
  if (token_ == '{') {
3713
124k
    ECHECK(DoParseJson());
3714
115k
  }
3715
125k
  return NoError();
3716
134k
}
3717
3718
134k
CheckedError Parser::CheckPrivateLeak() {
3719
134k
  if (!opts.no_leak_private_annotations) return NoError();
3720
  // Iterate over all structs/tables to validate we arent leaking
3721
  // any private (structs/tables/enums)
3722
0
  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); it++) {
3723
0
    auto& struct_def = **it;
3724
0
    for (auto fld_it = struct_def.fields.vec.begin();
3725
0
         fld_it != struct_def.fields.vec.end(); ++fld_it) {
3726
0
      auto& field = **fld_it;
3727
3728
0
      if (field.value.type.enum_def) {
3729
0
        auto err =
3730
0
            CheckPrivatelyLeakedFields(struct_def, *field.value.type.enum_def);
3731
0
        if (err.Check()) {
3732
0
          return err;
3733
0
        }
3734
0
      } else if (field.value.type.struct_def) {
3735
0
        auto err = CheckPrivatelyLeakedFields(struct_def,
3736
0
                                              *field.value.type.struct_def);
3737
0
        if (err.Check()) {
3738
0
          return err;
3739
0
        }
3740
0
      }
3741
0
    }
3742
0
  }
3743
  // Iterate over all enums to validate we arent leaking
3744
  // any private (structs/tables)
3745
0
  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
3746
0
    auto& enum_def = **it;
3747
0
    if (enum_def.is_union) {
3748
0
      for (auto val_it = enum_def.Vals().begin();
3749
0
           val_it != enum_def.Vals().end(); ++val_it) {
3750
0
        auto& val = **val_it;
3751
0
        if (val.union_type.struct_def) {
3752
0
          auto err =
3753
0
              CheckPrivatelyLeakedFields(enum_def, *val.union_type.struct_def);
3754
0
          if (err.Check()) {
3755
0
            return err;
3756
0
          }
3757
0
        }
3758
0
      }
3759
0
    }
3760
0
  }
3761
0
  return NoError();
3762
0
}
3763
3764
CheckedError Parser::CheckPrivatelyLeakedFields(const Definition& def,
3765
0
                                                const Definition& value_type) {
3766
0
  if (!opts.no_leak_private_annotations) return NoError();
3767
0
  const auto is_private = def.attributes.Lookup("private");
3768
0
  const auto is_field_private = value_type.attributes.Lookup("private");
3769
0
  if (!is_private && is_field_private) {
3770
0
    return Error(
3771
0
        "Leaking private implementation, verify all objects have similar "
3772
0
        "annotations");
3773
0
  }
3774
0
  return NoError();
3775
0
}
3776
3777
CheckedError Parser::DoParse(const char* source, const char** include_paths,
3778
                             const char* source_filename,
3779
148k
                             const char* include_filename) {
3780
148k
  uint64_t source_hash = 0;
3781
148k
  if (source_filename) {
3782
    // If the file is in-memory, don't include its contents in the hash as we
3783
    // won't be able to load them later.
3784
14
    if (FileExists(source_filename))
3785
14
      source_hash = HashFile(source_filename, source);
3786
0
    else
3787
0
      source_hash = HashFile(source_filename, nullptr);
3788
3789
14
    if (included_files_.find(source_hash) == included_files_.end()) {
3790
14
      included_files_[source_hash] = include_filename ? include_filename : "";
3791
14
      files_included_per_file_[source_filename] = std::set<IncludedFile>();
3792
14
    } else {
3793
0
      return NoError();
3794
0
    }
3795
14
  }
3796
148k
  if (!include_paths) {
3797
148k
    static const char* current_directory[] = {"", nullptr};
3798
148k
    include_paths = current_directory;
3799
148k
  }
3800
148k
  field_stack_.clear();
3801
148k
  builder_.Clear();
3802
  // Start with a blank namespace just in case this file doesn't have one.
3803
148k
  current_namespace_ = empty_namespace_;
3804
3805
148k
  ECHECK(StartParseFile(source, source_filename));
3806
3807
  // Includes must come before type declarations:
3808
147k
  for (;;) {
3809
    // Parse pre-include proto statements if any:
3810
147k
    if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
3811
0
                            attribute_ == "package")) {
3812
0
      ECHECK(ParseProtoDecl());
3813
147k
    } else if (IsIdent("native_include")) {
3814
296
      NEXT();
3815
295
      native_included_files_.emplace_back(attribute_);
3816
295
      EXPECT(kTokenStringConstant);
3817
280
      EXPECT(';');
3818
147k
    } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
3819
181
      NEXT();
3820
178
      if (opts.proto_mode && attribute_ == "public") NEXT();
3821
178
      auto name = flatbuffers::PosixPath(attribute_.c_str());
3822
178
      EXPECT(kTokenStringConstant);
3823
      // Look for the file relative to the directory of the current file.
3824
148
      std::string filepath;
3825
148
      if (source_filename) {
3826
0
        auto source_file_directory =
3827
0
            flatbuffers::StripFileName(source_filename);
3828
0
        filepath = flatbuffers::ConCatPathFileName(source_file_directory, name);
3829
0
      }
3830
148
      if (filepath.empty() || !FileExists(filepath.c_str())) {
3831
        // Look for the file in include_paths.
3832
273
        for (auto paths = include_paths; paths && *paths; paths++) {
3833
148
          filepath = flatbuffers::ConCatPathFileName(*paths, name);
3834
148
          if (FileExists(filepath.c_str())) break;
3835
148
        }
3836
148
      }
3837
148
      if (filepath.empty())
3838
3
        return Error("unable to locate include file: " + name);
3839
145
      if (source_filename) {
3840
0
        IncludedFile included_file;
3841
0
        included_file.filename = filepath;
3842
0
        included_file.schema_name = name;
3843
0
        files_included_per_file_[source_filename].insert(included_file);
3844
0
      }
3845
3846
145
      std::string contents;
3847
145
      bool file_loaded = LoadFile(filepath.c_str(), true, &contents);
3848
145
      if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) ==
3849
145
          included_files_.end()) {
3850
        // We found an include file that we have not parsed yet.
3851
        // Parse it.
3852
145
        if (!file_loaded) return Error("unable to load include file: " + name);
3853
14
        ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
3854
14
                       name.c_str()));
3855
        // We generally do not want to output code for any included files:
3856
0
        if (!opts.generate_all) MarkGenerated();
3857
        // Reset these just in case the included file had them, and the
3858
        // parent doesn't.
3859
0
        root_struct_def_ = nullptr;
3860
0
        file_identifier_.clear();
3861
0
        file_extension_.clear();
3862
        // This is the easiest way to continue this file after an include:
3863
        // instead of saving and restoring all the state, we simply start the
3864
        // file anew. This will cause it to encounter the same include
3865
        // statement again, but this time it will skip it, because it was
3866
        // entered into included_files_.
3867
        // This is recursive, but only go as deep as the number of include
3868
        // statements.
3869
0
        included_files_.erase(source_hash);
3870
0
        return DoParse(source, include_paths, source_filename,
3871
0
                       include_filename);
3872
14
      }
3873
0
      EXPECT(';');
3874
147k
    } else {
3875
147k
      break;
3876
147k
    }
3877
147k
  }
3878
  // Now parse all other kinds of declarations:
3879
559k
  while (token_ != kTokenEof) {
3880
546k
    if (opts.proto_mode) {
3881
0
      ECHECK(ParseProtoDecl());
3882
546k
    } else if (IsIdent("namespace")) {
3883
18.1k
      ECHECK(ParseNamespace());
3884
528k
    } else if (token_ == '{') {
3885
124k
      return NoError();
3886
404k
    } else if (IsIdent("enum")) {
3887
11.7k
      ECHECK(ParseEnum(false, nullptr, source_filename));
3888
392k
    } else if (IsIdent("union")) {
3889
84.3k
      ECHECK(ParseEnum(true, nullptr, source_filename));
3890
308k
    } else if (IsIdent("root_type")) {
3891
119k
      NEXT();
3892
119k
      auto root_type = attribute_;
3893
119k
      EXPECT(kTokenIdentifier);
3894
119k
      ECHECK(ParseNamespacing(&root_type, nullptr));
3895
119k
      if (opts.root_type.empty()) {
3896
119k
        if (!SetRootType(root_type.c_str()))
3897
29
          return Error("unknown root type: " + root_type);
3898
119k
        if (root_struct_def_->fixed) return Error("root type must be a table");
3899
119k
      }
3900
119k
      EXPECT(';');
3901
188k
    } else if (IsIdent("file_identifier")) {
3902
69
      NEXT();
3903
68
      file_identifier_ = attribute_;
3904
68
      EXPECT(kTokenStringConstant);
3905
65
      if (file_identifier_.length() != flatbuffers::kFileIdentifierLength)
3906
12
        return Error("file_identifier must be exactly " +
3907
12
                     NumToString(flatbuffers::kFileIdentifierLength) +
3908
12
                     " characters");
3909
53
      EXPECT(';');
3910
188k
    } else if (IsIdent("file_extension")) {
3911
214
      NEXT();
3912
213
      file_extension_ = attribute_;
3913
213
      EXPECT(kTokenStringConstant);
3914
210
      EXPECT(';');
3915
188k
    } else if (IsIdent("include")) {
3916
1
      return Error("includes must come before declarations");
3917
188k
    } else if (IsIdent("attribute")) {
3918
7.76k
      NEXT();
3919
7.76k
      auto name = attribute_;
3920
7.76k
      if (Is(kTokenIdentifier)) {
3921
6.61k
        NEXT();
3922
6.60k
      } else {
3923
1.15k
        EXPECT(kTokenStringConstant);
3924
1.14k
      }
3925
7.75k
      EXPECT(';');
3926
7.73k
      known_attributes_[name] = false;
3927
180k
    } else if (IsIdent("rpc_service")) {
3928
2.76k
      ECHECK(ParseService(source_filename));
3929
178k
    } else {
3930
178k
      ECHECK(ParseDecl(source_filename));
3931
173k
    }
3932
546k
  }
3933
12.1k
  EXPECT(kTokenEof);
3934
12.1k
  if (opts.warnings_as_errors && has_warning_) {
3935
0
    return Error("treating warnings as errors, failed due to above warnings");
3936
0
  }
3937
12.1k
  return NoError();
3938
12.1k
}
3939
3940
824k
CheckedError Parser::DoParseJson() {
3941
824k
  if (token_ != '{') {
3942
289
    EXPECT('{');
3943
824k
  } else {
3944
824k
    if (!root_struct_def_) return Error("no root type set to parse json with");
3945
824k
    if (builder_.GetSize()) {
3946
0
      return Error("cannot have more than one json object in a file");
3947
0
    }
3948
824k
    uoffset_t toff;
3949
824k
    ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
3950
329k
    if (opts.size_prefixed) {
3951
0
      builder_.FinishSizePrefixed(
3952
0
          Offset<Table>(toff),
3953
0
          file_identifier_.length() ? file_identifier_.c_str() : nullptr);
3954
329k
    } else {
3955
329k
      builder_.Finish(Offset<Table>(toff), file_identifier_.length()
3956
329k
                                               ? file_identifier_.c_str()
3957
329k
                                               : nullptr);
3958
329k
    }
3959
329k
  }
3960
329k
  if (opts.require_json_eof) {
3961
    // Check that JSON file doesn't contain more objects or IDL directives.
3962
    // Comments after JSON are allowed.
3963
329k
    EXPECT(kTokenEof);
3964
328k
  }
3965
328k
  return NoError();
3966
329k
}
3967
3968
std::set<std::string> Parser::GetIncludedFilesRecursive(
3969
0
    const std::string& file_name) const {
3970
0
  std::set<std::string> included_files;
3971
0
  std::list<std::string> to_process;
3972
3973
0
  if (file_name.empty()) return included_files;
3974
0
  to_process.push_back(file_name);
3975
3976
0
  while (!to_process.empty()) {
3977
0
    std::string current = to_process.front();
3978
0
    to_process.pop_front();
3979
0
    included_files.insert(current);
3980
3981
    // Workaround the lack of const accessor in C++98 maps.
3982
0
    auto& new_files =
3983
0
        (*const_cast<std::map<std::string, std::set<IncludedFile>>*>(
3984
0
            &files_included_per_file_))[current];
3985
0
    for (auto it = new_files.begin(); it != new_files.end(); ++it) {
3986
0
      if (included_files.find(it->filename) == included_files.end())
3987
0
        to_process.push_back(it->filename);
3988
0
    }
3989
0
  }
3990
3991
0
  return included_files;
3992
0
}
3993
3994
// Schema serialization functionality:
3995
3996
static flatbuffers::Offset<
3997
    flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
3998
SerializeAttributesCommon(const SymbolTable<Value>& attributes,
3999
254k
                          FlatBufferBuilder* builder, const Parser& parser) {
4000
254k
  std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
4001
255k
  for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
4002
1.08k
    auto it = parser.known_attributes_.find(kv->first);
4003
1.08k
    FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
4004
1.08k
    if (parser.opts.binary_schema_builtins || !it->second) {
4005
641
      auto key = builder->CreateString(kv->first);
4006
641
      auto val = builder->CreateString(kv->second->constant);
4007
641
      attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
4008
641
    }
4009
1.08k
  }
4010
254k
  if (attrs.size()) {
4011
641
    return builder->CreateVectorOfSortedTables(&attrs);
4012
254k
  } else {
4013
254k
    return 0;
4014
254k
  }
4015
254k
}
4016
4017
static bool DeserializeAttributesCommon(
4018
    SymbolTable<Value>& attributes, Parser& parser,
4019
292
    const Vector<Offset<reflection::KeyValue>>* attrs) {
4020
292
  if (attrs == nullptr) return true;
4021
376
  for (uoffset_t i = 0; i < attrs->size(); ++i) {
4022
230
    auto kv = attrs->Get(i);
4023
230
    auto value = new Value();
4024
230
    if (kv->value()) {
4025
230
      value->constant = kv->value()->str();
4026
230
    }
4027
230
    if (attributes.Add(kv->key()->str(), value)) {
4028
0
      delete value;
4029
0
      return false;
4030
0
    }
4031
230
    parser.known_attributes_[kv->key()->str()];
4032
230
  }
4033
146
  return true;
4034
146
}
4035
4036
4.70k
void Parser::Serialize() {
4037
4.70k
  builder_.Clear();
4038
4.70k
  AssignIndices(structs_.vec);
4039
4.70k
  AssignIndices(enums_.vec);
4040
4.70k
  std::vector<Offset<reflection::Object>> object_offsets;
4041
4.70k
  std::set<std::string> files;
4042
50.9k
  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
4043
46.2k
    auto offset = (*it)->Serialize(&builder_, *this);
4044
46.2k
    object_offsets.push_back(offset);
4045
46.2k
    (*it)->serialized_location = offset.o;
4046
46.2k
    const std::string* file = (*it)->declaration_file;
4047
46.2k
    if (file) files.insert(*file);
4048
46.2k
  }
4049
4.70k
  std::vector<Offset<reflection::Enum>> enum_offsets;
4050
73.9k
  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
4051
69.2k
    auto offset = (*it)->Serialize(&builder_, *this);
4052
69.2k
    enum_offsets.push_back(offset);
4053
69.2k
    const std::string* file = (*it)->declaration_file;
4054
69.2k
    if (file) files.insert(*file);
4055
69.2k
  }
4056
4.70k
  std::vector<Offset<reflection::Service>> service_offsets;
4057
5.43k
  for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
4058
731
    auto offset = (*it)->Serialize(&builder_, *this);
4059
731
    service_offsets.push_back(offset);
4060
731
    const std::string* file = (*it)->declaration_file;
4061
731
    if (file) files.insert(*file);
4062
731
  }
4063
4064
  // Create Schemafiles vector of tables.
4065
4.70k
  flatbuffers::Offset<
4066
4.70k
      flatbuffers::Vector<flatbuffers::Offset<reflection::SchemaFile>>>
4067
4.70k
      schema_files__;
4068
4.70k
  if (!opts.project_root.empty()) {
4069
0
    std::vector<Offset<reflection::SchemaFile>> schema_files;
4070
0
    std::vector<Offset<flatbuffers::String>> included_files;
4071
0
    for (auto f = files_included_per_file_.begin();
4072
0
         f != files_included_per_file_.end(); f++) {
4073
0
      const auto filename__ = builder_.CreateSharedString(FilePath(
4074
0
          opts.project_root, f->first, opts.binary_schema_absolute_paths));
4075
0
      for (auto i = f->second.begin(); i != f->second.end(); i++) {
4076
0
        included_files.push_back(builder_.CreateSharedString(
4077
0
            FilePath(opts.project_root, i->filename,
4078
0
                     opts.binary_schema_absolute_paths)));
4079
0
      }
4080
0
      const auto included_files__ = builder_.CreateVector(included_files);
4081
0
      included_files.clear();
4082
4083
0
      schema_files.push_back(
4084
0
          reflection::CreateSchemaFile(builder_, filename__, included_files__));
4085
0
    }
4086
0
    schema_files__ = builder_.CreateVectorOfSortedTables(&schema_files);
4087
0
  }
4088
4089
4.70k
  const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
4090
4.70k
  const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
4091
4.70k
  const auto fiid__ = builder_.CreateString(file_identifier_);
4092
4.70k
  const auto fext__ = builder_.CreateString(file_extension_);
4093
4.70k
  const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
4094
4.70k
  const auto schema_offset = reflection::CreateSchema(
4095
4.70k
      builder_, objs__, enum__, fiid__, fext__,
4096
4.70k
      (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
4097
4.70k
      static_cast<reflection::AdvancedFeatures>(advanced_features_),
4098
4.70k
      schema_files__);
4099
4.70k
  if (opts.size_prefixed) {
4100
0
    builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
4101
4.70k
  } else {
4102
4.70k
    builder_.Finish(schema_offset, reflection::SchemaIdentifier());
4103
4.70k
  }
4104
4.70k
}
4105
4106
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder* builder,
4107
46.2k
                                                const Parser& parser) const {
4108
46.2k
  std::vector<Offset<reflection::Field>> field_offsets;
4109
81.5k
  for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
4110
35.2k
    field_offsets.push_back((*it)->Serialize(
4111
35.2k
        builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
4112
35.2k
  }
4113
46.2k
  const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
4114
46.2k
  const auto name__ = builder->CreateString(qualified_name);
4115
46.2k
  const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
4116
46.2k
  const auto attr__ = SerializeAttributes(builder, parser);
4117
46.2k
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4118
46.2k
                          ? builder->CreateVectorOfStrings(doc_comment)
4119
46.2k
                          : 0;
4120
46.2k
  std::string decl_file_in_project = declaration_file ? *declaration_file : "";
4121
46.2k
  const auto file__ = builder->CreateSharedString(decl_file_in_project);
4122
46.2k
  return reflection::CreateObject(
4123
46.2k
      *builder, name__, flds__, fixed, static_cast<int>(minalign),
4124
46.2k
      static_cast<int>(bytesize), attr__, docs__, file__);
4125
46.2k
}
4126
4127
30
bool StructDef::Deserialize(Parser& parser, const reflection::Object* object) {
4128
30
  if (!DeserializeAttributes(parser, object->attributes())) return false;
4129
30
  DeserializeDoc(doc_comment, object->documentation());
4130
30
  name = parser.UnqualifiedName(object->name()->str());
4131
30
  predecl = false;
4132
30
  sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
4133
30
  const auto& of = *(object->fields());
4134
30
  auto indexes = std::vector<uoffset_t>(of.size());
4135
222
  for (uoffset_t i = 0; i < of.size(); i++) {
4136
192
  uint16_t field_id = of.Get(i)->id();
4137
192
  if (field_id >= of.size()) {
4138
0
    parser.error_ = "Field ID " + std::to_string(field_id) + 
4139
0
                    " exceeds field count " + std::to_string(of.size());
4140
0
    return false;
4141
0
  }
4142
192
  indexes[field_id] = i;
4143
192
}
4144
30
  size_t tmp_struct_size = 0;
4145
222
  for (size_t i = 0; i < indexes.size(); i++) {
4146
192
    auto field = of.Get(indexes[i]);
4147
192
    auto field_def = new FieldDef();
4148
192
    if (!field_def->Deserialize(parser, field) ||
4149
192
        fields.Add(field_def->name, field_def)) {
4150
0
      delete field_def;
4151
0
      return false;
4152
0
    }
4153
192
    if (field_def->key) {
4154
8
      if (has_key) {
4155
        // only one field may be set as key
4156
0
        delete field_def;
4157
0
        return false;
4158
0
      }
4159
8
      has_key = true;
4160
8
    }
4161
192
    if (fixed) {
4162
      // Recompute padding since that's currently not serialized.
4163
30
      auto size = InlineSize(field_def->value.type);
4164
30
      auto next_field =
4165
30
          i + 1 < indexes.size() ? of.Get(indexes[i + 1]) : nullptr;
4166
30
      tmp_struct_size += size;
4167
30
      field_def->padding =
4168
30
          next_field ? (next_field->offset() - field_def->value.offset) - size
4169
30
                     : PaddingBytes(tmp_struct_size, minalign);
4170
30
      tmp_struct_size += field_def->padding;
4171
30
    }
4172
192
  }
4173
30
  FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize());
4174
30
  return true;
4175
30
}
4176
4177
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder* builder,
4178
                                              uint16_t id,
4179
35.2k
                                              const Parser& parser) const {
4180
35.2k
  auto name__ = builder->CreateString(name);
4181
35.2k
  auto type__ = value.type.Serialize(builder);
4182
35.2k
  auto attr__ = SerializeAttributes(builder, parser);
4183
35.2k
  auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4184
35.2k
                    ? builder->CreateVectorOfStrings(doc_comment)
4185
35.2k
                    : 0;
4186
35.2k
  double d;
4187
35.2k
  StringToNumber(value.constant.c_str(), &d);
4188
35.2k
  return reflection::CreateField(
4189
35.2k
      *builder, name__, type__, id, value.offset,
4190
      // Is uint64>max(int64) tested?
4191
35.2k
      IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
4192
      // result may be platform-dependent if underlying is float (not double)
4193
35.2k
      IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key,
4194
35.2k
      attr__, docs__, IsOptional(), static_cast<uint16_t>(padding), offset64);
4195
  // TODO: value.constant is almost always "0", we could save quite a bit of
4196
  // space by sharing it. Same for common values of value.type.
4197
35.2k
}
4198
4199
192
bool FieldDef::Deserialize(Parser& parser, const reflection::Field* field) {
4200
192
  name = field->name()->str();
4201
192
  defined_namespace = parser.current_namespace_;
4202
192
  if (!value.type.Deserialize(parser, field->type())) return false;
4203
192
  value.offset = field->offset();
4204
192
  if (IsInteger(value.type.base_type)) {
4205
80
    value.constant = NumToString(field->default_integer());
4206
112
  } else if (IsFloat(value.type.base_type)) {
4207
34
    value.constant = FloatToString(field->default_real(), 17);
4208
34
  }
4209
192
  presence = FieldDef::MakeFieldPresence(field->optional(), field->required());
4210
192
  padding = field->padding();
4211
192
  key = field->key();
4212
192
  offset64 = field->offset64();
4213
192
  if (!DeserializeAttributes(parser, field->attributes())) return false;
4214
  // TODO: this should probably be handled by a separate attribute
4215
192
  if (attributes.Lookup("flexbuffer")) {
4216
2
    flexbuffer = true;
4217
2
    parser.uses_flexbuffers_ = true;
4218
2
    if (value.type.base_type != BASE_TYPE_VECTOR ||
4219
2
        value.type.element != BASE_TYPE_UCHAR)
4220
0
      return false;
4221
2
  }
4222
192
  if (auto nested = attributes.Lookup("nested_flatbuffer")) {
4223
4
    auto nested_qualified_name =
4224
4
        parser.current_namespace_->GetFullyQualifiedName(nested->constant);
4225
4
    nested_flatbuffer = parser.LookupStruct(nested_qualified_name);
4226
4
    if (!nested_flatbuffer) return false;
4227
4
  }
4228
192
  shared = attributes.Lookup("shared") != nullptr;
4229
192
  DeserializeDoc(doc_comment, field->documentation());
4230
192
  return true;
4231
192
}
4232
4233
Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder* builder,
4234
1.39k
                                               const Parser& parser) const {
4235
1.39k
  auto name__ = builder->CreateString(name);
4236
1.39k
  auto attr__ = SerializeAttributes(builder, parser);
4237
1.39k
  auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4238
1.39k
                    ? builder->CreateVectorOfStrings(doc_comment)
4239
1.39k
                    : 0;
4240
1.39k
  return reflection::CreateRPCCall(
4241
1.39k
      *builder, name__, request->serialized_location,
4242
1.39k
      response->serialized_location, attr__, docs__);
4243
1.39k
}
4244
4245
8
bool RPCCall::Deserialize(Parser& parser, const reflection::RPCCall* call) {
4246
8
  name = call->name()->str();
4247
8
  if (!DeserializeAttributes(parser, call->attributes())) return false;
4248
8
  DeserializeDoc(doc_comment, call->documentation());
4249
8
  request = parser.structs_.Lookup(call->request()->name()->str());
4250
8
  response = parser.structs_.Lookup(call->response()->name()->str());
4251
8
  if (!request || !response) {
4252
0
    return false;
4253
0
  }
4254
8
  return true;
4255
8
}
4256
4257
Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder* builder,
4258
731
                                                  const Parser& parser) const {
4259
731
  std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
4260
2.12k
  for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
4261
1.39k
    servicecall_offsets.push_back((*it)->Serialize(builder, parser));
4262
1.39k
  }
4263
731
  const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
4264
731
  const auto name__ = builder->CreateString(qualified_name);
4265
731
  const auto call__ = builder->CreateVector(servicecall_offsets);
4266
731
  const auto attr__ = SerializeAttributes(builder, parser);
4267
731
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4268
731
                          ? builder->CreateVectorOfStrings(doc_comment)
4269
731
                          : 0;
4270
731
  std::string decl_file_in_project = declaration_file ? *declaration_file : "";
4271
731
  const auto file__ = builder->CreateSharedString(decl_file_in_project);
4272
731
  return reflection::CreateService(*builder, name__, call__, attr__, docs__,
4273
731
                                   file__);
4274
731
}
4275
4276
bool ServiceDef::Deserialize(Parser& parser,
4277
2
                             const reflection::Service* service) {
4278
2
  name = parser.UnqualifiedName(service->name()->str());
4279
2
  if (service->calls()) {
4280
10
    for (uoffset_t i = 0; i < service->calls()->size(); ++i) {
4281
8
      auto call = new RPCCall();
4282
8
      if (!call->Deserialize(parser, service->calls()->Get(i)) ||
4283
8
          calls.Add(call->name, call)) {
4284
0
        delete call;
4285
0
        return false;
4286
0
      }
4287
8
    }
4288
2
  }
4289
2
  if (!DeserializeAttributes(parser, service->attributes())) return false;
4290
2
  DeserializeDoc(doc_comment, service->documentation());
4291
2
  return true;
4292
2
}
4293
4294
Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder* builder,
4295
69.2k
                                            const Parser& parser) const {
4296
69.2k
  std::vector<Offset<reflection::EnumVal>> enumval_offsets;
4297
171k
  for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
4298
101k
    enumval_offsets.push_back((*it)->Serialize(builder, parser));
4299
101k
  }
4300
69.2k
  const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
4301
69.2k
  const auto name__ = builder->CreateString(qualified_name);
4302
69.2k
  const auto vals__ = builder->CreateVector(enumval_offsets);
4303
69.2k
  const auto type__ = underlying_type.Serialize(builder);
4304
69.2k
  const auto attr__ = SerializeAttributes(builder, parser);
4305
69.2k
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4306
69.2k
                          ? builder->CreateVectorOfStrings(doc_comment)
4307
69.2k
                          : 0;
4308
69.2k
  std::string decl_file_in_project = declaration_file ? *declaration_file : "";
4309
69.2k
  const auto file__ = builder->CreateSharedString(decl_file_in_project);
4310
69.2k
  return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
4311
69.2k
                                attr__, docs__, file__);
4312
69.2k
}
4313
4314
14
bool EnumDef::Deserialize(Parser& parser, const reflection::Enum* _enum) {
4315
14
  name = parser.UnqualifiedName(_enum->name()->str());
4316
60
  for (uoffset_t i = 0; i < _enum->values()->size(); ++i) {
4317
46
    auto val = new EnumVal();
4318
46
    if (!val->Deserialize(parser, _enum->values()->Get(i)) ||
4319
46
        vals.Add(val->name, val)) {
4320
0
      delete val;
4321
0
      return false;
4322
0
    }
4323
46
  }
4324
14
  is_union = _enum->is_union();
4325
14
  if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
4326
0
    return false;
4327
0
  }
4328
14
  if (!DeserializeAttributes(parser, _enum->attributes())) return false;
4329
14
  DeserializeDoc(doc_comment, _enum->documentation());
4330
14
  return true;
4331
14
}
4332
4333
flatbuffers::Offset<
4334
    flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
4335
EnumVal::SerializeAttributes(FlatBufferBuilder* builder,
4336
101k
                             const Parser& parser) const {
4337
101k
  return SerializeAttributesCommon(attributes, builder, parser);
4338
101k
}
4339
4340
bool EnumVal::DeserializeAttributes(
4341
46
    Parser& parser, const Vector<Offset<reflection::KeyValue>>* attrs) {
4342
46
  return DeserializeAttributesCommon(attributes, parser, attrs);
4343
46
}
4344
4345
Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder* builder,
4346
101k
                                               const Parser& parser) const {
4347
101k
  const auto name__ = builder->CreateString(name);
4348
101k
  const auto type__ = union_type.Serialize(builder);
4349
101k
  const auto attr__ = SerializeAttributes(builder, parser);
4350
101k
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4351
101k
                          ? builder->CreateVectorOfStrings(doc_comment)
4352
101k
                          : 0;
4353
101k
  return reflection::CreateEnumVal(*builder, name__, value, type__, docs__,
4354
101k
                                   attr__);
4355
101k
}
4356
4357
46
bool EnumVal::Deserialize(Parser& parser, const reflection::EnumVal* val) {
4358
46
  name = val->name()->str();
4359
46
  value = val->value();
4360
46
  if (!union_type.Deserialize(parser, val->union_type())) return false;
4361
46
  if (!DeserializeAttributes(parser, val->attributes())) return false;
4362
46
  DeserializeDoc(doc_comment, val->documentation());
4363
46
  return true;
4364
46
}
4365
4366
206k
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder* builder) const {
4367
206k
  size_t element_size = SizeOf(element);
4368
206k
  if (base_type == BASE_TYPE_VECTOR && element == BASE_TYPE_STRUCT &&
4369
180
      struct_def->bytesize != 0) {
4370
    // struct_def->bytesize==0 means struct is table
4371
77
    element_size = struct_def->bytesize;
4372
77
  }
4373
206k
  return reflection::CreateType(
4374
206k
      *builder, static_cast<reflection::BaseType>(base_type),
4375
206k
      static_cast<reflection::BaseType>(element),
4376
206k
      struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
4377
206k
      fixed_length, static_cast<uint32_t>(SizeOf(base_type)),
4378
206k
      static_cast<uint32_t>(element_size));
4379
206k
}
4380
4381
252
bool Type::Deserialize(const Parser& parser, const reflection::Type* type) {
4382
252
  if (type == nullptr) return true;
4383
252
  base_type = static_cast<BaseType>(type->base_type());
4384
252
  element = static_cast<BaseType>(type->element());
4385
252
  fixed_length = type->fixed_length();
4386
252
  if (type->index() >= 0) {
4387
96
    bool is_series = type->base_type() == reflection::Vector ||
4388
80
                     type->base_type() == reflection::Array;
4389
96
    if (type->base_type() == reflection::Obj ||
4390
56
        (is_series && type->element() == reflection::Obj)) {
4391
56
      if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
4392
56
        struct_def = parser.structs_.vec[type->index()];
4393
56
        struct_def->refcount++;
4394
56
      } else {
4395
0
        return false;
4396
0
      }
4397
56
    } else {
4398
40
      if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) {
4399
40
        enum_def = parser.enums_.vec[type->index()];
4400
40
      } else {
4401
0
        return false;
4402
0
      }
4403
40
    }
4404
96
  }
4405
252
  return true;
4406
252
}
4407
4408
flatbuffers::Offset<
4409
    flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
4410
Definition::SerializeAttributes(FlatBufferBuilder* builder,
4411
152k
                                const Parser& parser) const {
4412
152k
  return SerializeAttributesCommon(attributes, builder, parser);
4413
152k
}
4414
4415
bool Definition::DeserializeAttributes(
4416
246
    Parser& parser, const Vector<Offset<reflection::KeyValue>>* attrs) {
4417
246
  return DeserializeAttributesCommon(attributes, parser, attrs);
4418
246
}
4419
4420
/************************************************************************/
4421
/* DESERIALIZATION                                                      */
4422
/************************************************************************/
4423
2
bool Parser::Deserialize(const uint8_t* buf, const size_t size) {
4424
2
  flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(buf), size);
4425
2
  bool size_prefixed = false;
4426
2
  if (!reflection::SchemaBufferHasIdentifier(buf)) {
4427
0
    if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
4428
0
                                          true))
4429
0
      return false;
4430
0
    else
4431
0
      size_prefixed = true;
4432
0
  }
4433
2
  auto verify_fn = size_prefixed
4434
2
                       ? &reflection::VerifySizePrefixedSchemaBuffer<false>
4435
2
                       : &reflection::VerifySchemaBuffer<false>;
4436
2
  if (!verify_fn(verifier)) {
4437
0
    return false;
4438
0
  }
4439
2
  auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
4440
2
                              : reflection::GetSchema(buf);
4441
2
  return Deserialize(schema);
4442
2
}
4443
4444
2
bool Parser::Deserialize(const reflection::Schema* schema) {
4445
2
  file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : "";
4446
2
  file_extension_ = schema->file_ext() ? schema->file_ext()->str() : "";
4447
2
  std::map<std::string, Namespace*> namespaces_index;
4448
4449
  // Create defs without deserializing so references from fields to structs and
4450
  // enums can be resolved.
4451
32
  for (auto it = schema->objects()->begin(); it != schema->objects()->end();
4452
30
       ++it) {
4453
30
    auto struct_def = new StructDef();
4454
30
    struct_def->bytesize = it->bytesize();
4455
30
    struct_def->fixed = it->is_struct();
4456
30
    struct_def->minalign = it->minalign();
4457
30
    if (structs_.Add(it->name()->str(), struct_def)) {
4458
0
      delete struct_def;
4459
0
      return false;
4460
0
    }
4461
30
    auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr);
4462
30
    if (types_.Add(it->name()->str(), type)) {
4463
0
      delete type;
4464
0
      return false;
4465
0
    }
4466
30
  }
4467
16
  for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
4468
14
    auto enum_def = new EnumDef();
4469
14
    if (enums_.Add(it->name()->str(), enum_def)) {
4470
0
      delete enum_def;
4471
0
      return false;
4472
0
    }
4473
14
    auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def);
4474
14
    if (types_.Add(it->name()->str(), type)) {
4475
0
      delete type;
4476
0
      return false;
4477
0
    }
4478
14
  }
4479
4480
  // Now fields can refer to structs and enums by index.
4481
32
  for (auto it = schema->objects()->begin(); it != schema->objects()->end();
4482
30
       ++it) {
4483
30
    std::string qualified_name = it->name()->str();
4484
30
    auto struct_def = structs_.Lookup(qualified_name);
4485
30
    struct_def->defined_namespace =
4486
30
        GetNamespace(qualified_name, namespaces_, namespaces_index);
4487
30
    if (!struct_def->Deserialize(*this, *it)) {
4488
0
      return false;
4489
0
    }
4490
30
    if (schema->root_table() == *it) {
4491
2
      root_struct_def_ = struct_def;
4492
2
    }
4493
30
  }
4494
16
  for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
4495
14
    std::string qualified_name = it->name()->str();
4496
14
    auto enum_def = enums_.Lookup(qualified_name);
4497
14
    enum_def->defined_namespace =
4498
14
        GetNamespace(qualified_name, namespaces_, namespaces_index);
4499
14
    if (!enum_def->Deserialize(*this, *it)) {
4500
0
      return false;
4501
0
    }
4502
14
  }
4503
4504
2
  if (schema->services()) {
4505
4
    for (auto it = schema->services()->begin(); it != schema->services()->end();
4506
2
         ++it) {
4507
2
      std::string qualified_name = it->name()->str();
4508
2
      auto service_def = new ServiceDef();
4509
2
      service_def->defined_namespace =
4510
2
          GetNamespace(qualified_name, namespaces_, namespaces_index);
4511
2
      if (!service_def->Deserialize(*this, *it) ||
4512
2
          services_.Add(qualified_name, service_def)) {
4513
0
        delete service_def;
4514
0
        return false;
4515
0
      }
4516
2
    }
4517
2
  }
4518
2
  advanced_features_ = schema->advanced_features();
4519
4520
2
  if (schema->fbs_files())
4521
8
    for (auto s = schema->fbs_files()->begin(); s != schema->fbs_files()->end();
4522
6
         ++s) {
4523
6
      for (auto f = s->included_filenames()->begin();
4524
16
           f != s->included_filenames()->end(); ++f) {
4525
10
        IncludedFile included_file;
4526
10
        included_file.filename = f->str();
4527
10
        files_included_per_file_[s->filename()->str()].insert(included_file);
4528
10
      }
4529
6
    }
4530
4531
2
  return true;
4532
2
}
4533
4534
0
std::string Parser::ConformTo(const Parser& base) {
4535
0
  for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
4536
0
    auto& struct_def = **sit;
4537
0
    auto qualified_name =
4538
0
        struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
4539
0
    auto struct_def_base = base.LookupStruct(qualified_name);
4540
0
    if (!struct_def_base) continue;
4541
0
    std::set<FieldDef*> renamed_fields;
4542
0
    for (auto fit = struct_def.fields.vec.begin();
4543
0
         fit != struct_def.fields.vec.end(); ++fit) {
4544
0
      auto& field = **fit;
4545
0
      auto field_base = struct_def_base->fields.Lookup(field.name);
4546
0
      const auto qualified_field_name = qualified_name + "." + field.name;
4547
0
      if (field_base) {
4548
0
        if (field.value.offset != field_base->value.offset) {
4549
0
          return "offsets differ for field: " + qualified_field_name;
4550
0
        }
4551
0
        if (field.value.constant != field_base->value.constant) {
4552
0
          return "defaults differ for field: " + qualified_field_name;
4553
0
        }
4554
0
        if (!EqualByName(field.value.type, field_base->value.type)) {
4555
0
          return "types differ for field: " + qualified_field_name;
4556
0
        }
4557
0
        if (field.offset64 != field_base->offset64) {
4558
0
          return "offset types differ for field: " + qualified_field_name;
4559
0
        }
4560
0
      } else {
4561
        // Doesn't have to exist, deleting fields is fine.
4562
        // But we should check if there is a field that has the same offset
4563
        // but is incompatible (in the case of field renaming).
4564
0
        for (auto fbit = struct_def_base->fields.vec.begin();
4565
0
             fbit != struct_def_base->fields.vec.end(); ++fbit) {
4566
0
          field_base = *fbit;
4567
0
          if (field.value.offset == field_base->value.offset) {
4568
0
            renamed_fields.insert(field_base);
4569
0
            if (!EqualByName(field.value.type, field_base->value.type)) {
4570
0
              const auto qualified_field_base =
4571
0
                  qualified_name + "." + field_base->name;
4572
0
              return "field renamed to different type: " +
4573
0
                     qualified_field_name + " (renamed from " +
4574
0
                     qualified_field_base + ")";
4575
0
            }
4576
0
            break;
4577
0
          }
4578
0
        }
4579
0
      }
4580
0
    }
4581
    // deletion of trailing fields are not allowed
4582
0
    for (auto fit = struct_def_base->fields.vec.begin();
4583
0
         fit != struct_def_base->fields.vec.end(); ++fit) {
4584
0
      auto& field_base = **fit;
4585
      // not a renamed field
4586
0
      if (renamed_fields.find(&field_base) == renamed_fields.end()) {
4587
0
        auto field = struct_def.fields.Lookup(field_base.name);
4588
0
        if (!field) {
4589
0
          return "field deleted: " + qualified_name + "." + field_base.name;
4590
0
        }
4591
0
      }
4592
0
    }
4593
0
  }
4594
4595
0
  for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
4596
0
    auto& enum_def = **eit;
4597
0
    auto qualified_name =
4598
0
        enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
4599
0
    auto enum_def_base = base.enums_.Lookup(qualified_name);
4600
0
    if (!enum_def_base) continue;
4601
0
    for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end();
4602
0
         ++evit) {
4603
0
      auto& enum_val = **evit;
4604
0
      auto enum_val_base = enum_def_base->Lookup(enum_val.name);
4605
0
      if (enum_val_base) {
4606
0
        if (enum_val != *enum_val_base)
4607
0
          return "values differ for enum: " + enum_val.name;
4608
0
      }
4609
0
    }
4610
    // Check underlying type changes
4611
0
    if (enum_def_base->underlying_type.base_type !=
4612
0
        enum_def.underlying_type.base_type) {
4613
0
      return "underlying type differ for " +
4614
0
             std::string(enum_def.is_union ? "union: " : "enum: ") +
4615
0
             qualified_name;
4616
0
    }
4617
0
  }
4618
0
  return "";
4619
0
}
4620
4621
}  // namespace flatbuffers