1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker // independent from idl_parser, since this code is not needed for most clients
18*890232f2SAndroid Build Coastguard Worker
19*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
20*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flexbuffers.h"
21*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
23*890232f2SAndroid Build Coastguard Worker
24*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
25*890232f2SAndroid Build Coastguard Worker
26*890232f2SAndroid Build Coastguard Worker struct PrintScalarTag {};
27*890232f2SAndroid Build Coastguard Worker struct PrintPointerTag {};
28*890232f2SAndroid Build Coastguard Worker template<typename T> struct PrintTag { typedef PrintScalarTag type; };
29*890232f2SAndroid Build Coastguard Worker template<> struct PrintTag<const void *> { typedef PrintPointerTag type; };
30*890232f2SAndroid Build Coastguard Worker
31*890232f2SAndroid Build Coastguard Worker struct JsonPrinter {
32*890232f2SAndroid Build Coastguard Worker // If indentation is less than 0, that indicates we don't want any newlines
33*890232f2SAndroid Build Coastguard Worker // either.
AddNewLineflatbuffers::JsonPrinter34*890232f2SAndroid Build Coastguard Worker void AddNewLine() {
35*890232f2SAndroid Build Coastguard Worker if (opts.indent_step >= 0) text += '\n';
36*890232f2SAndroid Build Coastguard Worker }
37*890232f2SAndroid Build Coastguard Worker
AddIndentflatbuffers::JsonPrinter38*890232f2SAndroid Build Coastguard Worker void AddIndent(int ident) { text.append(ident, ' '); }
39*890232f2SAndroid Build Coastguard Worker
Indentflatbuffers::JsonPrinter40*890232f2SAndroid Build Coastguard Worker int Indent() const { return std::max(opts.indent_step, 0); }
41*890232f2SAndroid Build Coastguard Worker
42*890232f2SAndroid Build Coastguard Worker // Output an identifier with or without quotes depending on strictness.
OutputIdentifierflatbuffers::JsonPrinter43*890232f2SAndroid Build Coastguard Worker void OutputIdentifier(const std::string &name) {
44*890232f2SAndroid Build Coastguard Worker if (opts.strict_json) text += '\"';
45*890232f2SAndroid Build Coastguard Worker text += name;
46*890232f2SAndroid Build Coastguard Worker if (opts.strict_json) text += '\"';
47*890232f2SAndroid Build Coastguard Worker }
48*890232f2SAndroid Build Coastguard Worker
49*890232f2SAndroid Build Coastguard Worker // Print (and its template specialization below for pointers) generate text
50*890232f2SAndroid Build Coastguard Worker // for a single FlatBuffer value into JSON format.
51*890232f2SAndroid Build Coastguard Worker // The general case for scalars:
52*890232f2SAndroid Build Coastguard Worker template<typename T>
PrintScalarflatbuffers::JsonPrinter53*890232f2SAndroid Build Coastguard Worker bool PrintScalar(T val, const Type &type, int /*indent*/) {
54*890232f2SAndroid Build Coastguard Worker if (IsBool(type.base_type)) {
55*890232f2SAndroid Build Coastguard Worker text += val != 0 ? "true" : "false";
56*890232f2SAndroid Build Coastguard Worker return true; // done
57*890232f2SAndroid Build Coastguard Worker }
58*890232f2SAndroid Build Coastguard Worker
59*890232f2SAndroid Build Coastguard Worker if (opts.output_enum_identifiers && type.enum_def) {
60*890232f2SAndroid Build Coastguard Worker const auto &enum_def = *type.enum_def;
61*890232f2SAndroid Build Coastguard Worker if (auto ev = enum_def.ReverseLookup(static_cast<int64_t>(val))) {
62*890232f2SAndroid Build Coastguard Worker text += '\"';
63*890232f2SAndroid Build Coastguard Worker text += ev->name;
64*890232f2SAndroid Build Coastguard Worker text += '\"';
65*890232f2SAndroid Build Coastguard Worker return true; // done
66*890232f2SAndroid Build Coastguard Worker } else if (val && enum_def.attributes.Lookup("bit_flags")) {
67*890232f2SAndroid Build Coastguard Worker const auto entry_len = text.length();
68*890232f2SAndroid Build Coastguard Worker const auto u64 = static_cast<uint64_t>(val);
69*890232f2SAndroid Build Coastguard Worker uint64_t mask = 0;
70*890232f2SAndroid Build Coastguard Worker text += '\"';
71*890232f2SAndroid Build Coastguard Worker for (auto it = enum_def.Vals().begin(), e = enum_def.Vals().end();
72*890232f2SAndroid Build Coastguard Worker it != e; ++it) {
73*890232f2SAndroid Build Coastguard Worker auto f = (*it)->GetAsUInt64();
74*890232f2SAndroid Build Coastguard Worker if (f & u64) {
75*890232f2SAndroid Build Coastguard Worker mask |= f;
76*890232f2SAndroid Build Coastguard Worker text += (*it)->name;
77*890232f2SAndroid Build Coastguard Worker text += ' ';
78*890232f2SAndroid Build Coastguard Worker }
79*890232f2SAndroid Build Coastguard Worker }
80*890232f2SAndroid Build Coastguard Worker // Don't slice if (u64 != mask)
81*890232f2SAndroid Build Coastguard Worker if (mask && (u64 == mask)) {
82*890232f2SAndroid Build Coastguard Worker text[text.length() - 1] = '\"';
83*890232f2SAndroid Build Coastguard Worker return true; // done
84*890232f2SAndroid Build Coastguard Worker }
85*890232f2SAndroid Build Coastguard Worker text.resize(entry_len); // restore
86*890232f2SAndroid Build Coastguard Worker }
87*890232f2SAndroid Build Coastguard Worker // print as numeric value
88*890232f2SAndroid Build Coastguard Worker }
89*890232f2SAndroid Build Coastguard Worker
90*890232f2SAndroid Build Coastguard Worker text += NumToString(val);
91*890232f2SAndroid Build Coastguard Worker return true;
92*890232f2SAndroid Build Coastguard Worker }
93*890232f2SAndroid Build Coastguard Worker
AddCommaflatbuffers::JsonPrinter94*890232f2SAndroid Build Coastguard Worker void AddComma() {
95*890232f2SAndroid Build Coastguard Worker if (!opts.protobuf_ascii_alike) text += ',';
96*890232f2SAndroid Build Coastguard Worker }
97*890232f2SAndroid Build Coastguard Worker
98*890232f2SAndroid Build Coastguard Worker // Print a vector or an array of JSON values, comma seperated, wrapped in
99*890232f2SAndroid Build Coastguard Worker // "[]".
100*890232f2SAndroid Build Coastguard Worker template<typename Container>
PrintContainerflatbuffers::JsonPrinter101*890232f2SAndroid Build Coastguard Worker bool PrintContainer(PrintScalarTag, const Container &c, size_t size,
102*890232f2SAndroid Build Coastguard Worker const Type &type, int indent, const uint8_t *) {
103*890232f2SAndroid Build Coastguard Worker const auto elem_indent = indent + Indent();
104*890232f2SAndroid Build Coastguard Worker text += '[';
105*890232f2SAndroid Build Coastguard Worker AddNewLine();
106*890232f2SAndroid Build Coastguard Worker for (uoffset_t i = 0; i < size; i++) {
107*890232f2SAndroid Build Coastguard Worker if (i) {
108*890232f2SAndroid Build Coastguard Worker AddComma();
109*890232f2SAndroid Build Coastguard Worker AddNewLine();
110*890232f2SAndroid Build Coastguard Worker }
111*890232f2SAndroid Build Coastguard Worker AddIndent(elem_indent);
112*890232f2SAndroid Build Coastguard Worker if (!PrintScalar(c[i], type, elem_indent)) { return false; }
113*890232f2SAndroid Build Coastguard Worker }
114*890232f2SAndroid Build Coastguard Worker AddNewLine();
115*890232f2SAndroid Build Coastguard Worker AddIndent(indent);
116*890232f2SAndroid Build Coastguard Worker text += ']';
117*890232f2SAndroid Build Coastguard Worker return true;
118*890232f2SAndroid Build Coastguard Worker }
119*890232f2SAndroid Build Coastguard Worker
120*890232f2SAndroid Build Coastguard Worker // Print a vector or an array of JSON values, comma seperated, wrapped in
121*890232f2SAndroid Build Coastguard Worker // "[]".
122*890232f2SAndroid Build Coastguard Worker template<typename Container>
PrintContainerflatbuffers::JsonPrinter123*890232f2SAndroid Build Coastguard Worker bool PrintContainer(PrintPointerTag, const Container &c, size_t size,
124*890232f2SAndroid Build Coastguard Worker const Type &type, int indent, const uint8_t *prev_val) {
125*890232f2SAndroid Build Coastguard Worker const auto is_struct = IsStruct(type);
126*890232f2SAndroid Build Coastguard Worker const auto elem_indent = indent + Indent();
127*890232f2SAndroid Build Coastguard Worker text += '[';
128*890232f2SAndroid Build Coastguard Worker AddNewLine();
129*890232f2SAndroid Build Coastguard Worker for (uoffset_t i = 0; i < size; i++) {
130*890232f2SAndroid Build Coastguard Worker if (i) {
131*890232f2SAndroid Build Coastguard Worker AddComma();
132*890232f2SAndroid Build Coastguard Worker AddNewLine();
133*890232f2SAndroid Build Coastguard Worker }
134*890232f2SAndroid Build Coastguard Worker AddIndent(elem_indent);
135*890232f2SAndroid Build Coastguard Worker auto ptr = is_struct ? reinterpret_cast<const void *>(
136*890232f2SAndroid Build Coastguard Worker c.Data() + type.struct_def->bytesize * i)
137*890232f2SAndroid Build Coastguard Worker : c[i];
138*890232f2SAndroid Build Coastguard Worker if (!PrintOffset(ptr, type, elem_indent, prev_val,
139*890232f2SAndroid Build Coastguard Worker static_cast<soffset_t>(i))) {
140*890232f2SAndroid Build Coastguard Worker return false;
141*890232f2SAndroid Build Coastguard Worker }
142*890232f2SAndroid Build Coastguard Worker }
143*890232f2SAndroid Build Coastguard Worker AddNewLine();
144*890232f2SAndroid Build Coastguard Worker AddIndent(indent);
145*890232f2SAndroid Build Coastguard Worker text += ']';
146*890232f2SAndroid Build Coastguard Worker return true;
147*890232f2SAndroid Build Coastguard Worker }
148*890232f2SAndroid Build Coastguard Worker
149*890232f2SAndroid Build Coastguard Worker template<typename T>
PrintVectorflatbuffers::JsonPrinter150*890232f2SAndroid Build Coastguard Worker bool PrintVector(const void *val, const Type &type, int indent,
151*890232f2SAndroid Build Coastguard Worker const uint8_t *prev_val) {
152*890232f2SAndroid Build Coastguard Worker typedef Vector<T> Container;
153*890232f2SAndroid Build Coastguard Worker typedef typename PrintTag<typename Container::return_type>::type tag;
154*890232f2SAndroid Build Coastguard Worker auto &vec = *reinterpret_cast<const Container *>(val);
155*890232f2SAndroid Build Coastguard Worker return PrintContainer<Container>(tag(), vec, vec.size(), type, indent,
156*890232f2SAndroid Build Coastguard Worker prev_val);
157*890232f2SAndroid Build Coastguard Worker }
158*890232f2SAndroid Build Coastguard Worker
159*890232f2SAndroid Build Coastguard Worker // Print an array a sequence of JSON values, comma separated, wrapped in "[]".
160*890232f2SAndroid Build Coastguard Worker template<typename T>
PrintArrayflatbuffers::JsonPrinter161*890232f2SAndroid Build Coastguard Worker bool PrintArray(const void *val, size_t size, const Type &type, int indent) {
162*890232f2SAndroid Build Coastguard Worker typedef Array<T, 0xFFFF> Container;
163*890232f2SAndroid Build Coastguard Worker typedef typename PrintTag<typename Container::return_type>::type tag;
164*890232f2SAndroid Build Coastguard Worker auto &arr = *reinterpret_cast<const Container *>(val);
165*890232f2SAndroid Build Coastguard Worker return PrintContainer<Container>(tag(), arr, size, type, indent, nullptr);
166*890232f2SAndroid Build Coastguard Worker }
167*890232f2SAndroid Build Coastguard Worker
PrintOffsetflatbuffers::JsonPrinter168*890232f2SAndroid Build Coastguard Worker bool PrintOffset(const void *val, const Type &type, int indent,
169*890232f2SAndroid Build Coastguard Worker const uint8_t *prev_val, soffset_t vector_index) {
170*890232f2SAndroid Build Coastguard Worker switch (type.base_type) {
171*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_UNION: {
172*890232f2SAndroid Build Coastguard Worker // If this assert hits, you have an corrupt buffer, a union type field
173*890232f2SAndroid Build Coastguard Worker // was not present or was out of range.
174*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(prev_val);
175*890232f2SAndroid Build Coastguard Worker auto union_type_byte = *prev_val; // Always a uint8_t.
176*890232f2SAndroid Build Coastguard Worker if (vector_index >= 0) {
177*890232f2SAndroid Build Coastguard Worker auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(
178*890232f2SAndroid Build Coastguard Worker prev_val + ReadScalar<uoffset_t>(prev_val));
179*890232f2SAndroid Build Coastguard Worker union_type_byte = type_vec->Get(static_cast<uoffset_t>(vector_index));
180*890232f2SAndroid Build Coastguard Worker }
181*890232f2SAndroid Build Coastguard Worker auto enum_val = type.enum_def->ReverseLookup(union_type_byte, true);
182*890232f2SAndroid Build Coastguard Worker if (enum_val) {
183*890232f2SAndroid Build Coastguard Worker return PrintOffset(val, enum_val->union_type, indent, nullptr, -1);
184*890232f2SAndroid Build Coastguard Worker } else {
185*890232f2SAndroid Build Coastguard Worker return false;
186*890232f2SAndroid Build Coastguard Worker }
187*890232f2SAndroid Build Coastguard Worker }
188*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRUCT:
189*890232f2SAndroid Build Coastguard Worker return GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val),
190*890232f2SAndroid Build Coastguard Worker indent);
191*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_STRING: {
192*890232f2SAndroid Build Coastguard Worker auto s = reinterpret_cast<const String *>(val);
193*890232f2SAndroid Build Coastguard Worker return EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8,
194*890232f2SAndroid Build Coastguard Worker opts.natural_utf8);
195*890232f2SAndroid Build Coastguard Worker }
196*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_VECTOR: {
197*890232f2SAndroid Build Coastguard Worker const auto vec_type = type.VectorType();
198*890232f2SAndroid Build Coastguard Worker // Call PrintVector above specifically for each element type:
199*890232f2SAndroid Build Coastguard Worker // clang-format off
200*890232f2SAndroid Build Coastguard Worker switch (vec_type.base_type) {
201*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
202*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ ## ENUM: \
203*890232f2SAndroid Build Coastguard Worker if (!PrintVector<CTYPE>( \
204*890232f2SAndroid Build Coastguard Worker val, vec_type, indent, prev_val)) { \
205*890232f2SAndroid Build Coastguard Worker return false; \
206*890232f2SAndroid Build Coastguard Worker } \
207*890232f2SAndroid Build Coastguard Worker break;
208*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
209*890232f2SAndroid Build Coastguard Worker #undef FLATBUFFERS_TD
210*890232f2SAndroid Build Coastguard Worker }
211*890232f2SAndroid Build Coastguard Worker // clang-format on
212*890232f2SAndroid Build Coastguard Worker return true;
213*890232f2SAndroid Build Coastguard Worker }
214*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ARRAY: {
215*890232f2SAndroid Build Coastguard Worker const auto vec_type = type.VectorType();
216*890232f2SAndroid Build Coastguard Worker // Call PrintArray above specifically for each element type:
217*890232f2SAndroid Build Coastguard Worker // clang-format off
218*890232f2SAndroid Build Coastguard Worker switch (vec_type.base_type) {
219*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
220*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ ## ENUM: \
221*890232f2SAndroid Build Coastguard Worker if (!PrintArray<CTYPE>( \
222*890232f2SAndroid Build Coastguard Worker val, type.fixed_length, vec_type, indent)) { \
223*890232f2SAndroid Build Coastguard Worker return false; \
224*890232f2SAndroid Build Coastguard Worker } \
225*890232f2SAndroid Build Coastguard Worker break;
226*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
227*890232f2SAndroid Build Coastguard Worker // Arrays of scalars or structs are only possible.
228*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
229*890232f2SAndroid Build Coastguard Worker #undef FLATBUFFERS_TD
230*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
231*890232f2SAndroid Build Coastguard Worker }
232*890232f2SAndroid Build Coastguard Worker // clang-format on
233*890232f2SAndroid Build Coastguard Worker return true;
234*890232f2SAndroid Build Coastguard Worker }
235*890232f2SAndroid Build Coastguard Worker default: FLATBUFFERS_ASSERT(0); return false;
236*890232f2SAndroid Build Coastguard Worker }
237*890232f2SAndroid Build Coastguard Worker }
238*890232f2SAndroid Build Coastguard Worker
GetFieldDefaultflatbuffers::JsonPrinter239*890232f2SAndroid Build Coastguard Worker template<typename T> static T GetFieldDefault(const FieldDef &fd) {
240*890232f2SAndroid Build Coastguard Worker T val;
241*890232f2SAndroid Build Coastguard Worker auto check = StringToNumber(fd.value.constant.c_str(), &val);
242*890232f2SAndroid Build Coastguard Worker (void)check;
243*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(check);
244*890232f2SAndroid Build Coastguard Worker return val;
245*890232f2SAndroid Build Coastguard Worker }
246*890232f2SAndroid Build Coastguard Worker
247*890232f2SAndroid Build Coastguard Worker // Generate text for a scalar field.
248*890232f2SAndroid Build Coastguard Worker template<typename T>
GenFieldflatbuffers::JsonPrinter249*890232f2SAndroid Build Coastguard Worker bool GenField(const FieldDef &fd, const Table *table, bool fixed,
250*890232f2SAndroid Build Coastguard Worker int indent) {
251*890232f2SAndroid Build Coastguard Worker if (fixed) {
252*890232f2SAndroid Build Coastguard Worker return PrintScalar(
253*890232f2SAndroid Build Coastguard Worker reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset),
254*890232f2SAndroid Build Coastguard Worker fd.value.type, indent);
255*890232f2SAndroid Build Coastguard Worker } else if (fd.IsOptional()) {
256*890232f2SAndroid Build Coastguard Worker auto opt = table->GetOptional<T, T>(fd.value.offset);
257*890232f2SAndroid Build Coastguard Worker if (opt) {
258*890232f2SAndroid Build Coastguard Worker return PrintScalar(*opt, fd.value.type, indent);
259*890232f2SAndroid Build Coastguard Worker } else {
260*890232f2SAndroid Build Coastguard Worker text += "null";
261*890232f2SAndroid Build Coastguard Worker return true;
262*890232f2SAndroid Build Coastguard Worker }
263*890232f2SAndroid Build Coastguard Worker } else {
264*890232f2SAndroid Build Coastguard Worker return PrintScalar(
265*890232f2SAndroid Build Coastguard Worker table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
266*890232f2SAndroid Build Coastguard Worker fd.value.type, indent);
267*890232f2SAndroid Build Coastguard Worker }
268*890232f2SAndroid Build Coastguard Worker }
269*890232f2SAndroid Build Coastguard Worker
270*890232f2SAndroid Build Coastguard Worker // Generate text for non-scalar field.
GenFieldOffsetflatbuffers::JsonPrinter271*890232f2SAndroid Build Coastguard Worker bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
272*890232f2SAndroid Build Coastguard Worker int indent, const uint8_t *prev_val) {
273*890232f2SAndroid Build Coastguard Worker const void *val = nullptr;
274*890232f2SAndroid Build Coastguard Worker if (fixed) {
275*890232f2SAndroid Build Coastguard Worker // The only non-scalar fields in structs are structs or arrays.
276*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type));
277*890232f2SAndroid Build Coastguard Worker val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>(
278*890232f2SAndroid Build Coastguard Worker fd.value.offset);
279*890232f2SAndroid Build Coastguard Worker } else if (fd.flexbuffer && opts.json_nested_flexbuffers) {
280*890232f2SAndroid Build Coastguard Worker // We could verify this FlexBuffer before access, but since this sits
281*890232f2SAndroid Build Coastguard Worker // inside a FlatBuffer that we don't know wether it has been verified or
282*890232f2SAndroid Build Coastguard Worker // not, there is little point making this part safer than the parent..
283*890232f2SAndroid Build Coastguard Worker // The caller should really be verifying the whole.
284*890232f2SAndroid Build Coastguard Worker // If the whole buffer is corrupt, we likely crash before we even get
285*890232f2SAndroid Build Coastguard Worker // here.
286*890232f2SAndroid Build Coastguard Worker auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
287*890232f2SAndroid Build Coastguard Worker auto root = flexbuffers::GetRoot(vec->data(), vec->size());
288*890232f2SAndroid Build Coastguard Worker root.ToString(true, opts.strict_json, text);
289*890232f2SAndroid Build Coastguard Worker return true;
290*890232f2SAndroid Build Coastguard Worker } else if (fd.nested_flatbuffer && opts.json_nested_flatbuffers) {
291*890232f2SAndroid Build Coastguard Worker auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
292*890232f2SAndroid Build Coastguard Worker auto root = GetRoot<Table>(vec->data());
293*890232f2SAndroid Build Coastguard Worker return GenStruct(*fd.nested_flatbuffer, root, indent);
294*890232f2SAndroid Build Coastguard Worker } else {
295*890232f2SAndroid Build Coastguard Worker val = IsStruct(fd.value.type)
296*890232f2SAndroid Build Coastguard Worker ? table->GetStruct<const void *>(fd.value.offset)
297*890232f2SAndroid Build Coastguard Worker : table->GetPointer<const void *>(fd.value.offset);
298*890232f2SAndroid Build Coastguard Worker }
299*890232f2SAndroid Build Coastguard Worker return PrintOffset(val, fd.value.type, indent, prev_val, -1);
300*890232f2SAndroid Build Coastguard Worker }
301*890232f2SAndroid Build Coastguard Worker
302*890232f2SAndroid Build Coastguard Worker // Generate text for a struct or table, values separated by commas, indented,
303*890232f2SAndroid Build Coastguard Worker // and bracketed by "{}"
GenStructflatbuffers::JsonPrinter304*890232f2SAndroid Build Coastguard Worker bool GenStruct(const StructDef &struct_def, const Table *table, int indent) {
305*890232f2SAndroid Build Coastguard Worker text += '{';
306*890232f2SAndroid Build Coastguard Worker int fieldout = 0;
307*890232f2SAndroid Build Coastguard Worker const uint8_t *prev_val = nullptr;
308*890232f2SAndroid Build Coastguard Worker const auto elem_indent = indent + Indent();
309*890232f2SAndroid Build Coastguard Worker for (auto it = struct_def.fields.vec.begin();
310*890232f2SAndroid Build Coastguard Worker it != struct_def.fields.vec.end(); ++it) {
311*890232f2SAndroid Build Coastguard Worker FieldDef &fd = **it;
312*890232f2SAndroid Build Coastguard Worker auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
313*890232f2SAndroid Build Coastguard Worker auto output_anyway = (opts.output_default_scalars_in_json || fd.key) &&
314*890232f2SAndroid Build Coastguard Worker IsScalar(fd.value.type.base_type) && !fd.deprecated;
315*890232f2SAndroid Build Coastguard Worker if (is_present || output_anyway) {
316*890232f2SAndroid Build Coastguard Worker if (fieldout++) { AddComma(); }
317*890232f2SAndroid Build Coastguard Worker AddNewLine();
318*890232f2SAndroid Build Coastguard Worker AddIndent(elem_indent);
319*890232f2SAndroid Build Coastguard Worker OutputIdentifier(fd.name);
320*890232f2SAndroid Build Coastguard Worker if (!opts.protobuf_ascii_alike ||
321*890232f2SAndroid Build Coastguard Worker (fd.value.type.base_type != BASE_TYPE_STRUCT &&
322*890232f2SAndroid Build Coastguard Worker fd.value.type.base_type != BASE_TYPE_VECTOR))
323*890232f2SAndroid Build Coastguard Worker text += ':';
324*890232f2SAndroid Build Coastguard Worker text += ' ';
325*890232f2SAndroid Build Coastguard Worker // clang-format off
326*890232f2SAndroid Build Coastguard Worker switch (fd.value.type.base_type) {
327*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
328*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ ## ENUM: \
329*890232f2SAndroid Build Coastguard Worker if (!GenField<CTYPE>(fd, table, struct_def.fixed, elem_indent)) { \
330*890232f2SAndroid Build Coastguard Worker return false; \
331*890232f2SAndroid Build Coastguard Worker } \
332*890232f2SAndroid Build Coastguard Worker break;
333*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
334*890232f2SAndroid Build Coastguard Worker #undef FLATBUFFERS_TD
335*890232f2SAndroid Build Coastguard Worker // Generate drop-thru case statements for all pointer types:
336*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_TD(ENUM, ...) \
337*890232f2SAndroid Build Coastguard Worker case BASE_TYPE_ ## ENUM:
338*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
339*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
340*890232f2SAndroid Build Coastguard Worker #undef FLATBUFFERS_TD
341*890232f2SAndroid Build Coastguard Worker if (!GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val)) {
342*890232f2SAndroid Build Coastguard Worker return false;
343*890232f2SAndroid Build Coastguard Worker }
344*890232f2SAndroid Build Coastguard Worker break;
345*890232f2SAndroid Build Coastguard Worker }
346*890232f2SAndroid Build Coastguard Worker // clang-format on
347*890232f2SAndroid Build Coastguard Worker // Track prev val for use with union types.
348*890232f2SAndroid Build Coastguard Worker if (struct_def.fixed) {
349*890232f2SAndroid Build Coastguard Worker prev_val = reinterpret_cast<const uint8_t *>(table) + fd.value.offset;
350*890232f2SAndroid Build Coastguard Worker } else {
351*890232f2SAndroid Build Coastguard Worker prev_val = table->GetAddressOf(fd.value.offset);
352*890232f2SAndroid Build Coastguard Worker }
353*890232f2SAndroid Build Coastguard Worker }
354*890232f2SAndroid Build Coastguard Worker }
355*890232f2SAndroid Build Coastguard Worker AddNewLine();
356*890232f2SAndroid Build Coastguard Worker AddIndent(indent);
357*890232f2SAndroid Build Coastguard Worker text += '}';
358*890232f2SAndroid Build Coastguard Worker return true;
359*890232f2SAndroid Build Coastguard Worker }
360*890232f2SAndroid Build Coastguard Worker
JsonPrinterflatbuffers::JsonPrinter361*890232f2SAndroid Build Coastguard Worker JsonPrinter(const Parser &parser, std::string &dest)
362*890232f2SAndroid Build Coastguard Worker : opts(parser.opts), text(dest) {
363*890232f2SAndroid Build Coastguard Worker text.reserve(1024); // Reduce amount of inevitable reallocs.
364*890232f2SAndroid Build Coastguard Worker }
365*890232f2SAndroid Build Coastguard Worker
366*890232f2SAndroid Build Coastguard Worker const IDLOptions &opts;
367*890232f2SAndroid Build Coastguard Worker std::string &text;
368*890232f2SAndroid Build Coastguard Worker };
369*890232f2SAndroid Build Coastguard Worker
GenerateTextImpl(const Parser & parser,const Table * table,const StructDef & struct_def,std::string * _text)370*890232f2SAndroid Build Coastguard Worker static bool GenerateTextImpl(const Parser &parser, const Table *table,
371*890232f2SAndroid Build Coastguard Worker const StructDef &struct_def, std::string *_text) {
372*890232f2SAndroid Build Coastguard Worker JsonPrinter printer(parser, *_text);
373*890232f2SAndroid Build Coastguard Worker if (!printer.GenStruct(struct_def, table, 0)) { return false; }
374*890232f2SAndroid Build Coastguard Worker printer.AddNewLine();
375*890232f2SAndroid Build Coastguard Worker return true;
376*890232f2SAndroid Build Coastguard Worker }
377*890232f2SAndroid Build Coastguard Worker
378*890232f2SAndroid Build Coastguard Worker // Generate a text representation of a flatbuffer in JSON format.
GenerateTextFromTable(const Parser & parser,const void * table,const std::string & table_name,std::string * _text)379*890232f2SAndroid Build Coastguard Worker bool GenerateTextFromTable(const Parser &parser, const void *table,
380*890232f2SAndroid Build Coastguard Worker const std::string &table_name, std::string *_text) {
381*890232f2SAndroid Build Coastguard Worker auto struct_def = parser.LookupStruct(table_name);
382*890232f2SAndroid Build Coastguard Worker if (struct_def == nullptr) { return false; }
383*890232f2SAndroid Build Coastguard Worker auto root = static_cast<const Table *>(table);
384*890232f2SAndroid Build Coastguard Worker return GenerateTextImpl(parser, root, *struct_def, _text);
385*890232f2SAndroid Build Coastguard Worker }
386*890232f2SAndroid Build Coastguard Worker
387*890232f2SAndroid Build Coastguard Worker // Generate a text representation of a flatbuffer in JSON format.
GenerateText(const Parser & parser,const void * flatbuffer,std::string * _text)388*890232f2SAndroid Build Coastguard Worker bool GenerateText(const Parser &parser, const void *flatbuffer,
389*890232f2SAndroid Build Coastguard Worker std::string *_text) {
390*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType()
391*890232f2SAndroid Build Coastguard Worker auto root = parser.opts.size_prefixed ? GetSizePrefixedRoot<Table>(flatbuffer)
392*890232f2SAndroid Build Coastguard Worker : GetRoot<Table>(flatbuffer);
393*890232f2SAndroid Build Coastguard Worker return GenerateTextImpl(parser, root, *parser.root_struct_def_, _text);
394*890232f2SAndroid Build Coastguard Worker }
395*890232f2SAndroid Build Coastguard Worker
TextFileName(const std::string & path,const std::string & file_name)396*890232f2SAndroid Build Coastguard Worker static std::string TextFileName(const std::string &path,
397*890232f2SAndroid Build Coastguard Worker const std::string &file_name) {
398*890232f2SAndroid Build Coastguard Worker return path + file_name + ".json";
399*890232f2SAndroid Build Coastguard Worker }
400*890232f2SAndroid Build Coastguard Worker
GenerateTextFile(const Parser & parser,const std::string & path,const std::string & file_name)401*890232f2SAndroid Build Coastguard Worker bool GenerateTextFile(const Parser &parser, const std::string &path,
402*890232f2SAndroid Build Coastguard Worker const std::string &file_name) {
403*890232f2SAndroid Build Coastguard Worker if (parser.opts.use_flexbuffers) {
404*890232f2SAndroid Build Coastguard Worker std::string json;
405*890232f2SAndroid Build Coastguard Worker parser.flex_root_.ToString(true, parser.opts.strict_json, json);
406*890232f2SAndroid Build Coastguard Worker return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
407*890232f2SAndroid Build Coastguard Worker json.c_str(), json.size(), true);
408*890232f2SAndroid Build Coastguard Worker }
409*890232f2SAndroid Build Coastguard Worker if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
410*890232f2SAndroid Build Coastguard Worker std::string text;
411*890232f2SAndroid Build Coastguard Worker if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
412*890232f2SAndroid Build Coastguard Worker return false;
413*890232f2SAndroid Build Coastguard Worker }
414*890232f2SAndroid Build Coastguard Worker return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text,
415*890232f2SAndroid Build Coastguard Worker false);
416*890232f2SAndroid Build Coastguard Worker }
417*890232f2SAndroid Build Coastguard Worker
TextMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)418*890232f2SAndroid Build Coastguard Worker std::string TextMakeRule(const Parser &parser, const std::string &path,
419*890232f2SAndroid Build Coastguard Worker const std::string &file_name) {
420*890232f2SAndroid Build Coastguard Worker if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
421*890232f2SAndroid Build Coastguard Worker std::string filebase =
422*890232f2SAndroid Build Coastguard Worker flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
423*890232f2SAndroid Build Coastguard Worker std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
424*890232f2SAndroid Build Coastguard Worker auto included_files =
425*890232f2SAndroid Build Coastguard Worker parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
426*890232f2SAndroid Build Coastguard Worker for (auto it = included_files.begin(); it != included_files.end(); ++it) {
427*890232f2SAndroid Build Coastguard Worker make_rule += " " + *it;
428*890232f2SAndroid Build Coastguard Worker }
429*890232f2SAndroid Build Coastguard Worker return make_rule;
430*890232f2SAndroid Build Coastguard Worker }
431*890232f2SAndroid Build Coastguard Worker
432*890232f2SAndroid Build Coastguard Worker } // namespace flatbuffers
433