Coverage Report

Created: 2026-04-12 06:27

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
32.8M
  {                            \
57
32.8M
    auto ce = (call);          \
58
32.8M
    if (ce.Check()) return ce; \
59
32.8M
  }
60
61
// These two functions are called hundreds of times below, so define a short
62
// form:
63
10.0M
#define NEXT() ECHECK(Next())
64
7.27M
#define EXPECT(tok) ECHECK(Expect(tok))
65
66
1.94k
static bool ValidateUTF8(const std::string& str) {
67
1.94k
  const char* s = &str[0];
68
1.94k
  const char* const sEnd = s + str.length();
69
10.3k
  while (s < sEnd) {
70
8.52k
    if (FromUTF8(&s) < 0) {
71
73
      return false;
72
73
    }
73
8.52k
  }
74
1.86k
  return true;
75
1.94k
}
76
77
0
static bool IsLowerSnakeCase(const std::string& str) {
78
0
  for (size_t i = 0; i < str.length(); i++) {
79
0
    char c = str[i];
80
0
    if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') {
81
0
      return false;
82
0
    }
83
0
  }
84
0
  return true;
85
0
}
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
29.1M
static CheckedError NoError() { return CheckedError(false); }
95
96
template <typename T>
97
797
static std::string TypeToIntervalString() {
98
797
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
797
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
797
}
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
179
static std::string TypeToIntervalString() {
98
179
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
179
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
179
}
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
138
static std::string TypeToIntervalString() {
98
138
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
138
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
138
}
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
119
static std::string TypeToIntervalString() {
98
119
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
119
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
119
}
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
142
static std::string TypeToIntervalString() {
98
142
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
142
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
142
}
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
66
static std::string TypeToIntervalString() {
98
66
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
66
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
66
}
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
105
static std::string TypeToIntervalString() {
98
105
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
105
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
105
}
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
21
static std::string TypeToIntervalString() {
98
21
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
21
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
21
}
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
27
static std::string TypeToIntervalString() {
98
27
  return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
99
27
         NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
100
27
}
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
397k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
397k
  return StringToNumber(s, val);
106
397k
}
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
82.3k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
82.3k
  return StringToNumber(s, val);
106
82.3k
}
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
30.8k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
30.8k
  return StringToNumber(s, val);
106
30.8k
}
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
65.1k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
65.1k
  return StringToNumber(s, val);
106
65.1k
}
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
11.9k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
11.9k
  return StringToNumber(s, val);
106
11.9k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<short>(char const*, short*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
13.3k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
13.3k
  return StringToNumber(s, val);
106
13.3k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<int>(char const*, int*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
4.33k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
4.33k
  return StringToNumber(s, val);
106
4.33k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<long>(char const*, long*, std::__1::integral_constant<bool, false>)
Line
Count
Source
104
54.9k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
54.9k
  return StringToNumber(s, val);
106
54.9k
}
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
134k
static bool atot_scalar(const char* s, T* val, bool_constant<false>) {
105
134k
  return StringToNumber(s, val);
106
134k
}
107
108
template <typename T>
109
95.2k
static bool atot_scalar(const char* s, T* val, bool_constant<true>) {
110
  // Normalize NaN parsed from fbs or json to unsigned NaN.
111
95.2k
  if (false == StringToNumber(s, val)) return false;
112
95.1k
  *val = (*val != *val) ? std::fabs(*val) : *val;
113
95.1k
  return true;
114
95.2k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<float>(char const*, float*, std::__1::integral_constant<bool, true>)
Line
Count
Source
109
22.5k
static bool atot_scalar(const char* s, T* val, bool_constant<true>) {
110
  // Normalize NaN parsed from fbs or json to unsigned NaN.
111
22.5k
  if (false == StringToNumber(s, val)) return false;
112
22.5k
  *val = (*val != *val) ? std::fabs(*val) : *val;
113
22.5k
  return true;
114
22.5k
}
idl_parser.cpp:bool flatbuffers::(anonymous namespace)::atot_scalar<double>(char const*, double*, std::__1::integral_constant<bool, true>)
Line
Count
Source
109
72.6k
static bool atot_scalar(const char* s, T* val, bool_constant<true>) {
110
  // Normalize NaN parsed from fbs or json to unsigned NaN.
111
72.6k
  if (false == StringToNumber(s, val)) return false;
112
72.6k
  *val = (*val != *val) ? std::fabs(*val) : *val;
113
72.6k
  return true;
114
72.6k
}
115
116
template <typename T>
117
492k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
492k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
492k
  if (done) return NoError();
120
1.26k
  if (0 == *val)
121
470
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
797
  else
123
797
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
797
                        ", constant does not fit " + TypeToIntervalString<T>());
125
1.26k
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned short>(char const*, flatbuffers::Parser&, unsigned short*)
Line
Count
Source
117
82.3k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
82.3k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
82.3k
  if (done) return NoError();
120
191
  if (0 == *val)
121
49
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
142
  else
123
142
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
142
                        ", constant does not fit " + TypeToIntervalString<T>());
125
191
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned int>(char const*, flatbuffers::Parser&, unsigned int*)
Line
Count
Source
117
30.8k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
30.8k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
30.8k
  if (done) return NoError();
120
138
  if (0 == *val)
121
33
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
105
  else
123
105
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
105
                        ", constant does not fit " + TypeToIntervalString<T>());
125
138
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned char>(char const*, flatbuffers::Parser&, unsigned char*)
Line
Count
Source
117
65.1k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
65.1k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
65.1k
  if (done) return NoError();
120
272
  if (0 == *val)
121
93
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
179
  else
123
179
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
179
                        ", constant does not fit " + TypeToIntervalString<T>());
125
272
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<signed char>(char const*, flatbuffers::Parser&, signed char*)
Line
Count
Source
117
11.9k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
11.9k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
11.9k
  if (done) return NoError();
120
169
  if (0 == *val)
121
31
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
138
  else
123
138
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
138
                        ", constant does not fit " + TypeToIntervalString<T>());
125
169
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<short>(char const*, flatbuffers::Parser&, short*)
Line
Count
Source
117
13.3k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
13.3k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
13.3k
  if (done) return NoError();
120
158
  if (0 == *val)
121
39
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
119
  else
123
119
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
119
                        ", constant does not fit " + TypeToIntervalString<T>());
125
158
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<int>(char const*, flatbuffers::Parser&, int*)
Line
Count
Source
117
4.33k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
4.33k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
4.33k
  if (done) return NoError();
120
111
  if (0 == *val)
121
45
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
66
  else
123
66
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
66
                        ", constant does not fit " + TypeToIntervalString<T>());
125
111
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<long>(char const*, flatbuffers::Parser&, long*)
Line
Count
Source
117
54.9k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
54.9k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
54.9k
  if (done) return NoError();
120
67
  if (0 == *val)
121
46
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
21
  else
123
21
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
21
                        ", constant does not fit " + TypeToIntervalString<T>());
125
67
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<unsigned long>(char const*, flatbuffers::Parser&, unsigned long*)
Line
Count
Source
117
134k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
134k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
134k
  if (done) return NoError();
120
66
  if (0 == *val)
121
39
    return parser.Error("invalid number: \"" + std::string(s) + "\"");
122
27
  else
123
27
    return parser.Error("invalid number: \"" + std::string(s) + "\"" +
124
27
                        ", constant does not fit " + TypeToIntervalString<T>());
125
66
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<float>(char const*, flatbuffers::Parser&, float*)
Line
Count
Source
117
22.5k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
22.5k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
22.5k
  if (done) return NoError();
120
39
  if (0 == *val)
121
39
    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
39
}
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::(anonymous namespace)::atot<double>(char const*, flatbuffers::Parser&, double*)
Line
Count
Source
117
72.6k
static CheckedError atot(const char* s, Parser& parser, T* val) {
118
72.6k
  auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>());
119
72.6k
  if (done) return NoError();
120
56
  if (0 == *val)
121
56
    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
56
}
126
template <>
127
CheckedError atot<Offset<void>>(const char* s, Parser& parser,
128
374k
                                Offset<void>* val) {
129
374k
  (void)parser;
130
374k
  *val = Offset<void>(atoi(s));
131
374k
  return NoError();
132
374k
}
133
134
template <>
135
CheckedError atot<Offset64<void>>(const char* s, Parser& parser,
136
0
                                  Offset64<void>* val) {
137
0
  (void)parser;
138
0
  *val = Offset64<void>(atoi(s));
139
0
  return NoError();
140
0
}
141
142
template <typename T>
143
static T* LookupTableByName(const SymbolTable<T>& table,
144
                            const std::string& name,
145
                            const Namespace& current_namespace,
146
3.45k
                            size_t skip_top) {
147
3.45k
  const auto& components = current_namespace.components;
148
3.45k
  if (table.dict.empty()) return nullptr;
149
3.45k
  if (components.size() < skip_top) return nullptr;
150
3.45k
  const auto N = components.size() - skip_top;
151
3.45k
  std::string full_name;
152
10.3k
  for (size_t i = 0; i < N; i++) {
153
6.90k
    full_name += components[i];
154
6.90k
    full_name += '.';
155
6.90k
  }
156
3.86k
  for (size_t i = N; i > 0; i--) {
157
3.65k
    full_name += name;
158
3.65k
    auto obj = table.Lookup(full_name);
159
3.65k
    if (obj) return obj;
160
410
    auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
161
410
    full_name.resize(len);
162
410
  }
163
207
  FLATBUFFERS_ASSERT(full_name.empty());
164
207
  return table.Lookup(name);  // lookup in global namespace
165
207
}
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
3.45k
                            size_t skip_top) {
147
3.45k
  const auto& components = current_namespace.components;
148
3.45k
  if (table.dict.empty()) return nullptr;
149
3.45k
  if (components.size() < skip_top) return nullptr;
150
3.45k
  const auto N = components.size() - skip_top;
151
3.45k
  std::string full_name;
152
10.3k
  for (size_t i = 0; i < N; i++) {
153
6.90k
    full_name += components[i];
154
6.90k
    full_name += '.';
155
6.90k
  }
156
3.86k
  for (size_t i = N; i > 0; i--) {
157
3.65k
    full_name += name;
158
3.65k
    auto obj = table.Lookup(full_name);
159
3.65k
    if (obj) return obj;
160
410
    auto len = full_name.size() - components[i - 1].size() - 1 - name.size();
161
410
    full_name.resize(len);
162
410
  }
163
207
  FLATBUFFERS_ASSERT(full_name.empty());
164
207
  return table.Lookup(name);  // lookup in global namespace
165
207
}
Unexecuted instantiation: 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)
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
9.06k
  TD(Eof, 256, "end of file") \
172
9.06k
  TD(StringConstant, 257, "string constant") \
173
9.06k
  TD(IntegerConstant, 258, "integer constant") \
174
9.06k
  TD(FloatConstant, 259, "float constant") \
175
9.06k
  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
9.06k
static std::string TokenToString(int t) {
186
9.06k
  static const char * const tokens[] = {
187
45.3k
    #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
188
45.3k
      FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
189
9.06k
    #undef FLATBUFFERS_TOKEN
190
9.06k
    #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \
191
172k
      IDLTYPE,
192
172k
      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
193
9.06k
    #undef FLATBUFFERS_TD
194
9.06k
  };
195
9.06k
  if (t < 256) {  // A single ascii char token.
196
4.49k
    std::string s;
197
4.49k
    s.append(1, static_cast<char>(t));
198
4.49k
    return s;
199
4.57k
  } else {       // Other tokens.
200
4.57k
    return tokens[t - 256];
201
4.57k
  }
202
9.06k
}
203
// clang-format on
204
205
7.74M
static bool IsIdentifierStart(char c) { return is_alpha(c) || (c == '_'); }
206
207
static bool CompareSerializedScalars(const uint8_t* a, const uint8_t* b,
208
214M
                                     const FieldDef& key) {
209
214M
  switch (key.value.type.base_type) {
210
0
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...)       \
211
214M
  case BASE_TYPE_##ENUM: {                              \
212
214M
    CTYPE def = static_cast<CTYPE>(0);                  \
213
214M
    if (!a || !b) {                                     \
214
199M
      StringToNumber(key.value.constant.c_str(), &def); \
215
199M
    }                                                   \
216
214M
    const auto av = a ? ReadScalar<CTYPE>(a) : def;     \
217
214M
    const auto bv = b ? ReadScalar<CTYPE>(b) : def;     \
218
214M
    return av < bv;                                     \
219
214M
  }
220
214M
    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
214M
  }
227
214M
}
228
229
static bool CompareTablesByScalarKey(const Offset<Table>* _a,
230
                                     const Offset<Table>* _b,
231
208M
                                     const FieldDef& key) {
232
208M
  const voffset_t offset = key.value.offset;
233
  // Indirect offset pointer to table pointer.
234
208M
  auto a = reinterpret_cast<const uint8_t*>(_a) + ReadScalar<uoffset_t>(_a);
235
208M
  auto b = reinterpret_cast<const uint8_t*>(_b) + ReadScalar<uoffset_t>(_b);
236
  // Fetch field address from table.
237
208M
  a = reinterpret_cast<const Table*>(a)->GetAddressOf(offset);
238
208M
  b = reinterpret_cast<const Table*>(b)->GetAddressOf(offset);
239
208M
  return CompareSerializedScalars(a, b, key);
240
208M
}
241
242
static bool CompareTablesByStringKey(const Offset<Table>* _a,
243
                                     const Offset<Table>* _b,
244
1.60M
                                     const FieldDef& key) {
245
1.60M
  const voffset_t offset = key.value.offset;
246
  // Indirect offset pointer to table pointer.
247
1.60M
  auto a = reinterpret_cast<const uint8_t*>(_a) + ReadScalar<uoffset_t>(_a);
248
1.60M
  auto b = reinterpret_cast<const uint8_t*>(_b) + ReadScalar<uoffset_t>(_b);
249
  // Fetch field address from table.
250
1.60M
  a = reinterpret_cast<const Table*>(a)->GetAddressOf(offset);
251
1.60M
  b = reinterpret_cast<const Table*>(b)->GetAddressOf(offset);
252
1.60M
  if (a && b) {
253
    // Indirect offset pointer to string pointer.
254
1.60M
    a += ReadScalar<uoffset_t>(a);
255
1.60M
    b += ReadScalar<uoffset_t>(b);
256
1.60M
    return *reinterpret_cast<const String*>(a) <
257
1.60M
           *reinterpret_cast<const String*>(b);
258
1.60M
  } else {
259
0
    return a ? true : false;
260
0
  }
261
1.60M
}
262
263
317k
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
317k
  ptrdiff_t diff = (b - a) * sizeof(Offset<Table>);
267
317k
  FLATBUFFERS_ASSERT(diff >= 0);  // Guaranteed by SimpleQsort.
268
317k
  auto udiff = static_cast<uoffset_t>(diff);
269
317k
  a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff);
270
317k
  b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff);
271
317k
  std::swap(*a, *b);
272
317k
}
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
441k
                        S swapper) {
278
441k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
218k
  auto l = begin + width;
280
218k
  auto r = end;
281
215M
  while (l < r) {
282
215M
    if (comparator(begin, l)) {
283
115k
      r -= width;
284
115k
      swapper(l, r);
285
215M
    } else {
286
215M
      l += width;
287
215M
    }
288
215M
  }
289
218k
  l -= width;
290
218k
  swapper(begin, l);
291
218k
  SimpleQsort(begin, l, width, comparator, swapper);
292
218k
  SimpleQsort(r, end, width, comparator, swapper);
293
218k
}
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
25.8k
                        S swapper) {
278
25.8k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
12.7k
  auto l = begin + width;
280
12.7k
  auto r = end;
281
6.00M
  while (l < r) {
282
5.99M
    if (comparator(begin, l)) {
283
3.41k
      r -= width;
284
3.41k
      swapper(l, r);
285
5.99M
    } else {
286
5.99M
      l += width;
287
5.99M
    }
288
5.99M
  }
289
12.7k
  l -= width;
290
12.7k
  swapper(begin, l);
291
12.7k
  SimpleQsort(begin, l, width, comparator, swapper);
292
12.7k
  SimpleQsort(r, end, width, comparator, swapper);
293
12.7k
}
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
78.1k
                        S swapper) {
278
78.1k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
37.7k
  auto l = begin + width;
280
37.7k
  auto r = end;
281
1.64M
  while (l < r) {
282
1.60M
    if (comparator(begin, l)) {
283
50.8k
      r -= width;
284
50.8k
      swapper(l, r);
285
1.55M
    } else {
286
1.55M
      l += width;
287
1.55M
    }
288
1.60M
  }
289
37.7k
  l -= width;
290
37.7k
  swapper(begin, l);
291
37.7k
  SimpleQsort(begin, l, width, comparator, swapper);
292
37.7k
  SimpleQsort(r, end, width, comparator, swapper);
293
37.7k
}
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
337k
                        S swapper) {
278
337k
  if (end - begin <= static_cast<ptrdiff_t>(width)) return;
279
167k
  auto l = begin + width;
280
167k
  auto r = end;
281
208M
  while (l < r) {
282
208M
    if (comparator(begin, l)) {
283
60.8k
      r -= width;
284
60.8k
      swapper(l, r);
285
208M
    } else {
286
208M
      l += width;
287
208M
    }
288
208M
  }
289
167k
  l -= width;
290
167k
  swapper(begin, l);
291
167k
  SimpleQsort(begin, l, width, comparator, swapper);
292
167k
  SimpleQsort(r, end, width, comparator, swapper);
293
167k
}
294
295
template <typename T>
296
0
static inline void SingleValueRepack(Value& e, T val) {
297
  // Remove leading zeros.
298
0
  if (IsInteger(e.type.base_type)) {
299
0
    e.constant = NumToString(val);
300
0
  }
301
0
}
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned char>(flatbuffers::Value&, unsigned char)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<signed char>(flatbuffers::Value&, signed char)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<short>(flatbuffers::Value&, short)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned short>(flatbuffers::Value&, unsigned short)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<int>(flatbuffers::Value&, int)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned int>(flatbuffers::Value&, unsigned int)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<long>(flatbuffers::Value&, long)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::SingleValueRepack<unsigned long>(flatbuffers::Value&, unsigned long)
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
0
static void SingleValueRepack(Value& e, float val) {
307
0
  if (val != val) e.constant = "nan";
308
0
}
309
0
static void SingleValueRepack(Value& e, double val) {
310
0
  if (val != val) e.constant = "nan";
311
0
}
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
0
static bool compareFieldDefs(const FieldDef* a, const FieldDef* b) {
325
0
  auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
326
0
  auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
327
0
  return a_id < b_id;
328
0
}
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
0
static uint64_t HashFile(const char* source_filename, const char* source) {
360
0
  uint64_t hash = 0;
361
362
0
  if (source_filename)
363
0
    hash = HashFnv1a<uint64_t>(StripPath(source_filename).c_str());
364
365
0
  if (source && *source) hash ^= HashFnv1a<uint64_t>(source);
366
367
0
  return hash;
368
0
}
369
370
template <typename T>
371
0
static bool compareName(const T* a, const T* b) {
372
0
  return a->defined_namespace->GetFullyQualifiedName(a->name) <
373
0
         b->defined_namespace->GetFullyQualifiedName(b->name);
374
0
}
Unexecuted instantiation: idl_parser.cpp:bool flatbuffers::(anonymous namespace)::compareName<flatbuffers::StructDef>(flatbuffers::StructDef const*, flatbuffers::StructDef const*)
Unexecuted instantiation: idl_parser.cpp:bool flatbuffers::(anonymous namespace)::compareName<flatbuffers::EnumDef>(flatbuffers::EnumDef const*, flatbuffers::EnumDef const*)
375
376
template <typename T>
377
0
static void AssignIndices(const std::vector<T*>& defvec) {
378
  // Pre-sort these vectors, such that we can set the correct indices for them.
379
0
  auto vec = defvec;
380
0
  std::sort(vec.begin(), vec.end(), compareName<T>);
381
0
  for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
382
0
}
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::AssignIndices<flatbuffers::StructDef>(std::__1::vector<flatbuffers::StructDef*, std::__1::allocator<flatbuffers::StructDef*> > const&)
Unexecuted instantiation: idl_parser.cpp:void flatbuffers::(anonymous namespace)::AssignIndices<flatbuffers::EnumDef>(std::__1::vector<flatbuffers::EnumDef*, std::__1::allocator<flatbuffers::EnumDef*> > const&)
383
384
}  // namespace
385
386
11.9k
void Parser::Message(const std::string& msg) {
387
11.9k
  if (!error_.empty()) error_ += "\n";  // log all warnings and errors
388
11.9k
  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
11.9k
    if (file_being_parsed_.length()) error_ += ":";
396
11.9k
    error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
397
11.9k
  #endif
398
  // clang-format on
399
11.9k
  error_ += ": " + msg;
400
11.9k
}
401
402
0
void Parser::Warning(const std::string& msg) {
403
0
  if (!opts.no_warnings) {
404
0
    Message("warning: " + msg);
405
0
    has_warning_ = true;  // for opts.warnings_as_errors
406
0
  }
407
0
}
408
409
11.9k
CheckedError Parser::Error(const std::string& msg) {
410
11.9k
  Message("error: " + msg);
411
11.9k
  return CheckedError(true);
412
11.9k
}
413
414
10
CheckedError Parser::RecurseError() {
415
10
  return Error("maximum parsing depth " + NumToString(parse_depth_counter_) +
416
10
               " reached");
417
10
}
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
3.69M
      : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) {
427
3.69M
    FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) &&
