xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_text.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
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