428
3.69M
                       "Check() must be called to prevent stack overflow");
429
3.69M
    parser_.parse_depth_counter_ += 1;
430
3.69M
  }
431
432
3.69M
  ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; }
433
434
3.69M
  CheckedError Check() {
435
3.69M
    return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH)
436
3.69M
               ? parser_.RecurseError()
437
3.69M
               : CheckedError(false);
438
3.69M
  }
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
4
                                             size_t max_components) const {
450
  // Early exit if we don't have a defined namespace.
451
4
  if (components.empty() || !max_components) {
452
0
    return name;
453
0
  }
454
4
  std::string stream_str;
455
12
  for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
456
8
    stream_str += components[i];
457
8
    stream_str += '.';
458
8
  }
459
4
  if (!stream_str.empty()) stream_str.pop_back();
460
4
  if (name.length()) {
461
4
    stream_str += '.';
462
4
    stream_str += name;
463
4
  }
464
4
  return stream_str;
465
4
}
466
467
4.99k
std::string Parser::TokenToStringId(int t) const {
468
4.99k
  return t == kTokenIdentifier ? attribute_ : TokenToString(t);
469
4.99k
}
470
471
// Parses exactly nibbles worth of hex digits into a number, or error.
472
320k
CheckedError Parser::ParseHexNum(int nibbles, uint64_t* val) {
473
320k
  FLATBUFFERS_ASSERT(nibbles > 0);
474
997k
  for (int i = 0; i < nibbles; i++)
475
677k
    if (!is_xdigit(cursor_[i]))
476
32
      return Error("escape code must be followed by " + NumToString(nibbles) +
477
32
                   " hex digits");
478
320k
  std::string target(cursor_, cursor_ + nibbles);
479
320k
  *val = StringToUInt(target.c_str(), 16);
480
320k
  cursor_ += nibbles;
481
320k
  return NoError();
482
320k
}
483
484
28.7k
CheckedError Parser::SkipByteOrderMark() {
485
28.7k
  if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
486
26
  cursor_++;
487
26
  if (static_cast<unsigned char>(*cursor_) != 0xbb)
488
12
    return Error("invalid utf-8 byte order mark");
489
14
  cursor_++;
490
14
  if (static_cast<unsigned char>(*cursor_) != 0xbf)
491
13
    return Error("invalid utf-8 byte order mark");
492
1
  cursor_++;
493
1
  return NoError();
494
14
}
495
496
10.0M
CheckedError Parser::Next() {
497
10.0M
  doc_comment_.clear();
498
10.0M
  prev_cursor_ = cursor_;
499
10.0M
  bool seen_newline = cursor_ == source_;
500
10.0M
  attribute_.clear();
501
10.0M
  attr_is_trivial_ascii_string_ = true;
502
17.1M
  for (;;) {
503
17.1M
    char c = *cursor_++;
504
17.1M
    token_ = c;
505
17.1M
    switch (c) {
506
42.1k
      case '\0':
507
42.1k
        cursor_--;
508
42.1k
        token_ = kTokenEof;
509
42.1k
        return NoError();
510
6.35M
      case ' ':
511
6.36M
      case '\r':
512
6.36M
      case '\t':
513
6.36M
        break;
514
664k
      case '\n':
515
664k
        MarkNewLine();
516
664k
        seen_newline = true;
517
664k
        break;
518
399k
      case '{':
519
786k
      case '}':
520
790k
      case '(':
521
794k
      case ')':
522
1.95M
      case '[':
523
3.11M
      case ']':
524
3.11M
      case '<':
525
3.11M
      case '>':
526
5.90M
      case ',':
527
6.65M
      case ':':
528
6.65M
      case ';':
529
6.65M
      case '=':
530
6.65M
        return NoError();
531
263k
      case '\"':
532
282k
      case '\'': {
533
282k
        int unicode_high_surrogate = -1;
534
535
3.81M
        while (*cursor_ != c) {
536
3.53M
          if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
537
190
            return Error("illegal character in string constant");
538
3.53M
          if (*cursor_ == '\\') {
539
327k
            attr_is_trivial_ascii_string_ = false;  // has escape sequence
540
327k
            cursor_++;
541
327k
            if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
542
14
              return Error(
543
14
                  "illegal Unicode sequence (unpaired high surrogate)");
544
14
            }
545
327k
            switch (*cursor_) {
546
777
              case 'n':
547
777
                attribute_ += '\n';
548
777
                cursor_++;
549
777
                break;
550
1.10k
              case 't':
551
1.10k
                attribute_ += '\t';
552
1.10k
                cursor_++;
553
1.10k
                break;
554
2.19k
              case 'r':
555
2.19k
                attribute_ += '\r';
556
2.19k
                cursor_++;
557
2.19k
                break;
558
553
              case 'b':
559
553
                attribute_ += '\b';
560
553
                cursor_++;
561
553
                break;
562
679
              case 'f':
563
679
                attribute_ += '\f';
564
679
                cursor_++;
565
679
                break;
566
1.10k
              case '\"':
567
1.10k
                attribute_ += '\"';
568
1.10k
                cursor_++;
569
1.10k
                break;
570
197
              case '\'':
571
197
                attribute_ += '\'';
572
197
                cursor_++;
573
197
                break;
574
234
              case '\\':
575
234
                attribute_ += '\\';
576
234
                cursor_++;
577
234
                break;
578
194
              case '/':
579
194
                attribute_ += '/';
580
194
                cursor_++;
581
194
                break;
582
301k
              case 'x': {  // Not in the JSON standard
583
301k
                cursor_++;
584
301k
                uint64_t val;
585
301k
                ECHECK(ParseHexNum(2, &val));
586
301k
                attribute_ += static_cast<char>(val);
587
301k
                break;
588
301k
              }
589
18.8k
              case 'u': {
590
18.8k
                cursor_++;
591
18.8k
                uint64_t val;
592
18.8k
                ECHECK(ParseHexNum(4, &val));
593
18.7k
                if (val >= 0xD800 && val <= 0xDBFF) {
594
1.17k
                  if (unicode_high_surrogate != -1) {
595
1
                    return Error(
596
1
                        "illegal Unicode sequence (multiple high surrogates)");
597
1.17k
                  } else {
598
1.17k
                    unicode_high_surrogate = static_cast<int>(val);
599
1.17k
                  }
600
17.6k
                } else if (val >= 0xDC00 && val <= 0xDFFF) {
601
1.13k
                  if (unicode_high_surrogate == -1) {
602
9
                    return Error(
603
9
                        "illegal Unicode sequence (unpaired low surrogate)");
604
1.12k
                  } else {
605
1.12k
                    int code_point = 0x10000 +
606
1.12k
                                     ((unicode_high_surrogate & 0x03FF) << 10) +
607
1.12k
                                     (val & 0x03FF);
608
1.12k
                    ToUTF8(code_point, &attribute_);
609
1.12k
                    unicode_high_surrogate = -1;
610
1.12k
                  }
611
16.4k
                } else {
612
16.4k
                  if (unicode_high_surrogate != -1) {
613
1
                    return Error(
614
1
                        "illegal Unicode sequence (unpaired high surrogate)");
615
1
                  }
616
16.4k
                  ToUTF8(static_cast<int>(val), &attribute_);
617
16.4k
                }
618
18.7k
                break;
619
18.7k
              }
620
18.7k
              default:
621
5
                return Error("unknown escape code in string constant");
622
327k
            }
623
3.20M
          } else {  // printable chars + UTF-8 bytes
624
3.20M
            if (unicode_high_surrogate != -1) {
625
10
              return Error(
626
10
                  "illegal Unicode sequence (unpaired high surrogate)");
627
10
            }
628
            // reset if non-printable
629
3.20M
            attr_is_trivial_ascii_string_ &=
630
3.20M
                check_ascii_range(*cursor_, ' ', '~');
631
632
3.20M
            attribute_ += *cursor_++;
633
3.20M
          }
634
3.53M
        }
635
282k
        if (unicode_high_surrogate != -1) {
636
11
          return Error("illegal Unicode sequence (unpaired high surrogate)");
637
11
        }
638
282k
        cursor_++;
639
282k
        if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
640
1.94k
            !ValidateUTF8(attribute_)) {
641
73
          return Error("illegal UTF-8 sequence");
642
73
        }
643
282k
        token_ = kTokenStringConstant;
644
282k
        return NoError();
645
282k
      }
646
31.4k
      case '/':
647
31.4k
        if (*cursor_ == '/') {
648
31.2k
          const char* start = ++cursor_;
649
319k
          while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
650
31.2k
          if (*start == '/') {  // documentation comment
651
16.0k
            if (!seen_newline)
652
1
              return Error(
653
1
                  "a documentation comment should be on a line on its own");
654
16.0k
            doc_comment_.push_back(std::string(start + 1, cursor_));
655
16.0k
          }
656
31.2k
          break;
657
31.2k
        } else if (*cursor_ == '*') {
658
259
          cursor_++;
659
          // TODO: make nested.
660
1.08k
          while (*cursor_ != '*' || cursor_[1] != '/') {
661
866
            if (*cursor_ == '\n') MarkNewLine();
662
866
            if (!*cursor_) return Error("end of file in comment");
663
821
            cursor_++;
664
821
          }
665
214
          cursor_ += 2;
666
214
          break;
667
259
        }
668
21
        FLATBUFFERS_FALLTHROUGH();  // else fall thru
669
3.12M
      default:
670
3.12M
        if (IsIdentifierStart(c)) {
671
          // Collect all chars of an identifier:
672
764k
          const char* start = cursor_ - 1;
673
4.59M
          while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
674
764k
          attribute_.append(start, cursor_);
675
764k
          token_ = kTokenIdentifier;
676
764k
          return NoError();
677
764k
        }
678
679
2.35M
        const auto has_sign = (c == '+') || (c == '-');
680
2.35M
        if (has_sign) {
681
          // Check for +/-inf which is considered a float constant.
682
21.0k
          if (strncmp(cursor_, "inf", 3) == 0 &&
683
1.34k
              !(IsIdentifierStart(cursor_[3]) || is_digit(cursor_[3]))) {
684
606
            attribute_.assign(cursor_ - 1, cursor_ + 3);
685
606
            token_ = kTokenFloatConstant;
686
606
            cursor_ += 3;
687
606
            return NoError();
688
606
          }
689
690
20.4k
          if (IsIdentifierStart(*cursor_)) {
691
            // '-'/'+' and following identifier - it could be a predefined
692
            // constant. Return the sign in token_, see ParseSingleValue.
693
3.24k
            return NoError();
694
3.24k
          }
695
20.4k
        }
696
697
2.35M
        auto dot_lvl =
698
2.35M
            (c == '.') ? 0 : 1;  // dot_lvl==0 <=> exactly one '.' seen
699
2.35M
        if (!dot_lvl && !is_digit(*cursor_)) return NoError();  // enum?
700
        // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
701
2.35M
        if (is_digit(c) || has_sign || !dot_lvl) {
702
2.35M
          const auto start = cursor_ - 1;
703
2.35M
          auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
704
2.35M
          if (!is_digit(c) && is_digit(*cursor_)) {
705
574k
            start_digits = cursor_;  // see digit in cursor_ position
706
574k
            c = *cursor_++;
707
574k
          }
708
          // hex-float can't begind with '.'
709
2.35M
          auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
710
2.35M
          if (use_hex) start_digits = ++cursor_;  // '0x' is the prefix, skip it
711
          // Read an integer number or mantisa of float-point number.
712
2.94M
          do {
713
2.94M
            if (use_hex) {
714
162k
              while (is_xdigit(*cursor_)) cursor_++;
715
2.94M
            } else {
716
11.7M
              while (is_digit(*cursor_)) cursor_++;
717
2.94M
            }
718
2.94M
          } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
719
          // Exponent of float-point number.
720
2.35M
          if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
721
            // The exponent suffix of hexadecimal float number is mandatory.
722
2.35M
            if (use_hex && !dot_lvl) start_digits = cursor_;
723
2.35M
            if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
724
2.35M
                is_alpha_char(*cursor_, 'E')) {
725
28.4k
              dot_lvl = 0;  // Emulate dot to signal about float-point number.
726
28.4k
              cursor_++;
727
28.4k
              if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
728
28.4k
              start_digits = cursor_;  // the exponent-part has to have digits
729
              // Exponent is decimal integer number
730
112k
              while (is_digit(*cursor_)) cursor_++;
731
28.4k
              if (*cursor_ == '.') {
732
2
                cursor_++;  // If see a dot treat it as part of invalid number.
733
2
                dot_lvl = -1;  // Fall thru to Error().
734
2
              }
735
28.4k
            }
736
2.35M
          }
737
          // Finalize.
738
2.35M
          if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
739
2.35M
            attribute_.append(start, cursor_);
740
2.35M
            token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
741
2.35M
            return NoError();
742
2.35M
          } else {
743
118
            return Error("invalid number: " + std::string(start, cursor_));
744
118
          }
745
2.35M
        }
746
169
        std::string ch;
747
169
        ch = c;
748
169
        if (false == check_ascii_range(c, ' ', '~'))
749
110
          ch = "code: " + NumToString(c);
750
169
        return Error("illegal character: " + ch);
751
17.1M
    }
752
17.1M
  }
753
10.0M
}
754
755
// Check if a given token is next.
756
9.55M
bool Parser::Is(int t) const { return t == token_; }
757
758
407k
bool Parser::IsIdent(const char* id) const {
759
407k
  return token_ == kTokenIdentifier && attribute_ == id;
760
407k
}
761
762
// Expect a given token to be next, consume it, or error if not present.
763
7.27M
CheckedError Parser::Expect(int t) {
764
7.27M
  if (t != token_) {
765
4.39k
    return Error("expecting: " + TokenToString(t) +
766
4.39k
                 " instead got: " + TokenToStringId(token_));
767
4.39k
  }
768
7.27M
  NEXT();
769
7.27M
  return NoError();
770
7.27M
}
771
772
0
CheckedError Parser::ParseNamespacing(std::string* id, std::string* last) {
773
0
  while (Is('.')) {
774
0
    NEXT();
775
0
    *id += ".";
776
0
    *id += attribute_;
777
0
    if (last) *last = attribute_;
778
0
    EXPECT(kTokenIdentifier);
779
0
  }
780
0
  return NoError();
781
0
}
782
783
3.45k
EnumDef* Parser::LookupEnum(const std::string& id) {
784
  // Search thru parent namespaces.
785
3.45k
  return LookupTableByName(enums_, id, *current_namespace_, 0);
786
3.45k
}
787
788
4
StructDef* Parser::LookupStruct(const std::string& id) const {
789
4
  auto sd = structs_.Lookup(id);
790
4
  if (sd) sd->refcount++;
791
4
  return sd;
792
4
}
793
794
StructDef* Parser::LookupStructThruParentNamespaces(
795
0
    const std::string& id) const {
796
0
  auto sd = LookupTableByName(structs_, id, *current_namespace_, 1);
797
0
  if (sd) sd->refcount++;
798
0
  return sd;
799
0
}
800
801
0
CheckedError Parser::ParseTypeIdent(Type& type) {
802
0
  std::string id = attribute_;
803
0
  EXPECT(kTokenIdentifier);
804
0
  ECHECK(ParseNamespacing(&id, nullptr));
805
0
  auto enum_def = LookupEnum(id);
806
0
  if (enum_def) {
807
0
    type = enum_def->underlying_type;
808
0
    if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
809
0
  } else {
810
0
    type.base_type = BASE_TYPE_STRUCT;
811
0
    type.struct_def = LookupCreateStruct(id);
812
0
  }
813
0
  return NoError();
814
0
}
815
816
// Parse any IDL type.
817
0
CheckedError Parser::ParseType(Type& type) {
818
0
  if (token_ == kTokenIdentifier) {
819
0
    if (IsIdent("bool")) {
820
0
      type.base_type = BASE_TYPE_BOOL;
821
0
      NEXT();
822
0
    } else if (IsIdent("byte") || IsIdent("int8")) {
823
0
      type.base_type = BASE_TYPE_CHAR;
824
0
      NEXT();
825
0
    } else if (IsIdent("ubyte") || IsIdent("uint8")) {
826
0
      type.base_type = BASE_TYPE_UCHAR;
827
0
      NEXT();
828
0
    } else if (IsIdent("short") || IsIdent("int16")) {
829
0
      type.base_type = BASE_TYPE_SHORT;
830
0
      NEXT();
831
0
    } else if (IsIdent("ushort") || IsIdent("uint16")) {
832
0
      type.base_type = BASE_TYPE_USHORT;
833
0
      NEXT();
834
0
    } else if (IsIdent("int") || IsIdent("int32")) {
835
0
      type.base_type = BASE_TYPE_INT;
836
0
      NEXT();
837
0
    } else if (IsIdent("uint") || IsIdent("uint32")) {
838
0
      type.base_type = BASE_TYPE_UINT;
839
0
      NEXT();
840
0
    } else if (IsIdent("long") || IsIdent("int64")) {
841
0
      type.base_type = BASE_TYPE_LONG;
842
0
      NEXT();
843
0
    } else if (IsIdent("ulong") || IsIdent("uint64")) {
844
0
      type.base_type = BASE_TYPE_ULONG;
845
0
      NEXT();
846
0
    } else if (IsIdent("float") || IsIdent("float32")) {
847
0
      type.base_type = BASE_TYPE_FLOAT;
848
0
      NEXT();
849
0
    } else if (IsIdent("double") || IsIdent("float64")) {
850
0
      type.base_type = BASE_TYPE_DOUBLE;
851
0
      NEXT();
852
0
    } else if (IsIdent("string")) {
853
0
      type.base_type = BASE_TYPE_STRING;
854
0
      NEXT();
855
0
    } else {
856
0
      ECHECK(ParseTypeIdent(type));
857
0
    }
858
0
  } else if (token_ == '[') {
859
0
    ParseDepthGuard depth_guard(this);
860
0
    ECHECK(depth_guard.Check());
861
0
    NEXT();
862
0
    Type subtype;
863
0
    ECHECK(ParseType(subtype));
864
0
    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
0
      return Error("nested vector types not supported (wrap in table first)");
868
0
    }
869
0
    if (token_ == ':') {
870
0
      NEXT();
871
0
      if (token_ != kTokenIntegerConstant) {
872
0
        return Error("length of fixed-length array must be an integer value");
873
0
      }
874
0
      uint16_t fixed_length = 0;
875
0
      bool check = StringToNumber(attribute_.c_str(), &fixed_length);
876
0
      if (!check || fixed_length < 1) {
877
0
        return Error(
878
0
            "length of fixed-length array must be positive and fit to "
879
0
            "uint16_t type");
880
0
      }
881
0
      type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
882
0
                  fixed_length);
883
0
      NEXT();
884
0
    } else {
885
0
      type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
886
0
    }
887
0
    type.element = subtype.base_type;
888
0
    EXPECT(']');
889
0
  } else {
890
0
    return Error("illegal type syntax");
891
0
  }
892
0
  return NoError();
893
0
}
894
895
CheckedError Parser::AddField(StructDef& struct_def, const std::string& name,
896
0
                              const Type& type, FieldDef** dest) {
897
0
  auto& field = *new FieldDef();
898
0
  field.value.offset =
899
0
      FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
900
0
  field.name = name;
901
0
  field.file = struct_def.file;
902
0
  field.value.type = type;
903
0
  if (struct_def.fixed) {  // statically compute the field offset
904
0
    auto size = InlineSize(type);
905
0
    auto alignment = InlineAlignment(type);
906
    // structs_ need to have a predictable format, so we need to align to
907
    // the largest scalar
908
0
    struct_def.minalign = std::max(struct_def.minalign, alignment);
909
0
    struct_def.PadLastField(alignment);
910
0
    field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
911
0
    struct_def.bytesize += size;
912
0
  }
913
0
  if (struct_def.fields.Add(name, &field))
914
0
    return Error("field already exists: " + name);
915
0
  *dest = &field;
916
0
  return NoError();
917
0
}
918
919
0
CheckedError Parser::ParseField(StructDef& struct_def) {
920
0
  std::string name = attribute_;
921
922
0
  if (LookupCreateStruct(name, false, false))
923
0
    return Error("field name can not be the same as table/struct name");
924
925
0
  if (!IsLowerSnakeCase(name)) {
926
0
    Warning("field names should be lowercase snake_case, got: " + name);
927
0
  }
928
929
0
  std::vector<std::string> dc = doc_comment_;
930
0
  EXPECT(kTokenIdentifier);
931
0
  EXPECT(':');
932
0
  Type type;
933
0
  ECHECK(ParseType(type));
934
935
0
  if (struct_def.fixed) {
936
0
    if (IsIncompleteStruct(type) ||
937
0
        (IsArray(type) && IsIncompleteStruct(type.VectorType()))) {
938
0
      std::string type_name = IsArray(type) ? type.VectorType().struct_def->name
939
0
                                            : type.struct_def->name;
940
0
      return Error(
941
0
          std::string("Incomplete type in struct is not allowed, type name: ") +
942
0
          type_name);
943
0
    }
944
945
0
    auto valid = IsScalar(type.base_type) || IsStruct(type);
946
0
    if (!valid && IsArray(type)) {
947
0
      const auto& elem_type = type.VectorType();
948
0
      valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type);
949
0
    }
950
0
    if (!valid)
951
0
      return Error("structs may contain only scalar or struct fields");
952
0
  }
953
954
0
  if (!struct_def.fixed && IsArray(type))
955
0
    return Error("fixed-length array in table must be wrapped in struct");
956
957
0
  if (IsArray(type)) {
958
0
    advanced_features_ |= reflection::AdvancedArrayFeatures;
959
0
    if (!SupportsAdvancedArrayFeatures()) {
960
0
      return Error(
961
0
          "Arrays are not yet supported in all "
962
0
          "the specified programming languages.");
963
0
    }
964
0
  }
965
966
0
  FieldDef* typefield = nullptr;
967
0
  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
0
    Type union_type(type.enum_def->underlying_type);
974
0
    union_type.base_type = BASE_TYPE_UTYPE;
975
0
    ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_type,
976
0
                    &typefield));
977
978
0
  } else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
979
0
    advanced_features_ |= reflection::AdvancedUnionFeatures;
980
    // Only cpp, js and ts supports the union vector feature so far.
981
0
    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
0
    Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
989
0
    union_vector.element = BASE_TYPE_UTYPE;
990
0
    ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
991
0
                    &typefield));
992
0
  }
993
994
0
  FieldDef* field;
995
0
  ECHECK(AddField(struct_def, name, type, &field));
996
997
0
  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
0
    typefield->sibling_union_field = field;
1002
0
    field->sibling_union_field = typefield;
1003
0
  }
1004
1005
0
  if (token_ == '=') {
1006
0
    NEXT();
1007
0
    ECHECK(ParseSingleValue(&field->name, field->value, true));
1008
0
    if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
1009
0
      return Error(
1010
0
          "default values are not supported for struct fields, table fields, "
1011
0
          "or in structs.");
1012
0
    if (IsString(type) || IsVector(type)) {
1013
0
      advanced_features_ |= reflection::DefaultVectorsAndStrings;
1014
0
      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
0
    }
1020
1021
0
    if (IsVector(type) && field->value.constant != "0" &&
1022
0
        field->value.constant != "[]") {
1023
0
      return Error("The only supported default for vectors is `[]`.");
1024
0
    }
1025
0
  }
1026
1027
  // Append .0 if the value has not it (skip hex and scientific floats).
1028
  // This suffix needed for generated C++ code.
1029
0
  if (IsFloat(type.base_type)) {
1030
0
    auto& text = field->value.constant;
1031
0
    FLATBUFFERS_ASSERT(false == text.empty());
1032
0
    auto s = text.c_str();
1033
0
    while (*s == ' ') s++;
1034
0
    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
0
    if ((false == IsIdentifierStart(*s)) &&
1038
0
        (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
1039
0
      field->value.constant += ".0";
1040
0
    }
1041
0
  }
1042
1043
0
  field->doc_comment = dc;
1044
0
  ECHECK(ParseMetaData(&field->attributes));
1045
0
  field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
1046
0
  auto hash_name = field->attributes.Lookup("hash");
1047
0
  if (hash_name) {
1048
0
    switch ((IsVector(type)) ? type.element : type.base_type) {
1049
0
      case BASE_TYPE_SHORT:
1050
0
      case BASE_TYPE_USHORT: {
1051
0
        if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
1052
0
          return Error("Unknown hashing algorithm for 16 bit types: " +
1053
0
                       hash_name->constant);
1054
0
        break;
1055
0
      }
1056
0
      case BASE_TYPE_INT:
1057
0
      case BASE_TYPE_UINT: {
1058
0
        if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
1059
0
          return Error("Unknown hashing algorithm for 32 bit types: " +
1060
0
                       hash_name->constant);
1061
0
        break;
1062
0
      }
1063
0
      case BASE_TYPE_LONG:
1064
0
      case BASE_TYPE_ULONG: {
1065
0
        if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
1066
0
          return Error("Unknown hashing algorithm for 64 bit types: " +
1067
0
                       hash_name->constant);
1068
0
        break;
1069
0
      }
1070
0
      default:
1071
0
        return Error(
1072
0
            "only short, ushort, int, uint, long and ulong data types support "
1073
0
            "hashing.");
1074
0
    }
1075
0
  }
1076
1077
0
  if (field->attributes.Lookup("vector64") != nullptr) {
1078
0
    if (!IsVector(type)) {
1079
0
      return Error("`vector64` attribute can only be applied on vectors.");
1080
0
    }
1081
1082
    // Upgrade the type to be a BASE_TYPE_VECTOR64, since the attributes are
1083
    // parsed after the type.
1084
0
    const BaseType element_base_type = type.element;
1085
0
    type = Type(BASE_TYPE_VECTOR64, type.struct_def, type.enum_def);
1086
0
    type.element = element_base_type;
1087
1088
    // Since the field was already added to the parent object, update the type
1089
    // in place.
1090
0
    field->value.type = type;
1091
1092
    // 64-bit vectors imply the offset64 attribute.
1093
0
    field->offset64 = true;
1094
0
  }
1095
1096
  // Record that this field uses 64-bit offsets.
1097
0
  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
0
    if (type.base_type == BASE_TYPE_VECTOR64) {
1101
0
      Warning("attribute `vector64` implies `offset64` and isn't required.");
1102
0
    }
1103
1104
0
    field->offset64 = true;
1105
0
  }
1106
1107
  // Check for common conditions with Offset64 fields.
1108
0
  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
0
    if (!IsString(type) && !IsVector(type)) {
1112
0
      return Error(
1113
0
          "only string and vectors can have `offset64` attribute applied");
1114
0
    }
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
0
    if (IsVector(type) &&
1121
0
        !((IsScalar(type.element) && !IsEnum(type.VectorType())) ||
1122
0
          IsStruct(type.VectorType()))) {
1123
0
      return Error("only vectors of scalars are allowed to be 64-bit.");
1124
0
    }
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
0
    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
0
  }
1135
1136
0
  field->key = field->attributes.Lookup("key") != nullptr;
1137
1138
0
  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
0
    const bool required = field->attributes.Lookup("required") != nullptr ||
1143
0
                          (IsString(type) && field->key);
1144
0
    const bool default_str_or_vec =
1145
0
        ((IsString(type) || IsVector(type)) && field->value.constant != "0");
1146
0
    const bool optional = IsScalar(type.base_type)
1147
0
                              ? (field->value.constant == "null")
1148
0
                              : !(required || default_str_or_vec);
1149
0
    if (required && optional) {
1150
0
      return Error("Fields cannot be both optional and required.");
1151
0
    }
1152
0
    field->presence = FieldDef::MakeFieldPresence(optional, required);
1153
1154
0
    if (required && IsScalar(type.base_type)) {
1155
0
      return Error("only non-scalar fields in tables may be 'required'");
1156
0
    }
1157
0
  } else {
1158
    // all struct fields are required
1159
0
    field->presence = FieldDef::kDefault;
1160
1161
    // setting required or optional on a struct field is meaningless
1162
0
    if (field->attributes.Lookup("required") != nullptr ||
1163
0
        field->attributes.Lookup("optional") != nullptr) {
1164
0
      return Error("struct fields are always required");
1165
0
    }
1166
0
  }
1167
1168
0
  if (field->key) {
1169
0
    if (struct_def.has_key) return Error("only one field may be set as 'key'");
1170
0
    struct_def.has_key = true;
1171
0
    auto is_valid =
1172
0
        IsScalar(type.base_type) || IsString(type) || IsStruct(type);
1173
0
    if (IsArray(type)) {
1174
0
      is_valid |=
1175
0
          IsScalar(type.VectorType().base_type) || IsStruct(type.VectorType());
1176
0
    }
1177
0
    if (!is_valid) {
1178
0
      return Error(
1179
0
          "'key' field must be string, scalar type or fixed size array of "
1180
0
          "scalars");
1181
0
    }
1182
0
  }
1183
1184
0
  if (field->IsScalarOptional()) {
1185
0
    advanced_features_ |= reflection::OptionalScalars;
1186
0
    if (type.enum_def && type.enum_def->Lookup("null")) {
1187
0
      FLATBUFFERS_ASSERT(IsInteger(type.base_type));
1188
0
      return Error(
1189
0
          "the default 'null' is reserved for declaring optional scalar "
1190
0
          "fields, it conflicts with declaration of enum '" +
1191
0
          type.enum_def->name + "'.");
1192
0
    }
1193
0
    if (field->attributes.Lookup("key")) {
1194
0
      return Error(
1195
0
          "only a non-optional scalar field can be used as a 'key' field");
1196
0
    }
1197
0
    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
0
  }
1203
1204
0
  auto check_enum = [this](const FieldDef* field, const Type& type,
1205
0
                           const std::string& name,
1206
0
                           const std::string& constant) -> CheckedError {
1207
    // Optional and bitflags enums may have default constants that are not
1208
    // their specified variants.
1209
0
    if (!field->IsOptional() &&
1210
0
        type.enum_def->attributes.Lookup("bit_flags") == nullptr) {
1211
0
      if (type.enum_def->FindByValue(constant) == nullptr) {
1212
0
        return Error("default value of `" + constant + "` for " + "field `" +
1213
0
                     name + "` is not part of enum `" + type.enum_def->name +
1214
0
                     "`.");
1215
0
      }
1216
0
    }
1217
1218
0
    return NoError();
1219
0
  };
1220
1221
0
  if (type.enum_def) {
1222
    // Verify the enum's type and default value.
1223
0
    const std::string& constant = field->value.constant;
1224
0
    if (type.base_type == BASE_TYPE_UNION) {
1225
0
      if (constant != "0") {
1226
0
        return Error("Union defaults must be NONE");
1227
0
      }
1228
0
    } else if (IsVector(type)) {
1229
0
      if (constant != "0" && constant != "[]") {
1230
0
        return Error("Vector defaults may only be `[]`.");
1231
0
      }
1232
0
    } else if (IsArray(type)) {
1233
0
      if (constant != "0") {
1234
0
        return Error("Array defaults are not supported yet.");
1235
0
      }
1236
0
      CheckedError err = check_enum(field, type.VectorType(), name, constant);
1237
0
      if (err.Check()) {
1238
        // reset the check state of the error
1239
0
        return CheckedError{err};
1240
0
      }
1241
0
    } else {
1242
0
      if (!IsInteger(type.base_type)) {
1243
0
        return Error("Enums must have integer base types");
1244
0
      }
1245
0
      CheckedError err = check_enum(field, type, name, constant);
1246
0
      if (err.Check()) {
1247
        // reset the check state of the error
1248
0
        return CheckedError{err};
1249
0
      }
1250
0
    }
1251
0
  }
1252
1253
0
  if (field->deprecated && struct_def.fixed)
1254
0
    return Error("can't deprecate fields in a struct");
1255
1256
0
  auto cpp_type = field->attributes.Lookup("cpp_type");
1257
0
  if (cpp_type) {
1258
0
    if (!hash_name)
1259
0
      return Error("cpp_type can only be used with a hashed field");
1260
    /// forcing cpp_ptr_type to 'naked' if unset
1261
0
    auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
1262
0
    if (!cpp_ptr_type) {
1263
0
      auto val = new Value();
1264
0
      val->type = cpp_type->type;
1265
0
      val->constant = "naked";
1266
0
      field->attributes.Add("cpp_ptr_type", val);
1267
0
    }
1268
0
  }
1269
1270
0
  field->shared = field->attributes.Lookup("shared") != nullptr;
1271
0
  if (field->shared && field->value.type.base_type != BASE_TYPE_STRING)
1272
0
    return Error("shared can only be defined on strings");
1273
1274
0
  auto field_native_custom_alloc =
1275
0
      field->attributes.Lookup("native_custom_alloc");
1276
0
  if (field_native_custom_alloc)
1277
0
    return Error(
1278
0
        "native_custom_alloc can only be used with a table or struct "
1279
0
        "definition");
1280
1281
0
  field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
1282
0
  if (field->native_inline && !IsStruct(field->value.type) &&
1283
0
      !IsVectorOfStruct(field->value.type) &&
1284
0
      !IsVectorOfTable(field->value.type))
1285
0
    return Error(
1286
0
        "'native_inline' can only be defined on structs, vector of structs or "
1287
0
        "vector of tables");
1288
1289
0
  auto nested = field->attributes.Lookup("nested_flatbuffer");
1290
0
  if (nested) {
1291
0
    if (nested->type.base_type != BASE_TYPE_STRING)
1292
0
      return Error(
1293
0
          "nested_flatbuffer attribute must be a string (the root type)");
1294
0
    if (!IsVector(type.base_type) || type.element != BASE_TYPE_UCHAR)
1295
0
      return Error(
1296
0
          "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
0
    field->nested_flatbuffer = LookupCreateStruct(nested->constant);
1300
0
  }
1301
1302
0
  if (field->attributes.Lookup("flexbuffer")) {
1303
0
    field->flexbuffer = true;
1304
0
    uses_flexbuffers_ = true;
1305
0
    if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
1306
0
      return Error("flexbuffer attribute may only apply to a vector of ubyte");
1307
0
  }
1308
1309
0
  if (typefield) {
1310
0
    if (!IsScalar(typefield->value.type.base_type)) {
1311
      // this is a union vector field
1312
0
      typefield->presence = field->presence;
1313
0
    }
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
0
    auto attr = field->attributes.Lookup("id");
1317
0
    if (attr) {
1318
0
      const auto& id_str = attr->constant;
1319
0
      voffset_t id = 0;
1320
0
      const auto done = !atot(id_str.c_str(), *this, &id).Check();
1321
0
      if (done && id > 0) {
1322
0
        auto val = new Value();
1323
0
        val->type = attr->type;
1324
0
        val->constant = NumToString(id - 1);
1325
0
        typefield->attributes.Add("id", val);
1326
0
      } else {
1327
0
        return Error(
1328
0
            "a union type effectively adds two fields with non-negative ids, "
1329
0
            "its id must be that of the second field (the first field is "
1330
0
            "the type field and not explicitly declared in the schema);\n"
1331
0
            "field: " +
1332
0
            field->name + ", id: " + id_str);
1333
0
      }
1334
0
    }
1335
    // if this field is a union that is deprecated,
1336
    // the automatically added type field should be deprecated as well
1337
0
    if (field->deprecated) {
1338
0
      typefield->deprecated = true;
1339
0
    }
1340
0
  }
1341
1342
0
  EXPECT(';');
1343
0
  return NoError();
1344
0
}
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
0
    val.constant = NumToString(builder_.CreateSharedString(s).o);
1351
123k
  } else {
1352
123k
    val.constant = NumToString(builder_.CreateString(s).o);
1353
123k
  }
1354
123k
  return NoError();
1355
123k
}
1356
1357
2.79M
CheckedError Parser::ParseComma() {
1358
2.79M
  if (!opts.protobuf_ascii_alike) EXPECT(',');
1359
2.79M
  return NoError();
1360
2.79M
}
1361
1362
CheckedError Parser::ParseAnyValue(Value& val, FieldDef* field,
1363
                                   size_t parent_fieldn,
1364
                                   const StructDef* parent_struct_def,
1365
773k
                                   size_t count, bool inside_vector) {
1366
773k
  switch (val.type.base_type) {
1367
3.02k
    case BASE_TYPE_UNION: {
1368
3.02k
      FLATBUFFERS_ASSERT(field);
1369
3.02k
      std::string constant;
1370
3.02k
      Vector<uint8_t>* vector_of_union_types = nullptr;
1371
      // Find corresponding type field we may have already parsed.
1372
3.02k
      for (auto elem = field_stack_.rbegin() + count;
1373
3.29k
           elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) {
1374
1.91k
        auto& type = elem->second->value.type;
1375
1.91k
        if (type.enum_def == val.type.enum_def) {
1376
1.75k
          if (inside_vector) {
1377
0
            if (IsVector(type) && type.element == BASE_TYPE_UTYPE) {
1378
              // Vector of union type field.
1379
0
              uoffset_t offset;
1380
0
              ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
1381
0
              vector_of_union_types = reinterpret_cast<Vector<uint8_t>*>(
1382
0
                  builder_.GetCurrentBufferPointer() + builder_.GetSize() -
1383
0
                  offset);
1384
0
              break;
1385
0
            }
1386
1.75k
          } else {
1387
1.75k
            if (type.base_type == BASE_TYPE_UTYPE) {
1388
              // Union type field.
1389
1.65k
              constant = elem->first.constant;
1390
1.65k
              break;
1391
1.65k
            }
1392
1.75k
          }
1393
1.75k
        }
1394
1.91k
      }
1395
3.02k
      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.37k
        auto type_name = field->name + UnionTypeFieldSuffix();
1402
1.37k
        FLATBUFFERS_ASSERT(parent_struct_def);
1403
1.37k
        auto type_field = parent_struct_def->fields.Lookup(type_name);
1404
1.37k
        FLATBUFFERS_ASSERT(type_field);  // Guaranteed by ParseField().
1405
        // Remember where we are in the source file, so we can come back here.
1406
1.37k
        auto backup = *static_cast<ParserState*>(this);
1407
1.37k
        ECHECK(SkipAnyJsonValue());  // The table.
1408
1.34k
        ECHECK(ParseComma());
1409
1.33k
        auto next_name = attribute_;
1410
1.33k
        if (Is(kTokenStringConstant)) {
1411
41
          NEXT();
1412
1.29k
        } else {
1413
1.29k
          EXPECT(kTokenIdentifier);
1414
1.28k
        }
1415
1.32k
        if (next_name == type_name) {
1416
1.29k
          EXPECT(':');
1417
1.29k
          ParseDepthGuard depth_guard(this);
1418
1.29k
          ECHECK(depth_guard.Check());
1419
1.29k
          Value type_val = type_field->value;
1420
1.29k
          ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0));
1421
1.29k
          constant = type_val.constant;
1422
          // Got the information we needed, now rewind:
1423
1.29k
          *static_cast<ParserState*>(this) = backup;
1424
1.29k
        }
1425
1.32k
      }
1426
2.98k
      if (constant.empty() && !vector_of_union_types) {
1427
29
        return Error("missing type field for this union value: " + field->name);
1428
29
      }
1429
2.95k
      uint8_t enum_idx;
1430
2.95k
      if (vector_of_union_types) {
1431
0
        if (vector_of_union_types->size() <= count)
1432
0
          return Error(
1433
0
              "union types vector smaller than union values vector for: " +
1434
0
              field->name);
1435
0
        enum_idx = vector_of_union_types->Get(static_cast<uoffset_t>(count));
1436
2.95k
      } else {
1437
2.95k
        ECHECK(atot(constant.c_str(), *this, &enum_idx));
1438
2.92k
      }
1439
2.92k
      auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true);
1440
2.92k
      if (!enum_val) return Error("illegal type id for: " + field->name);
1441
2.88k
      if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
1442
2.88k
        ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
1443
2.88k
                          nullptr));
1444
2.68k
        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
2.68k
      } 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
2.68k
      break;
1456
2.88k
    }
1457
253k
    case BASE_TYPE_STRUCT:
1458
253k
      ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
1459
251k
      break;
1460
123k
    case BASE_TYPE_STRING: {
1461
123k
      ECHECK(ParseString(val, field->shared));
1462
123k
      break;
1463
123k
    }
1464
0
    case BASE_TYPE_VECTOR64:
1465
12.6k
    case BASE_TYPE_VECTOR: {
1466
12.6k
      uoffset_t off;
1467
12.6k
      ECHECK(ParseVector(val.type, &off, field, parent_fieldn));
1468
11.2k
      val.constant = NumToString(off);
1469
11.2k
      break;
1470
12.6k
    }
1471
0
    case BASE_TYPE_ARRAY: {
1472
0
      ECHECK(ParseArray(val));
1473
0
      break;
1474
0
    }
1475
2.30k
    case BASE_TYPE_INT:
1476
31.4k
    case BASE_TYPE_UINT:
1477
82.4k
    case BASE_TYPE_LONG:
1478
172k
    case BASE_TYPE_ULONG: {
1479
172k
      if (field && field->attributes.Lookup("hash") &&
1480
93.8k
          (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
1481
5.21k
        ECHECK(ParseHash(val, field));
1482
167k
      } else {
1483
167k
        ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
1484
167k
      }
1485
172k
      break;
1486
172k
    }
1487
208k
    default:
1488
208k
      ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
1489
208k
      break;
1490
773k
  }
1491
769k
  return NoError();
1492
773k
}
1493
1494
25.4k
void Parser::SerializeStruct(const StructDef& struct_def, const Value& val) {
1495
25.4k
  SerializeStruct(builder_, struct_def, val);
1496
25.4k
}
1497
1498
void Parser::SerializeStruct(FlatBufferBuilder& builder,
1499
25.4k
                             const StructDef& struct_def, const Value& val) {
1500
25.4k
  FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
1501
25.4k
  builder.Align(struct_def.minalign);
1502
25.4k
  builder.PushBytes(reinterpret_cast<const uint8_t*>(val.constant.c_str()),
1503
25.4k
                    struct_def.bytesize);
1504
25.4k
  builder.AddStructOffset(val.offset, builder.GetSize());
1505
25.4k
}
1506
1507
template <typename F>
1508
CheckedError Parser::ParseTableDelimiters(size_t& fieldn,
1509
435k
                                          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
435k
  char terminator = '}';
1513
435k
  bool is_nested_vector = struct_def && Is('[');
1514
435k
  if (is_nested_vector) {
1515
35.1k
    NEXT();
1516
35.1k
    terminator = ']';
1517
400k
  } else {
1518
400k
    EXPECT('{');
1519
399k
  }
1520
959k
  for (;;) {
1521
959k
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
809k
    std::string name;
1523
809k
    if (is_nested_vector) {
1524
64.0k
      if (fieldn >= struct_def->fields.vec.size()) {
1525
3
        return Error("too many unnamed fields in nested array");
1526
3
      }
1527
64.0k
      name = struct_def->fields.vec[fieldn]->name;
1528
745k
    } else {
1529
745k
      name = attribute_;
1530
745k
      if (Is(kTokenStringConstant)) {
1531
32.7k
        NEXT();
1532
712k
      } else {
1533
712k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
712k
      }
1535
744k
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
744k
    }
1537
808k
    ECHECK(body(name, fieldn, struct_def));
1538
798k
    if (Is(terminator)) break;
1539
527k
    ECHECK(ParseComma());
1540
524k
  }
1541
421k
  NEXT();
1542
421k
  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1543
12
    return Error("wrong number of unnamed fields in table vector");
1544
12
  }
1545
421k
  return NoError();
1546
421k
}
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
284k
                                          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
284k
  char terminator = '}';
1513
284k
  bool is_nested_vector = struct_def && Is('[');
1514
284k
  if (is_nested_vector) {
1515
35.1k
    NEXT();
1516
35.1k
    terminator = ']';
1517
248k
  } else {
1518
248k
    EXPECT('{');
1519
248k
  }
1520
437k
  for (;;) {
1521
437k
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
347k
    std::string name;
1523
347k
    if (is_nested_vector) {
1524
64.0k
      if (fieldn >= struct_def->fields.vec.size()) {
1525
3
        return Error("too many unnamed fields in nested array");
1526
3
      }
1527
64.0k
      name = struct_def->fields.vec[fieldn]->name;
1528
282k
    } else {
1529
282k
      name = attribute_;
1530
282k
      if (Is(kTokenStringConstant)) {
1531
2.74k
        NEXT();
1532
280k
      } else {
1533
280k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
280k
      }
1535
282k
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
282k
    }
1537
346k
    ECHECK(body(name, fieldn, struct_def));
1538
337k
    if (Is(terminator)) break;
1539
156k
    ECHECK(ParseComma());
1540
153k
  }
1541
271k
  NEXT();
1542
271k
  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
1543
12
    return Error("wrong number of unnamed fields in table vector");
1544
12
  }
1545
271k
  return NoError();
1546
271k
}
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
81.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
81.3k
  char terminator = '}';
1513
81.3k
  bool is_nested_vector = struct_def && Is('[');
1514
81.3k
  if (is_nested_vector) {
1515
0
    NEXT();
1516
0
    terminator = ']';
1517
81.3k
  } else {
1518
81.3k
    EXPECT('{');
1519
81.3k
  }
1520
199k
  for (;;) {
1521
199k
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
192k
    std::string name;
1523
192k
    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
192k
    } else {
1529
192k
      name = attribute_;
1530
192k
      if (Is(kTokenStringConstant)) {
1531
2.22k
        NEXT();
1532
189k
      } else {
1533
189k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
189k
      }
1535
192k
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
192k
    }
1537
192k
    ECHECK(body(name, fieldn, struct_def));
1538
191k
    if (Is(terminator)) break;
1539
118k
    ECHECK(ParseComma());
1540
118k
  }
1541
81.1k
  NEXT();
1542
81.1k
  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
81.1k
  return NoError();
1546
81.1k
}
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
69.7k
                                          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
69.7k
  char terminator = '}';
1513
69.7k
  bool is_nested_vector = struct_def && Is('[');
1514
69.7k
  if (is_nested_vector) {
1515
0
    NEXT();
1516
0
    terminator = ']';
1517
69.7k
  } else {
1518
69.7k
    EXPECT('{');
1519
69.7k
  }
1520
322k
  for (;;) {
1521
322k
    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
1522
269k
    std::string name;
1523
269k
    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
269k
    } else {
1529
269k
      name = attribute_;
1530
269k
      if (Is(kTokenStringConstant)) {
1531
27.8k
        NEXT();
1532
242k
      } else {
1533
242k
        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
1534
242k
      }
1535
269k
      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
1536
269k
    }
1537
269k
    ECHECK(body(name, fieldn, struct_def));
1538
268k
    if (Is(terminator)) break;
1539
252k
    ECHECK(ParseComma());
1540
252k
  }
1541
68.6k
  NEXT();
1542
68.6k
  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
68.6k
  return NoError();
1546
68.6k
}
1547
1548
CheckedError Parser::ParseTable(const StructDef& struct_def, std::string* value,
1549
284k
                                uoffset_t* ovalue) {
1550
284k
  ParseDepthGuard depth_guard(this);
1551
284k
  ECHECK(depth_guard.Check());
1552
1553
284k
  size_t fieldn_outer = 0;
1554
284k
  auto err = ParseTableDelimiters(
1555
284k
      fieldn_outer, &struct_def,
1556
284k
      [&](const std::string& name, size_t& fieldn,
1557
346k
          const StructDef* struct_def_inner) -> CheckedError {
1558
346k
        if (name == "$schema") {
1559
201
          ECHECK(Expect(kTokenStringConstant));
1560
198
          return NoError();
1561
201
        }
1562
346k
        auto field = struct_def_inner->fields.Lookup(name);
1563
346k
        if (!field) {
1564
25.6k
          if (!opts.skip_unexpected_fields_in_json) {
1565
62
            return Error("unknown field: " + name);
1566
25.5k
          } else {
1567
25.5k
            ECHECK(SkipAnyJsonValue());
1568
25.1k
          }
1569
320k
        } else {
1570
320k
          if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
1571
321
            ECHECK(Next());  // Ignore this field.
1572
320k
          } else {
1573
320k
            Value val = field->value;
1574
320k
            if (field->flexbuffer) {
1575
17.9k
              flexbuffers::Builder builder(1024,
1576
17.9k
                                           flexbuffers::BUILDER_FLAG_SHARE_ALL);
1577
17.9k
              ECHECK(ParseFlexBufferValue(&builder));
1578
14.2k
              builder.Finish();
1579
              // Force alignment for nested flexbuffer
1580
14.2k
              builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
1581
14.2k
                                            sizeof(largest_scalar_t));
1582
14.2k
              auto off = builder_.CreateVector(builder.GetBuffer());
1583
14.2k
              val.constant = NumToString(off.o);
1584
302k
            } else if (field->nested_flatbuffer) {
1585
10.2k
              ECHECK(
1586
10.2k
                  ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
1587
292k
            } else {
1588
292k
              ECHECK(ParseAnyValue(val, field, fieldn, struct_def_inner, 0));
1589
288k
            }
1590
            // Hardcoded insertion-sort with error-check.
1591
            // If fields are specified in order, then this loop exits
1592
            // immediately.
1593
312k
            auto elem = field_stack_.rbegin();
1594
357k
            for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
1595
138k
              auto existing_field = elem->second;
1596
138k
              if (existing_field == field)
1597
105
                return Error("field set more than once: " + field->name);
1598
137k
              if (existing_field->value.offset < field->value.offset) break;
1599
137k
            }
1600
            // Note: elem points to before the insertion point, thus .base()
1601
            // points to the correct spot.
1602
312k
            field_stack_.insert(elem.base(), std::make_pair(val, field));
1603
312k
            fieldn++;
1604
312k
          }
1605
320k
        }
1606
337k
        return NoError();
1607
346k
      });
1608
284k
  ECHECK(err);
1609
1610
  // Check if all required fields are parsed.
1611
271k
  for (auto field_it = struct_def.fields.vec.begin();
1612
4.95M
       field_it != struct_def.fields.vec.end(); ++field_it) {
1613
4.68M
    auto required_field = *field_it;
1614
4.68M
    if (!required_field->IsRequired()) {
1615
4.61M
      continue;
1616
4.61M
    }
1617
68.9k
    bool found = false;
1618
68.9k
    for (auto pf_it = field_stack_.end() - fieldn_outer;
1619
77.4k
         pf_it != field_stack_.end(); ++pf_it) {
1620
77.2k
      auto parsed_field = pf_it->second;
1621
77.2k
      if (parsed_field == required_field) {
1622
68.8k
        found = true;
1623
68.8k
        break;
1624
68.8k
      }
1625
77.2k
    }
1626
68.9k
    if (!found) {
1627
160
      return Error("required field is missing: " + required_field->name +
1628
160
                   " in " + struct_def.name);
1629
160
    }
1630
68.9k
  }
1631
1632
271k
  if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
1633
3
    return Error("struct: wrong number of initializers: " + struct_def.name);
1634
1635
271k
  auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
1636
271k
                                : builder_.StartTable();
1637
1638
1.27M
  for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
1639
1.00M
       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
1.00M
    for (auto it = field_stack_.rbegin();
1645
1.99M
         it != field_stack_.rbegin() + fieldn_outer; ++it) {
1646
995k
      auto& field_value = it->first;
1647
995k
      auto field = it->second;
1648
995k
      if (!struct_def.sortbysize ||
1649
918k
          size == SizeOf(field_value.type.base_type)) {
1650
306k
        switch (field_value.type.base_type) {
1651
          // clang-format off
1652
0
          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1653
185k
            case BASE_TYPE_ ## ENUM: \
1654
184k
              builder_.Pad(field->padding); \
1655
185k
              if (struct_def.fixed) { \
1656
70.7k
                CTYPE val; \
1657
70.7k
                ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1658
70.3k
                builder_.PushElement(val); \
1659
115k
              } else { \
1660
115k
                if (field->IsScalarOptional()) { \
1661
0
                  if (field_value.constant != "null") { \
1662
0
                    CTYPE val; \
1663
0
                    ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1664
0
                    builder_.AddElement(field_value.offset, val); \
1665
0
                  } \
1666
115k
                } else { \
1667
115k
                  CTYPE val, valdef; \
1668
115k
                  ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1669
114k
                  ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
1670
114k
                  builder_.AddElement(field_value.offset, val, valdef); \
1671
114k
                } \
1672
115k
              } \
1673
184k
              break;
1674
185k
            FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
1675
7.74k
          #undef FLATBUFFERS_TD
1676
7.74k
          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1677
120k
            case BASE_TYPE_ ## ENUM: \
1678
120k
              builder_.Pad(field->padding); \
1679
120k
              if (IsStruct(field->value.type)) { \
1680
11.5k
                SerializeStruct(*field->value.type.struct_def, field_value); \
1681
109k
              } else { \
1682
                /* Special case for fields that use 64-bit addressing */ \
1683
109k
                if(field->offset64) { \
1684
0
                  Offset64<void> offset; \
1685
0
                  ECHECK(atot(field_value.constant.c_str(), *this, &offset)); \
1686
0
                  builder_.AddOffset(field_value.offset, offset); \
1687
109k
                } else { \
1688
109k
                  CTYPE val; \
1689
109k
                  ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
1690
109k
                  builder_.AddOffset(field_value.offset, val); \
1691
109k
                } \
1692
109k
              } \
1693
120k
              break;
1694
120k
            FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
1695
2.31k
          #undef FLATBUFFERS_TD
1696
2.31k
            case BASE_TYPE_ARRAY:
1697
0
              builder_.Pad(field->padding);
1698
0
              builder_.PushBytes(
1699
0
                reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
1700
0
                InlineSize(field_value.type));
1701
0
              break;
1702
            // clang-format on
1703
306k
        }
1704
306k
      }
1705
995k
    }
1706
1.00M
  }
1707
575k
  for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
1708
1709
270k
  if (struct_def.fixed) {
1710
26.6k
    builder_.ClearOffsets();
1711
26.6k
    builder_.EndStruct();
1712
26.6k
    FLATBUFFERS_ASSERT(value);
1713
    // Temporarily store this struct in the value string, since it is to
1714
    // be serialized in-place elsewhere.
1715
26.6k
    value->assign(
1716
26.6k
        reinterpret_cast<const char*>(builder_.GetCurrentBufferPointer()),
1717
26.6k
        struct_def.bytesize);
1718
26.6k
    builder_.PopBytes(struct_def.bytesize);
1719
26.6k
    FLATBUFFERS_ASSERT(!ovalue);
1720
244k
  } else {
1721
244k
    auto val = builder_.EndTable(start);
1722
244k
    if (ovalue) *ovalue = val;
1723
244k
    if (value) *value = NumToString(val);
1724
244k
  }
1725
270k
  return NoError();
1726
270k
}
1727
1728
template <typename F>
1729
1.12M
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
1.12M
  EXPECT('[');
1731
3.39M
  for (;;) {
1732
3.39M
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
3.36M
    ECHECK(body(count));
1734
3.36M
    count++;
1735
3.36M
    if (Is(']')) break;
1736
2.26M
    ECHECK(ParseComma());
1737
2.26M
  }
1738
1.12M
  NEXT();
1739
1.12M
  return NoError();
1740
1.12M
}
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
12.6k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
12.6k
  EXPECT('[');
1731
484k
  for (;;) {
1732
484k
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
479k
    ECHECK(body(count));
1734
479k
    count++;
1735
479k
    if (Is(']')) break;
1736
471k
    ECHECK(ParseComma());
1737
471k
  }
1738
11.5k
  NEXT();
1739
11.5k
  return NoError();
1740
11.5k
}
Unexecuted instantiation: idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::ParseArray(flatbuffers::Value&)::$_0>(unsigned long&, flatbuffers::Parser::ParseArray(flatbuffers::Value&)::$_0)
idl_parser.cpp:flatbuffers::CheckedError flatbuffers::Parser::ParseVectorDelimiters<flatbuffers::Parser::SkipAnyJsonValue()::$_1>(unsigned long&, flatbuffers::Parser::SkipAnyJsonValue()::$_1)
Line
Count
Source
1729
418k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
418k
  EXPECT('[');
1731
1.06M
  for (;;) {
1732
1.06M
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
1.05M
    ECHECK(body(count));
1734
1.05M
    count++;
1735
1.05M
    if (Is(']')) break;
1736
643k
    ECHECK(ParseComma());
1737
643k
  }
1738
417k
  NEXT();
1739
417k
  return NoError();
1740
417k
}
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
693k
CheckedError Parser::ParseVectorDelimiters(size_t& count, F body) {
1730
693k
  EXPECT('[');
1731
1.84M
  for (;;) {
1732
1.84M
    if ((!opts.strict_json || !count) && Is(']')) break;
1733
1.83M
    ECHECK(body(count));
1734
1.83M
    count++;
1735
1.83M
    if (Is(']')) break;
1736
1.15M
    ECHECK(ParseComma());
1737
1.15M
  }
1738
692k
  NEXT();
1739
692k
  return NoError();
1740
692k
}
1741
1742
CheckedError Parser::ParseAlignAttribute(const std::string& align_constant,
1743
0
                                         size_t min_align, size_t* align) {
1744
  // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64.
1745
0
  uint8_t align_value;
1746
0
  if (StringToNumber(align_constant.c_str(), &align_value) &&
1747
0
      VerifyAlignmentRequirements(static_cast<size_t>(align_value),
1748
0
                                  min_align)) {
1749
0
    *align = align_value;
1750
0
    return NoError();
1751
0
  }
1752
0
  return Error("unexpected force_align value '" + align_constant +
1753
0
               "', alignment must be a power of two integer ranging from the "
1754
0
               "type\'s natural alignment " +
1755
0
               NumToString(min_align) + " to " +
1756
0
               NumToString(FLATBUFFERS_MAX_ALIGNMENT));
1757
0
}
1758
1759
CheckedError Parser::ParseVector(const Type& vector_type, uoffset_t* ovalue,
1760
12.6k
                                 FieldDef* field, size_t fieldn) {
1761
12.6k
  Type type = vector_type.VectorType();
1762
12.6k
  size_t count = 0;
1763
479k
  auto err = ParseVectorDelimiters(count, [&](size_t&) -> CheckedError {
1764
479k
    Value val;
1765
479k
    val.type = type;
1766
479k
    ECHECK(ParseAnyValue(val, field, fieldn, nullptr, count, true));
1767
479k
    field_stack_.push_back(std::make_pair(val, nullptr));
1768
479k
    return NoError();
1769
479k
  });
1770
12.6k
  ECHECK(err);
1771
1772
11.5k
  const size_t alignment = InlineAlignment(type);
1773
11.5k
  const size_t len = count * InlineSize(type) / InlineAlignment(type);
1774
11.5k
  const size_t elemsize = InlineAlignment(type);
1775
11.5k
  const auto force_align = field->attributes.Lookup("force_align");
1776
11.5k
  if (force_align) {
1777
0
    size_t align;
1778
0
    ECHECK(ParseAlignAttribute(force_align->constant, 1, &align));
1779
0
    if (align > 1) {
1780
0
      builder_.ForceVectorAlignment(len, elemsize, align);
1781
0
    }
1782
0
  }
1783
1784
  // TODO Fix using element alignment as size (`elemsize`)!
1785
11.5k
  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
0
    builder_.StartVector(len, elemsize, alignment);
1789
11.5k
  } else {
1790
11.5k
    builder_.StartVector(len, elemsize, alignment);
1791
11.5k
  }
1792
475k
  for (size_t i = 0; i < count; i++) {
1793
    // start at the back, since we're building the data backwards.
1794
464k
    auto& val = field_stack_.back().first;
1795
464k
    switch (val.type.base_type) {
1796
      // clang-format off
1797
0
      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \
1798
464k
        case BASE_TYPE_ ## ENUM: \
1799
464k
          if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
1800
464k
          else { \
1801
450k
             CTYPE elem; \
1802
450k
             ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1803
450k
             builder_.PushElement(elem); \
1804
450k
          } \
1805
464k
          break;
1806
464k
        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1807
464k
      #undef FLATBUFFERS_TD
1808
      // clang-format on
1809
464k
    }
1810
464k
    field_stack_.pop_back();
1811
464k
  }
1812
1813
11.2k
  builder_.ClearOffsets();
1814
11.2k
  if (vector_type.base_type == BASE_TYPE_VECTOR64) {
1815
0
    *ovalue = builder_.EndVector<uoffset64_t>(count);
1816
11.2k
  } else {
1817
11.2k
    *ovalue = builder_.EndVector(count);
1818
11.2k
  }
1819
1820
11.2k
  if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) {
1821
    // We should sort this vector. Find the key first.
1822
4.63k
    const FieldDef* key = nullptr;
1823
4.63k
    for (auto it = type.struct_def->fields.vec.begin();
1824
14.1k
         it != type.struct_def->fields.vec.end(); ++it) {
1825
14.1k
      if ((*it)->key) {
1826
4.63k
        key = (*it);
1827
4.63k
        break;
1828
4.63k
      }
1829
14.1k
    }
1830
4.63k
    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
4.63k
    if (type.struct_def->fixed) {
1841
381
      const voffset_t offset = key->value.offset;
1842
381
      const size_t struct_size = type.struct_def->bytesize;
1843
381
      auto v =
1844
381
          reinterpret_cast<VectorOfAny*>(builder_.GetCurrentBufferPointer());
1845
381
      SimpleQsort<uint8_t>(
1846
381
          v->Data(), v->Data() + v->size() * type.struct_def->bytesize,
1847
381
          type.struct_def->bytesize,
1848
5.99M
          [offset, key](const uint8_t* a, const uint8_t* b) -> bool {
1849
5.99M
            return CompareSerializedScalars(a + offset, b + offset, *key);
1850
5.99M
          },
1851
16.1k
          [struct_size](uint8_t* a, uint8_t* b) {
1852
            // FIXME: faster?
1853
145k
            for (size_t i = 0; i < struct_size; i++) {
1854
129k
              std::swap(a[i], b[i]);
1855
129k
            }
1856
16.1k
          });
1857
4.25k
    } else {
1858
4.25k
      auto v = reinterpret_cast<Vector<Offset<Table>>*>(
1859
4.25k
          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
4.25k
      if (key->value.type.base_type == BASE_TYPE_STRING) {
1864
2.61k
        SimpleQsort<Offset<Table>>(
1865
2.61k
            v->data(), v->data() + v->size(), 1,
1866
1.60M
            [key](const Offset<Table>* _a, const Offset<Table>* _b) -> bool {
1867
1.60M
              return CompareTablesByStringKey(_a, _b, *key);
1868
1.60M
            },
1869
2.61k
            SwapSerializedTables);
1870
2.61k
      } else {
1871
1.64k
        SimpleQsort<Offset<Table>>(
1872
1.64k
            v->data(), v->data() + v->size(), 1,
1873
208M
            [key](const Offset<Table>* _a, const Offset<Table>* _b) -> bool {
1874
208M
              return CompareTablesByScalarKey(_a, _b, *key);
1875
208M
            },
1876
1.64k
            SwapSerializedTables);
1877
1.64k
      }
1878
4.25k
    }
1879
4.63k
  }
1880
11.2k
  return NoError();
1881
11.2k
}
1882
1883
0
CheckedError Parser::ParseArray(Value& array) {
1884
0
  std::vector<Value> stack;
1885
0
  FlatBufferBuilder builder;
1886
0
  const auto& type = array.type.VectorType();
1887
0
  auto length = array.type.fixed_length;
1888
0
  size_t count = 0;
1889
0
  auto err = ParseVectorDelimiters(count, [&](size_t&) -> CheckedError {
1890
0
    stack.emplace_back(Value());
1891
0
    auto& val = stack.back();
1892
0
    val.type = type;
1893
0
    if (IsStruct(type)) {
1894
0
      ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
1895
0
    } else {
1896
0
      ECHECK(ParseSingleValue(nullptr, val, false));
1897
0
    }
1898
0
    return NoError();
1899
0
  });
1900
0
  ECHECK(err);
1901
0
  if (length != count) return Error("Fixed-length array size is incorrect.");
1902
1903
0
  for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
1904
0
    auto& val = *it;
1905
    // clang-format off
1906
0
    switch (val.type.base_type) {
1907
0
      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
1908
0
        case BASE_TYPE_ ## ENUM: \
1909
0
          if (IsStruct(val.type)) { \
1910
0
            SerializeStruct(builder, *val.type.struct_def, val); \
1911
0
          } else { \
1912
0
            CTYPE elem; \
1913
0
            ECHECK(atot(val.constant.c_str(), *this, &elem)); \
1914
0
            builder.PushElement(elem); \
1915
0
          } \
1916
0
        break;
1917
0
        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1918
0
      #undef FLATBUFFERS_TD
1919
0
      default: FLATBUFFERS_ASSERT(0);
1920
0
    }
1921
    // clang-format on
1922
0
  }
1923
1924
0
  array.constant.assign(
1925
0
      reinterpret_cast<const char*>(builder.GetCurrentBufferPointer()),
1926
0
      InlineSize(array.type));
1927
0
  return NoError();
1928
0
}
1929
1930
CheckedError Parser::ParseNestedFlatbuffer(Value& val, FieldDef* field,
1931
                                           size_t fieldn,
1932
10.2k
                                           const StructDef* parent_struct_def) {
1933
10.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
10.2k
  } else {
1942
10.2k
    auto cursor_at_value_begin = cursor_;
1943
10.2k
    ECHECK(SkipAnyJsonValue());
1944
10.2k
    std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
1945
1946
    // Create and initialize new parser
1947
10.2k
    Parser nested_parser;
1948
10.2k
    FLATBUFFERS_ASSERT(field->nested_flatbuffer);
1949
10.2k
    nested_parser.root_struct_def_ = field->nested_flatbuffer;
1950
10.2k
    nested_parser.enums_ = enums_;
1951
10.2k
    nested_parser.opts = opts;
1952
10.2k
    nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
1953
10.2k
    nested_parser.parse_depth_counter_ = parse_depth_counter_;
1954
    // Parse JSON substring into new flatbuffer builder using nested_parser
1955
10.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
10.2k
    nested_parser.enums_.dict.clear();
1960
10.2k
    nested_parser.enums_.vec.clear();
1961
1962
10.2k
    if (!ok) {
1963
860
      ECHECK(Error(nested_parser.error_));
1964
0
    }
1965
    // Force alignment for nested flatbuffer
1966
9.35k
    builder_.ForceVectorAlignment(
1967
9.35k
        nested_parser.builder_.GetSize(), sizeof(uint8_t),
1968
9.35k
        nested_parser.builder_.GetBufferMinAlignment());
1969
1970
9.35k
    auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
1971
9.35k
                                     nested_parser.builder_.GetSize());
1972
9.35k
    val.constant = NumToString(off.o);
1973
9.35k
  }
1974
9.35k
  return NoError();
1975
10.2k
}
1976
1977
0
CheckedError Parser::ParseMetaData(SymbolTable<Value>* attributes) {
1978
0
  if (Is('(')) {
1979
0
    NEXT();
1980
0
    for (;;) {
1981
0
      auto name = attribute_;
1982
0
      if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
1983
0
        return Error("attribute name must be either identifier or string: " +
1984
0
                     name);
1985
0
      if (known_attributes_.find(name) == known_attributes_.end())
1986
0
        return Error("user define attributes must be declared before use: " +
1987
0
                     name);
1988
0
      NEXT();
1989
0
      auto e = new Value();
1990
0
      if (attributes->Add(name, e)) Warning("attribute already found: " + name);
1991
0
      if (Is(':')) {
1992
0
        NEXT();
1993
0
        ECHECK(ParseSingleValue(&name, *e, true));
1994
0
      }
1995
0
      if (Is(')')) {
1996
0
        NEXT();
1997
0
        break;
1998
0
      }
1999
0
      EXPECT(',');
2000
0
    }
2001
0
  }
2002
0
  return NoError();
2003
0
}
2004
2005
CheckedError Parser::ParseEnumFromString(const Type& type,
2006
13.6k
                                         std::string* result) {
2007
13.6k
  const auto base_type =
2008
13.6k
      type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type;
2009
13.6k
  if (!IsInteger(base_type)) return Error("not a valid value for this field");
2010
13.6k
  uint64_t u64 = 0;
2011
33.5k
  for (size_t pos = 0; pos != std::string::npos;) {
2012
20.3k
    const auto delim = attribute_.find_first_of(' ', pos);
2013
20.3k
    const auto last = (std::string::npos == delim);
2014
20.3k
    auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos);
2015
20.3k
    pos = !last ? delim + 1 : std::string::npos;
2016
20.3k
    const EnumVal* ev = nullptr;
2017
20.3k
    if (type.enum_def) {
2018
16.8k
      ev = type.enum_def->Lookup(word);
2019
16.8k
    } else {
2020
3.50k
      auto dot = word.find_first_of('.');
2021
3.50k
      if (std::string::npos == dot)
2022
51
        return Error("enum values need to be qualified by an enum type");
2023
3.45k
      auto enum_def_str = word.substr(0, dot);
2024
3.45k
      const auto enum_def = LookupEnum(enum_def_str);
2025
3.45k
      if (!enum_def) return Error("unknown enum: " + enum_def_str);
2026
3.24k
      auto enum_val_str = word.substr(dot + 1);
2027
3.24k
      ev = enum_def->Lookup(enum_val_str);
2028
3.24k
    }
2029
20.0k
    if (!ev) return Error("unknown enum value: " + word);
2030
19.9k
    u64 |= ev->GetAsUInt64();
2031
19.9k
  }
2032
13.1k
  *result = IsUnsigned(base_type) ? NumToString(u64)
2033
13.1k
                                  : NumToString(static_cast<int64_t>(u64));
2034
13.1k
  return NoError();
2035
13.6k
}
2036
2037
5.21k
CheckedError Parser::ParseHash(Value& e, FieldDef* field) {
2038
5.21k
  FLATBUFFERS_ASSERT(field);
2039
5.21k
  Value* hash_name = field->attributes.Lookup("hash");
2040
5.21k
  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
637
    case BASE_TYPE_INT: {
2054
637
      auto hash = FindHashFunction32(hash_name->constant.c_str());
2055
637
      int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
2056
637
      e.constant = NumToString(hashed_value);
2057
637
      break;
2058
0
    }
2059
1.20k
    case BASE_TYPE_UINT: {
2060
1.20k
      auto hash = FindHashFunction32(hash_name->constant.c_str());
2061
1.20k
      uint32_t hashed_value = hash(attribute_.c_str());
2062
1.20k
      e.constant = NumToString(hashed_value);
2063
1.20k
      break;
2064
0
    }
2065
1.45k
    case BASE_TYPE_LONG: {
2066
1.45k
      auto hash = FindHashFunction64(hash_name->constant.c_str());
2067
1.45k
      int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
2068
1.45k
      e.constant = NumToString(hashed_value);
2069
1.45k
      break;
2070
0
    }
2071
1.92k
    case BASE_TYPE_ULONG: {
2072
1.92k
      auto hash = FindHashFunction64(hash_name->constant.c_str());
2073
1.92k
      uint64_t hashed_value = hash(attribute_.c_str());
2074
1.92k
      e.constant = NumToString(hashed_value);
2075
1.92k
      break;
2076
0
    }
2077
0
    default:
2078
0
      FLATBUFFERS_ASSERT(0);
2079
5.21k
  }
2080
5.21k
  NEXT();
2081
5.21k
  return NoError();
2082
5.21k
}
2083
2084
506
CheckedError Parser::TokenError() {
2085
506
  return Error("cannot parse value starting with: " + TokenToStringId(token_));
2086
506
}
2087
2088
4.32k
CheckedError Parser::ParseFunction(const std::string* name, Value& e) {
2089
4.32k
  ParseDepthGuard depth_guard(this);
2090
4.32k
  ECHECK(depth_guard.Check());
2091
2092
  // Copy name, attribute will be changed on NEXT().
2093
4.32k
  const auto functionname = attribute_;
2094
4.32k
  if (!IsFloat(e.type.base_type)) {
2095
25
    return Error(functionname + ": type of argument mismatch, expecting: " +
2096
25
                 TypeName(BASE_TYPE_DOUBLE) +
2097
25
                 ", found: " + TypeName(e.type.base_type) +
2098
25
                 ", name: " + (name ? *name : "") + ", value: " + e.constant);
2099
25
  }
2100
4.29k
  NEXT();
2101
4.29k
  EXPECT('(');
2102
4.28k
  ECHECK(ParseSingleValue(name, e, false));
2103
3.95k
  EXPECT(')');
2104
  // calculate with double precision
2105
3.92k
  double x, y = 0.0;
2106
3.92k
  ECHECK(atot(e.constant.c_str(), *this, &x));
2107
  // clang-format off
2108
3.88k
  auto func_match = false;
2109
3.88k
  #define FLATBUFFERS_FN_DOUBLE(name, op) \
2110
31.0k
    if (!func_match && functionname == name) { y = op; func_match = true; }
2111
3.88k
  FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
2112
3.88k
  FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
2113
3.88k
  FLATBUFFERS_FN_DOUBLE("sin", sin(x));
2114
3.88k
  FLATBUFFERS_FN_DOUBLE("cos", cos(x));
2115
3.88k
  FLATBUFFERS_FN_DOUBLE("tan", tan(x));
2116
3.88k
  FLATBUFFERS_FN_DOUBLE("asin", asin(x));
2117
3.88k
  FLATBUFFERS_FN_DOUBLE("acos", acos(x));
2118
3.88k
  FLATBUFFERS_FN_DOUBLE("atan", atan(x));
2119
  // TODO(wvo): add more useful conversion functions here.
2120
3.88k
  #undef FLATBUFFERS_FN_DOUBLE
2121
  // clang-format on
2122
3.88k
  if (true != func_match) {
2123
51
    return Error(std::string("Unknown conversion function: ") + functionname +
2124
51
                 ", field name: " + (name ? *name : "") +
2125
51
                 ", value: " + e.constant);
2126
51
  }
2127
3.82k
  e.constant = NumToString(y);
2128
3.82k
  return NoError();
2129
3.88k
}
2130
2131
CheckedError Parser::TryTypedValue(const std::string* name, int dtoken,
2132
                                   bool check, Value& e, BaseType req,
2133
362k
                                   bool* destmatch) {
2134
362k
  FLATBUFFERS_ASSERT(*destmatch == false && dtoken == token_);
2135
362k
  *destmatch = true;
2136
362k
  e.constant = attribute_;
2137
  // Check token match
2138
362k
  if (!check) {
2139
0
    if (e.type.base_type == BASE_TYPE_NONE) {
2140
0
      e.type.base_type = req;
2141
0
    } else {
2142
0
      return Error(std::string("type mismatch: expecting: ") +
2143
0
                   TypeName(e.type.base_type) + ", found: " + TypeName(req) +
2144
0
                   ", name: " + (name ? *name : "") + ", value: " + e.constant);
2145
0
    }
2146
0
  }
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
362k
  if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
2150
50.8k
    const auto& s = e.constant;
2151
50.8k
    const auto k = s.find_first_of("0123456789.");
2152
50.8k
    if ((std::string::npos != k) && (s.length() > (k + 1)) &&
2153
3.02k
        (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
2154
306
        (std::string::npos == s.find_first_of("pP", k + 2))) {
2155
28
      return Error(
2156
28
          "invalid number, the exponent suffix of hexadecimal "
2157
28
          "floating-point literals is mandatory: \"" +
2158
28
          s + "\"");
2159
28
    }
2160
50.8k
  }
2161
362k
  NEXT();
2162
362k
  return NoError();
2163
362k
}
2164
2165
CheckedError Parser::ParseSingleValue(const std::string* name, Value& e,
2166
380k
                                      bool check_now) {
2167
380k
  if (token_ == '+' || token_ == '-') {
2168
1.43k
    const char sign = static_cast<char>(token_);
2169
    // Get an indentifier: NAN, INF, or function name like cos/sin/deg.
2170
1.43k
    NEXT();
2171
1.43k
    if (token_ != kTokenIdentifier) return Error("constant name expected");
2172
1.43k
    attribute_.insert(size_t(0), size_t(1), sign);
2173
1.43k
  }
2174
2175
380k
  const auto in_type = e.type.base_type;
2176
380k
  const auto is_tok_ident = (token_ == kTokenIdentifier);
2177
380k
  const auto is_tok_string = (token_ == kTokenStringConstant);
2178
2179
  // First see if this could be a conversion function.
2180
380k
  if (is_tok_ident && *cursor_ == '(') {
2181
4.32k
    return ParseFunction(name, e);
2182
4.32k
  }
2183
2184
  // clang-format off
2185
376k
  auto match = false;
2186
2187
376k
  #define IF_ECHECK_(force, dtoken, check, req)    \
2188
816k
    if (!match && ((dtoken) == token_) && ((check) || flatbuffers::IsConstTrue(force))) \
2189
816k
      ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
2190
441k
  #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req)
2191
376k
  #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
2192
  // clang-format on
2193
2194
376k
  if (is_tok_ident || is_tok_string) {
2195
29.4k
    const auto kTokenStringOrIdent = token_;
2196
    // The string type is a most probable type, check it first.
2197
29.4k
    TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
2198
29.4k
               BASE_TYPE_STRING);
2199
2200
    // avoid escaped and non-ascii in the string
2201
29.4k
    if (!match && is_tok_string && IsScalar(in_type) &&
2202
14.7k
        !attr_is_trivial_ascii_string_) {
2203
5
      return Error(
2204
5
          std::string("type mismatch or invalid value, an initializer of "
2205
5
                      "non-string field must be trivial ASCII string: type: ") +
2206
5
          TypeName(in_type) + ", name: " + (name ? *name : "") +
2207
5
          ", value: " + attribute_);
2208
5
    }
2209
2210
    // A boolean as true/false. Boolean as Integer check below.
2211
29.4k
    if (!match && IsBool(in_type)) {
2212
8.57k
      auto is_true = attribute_ == "true";
2213
8.57k
      if (is_true || attribute_ == "false") {
2214
7.12k
        attribute_ = is_true ? "1" : "0";
2215
        // accepts both kTokenStringConstant and kTokenIdentifier
2216
7.12k
        TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
2217
7.12k
      }
2218
8.57k
    }
2219
    // Check for optional scalars.
2220
29.4k
    if (!match && IsScalar(in_type) && attribute_ == "null") {
2221
351
      e.constant = "null";
2222
351
      NEXT();
2223
349
      match = true;
2224
349
    }
2225
    // Check if this could be a string/identifier enum value.
2226
    // Enum can have only true integer base type.
2227
29.4k
    if (!match && IsInteger(in_type) && !IsBool(in_type) &&
2228
14.4k
        IsIdentifierStart(*attribute_.c_str())) {
2229
13.6k
      ECHECK(ParseEnumFromString(e.type, &e.constant));
2230
13.1k
      NEXT();
2231
13.1k
      match = true;
2232
13.1k
    }
2233
    // Parse a float/integer number from the string.
2234
    // A "scalar-in-string" value needs extra checks.
2235
28.9k
    if (!match && is_tok_string && IsScalar(in_type)) {
2236
      // Strip trailing whitespaces from attribute_.
2237
1.23k
      auto last_non_ws = attribute_.find_last_not_of(' ');
2238
1.23k
      if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1);
2239
1.23k
      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
690
        if (attribute_.find_last_of(')') != std::string::npos) {
2244
18
          return Error("invalid number: " + attribute_);
2245
18
        }
2246
690
      }
2247
1.23k
    }
2248
    // Float numbers or nan, inf, pi, etc.
2249
28.9k
    TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
2250
    // An integer constant in string.
2251
28.9k
    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
28.9k
    FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
2255
28.9k
                 BASE_TYPE_STRING);
2256
346k
  } else {
2257
    // Try a float number.
2258
346k
    TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
2259
    // Integer token can init any scalar (integer of float).
2260
346k
    FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
2261
346k
  }
2262
  // Match empty vectors for default-empty-vectors.
2263
375k
  if (!match && IsVector(e.type) && token_ == '[') {
2264
0
    NEXT();
2265
0
    if (token_ != ']') {
2266
0
      return Error("Expected `]` in vector default");
2267
0
    }
2268
0
    NEXT();
2269
0
    match = true;
2270
0
    e.constant = "[]";
2271
0
  }
2272
2273
375k
#undef FORCE_ECHECK
2274
375k
#undef TRY_ECHECK
2275
375k
#undef IF_ECHECK_
2276
2277
375k
  if (!match) {
2278
93
    std::string msg;
2279
93
    msg += "Cannot assign token starting with '" + TokenToStringId(token_) +
2280
93
           "' to value of <" + std::string(TypeName(in_type)) + "> type.";
2281
93
    return Error(msg);
2282
93
  }
2283
375k
  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
375k
  if (check_now && IsScalar(match_type) && e.constant != "null") {
2290
    // clang-format off
2291
0
    switch (match_type) {
2292
0
    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
2293
0
      case BASE_TYPE_ ## ENUM: {\
2294
0
          CTYPE val; \
2295
0
          ECHECK(atot(e.constant.c_str(), *this, &val)); \
2296
0
          SingleValueRepack(e, val); \
2297
0
        break; }
2298
0
    FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
2299
0
    #undef FLATBUFFERS_TD
2300
0
    default: break;
2301
0
    }
2302
    // clang-format on
2303
0
  }
2304
375k
  return NoError();
2305
375k
}
2306
2307
StructDef* Parser::LookupCreateStruct(const std::string& name,
2308
0
                                      bool create_if_new, bool definition) {
2309
0
  std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
2310
  // See if it exists pre-declared by an unqualified use.
2311
0
  auto struct_def = LookupStruct(name);
2312
0
  if (struct_def && struct_def->predecl) {
2313
0
    if (definition) {
2314
      // Make sure it has the current namespace, and is registered under its
2315
      // qualified name.
2316
0
      struct_def->defined_namespace = current_namespace_;
2317
0
      structs_.Move(name, qualified_name);
2318
0
    }
2319
0
    return struct_def;
2320
0
  }
2321
  // See if it exists pre-declared by an qualified use.
2322
0
  struct_def = LookupStruct(qualified_name);
2323
0
  if (struct_def && struct_def->predecl) {
2324
0
    if (definition) {
2325
      // Make sure it has the current namespace.
2326
0
      struct_def->defined_namespace = current_namespace_;
2327
0
    }
2328
0
    return struct_def;
2329
0
  }
2330
0
  if (!definition && !struct_def) {
2331
0
    struct_def = LookupStructThruParentNamespaces(name);
2332
0
  }
2333
0
  if (!struct_def && create_if_new) {
2334
0
    struct_def = new StructDef();
2335
0
    if (definition) {
2336
0
      structs_.Add(qualified_name, struct_def);
2337
0
      struct_def->name = name;
2338
0
      struct_def->defined_namespace = current_namespace_;
2339
0
    } 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
0
      structs_.Add(name, struct_def);
2346
0
      struct_def->name = name;
2347
0
      struct_def->defined_namespace = current_namespace_;
2348
0
      struct_def->original_location.reset(
2349
0
          new std::string(file_being_parsed_ + ":" + NumToString(line_)));
2350
0
    }
2351
0
  }
2352
0
  return struct_def;
2353
0
}
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
42.4k
                                bool skip_union_default) const {
2378
42.4k
  auto skip_first = static_cast<int>(is_union && skip_union_default);
2379
141k
  for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) {
2380
122k
    if ((*it)->GetAsInt64() == enum_idx) {
2381
23.7k
      return *it;
2382
23.7k
    }
2383
122k
  }
2384
18.7k
  return nullptr;
2385
42.4k
}
2386
2387
0
EnumVal* EnumDef::FindByValue(const std::string& constant) const {
2388
0
  int64_t i64;
2389
0
  auto done = false;
2390
0
  if (IsUInt64()) {
2391
0
    uint64_t u64;  // avoid reinterpret_cast of pointers
2392
0
    done = StringToNumber(constant.c_str(), &u64);
2393
0
    i64 = static_cast<int64_t>(u64);
2394
0
  } else {
2395
0
    done = StringToNumber(constant.c_str(), &i64);
2396
0
  }
2397
0
  FLATBUFFERS_ASSERT(done);
2398
0
  if (!done) return nullptr;
2399
0
  return ReverseLookup(i64, false);
2400
0
}
2401
2402
0
void EnumDef::SortByValue() {
2403
0
  auto& v = vals.vec;
2404
0
  if (IsUInt64())
2405
0
    std::sort(v.begin(), v.end(), [](const EnumVal* e1, const EnumVal* e2) {
2406
0
      if (e1->GetAsUInt64() == e2->GetAsUInt64()) {
2407
0
        return e1->name < e2->name;
2408
0
      }
2409
0
      return e1->GetAsUInt64() < e2->GetAsUInt64();
2410
0
    });
2411
0
  else
2412
0
    std::sort(v.begin(), v.end(), [](const EnumVal* e1, const EnumVal* e2) {
2413
0
      if (e1->GetAsInt64() == e2->GetAsInt64()) {
2414
0
        return e1->name < e2->name;
2415
0
      }
2416
0
      return e1->GetAsInt64() < e2->GetAsInt64();
2417
0
    });
2418
0
}
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
0
void EnumDef::ChangeEnumValue(EnumVal* ev, T new_value) {
2445
0
  ev->value = static_cast<int64_t>(new_value);
2446
0
}
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
0
  EnumVal* CreateEnumerator(const std::string& ev_name) {
2461
0
    FLATBUFFERS_ASSERT(!temp);
2462
0
    auto first = enum_def.vals.vec.empty();
2463
0
    user_value = first;
2464
0
    temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value);
2465
0
    return temp;
2466
0
  }
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
0
  FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string& name) {
2476
0
    FLATBUFFERS_ASSERT(temp);
2477
0
    ECHECK(ValidateValue(&temp->value, false == user_value));
2478
0
    FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) ||
2479
0
                       (temp->union_type.enum_def == &enum_def));
2480
0
    auto not_unique = enum_def.vals.Add(name, temp);
2481
0
    temp = nullptr;
2482
0
    if (not_unique) return parser.Error("enum value already exists: " + name);
2483
0
    return NoError();
2484
0
  }
2485
2486
0
  FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() {
2487
0
    return AcceptEnumerator(temp->name);
2488
0
  }
2489
2490
0
  FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string& value) {
2491
0
    user_value = true;
2492
0
    auto fit = false;
2493
0
    if (enum_def.IsUInt64()) {
2494
0
      uint64_t u64;
2495
0
      fit = StringToNumber(value.c_str(), &u64);
2496
0
      temp->value = static_cast<int64_t>(u64);  // well-defined since C++20.
2497
0
    } else {
2498
0
      int64_t i64;
2499
0
      fit = StringToNumber(value.c_str(), &i64);
2500
0
      temp->value = i64;
2501
0
    }
2502
0
    if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
2503
0
    return NoError();
2504
0
  }
2505
2506
  template <BaseType E, typename CTYPE>
2507
0
  inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t* ev, int m) {
2508
0
    typedef typename EnumHelper::EnumValType<E>::type T;  // int64_t or uint64_t
2509
0
    static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
2510
0
    const auto v = static_cast<T>(*ev);
2511
0
    auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
2512
0
    auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
2513
0
    if (v < dn || v > (up - m)) {
2514
0
      return parser.Error("enum value does not fit, \"" + NumToString(v) +
2515
0
                          (m ? " + 1\"" : "\"") + " out of " +
2516
0
                          TypeToIntervalString<CTYPE>());
2517
0
    }
2518
0
    *ev = static_cast<int64_t>(v + m);  // well-defined since C++20.
2519
0
    return NoError();
2520
0
  }
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)0, unsigned char>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)1, unsigned char>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)2, unsigned char>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)3, signed char>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)4, unsigned char>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)5, short>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)6, unsigned short>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)7, int>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)8, unsigned int>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)9, long>(long*, int)
Unexecuted instantiation: flatbuffers::CheckedError flatbuffers::EnumValBuilder::ValidateImpl<(flatbuffers::BaseType)10, unsigned long>(long*, int)
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
0
  FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t* ev, bool next) {
2523
    // clang-format off
2524
0
    switch (enum_def.underlying_type.base_type) {
2525
0
    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...)                   \
2526
0
      case BASE_TYPE_##ENUM: {                                          \
2527
0
        if (!IsInteger(BASE_TYPE_##ENUM)) break;                        \
2528
0
        return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
2529
0
      }
2530
0
      FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
2531
0
    #undef FLATBUFFERS_TD
2532
0
    default: break;
2533
0
    }
2534
    // clang-format on
2535
0
    return parser.Error("fatal: invalid enum underlying type");
2536
0
  }
2537
2538
  EnumValBuilder(Parser& _parser, EnumDef& _enum_def)
2539
0
      : parser(_parser),
2540
0
        enum_def(_enum_def),
2541
0
        temp(nullptr),
2542
0
        user_value(false) {}
2543
2544
0
  ~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
1
                               const char* filename) {
2554
1
  std::vector<std::string> enum_comment = doc_comment_;
2555
1
  NEXT();
2556
1
  std::string enum_name = attribute_;
2557
1
  EXPECT(kTokenIdentifier);
2558
0
  EnumDef* enum_def;
2559
0
  ECHECK(StartEnum(enum_name, is_union, &enum_def));
2560
0
  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
0
  enum_def->doc_comment = enum_comment;
2565
0
  if (!opts.proto_mode) {
2566
    // Give specialized error message, since this type spec used to
2567
    // be optional in the first FlatBuffers release.
2568
0
    bool explicit_underlying_type = false;
2569
0
    if (!Is(':')) {
2570
      // Enum is forced to have an explicit underlying type in declaration.
2571
0
      if (!is_union) {
2572
0
        return Error(
2573
0
            "must specify the underlying integer type for this"
2574
0
            " enum (e.g. \': short\', which was the default).");
2575
0
      }
2576
0
    } else {
2577
      // Union underlying type is only supported for cpp
2578
0
      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
0
      NEXT();
2584
0
      explicit_underlying_type = true;
2585
0
    }
2586
2587
0
    if (explicit_underlying_type) {
2588
      // Specify the integer type underlying this enum.
2589
0
      ECHECK(ParseType(enum_def->underlying_type));
2590
0
      if (!IsInteger(enum_def->underlying_type.base_type) ||
2591
0
          IsBool(enum_def->underlying_type.base_type)) {
2592
0
        return Error("underlying " + std::string(is_union ? "union" : "enum") +
2593
0
                     "type must be integral");
2594
0
      }
2595
2596
      // Make this type refer back to the enum it was derived from.
2597
0
      enum_def->underlying_type.enum_def = enum_def;
2598
0
    }
2599
0
  }
2600
0
  ECHECK(ParseMetaData(&enum_def->attributes));
2601
0
  const auto underlying_type = enum_def->underlying_type.base_type;
2602
0
  if (enum_def->attributes.Lookup("bit_flags") &&
2603
0
      !IsUnsigned(underlying_type)) {
2604
    // todo: Convert to the Error in the future?
2605
0
    Warning("underlying type of bit_flags enum must be unsigned");
2606
0
  }
2607
0
  if (enum_def->attributes.Lookup("force_align")) {
2608
0
    return Error("`force_align` is not a valid attribute for Enums. ");
2609
0
  }
2610
0
  EnumValBuilder evb(*this, *enum_def);
2611
0
  EXPECT('{');
2612
  // A lot of code generatos expect that an enum is not-empty.
2613
0
  if ((is_union || Is('}')) && !opts.proto_mode) {
2614
0
    evb.CreateEnumerator("NONE");
2615
0
    ECHECK(evb.AcceptEnumerator());
2616
0
  }
2617
0
  std::set<std::pair<BaseType, StructDef*>> union_types;
2618
0
  while (!Is('}')) {
2619
0
    if (opts.proto_mode && attribute_ == "option") {
2620
0
      ECHECK(ParseProtoOption());
2621
0
    } else {
2622
0
      auto& ev = *evb.CreateEnumerator(attribute_);
2623
0
      auto full_name = ev.name;
2624
0
      ev.doc_comment = doc_comment_;
2625
0
      EXPECT(kTokenIdentifier);
2626
0
      if (is_union) {
2627
0
        ECHECK(ParseNamespacing(&full_name, &ev.name));
2628
0
        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
0
          ev.name = full_name;
2632
0
          std::replace(ev.name.begin(), ev.name.end(), '.', '_');
2633
0
        }
2634
0
        if (Is(':')) {
2635
0
          NEXT();
2636
0
          ECHECK(ParseType(ev.union_type));
2637
0
          if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
2638
0
              ev.union_type.base_type != BASE_TYPE_STRING)
2639
0
            return Error("union value type may only be table/struct/string");
2640
0
        } else {
2641
0
          ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
2642
0
        }
2643
0
        if (!enum_def->uses_multiple_type_instances) {
2644
0
          auto ins = union_types.insert(std::make_pair(
2645
0
              ev.union_type.base_type, ev.union_type.struct_def));
2646
0
          enum_def->uses_multiple_type_instances = (false == ins.second);
2647
0
        }
2648
0
      }
2649
2650
0
      if (Is('=')) {
2651
0
        NEXT();
2652
0
        ECHECK(evb.AssignEnumeratorValue(attribute_));
2653
0
        EXPECT(kTokenIntegerConstant);
2654
0
      }
2655
2656
0
      if (opts.proto_mode && Is('[')) {
2657
0
        NEXT();
2658
        // ignore attributes on enums.
2659
0
        while (token_ != ']') NEXT();
2660
0
        NEXT();
2661
0
      } else {
2662
        // parse attributes in fbs schema
2663
0
        ECHECK(ParseMetaData(&ev.attributes));
2664
0
      }
2665
2666
0
      ECHECK(evb.AcceptEnumerator());
2667
0
    }
2668
0
    if (!Is(opts.proto_mode ? ';' : ',')) break;
2669
0
    NEXT();
2670
0
  }
2671
0
  EXPECT('}');
2672
2673
  // At this point, the enum can be empty if input is invalid proto-file.
2674
0
  if (!enum_def->size())
2675
0
    return Error("incomplete enum declaration, values not found");
2676
2677
0
  if (enum_def->attributes.Lookup("bit_flags")) {
2678
0
    const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type));
2679
0
    for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
2680
0
         ++it) {
2681
0
      auto ev = *it;
2682
0
      const auto u = ev->GetAsUInt64();
2683
      // Stop manipulations with the sign.
2684
0
      if (!IsUnsigned(underlying_type) && u == (base_width - 1))
2685
0
        return Error("underlying type of bit_flags enum must be unsigned");
2686
0
      if (u >= base_width)
2687
0
        return Error("bit flag out of range of underlying integral type");
2688
0
      enum_def->ChangeEnumValue(ev, 1ULL << u);
2689
0
    }
2690
0
  }
2691
2692
0
  enum_def->SortByValue();  // Must be sorted to use MinValue/MaxValue.
2693
2694
  // Ensure enum value uniqueness.
2695
0
  auto prev_it = enum_def->Vals().begin();
2696
0
  for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) {
2697
0
    auto prev_ev = *prev_it;
2698
0
    auto ev = *it;
2699
0
    if (prev_ev->GetAsUInt64() == ev->GetAsUInt64())
2700
0
      return Error("all enum values must be unique: " + prev_ev->name +
2701
0
                   " and " + ev->name + " are both " +
2702
0
                   NumToString(ev->GetAsInt64()));
2703
0
  }
2704
2705
0
  if (dest) *dest = enum_def;
2706
0
  const auto qualified_name =
2707
0
      current_namespace_->GetFullyQualifiedName(enum_def->name);
2708
0
  if (types_.Add(qualified_name, new Type(BASE_TYPE_UNION, nullptr, enum_def)))
2709
0
    return Error("datatype already exists: " + qualified_name);
2710
0
  return NoError();
2711
0
}
2712
2713
0
CheckedError Parser::StartStruct(const std::string& name, StructDef** dest) {
2714
0
  auto& struct_def = *LookupCreateStruct(name, true, true);
2715
0
  if (!struct_def.predecl)
2716
0
    return Error("datatype already exists: " +
2717
0
                 current_namespace_->GetFullyQualifiedName(name));
2718
0
  struct_def.predecl = false;
2719
0
  struct_def.name = name;
2720
0
  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
0
  *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
2724
0
      &struct_def;
2725
0
  *dest = &struct_def;
2726
0
  return NoError();
2727
0
}
2728
2729
CheckedError Parser::CheckClash(std::vector<FieldDef*>& fields,
2730
                                StructDef* struct_def, const char* suffix,
2731
0
                                BaseType basetype) {
2732
0
  auto len = strlen(suffix);
2733
0
  for (auto it = fields.begin(); it != fields.end(); ++it) {
2734
0
    auto& fname = (*it)->name;
2735
0
    if (fname.length() > len &&
2736
0
        fname.compare(fname.length() - len, len, suffix) == 0 &&
2737
0
        (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
2738
0
      auto field =
2739
0
          struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
2740
0
      if (field && field->value.type.base_type == basetype)
2741
0
        return Error("Field " + fname +
2742
0
                     " would clash with generated functions for field " +
2743
0
                     field->name);
2744
0
    }
2745
0
  }
2746
0
  return NoError();
2747
0
}
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
0
bool Parser::SupportsOptionalScalars() const {
2805
  // Check in general if a language isn't specified.
2806
0
  return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
2807
0
}
2808
2809
0
bool Parser::SupportsDefaultVectorsAndStrings() const {
2810
0
  static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
2811
0
      IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim |
2812
0
      IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson |
2813
0
      IDLOptions::kTs;
2814
0
  return !(opts.lang_to_generate & ~supported_langs);
2815
0
}
2816
2817
0
bool Parser::SupportsAdvancedUnionFeatures() const {
2818
0
  return (opts.lang_to_generate &
2819
0
          ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp |
2820
0
            IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin |
2821
0
            IDLOptions::kBinary | IDLOptions::kSwift | IDLOptions::kNim |
2822
0
            IDLOptions::kJson | IDLOptions::kKotlinKmp)) == 0;
2823
0
}
2824
2825
0
bool Parser::SupportsAdvancedArrayFeatures() const {
2826
0
  return (opts.lang_to_generate &
2827
0
          ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
2828
0
            IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
2829
0
            IDLOptions::kBinary | IDLOptions::kRust | IDLOptions::kTs |
2830
0
            IDLOptions::kSwift)) == 0;
2831
0
}
2832
2833
0
bool Parser::Supports64BitOffsets() const {
2834
0
  return (opts.lang_to_generate &
2835
0
          ~(IDLOptions::kCpp | IDLOptions::kJson | IDLOptions::kBinary)) == 0;
2836
0
}
2837
2838
0
bool Parser::SupportsUnionUnderlyingType() const {
2839
0
  return (opts.lang_to_generate &
2840
0
          ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kBinary)) == 0;
2841
0
}
2842
2843
46
Namespace* Parser::UniqueNamespace(Namespace* ns) {
2844
114
  for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
2845
114
    if (ns->components == (*it)->components) {
2846
46
      delete ns;
2847
46
      return *it;
2848
46
    }
2849
114
  }
2850
0
  namespaces_.push_back(ns);
2851
0
  return ns;
2852
46
}
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
4
CheckedError Parser::ParseDecl(const char* filename) {
2870
4
  std::vector<std::string> dc = doc_comment_;
2871
4
  bool fixed = IsIdent("struct");
2872
4
  if (!fixed && !IsIdent("table")) return Error("declaration expected");
2873
0
  NEXT();
2874
0
  std::string name = attribute_;
2875
0
  EXPECT(kTokenIdentifier);
2876
0
  StructDef* struct_def;
2877
0
  ECHECK(StartStruct(name, &struct_def));
2878
0
  struct_def->doc_comment = dc;
2879
0
  struct_def->fixed = fixed;
2880
0
  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
0
  ECHECK(ParseMetaData(&struct_def->attributes));
2885
0
  struct_def->sortbysize =
2886
0
      struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
2887
0
  EXPECT('{');
2888
0
  while (token_ != '}') ECHECK(ParseField(*struct_def));
2889
0
  if (fixed) {
2890
0
    const auto force_align = struct_def->attributes.Lookup("force_align");
2891
0
    if (force_align) {
2892
0
      size_t align;
2893
0
      ECHECK(ParseAlignAttribute(force_align->constant, struct_def->minalign,
2894
0
                                 &align));
2895
0
      struct_def->minalign = align;
2896
0
    }
2897
0
    if (!struct_def->bytesize) return Error("size 0 structs not allowed");
2898
0
  }
2899
0
  struct_def->PadLastField(struct_def->minalign);
2900
  // Check if this is a table that has manual id assignments
2901
0
  auto& fields = struct_def->fields.vec;
2902
0
  if (!fixed && fields.size()) {
2903
0
    size_t num_id_fields = 0;
2904
0
    for (auto it = fields.begin(); it != fields.end(); ++it) {
2905
0
      if ((*it)->attributes.Lookup("id")) num_id_fields++;
2906
0
    }
2907
    // If any fields have ids..
2908
0
    if (num_id_fields || opts.require_explicit_ids) {
2909
      // Then all fields must have them.
2910
0
      if (num_id_fields != fields.size()) {
2911
0
        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
0
        } else {
2916
0
          return Error(
2917
0
              "either all fields or no fields must have an 'id' attribute");
2918
0
        }
2919
0
      }
2920
      // Simply sort by id, then the fields are the same as if no ids had
2921
      // been specified.
2922
0
      std::sort(fields.begin(), fields.end(), compareFieldDefs);
2923
      // Verify we have a contiguous set, and reassign vtable offsets.
2924
0
      FLATBUFFERS_ASSERT(fields.size() <=
2925
0
                         flatbuffers::numeric_limits<voffset_t>::max());
2926
0
      for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) {
2927
0
        auto& field = *fields[i];
2928
0
        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
0
        voffset_t id = 0;
2935
0
        const auto done = !atot(id_str.c_str(), *this, &id).Check();
2936
0
        if (!done)
2937
0
          return Error("field id\'s must be non-negative number, field: " +
2938
0
                       field.name + ", id: " + id_str);
2939
0
        if (i != id)
2940
0
          return Error("field id\'s must be consecutive from 0, id " +
2941
0
                       NumToString(i) + " missing or set twice, field: " +
2942
0
                       field.name + ", id: " + id_str);
2943
0
        field.value.offset = FieldIndexToOffset(i);
2944
0
      }
2945
0
    }
2946
0
  }
2947
2948
0
  ECHECK(
2949
0
      CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
2950
0
  ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
2951
0
  ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
2952
0
  ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
2953
0
  ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
2954
0
  ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
2955
0
  EXPECT('}');
2956
0
  const auto qualified_name =
2957
0
      current_namespace_->GetFullyQualifiedName(struct_def->name);
2958
0
  if (types_.Add(qualified_name,
2959
0
                 new Type(BASE_TYPE_STRUCT, struct_def, nullptr)))
2960
0
    return Error("datatype already exists: " + qualified_name);
2961
0
  return NoError();
2962
0
}
2963
2964
0
CheckedError Parser::ParseService(const char* filename) {
2965
0
  std::vector<std::string> service_comment = doc_comment_;
2966
0
  NEXT();
2967
0
  auto service_name = attribute_;
2968
0
  EXPECT(kTokenIdentifier);
2969
0
  auto& service_def = *new ServiceDef();
2970
0
  service_def.name = service_name;
2971
0
  service_def.file = file_being_parsed_;
2972
0
  service_def.doc_comment = service_comment;
2973
0
  service_def.defined_namespace = current_namespace_;
2974
0
  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
0
  if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
2979
0
                    &service_def))
2980
0
    return Error("service already exists: " + service_name);
2981
0
  ECHECK(ParseMetaData(&service_def.attributes));
2982
0
  EXPECT('{');
2983
0
  do {
2984
0
    std::vector<std::string> doc_comment = doc_comment_;
2985
0
    auto rpc_name = attribute_;
2986
0
    EXPECT(kTokenIdentifier);
2987
0
    EXPECT('(');
2988
0
    Type reqtype, resptype;
2989
0
    ECHECK(ParseTypeIdent(reqtype));
2990
0
    EXPECT(')');
2991
0
    EXPECT(':');
2992
0
    ECHECK(ParseTypeIdent(resptype));
2993
0
    if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
2994
0
        resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
2995
0
      return Error("rpc request and response types must be tables");
2996
0
    auto& rpc = *new RPCCall();
2997
0
    rpc.name = rpc_name;
2998
0
    rpc.request = reqtype.struct_def;
2999
0
    rpc.response = resptype.struct_def;
3000
0
    rpc.doc_comment = doc_comment;
3001
0
    if (service_def.calls.Add(rpc_name, &rpc))
3002
0
      return Error("rpc already exists: " + rpc_name);
3003
0
    ECHECK(ParseMetaData(&rpc.attributes));
3004
0
    EXPECT(';');
3005
0
  } while (token_ != '}');
3006
0
  NEXT();
3007
0
  return NoError();
3008
0
}
3009
3010
0
bool Parser::SetRootType(const char* name) {
3011
0
  root_struct_def_ = LookupStruct(name);
3012
0
  if (!root_struct_def_)
3013
0
    root_struct_def_ =
3014
0
        LookupStruct(current_namespace_->GetFullyQualifiedName(name));
3015
0
  return root_struct_def_ != nullptr;
3016
0
}
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
0
CheckedError Parser::ParseNamespace() {
3036
0
  NEXT();
3037
0
  auto ns = new Namespace();
3038
0
  namespaces_.push_back(ns);  // Store it here to not leak upon error.
3039
0
  if (token_ != ';') {
3040
0
    for (;;) {
3041
0
      ns->components.push_back(attribute_);
3042
0
      EXPECT(kTokenIdentifier);
3043
0
      if (Is('.')) NEXT() else break;
3044
0
    }
3045
0
  }
3046
0
  namespaces_.pop_back();
3047
0
  current_namespace_ = UniqueNamespace(ns);
3048
0
  EXPECT(';');
3049
0
  return NoError();
3050
0
}
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
0
                               EnumDef** dest) {
3122
0
  auto& enum_def = *new EnumDef();
3123
0
  enum_def.name = name;
3124
0
  enum_def.file = file_being_parsed_;
3125
0
  enum_def.doc_comment = doc_comment_;
3126
0
  enum_def.is_union = is_union;
3127
0
  enum_def.defined_namespace = current_namespace_;
3128
0
  const auto qualified_name = current_namespace_->GetFullyQualifiedName(name);
3129
0
  if (enums_.Add(qualified_name, &enum_def))
3130
0
    return Error("enum already exists: " + qualified_name);
3131
0
  enum_def.underlying_type.base_type =
3132
0
      is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT;
3133
0
  enum_def.underlying_type.enum_def = &enum_def;
3134
0
  if (dest) *dest = &enum_def;
3135
0
  return NoError();
3136
0
}
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.28M
CheckedError Parser::SkipAnyJsonValue() {
3454
1.28M
  ParseDepthGuard depth_guard(this);
3455
1.28M
  ECHECK(depth_guard.Check());
3456
3457
1.28M
  switch (token_) {
3458
81.3k
    case '{': {
3459
81.3k
      size_t fieldn_outer = 0;
3460
81.3k
      return ParseTableDelimiters(fieldn_outer, nullptr,
3461
81.3k
                                  [&](const std::string&, size_t& fieldn,
3462
192k
                                      const StructDef*) -> CheckedError {
3463
192k
                                    ECHECK(SkipAnyJsonValue());
3464
191k
                                    fieldn++;
3465
191k
                                    return NoError();
3466
192k
                                  });
3467
0
    }
3468
418k
    case '[': {
3469
418k
      size_t count = 0;
3470
418k
      return ParseVectorDelimiters(
3471
1.05M
          count, [&](size_t&) -> CheckedError { return SkipAnyJsonValue(); });
3472
0
    }
3473
88.4k
    case kTokenStringConstant:
3474
333k
    case kTokenIntegerConstant:
3475
764k
    case kTokenFloatConstant:
3476
764k
      NEXT();
3477
764k
      break;
3478
20.9k
    default:
3479
20.9k
      if (IsIdent("true") || IsIdent("false") || IsIdent("null") ||
3480
20.7k
          IsIdent("inf")) {
3481
20.7k
        NEXT();
3482
20.7k
      } else
3483
227
        return TokenError();
3484
1.28M
  }
3485
785k
  return NoError();
3486
1.28M
}
3487
3488
CheckedError Parser::ParseFlexBufferNumericConstant(
3489
5.51k
    flexbuffers::Builder* builder) {
3490
5.51k
  double d;
3491
5.51k
  if (!StringToNumber(attribute_.c_str(), &d))
3492
21
    return Error("unexpected floating-point constant: " + attribute_);
3493
5.49k
  builder->Double(d);
3494
5.49k
  return NoError();
3495
5.51k
}
3496
3497
2.12M
CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder* builder) {
3498
2.12M
  ParseDepthGuard depth_guard(this);
3499
2.12M
  ECHECK(depth_guard.Check());
3500
3501
2.12M
  switch (token_) {
3502
69.7k
    case '{': {
3503
69.7k
      auto start = builder->StartMap();
3504
69.7k
      size_t fieldn_outer = 0;
3505
69.7k
      auto err =
3506
69.7k
          ParseTableDelimiters(fieldn_outer, nullptr,
3507
69.7k
                               [&](const std::string& name, size_t& fieldn,
3508
269k
                                   const StructDef*) -> CheckedError {
3509
269k
                                 builder->Key(name);
3510
269k
                                 ECHECK(ParseFlexBufferValue(builder));
3511
268k
                                 fieldn++;
3512
268k
                                 return NoError();
3513
269k
                               });
3514
69.7k
      ECHECK(err);
3515
68.6k
      builder->EndMap(start);
3516
68.6k
      if (builder->HasDuplicateKeys())
3517
2.94k
        return Error("FlexBuffers map has duplicate keys");
3518
65.6k
      break;
3519
68.6k
    }
3520
693k
    case '[': {
3521
693k
      auto start = builder->StartVector();
3522
693k
      size_t count = 0;
3523
693k
      ECHECK(ParseVectorDelimiters(count, [&](size_t&) -> CheckedError {
3524
693k
        return ParseFlexBufferValue(builder);
3525
693k
      }));
3526
692k
      builder->EndVector(start, false, false);
3527
692k
      break;
3528
693k
    }
3529
19.0k
    case kTokenStringConstant:
3530
19.0k
      builder->String(attribute_);
3531
19.0k
      EXPECT(kTokenStringConstant);
3532
18.9k
      break;
3533
623k
    case kTokenIntegerConstant:
3534
623k
      builder->Int(StringToInt(attribute_.c_str()));
3535
623k
      EXPECT(kTokenIntegerConstant);
3536
623k
      break;
3537
706k
    case kTokenFloatConstant: {
3538
706k
      double d;
3539
706k
      StringToNumber(attribute_.c_str(), &d);
3540
706k
      builder->Double(d);
3541
706k
      EXPECT(kTokenFloatConstant);
3542
706k
      break;
3543
706k
    }
3544
224
    case '-':
3545
1.74k
    case '+': {
3546
      // `[-+]?(nan|inf|infinity)`, see ParseSingleValue().
3547
1.74k
      const auto sign = static_cast<char>(token_);
3548
1.74k
      NEXT();
3549
1.74k
      if (token_ != kTokenIdentifier)
3550
0
        return Error("floating-point constant expected");
3551
1.74k
      attribute_.insert(size_t(0), size_t(1), sign);
3552
1.74k
      ECHECK(ParseFlexBufferNumericConstant(builder));
3553
1.72k
      NEXT();
3554
1.72k
      break;
3555
1.72k
    }
3556
7.66k
    default:
3557
7.66k
      if (IsIdent("true")) {
3558
1.48k
        builder->Bool(true);
3559
1.48k
        NEXT();
3560
6.18k
      } else if (IsIdent("false")) {
3561
1.02k
        builder->Bool(false);
3562
1.02k
        NEXT();
3563
5.16k
      } else if (IsIdent("null")) {
3564
1.11k
        builder->Null();
3565
1.11k
        NEXT();
3566
4.04k
      } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) {
3567
3.76k
        ECHECK(ParseFlexBufferNumericConstant(builder));
3568
3.76k
        NEXT();
3569
3.76k
      } else
3570
279
        return TokenError();
3571
2.12M
  }
3572
2.11M
  return NoError();
3573
2.12M
}
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
10.2k
                   const char* source_filename) {
3588
10.2k
  const auto initial_depth = parse_depth_counter_;
3589
10.2k
  (void)initial_depth;
3590
10.2k
  bool r;
3591
3592
10.2k
  if (opts.use_flexbuffers) {
3593
0
    r = ParseFlexBuffer(source, source_filename, &flex_builder_);
3594
10.2k
  } else {
3595
10.2k
    r = !ParseRoot(source, include_paths, source_filename).Check();
3596
10.2k
  }
3597
10.2k
  FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3598
10.2k
  return r;
3599
10.2k
}
3600
3601
18.5k
bool Parser::ParseJson(const char* json, const char* json_filename) {
3602
18.5k
  const auto initial_depth = parse_depth_counter_;
3603
18.5k
  (void)initial_depth;
3604
18.5k
  builder_.Clear();
3605
18.5k
  const auto done =
3606
18.5k
      !StartParseFile(json, json_filename).Check() && !DoParseJson().Check();
3607
18.5k
  FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_);
3608
18.5k
  return done;
3609
18.5k
}
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
28.7k
                                    const char* source_filename) {
3617
28.7k
  file_being_parsed_ = source_filename ? source_filename : "";
3618
28.7k
  source_ = source;
3619
28.7k
  ResetState(source_);
3620
28.7k
  error_.clear();
3621
28.7k
  ECHECK(SkipByteOrderMark());
3622
28.7k
  NEXT();
3623
28.3k
  if (Is(kTokenEof)) return Error("input file is empty");
3624
28.1k
  return NoError();
3625
28.3k
}
3626
3627
CheckedError Parser::ParseRoot(const char* source, const char** include_paths,
3628
10.2k
                               const char* source_filename) {
3629
10.2k
  ECHECK(DoParse(source, include_paths, source_filename, nullptr));
3630
3631
  // Check that all types were defined.
3632
10.2k
  for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
3633
0
    auto& struct_def = **it;
3634
0
    if (struct_def.predecl) {
3635
0
      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
0
      auto err = "type referenced but not defined (check namespace): " +
3681
0
                 struct_def.name;
3682
0
      if (struct_def.original_location)
3683
0
        err += ", originally at: " + *struct_def.original_location;
3684
0
      return Error(err);
3685
0
    }
3686
0
    ++it;
3687
0
  }
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
81.6k
  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
3692
71.4k
    auto& enum_def = **it;
3693
71.4k
    if (enum_def.is_union) {
3694
30.6k
      for (auto val_it = enum_def.Vals().begin();
3695
153k
           val_it != enum_def.Vals().end(); ++val_it) {
3696
122k
        auto& val = **val_it;
3697
3698
122k
        if (!(opts.lang_to_generate != 0 && SupportsAdvancedUnionFeatures()) &&
3699
122k
            (IsStruct(val.union_type) || IsString(val.union_type)))
3700
3701
0
          return Error(
3702
0
              "only tables can be union elements in the generated language: " +
3703
0
              val.name);
3704
122k
      }
3705
30.6k
    }
3706
71.4k
  }
3707
3708
10.2k
  auto err = CheckPrivateLeak();
3709
10.2k
  if (err.Check()) return err;
3710
3711
  // Parse JSON object only if the scheme has been parsed.
3712
10.2k
  if (token_ == '{') {
3713
10.2k
    ECHECK(DoParseJson());
3714
9.35k
  }
3715
9.35k
  return NoError();
3716
10.2k
}
3717
3718
10.2k
CheckedError Parser::CheckPrivateLeak() {
3719
10.2k
  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
10.2k
                             const char* include_filename) {
3780
10.2k
  uint64_t source_hash = 0;
3781
10.2k
  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
0
    if (FileExists(source_filename))
3785
0
      source_hash = HashFile(source_filename, source);
3786
0
    else
3787
0
      source_hash = HashFile(source_filename, nullptr);
3788
3789
0
    if (included_files_.find(source_hash) == included_files_.end()) {
3790
0
      included_files_[source_hash] = include_filename ? include_filename : "";
3791
0
      files_included_per_file_[source_filename] = std::set<IncludedFile>();
3792
0
    } else {
3793
0
      return NoError();
3794
0
    }
3795
0
  }
3796
10.2k
  if (!include_paths) {
3797
10.2k
    static const char* current_directory[] = {"", nullptr};
3798
10.2k
    include_paths = current_directory;
3799
10.2k
  }
3800
10.2k
  field_stack_.clear();
3801
10.2k
  builder_.Clear();
3802
  // Start with a blank namespace just in case this file doesn't have one.
3803
10.2k
  current_namespace_ = empty_namespace_;
3804
3805
10.2k
  ECHECK(StartParseFile(source, source_filename));
3806
3807
  // Includes must come before type declarations:
3808
10.2k
  for (;;) {
3809
    // Parse pre-include proto statements if any:
3810
10.2k
    if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
3811
0
                            attribute_ == "package")) {
3812
0
      ECHECK(ParseProtoDecl());
3813
10.2k
    } else if (IsIdent("native_include")) {
3814
0
      NEXT();
3815
0
      native_included_files_.emplace_back(attribute_);
3816
0
      EXPECT(kTokenStringConstant);
3817
0
      EXPECT(';');
3818
10.2k
    } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
3819
0
      NEXT();
3820
0
      if (opts.proto_mode && attribute_ == "public") NEXT();
3821
0
      auto name = flatbuffers::PosixPath(attribute_.c_str());
3822
0
      EXPECT(kTokenStringConstant);
3823
      // Look for the file relative to the directory of the current file.
3824
0
      std::string filepath;
3825
0
      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
0
      if (filepath.empty() || !FileExists(filepath.c_str())) {
3831
        // Look for the file in include_paths.
3832
0
        for (auto paths = include_paths; paths && *paths; paths++) {
3833
0
          filepath = flatbuffers::ConCatPathFileName(*paths, name);
3834
0
          if (FileExists(filepath.c_str())) break;
3835
0
        }
3836
0
      }
3837
0
      if (filepath.empty())
3838
0
        return Error("unable to locate include file: " + name);
3839
0
      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
0
      std::string contents;
3847
0
      bool file_loaded = LoadFile(filepath.c_str(), true, &contents);
3848
0
      if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) ==
3849
0
          included_files_.end()) {
3850
        // We found an include file that we have not parsed yet.
3851
        // Parse it.
3852
0
        if (!file_loaded) return Error("unable to load include file: " + name);
3853
0
        ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
3854
0
                       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
0
      }
3873
0
      EXPECT(';');
3874
10.2k
    } else {
3875
10.2k
      break;
3876
10.2k
    }
3877
10.2k
  }
3878
  // Now parse all other kinds of declarations:
3879
10.2k
  while (token_ != kTokenEof) {
3880
10.2k
    if (opts.proto_mode) {
3881
0
      ECHECK(ParseProtoDecl());
3882
10.2k
    } else if (IsIdent("namespace")) {
3883
0
      ECHECK(ParseNamespace());
3884
10.2k
    } else if (token_ == '{') {
3885
10.2k
      return NoError();
3886
10.2k
    } else if (IsIdent("enum")) {
3887
1
      ECHECK(ParseEnum(false, nullptr, source_filename));
3888
7
    } else if (IsIdent("union")) {
3889
0
      ECHECK(ParseEnum(true, nullptr, source_filename));
3890
7
    } else if (IsIdent("root_type")) {
3891
0
      NEXT();
3892
0
      auto root_type = attribute_;
3893
0
      EXPECT(kTokenIdentifier);
3894
0
      ECHECK(ParseNamespacing(&root_type, nullptr));
3895
0
      if (opts.root_type.empty()) {
3896
0
        if (!SetRootType(root_type.c_str()))
3897
0
          return Error("unknown root type: " + root_type);
3898
0
        if (root_struct_def_->fixed) return Error("root type must be a table");
3899
0
      }
3900
0
      EXPECT(';');
3901
7
    } else if (IsIdent("file_identifier")) {
3902
1
      NEXT();
3903
1
      file_identifier_ = attribute_;
3904
1
      EXPECT(kTokenStringConstant);
3905
0
      if (file_identifier_.length() != flatbuffers::kFileIdentifierLength)
3906
0
        return Error("file_identifier must be exactly " +
3907
0
                     NumToString(flatbuffers::kFileIdentifierLength) +
3908
0
                     " characters");
3909
0
      EXPECT(';');
3910
6
    } else if (IsIdent("file_extension")) {
3911
1
      NEXT();
3912
1
      file_extension_ = attribute_;
3913
1
      EXPECT(kTokenStringConstant);
3914
0
      EXPECT(';');
3915
5
    } else if (IsIdent("include")) {
3916
0
      return Error("includes must come before declarations");
3917
5
    } else if (IsIdent("attribute")) {
3918
1
      NEXT();
3919
1
      auto name = attribute_;
3920
1
      if (Is(kTokenIdentifier)) {
3921
0
        NEXT();
3922
1
      } else {
3923
1
        EXPECT(kTokenStringConstant);
3924
0
      }
3925
0
      EXPECT(';');
3926
0
      known_attributes_[name] = false;
3927
4
    } else if (IsIdent("rpc_service")) {
3928
0
      ECHECK(ParseService(source_filename));
3929
4
    } else {
3930
4
      ECHECK(ParseDecl(source_filename));
3931
0
    }
3932
10.2k
  }
3933
0
  EXPECT(kTokenEof);
3934
0
  if (opts.warnings_as_errors && has_warning_) {
3935
0
    return Error("treating warnings as errors, failed due to above warnings");
3936
0
  }
3937
0
  return NoError();
3938
0
}
3939
3940
28.1k
CheckedError Parser::DoParseJson() {
3941
28.1k
  if (token_ != '{') {
3942
290
    EXPECT('{');
3943
27.8k
  } else {
3944
27.8k
    if (!root_struct_def_) return Error("no root type set to parse json with");
3945
27.8k
    if (builder_.GetSize()) {
3946
0
      return Error("cannot have more than one json object in a file");
3947
0
    }
3948
27.8k
    uoffset_t toff;
3949
27.8k
    ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
3950
16.9k
    if (opts.size_prefixed) {
3951
0
      builder_.FinishSizePrefixed(
3952
0
          Offset<Table>(toff),
3953
0
          file_identifier_.length() ? file_identifier_.c_str() : nullptr);
3954
16.9k
    } else {
3955
16.9k
      builder_.Finish(Offset<Table>(toff), file_identifier_.length()
3956
16.9k
                                               ? file_identifier_.c_str()
3957
16.9k
                                               : nullptr);
3958
16.9k
    }
3959
16.9k
  }
3960
16.9k
  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
16.9k
    EXPECT(kTokenEof);
3964
16.8k
  }
3965
16.8k
  return NoError();
3966
16.9k
}
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
0
                          FlatBufferBuilder* builder, const Parser& parser) {
4000
0
  std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
4001
0
  for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
4002
0
    auto it = parser.known_attributes_.find(kv->first);
4003
0
    FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
4004
0
    if (parser.opts.binary_schema_builtins || !it->second) {
4005
0
      auto key = builder->CreateString(kv->first);
4006
0
      auto val = builder->CreateString(kv->second->constant);
4007
0
      attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
4008
0
    }
4009
0
  }
4010
0
  if (attrs.size()) {
4011
0
    return builder->CreateVectorOfSortedTables(&attrs);
4012
0
  } else {
4013
0
    return 0;
4014
0
  }
4015
0
}
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
0
void Parser::Serialize() {
4037
0
  builder_.Clear();
4038
0
  AssignIndices(structs_.vec);
4039
0
  AssignIndices(enums_.vec);
4040
0
  std::vector<Offset<reflection::Object>> object_offsets;
4041
0
  std::set<std::string> files;
4042
0
  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
4043
0
    auto offset = (*it)->Serialize(&builder_, *this);
4044
0
    object_offsets.push_back(offset);
4045
0
    (*it)->serialized_location = offset.o;
4046
0
    const std::string* file = (*it)->declaration_file;
4047
0
    if (file) files.insert(*file);
4048
0
  }
4049
0
  std::vector<Offset<reflection::Enum>> enum_offsets;
4050
0
  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
4051
0
    auto offset = (*it)->Serialize(&builder_, *this);
4052
0
    enum_offsets.push_back(offset);
4053
0
    const std::string* file = (*it)->declaration_file;
4054
0
    if (file) files.insert(*file);
4055
0
  }
4056
0
  std::vector<Offset<reflection::Service>> service_offsets;
4057
0
  for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
4058
0
    auto offset = (*it)->Serialize(&builder_, *this);
4059
0
    service_offsets.push_back(offset);
4060
0
    const std::string* file = (*it)->declaration_file;
4061
0
    if (file) files.insert(*file);
4062
0
  }
4063
4064
  // Create Schemafiles vector of tables.
4065
0
  flatbuffers::Offset<
4066
0
      flatbuffers::Vector<flatbuffers::Offset<reflection::SchemaFile>>>
4067
0
      schema_files__;
4068
0
  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
0
  const auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
4090
0
  const auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
4091
0
  const auto fiid__ = builder_.CreateString(file_identifier_);
4092
0
  const auto fext__ = builder_.CreateString(file_extension_);
4093
0
  const auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
4094
0
  const auto schema_offset = reflection::CreateSchema(
4095
0
      builder_, objs__, enum__, fiid__, fext__,
4096
0
      (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__,
4097
0
      static_cast<reflection::AdvancedFeatures>(advanced_features_),
4098
0
      schema_files__);
4099
0
  if (opts.size_prefixed) {
4100
0
    builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
4101
0
  } else {
4102
0
    builder_.Finish(schema_offset, reflection::SchemaIdentifier());
4103
0
  }
4104
0
}
4105
4106
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder* builder,
4107
0
                                                const Parser& parser) const {
4108
0
  std::vector<Offset<reflection::Field>> field_offsets;
4109
0
  for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
4110
0
    field_offsets.push_back((*it)->Serialize(
4111
0
        builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
4112
0
  }
4113
0
  const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
4114
0
  const auto name__ = builder->CreateString(qualified_name);
4115
0
  const auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
4116
0
  const auto attr__ = SerializeAttributes(builder, parser);
4117
0
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4118
0
                          ? builder->CreateVectorOfStrings(doc_comment)
4119
0
                          : 0;
4120
0
  std::string decl_file_in_project = declaration_file ? *declaration_file : "";
4121
0
  const auto file__ = builder->CreateSharedString(decl_file_in_project);
4122
0
  return reflection::CreateObject(
4123
0
      *builder, name__, flds__, fixed, static_cast<int>(minalign),
4124
0
      static_cast<int>(bytesize), attr__, docs__, file__);
4125
0
}
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
0
                                              const Parser& parser) const {
4180
0
  auto name__ = builder->CreateString(name);
4181
0
  auto type__ = value.type.Serialize(builder);
4182
0
  auto attr__ = SerializeAttributes(builder, parser);
4183
0
  auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4184
0
                    ? builder->CreateVectorOfStrings(doc_comment)
4185
0
                    : 0;
4186
0
  double d;
4187
0
  StringToNumber(value.constant.c_str(), &d);
4188
0
  return reflection::CreateField(
4189
0
      *builder, name__, type__, id, value.offset,
4190
      // Is uint64>max(int64) tested?
4191
0
      IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
4192
      // result may be platform-dependent if underlying is float (not double)
4193
0
      IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key,
4194
0
      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
0
}
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
0
                                               const Parser& parser) const {
4235
0
  auto name__ = builder->CreateString(name);
4236
0
  auto attr__ = SerializeAttributes(builder, parser);
4237
0
  auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4238
0
                    ? builder->CreateVectorOfStrings(doc_comment)
4239
0
                    : 0;
4240
0
  return reflection::CreateRPCCall(
4241
0
      *builder, name__, request->serialized_location,
4242
0
      response->serialized_location, attr__, docs__);
4243
0
}
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
0
                                                  const Parser& parser) const {
4259
0
  std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
4260
0
  for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
4261
0
    servicecall_offsets.push_back((*it)->Serialize(builder, parser));
4262
0
  }
4263
0
  const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
4264
0
  const auto name__ = builder->CreateString(qualified_name);
4265
0
  const auto call__ = builder->CreateVector(servicecall_offsets);
4266
0
  const auto attr__ = SerializeAttributes(builder, parser);
4267
0
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4268
0
                          ? builder->CreateVectorOfStrings(doc_comment)
4269
0
                          : 0;
4270
0
  std::string decl_file_in_project = declaration_file ? *declaration_file : "";
4271
0
  const auto file__ = builder->CreateSharedString(decl_file_in_project);
4272
0
  return reflection::CreateService(*builder, name__, call__, attr__, docs__,
4273
0
                                   file__);
4274
0
}
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
0
                                            const Parser& parser) const {
4296
0
  std::vector<Offset<reflection::EnumVal>> enumval_offsets;
4297
0
  for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
4298
0
    enumval_offsets.push_back((*it)->Serialize(builder, parser));
4299
0
  }
4300
0
  const auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
4301
0
  const auto name__ = builder->CreateString(qualified_name);
4302
0
  const auto vals__ = builder->CreateVector(enumval_offsets);
4303
0
  const auto type__ = underlying_type.Serialize(builder);
4304
0
  const auto attr__ = SerializeAttributes(builder, parser);
4305
0
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4306
0
                          ? builder->CreateVectorOfStrings(doc_comment)
4307
0
                          : 0;
4308
0
  std::string decl_file_in_project = declaration_file ? *declaration_file : "";
4309
0
  const auto file__ = builder->CreateSharedString(decl_file_in_project);
4310
0
  return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
4311
0
                                attr__, docs__, file__);
4312
0
}
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
0
                             const Parser& parser) const {
4337
0
  return SerializeAttributesCommon(attributes, builder, parser);
4338
0
}
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
0
                                               const Parser& parser) const {
4347
0
  const auto name__ = builder->CreateString(name);
4348
0
  const auto type__ = union_type.Serialize(builder);
4349
0
  const auto attr__ = SerializeAttributes(builder, parser);
4350
0
  const auto docs__ = parser.opts.binary_schema_comments && !doc_comment.empty()
4351
0
                          ? builder->CreateVectorOfStrings(doc_comment)
4352
0
                          : 0;
4353
0
  return reflection::CreateEnumVal(*builder, name__, value, type__, docs__,
4354
0
                                   attr__);
4355
0
}
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
0
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder* builder) const {
4367
0
  size_t element_size = SizeOf(element);
4368
0
  if (base_type == BASE_TYPE_VECTOR && element == BASE_TYPE_STRUCT &&
4369
0
      struct_def->bytesize != 0) {
4370
    // struct_def->bytesize==0 means struct is table
4371
0
    element_size = struct_def->bytesize;
4372
0
  }
4373
0
  return reflection::CreateType(
4374
0
      *builder, static_cast<reflection::BaseType>(base_type),
4375
0
      static_cast<reflection::BaseType>(element),
4376
0
      struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
4377
0
      fixed_length, static_cast<uint32_t>(SizeOf(base_type)),
4378
0
      static_cast<uint32_t>(element_size));
4379
0
}
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
0
                                const Parser& parser) const {
4412
0
  return SerializeAttributesCommon(attributes, builder, parser);
4413
0
}
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