xref: /aosp_15_r20/external/flatbuffers/src/reflection.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2015 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 #include "flatbuffers/reflection.h"
18*890232f2SAndroid Build Coastguard Worker 
19*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
20*890232f2SAndroid Build Coastguard Worker 
21*890232f2SAndroid Build Coastguard Worker // Helper functionality for reflection.
22*890232f2SAndroid Build Coastguard Worker 
23*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
24*890232f2SAndroid Build Coastguard Worker 
25*890232f2SAndroid Build Coastguard Worker namespace {
26*890232f2SAndroid Build Coastguard Worker 
CopyInline(FlatBufferBuilder & fbb,const reflection::Field & fielddef,const Table & table,size_t align,size_t size)27*890232f2SAndroid Build Coastguard Worker static void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
28*890232f2SAndroid Build Coastguard Worker                 const Table &table, size_t align, size_t size) {
29*890232f2SAndroid Build Coastguard Worker   fbb.Align(align);
30*890232f2SAndroid Build Coastguard Worker   fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
31*890232f2SAndroid Build Coastguard Worker   fbb.TrackField(fielddef.offset(), fbb.GetSize());
32*890232f2SAndroid Build Coastguard Worker }
33*890232f2SAndroid Build Coastguard Worker 
VerifyStruct(flatbuffers::Verifier & v,const flatbuffers::Table & parent_table,voffset_t field_offset,const reflection::Object & obj,bool required)34*890232f2SAndroid Build Coastguard Worker static bool VerifyStruct(flatbuffers::Verifier &v,
35*890232f2SAndroid Build Coastguard Worker                   const flatbuffers::Table &parent_table,
36*890232f2SAndroid Build Coastguard Worker                   voffset_t field_offset, const reflection::Object &obj,
37*890232f2SAndroid Build Coastguard Worker                   bool required) {
38*890232f2SAndroid Build Coastguard Worker   auto offset = parent_table.GetOptionalFieldOffset(field_offset);
39*890232f2SAndroid Build Coastguard Worker   if (required && !offset) { return false; }
40*890232f2SAndroid Build Coastguard Worker 
41*890232f2SAndroid Build Coastguard Worker   return !offset ||
42*890232f2SAndroid Build Coastguard Worker          v.VerifyFieldStruct(reinterpret_cast<const uint8_t *>(&parent_table),
43*890232f2SAndroid Build Coastguard Worker                              offset, obj.bytesize(), obj.minalign());
44*890232f2SAndroid Build Coastguard Worker }
45*890232f2SAndroid Build Coastguard Worker 
VerifyVectorOfStructs(flatbuffers::Verifier & v,const flatbuffers::Table & parent_table,voffset_t field_offset,const reflection::Object & obj,bool required)46*890232f2SAndroid Build Coastguard Worker static bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
47*890232f2SAndroid Build Coastguard Worker                            const flatbuffers::Table &parent_table,
48*890232f2SAndroid Build Coastguard Worker                            voffset_t field_offset,
49*890232f2SAndroid Build Coastguard Worker                            const reflection::Object &obj, bool required) {
50*890232f2SAndroid Build Coastguard Worker   auto p = parent_table.GetPointer<const uint8_t *>(field_offset);
51*890232f2SAndroid Build Coastguard Worker   if (required && !p) { return false; }
52*890232f2SAndroid Build Coastguard Worker 
53*890232f2SAndroid Build Coastguard Worker   return !p || v.VerifyVectorOrString(p, obj.bytesize());
54*890232f2SAndroid Build Coastguard Worker }
55*890232f2SAndroid Build Coastguard Worker 
56*890232f2SAndroid Build Coastguard Worker // forward declare to resolve cyclic deps between VerifyObject and VerifyVector
57*890232f2SAndroid Build Coastguard Worker static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
58*890232f2SAndroid Build Coastguard Worker                   const reflection::Object &obj,
59*890232f2SAndroid Build Coastguard Worker                   const flatbuffers::Table *table, bool required);
60*890232f2SAndroid Build Coastguard Worker 
VerifyUnion(flatbuffers::Verifier & v,const reflection::Schema & schema,uint8_t utype,const uint8_t * elem,const reflection::Field & union_field)61*890232f2SAndroid Build Coastguard Worker static bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema,
62*890232f2SAndroid Build Coastguard Worker                  uint8_t utype, const uint8_t *elem,
63*890232f2SAndroid Build Coastguard Worker                  const reflection::Field &union_field) {
64*890232f2SAndroid Build Coastguard Worker   if (!utype) return true;  // Not present.
65*890232f2SAndroid Build Coastguard Worker   auto fb_enum = schema.enums()->Get(union_field.type()->index());
66*890232f2SAndroid Build Coastguard Worker   if (utype >= fb_enum->values()->size()) return false;
67*890232f2SAndroid Build Coastguard Worker   auto elem_type = fb_enum->values()->Get(utype)->union_type();
68*890232f2SAndroid Build Coastguard Worker   switch (elem_type->base_type()) {
69*890232f2SAndroid Build Coastguard Worker     case reflection::Obj: {
70*890232f2SAndroid Build Coastguard Worker       auto elem_obj = schema.objects()->Get(elem_type->index());
71*890232f2SAndroid Build Coastguard Worker       if (elem_obj->is_struct()) {
72*890232f2SAndroid Build Coastguard Worker         return v.VerifyFromPointer(elem, elem_obj->bytesize());
73*890232f2SAndroid Build Coastguard Worker       } else {
74*890232f2SAndroid Build Coastguard Worker         return VerifyObject(v, schema, *elem_obj,
75*890232f2SAndroid Build Coastguard Worker                             reinterpret_cast<const flatbuffers::Table *>(elem),
76*890232f2SAndroid Build Coastguard Worker                             true);
77*890232f2SAndroid Build Coastguard Worker       }
78*890232f2SAndroid Build Coastguard Worker     }
79*890232f2SAndroid Build Coastguard Worker     case reflection::String:
80*890232f2SAndroid Build Coastguard Worker       return v.VerifyString(
81*890232f2SAndroid Build Coastguard Worker           reinterpret_cast<const flatbuffers::String *>(elem));
82*890232f2SAndroid Build Coastguard Worker     default: return false;
83*890232f2SAndroid Build Coastguard Worker   }
84*890232f2SAndroid Build Coastguard Worker }
85*890232f2SAndroid Build Coastguard Worker 
VerifyVector(flatbuffers::Verifier & v,const reflection::Schema & schema,const flatbuffers::Table & table,const reflection::Field & vec_field)86*890232f2SAndroid Build Coastguard Worker static bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
87*890232f2SAndroid Build Coastguard Worker                   const flatbuffers::Table &table,
88*890232f2SAndroid Build Coastguard Worker                   const reflection::Field &vec_field) {
89*890232f2SAndroid Build Coastguard Worker   FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector);
90*890232f2SAndroid Build Coastguard Worker   if (!table.VerifyField<uoffset_t>(v, vec_field.offset(), sizeof(uoffset_t)))
91*890232f2SAndroid Build Coastguard Worker     return false;
92*890232f2SAndroid Build Coastguard Worker 
93*890232f2SAndroid Build Coastguard Worker   switch (vec_field.type()->element()) {
94*890232f2SAndroid Build Coastguard Worker     case reflection::UType:
95*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
96*890232f2SAndroid Build Coastguard Worker     case reflection::Bool:
97*890232f2SAndroid Build Coastguard Worker     case reflection::Byte:
98*890232f2SAndroid Build Coastguard Worker     case reflection::UByte:
99*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field));
100*890232f2SAndroid Build Coastguard Worker     case reflection::Short:
101*890232f2SAndroid Build Coastguard Worker     case reflection::UShort:
102*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field));
103*890232f2SAndroid Build Coastguard Worker     case reflection::Int:
104*890232f2SAndroid Build Coastguard Worker     case reflection::UInt:
105*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field));
106*890232f2SAndroid Build Coastguard Worker     case reflection::Long:
107*890232f2SAndroid Build Coastguard Worker     case reflection::ULong:
108*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field));
109*890232f2SAndroid Build Coastguard Worker     case reflection::Float:
110*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field));
111*890232f2SAndroid Build Coastguard Worker     case reflection::Double:
112*890232f2SAndroid Build Coastguard Worker       return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field));
113*890232f2SAndroid Build Coastguard Worker     case reflection::String: {
114*890232f2SAndroid Build Coastguard Worker       auto vec_string =
115*890232f2SAndroid Build Coastguard Worker           flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
116*890232f2SAndroid Build Coastguard Worker               table, vec_field);
117*890232f2SAndroid Build Coastguard Worker       if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) {
118*890232f2SAndroid Build Coastguard Worker         return true;
119*890232f2SAndroid Build Coastguard Worker       } else {
120*890232f2SAndroid Build Coastguard Worker         return false;
121*890232f2SAndroid Build Coastguard Worker       }
122*890232f2SAndroid Build Coastguard Worker     }
123*890232f2SAndroid Build Coastguard Worker     case reflection::Obj: {
124*890232f2SAndroid Build Coastguard Worker       auto obj = schema.objects()->Get(vec_field.type()->index());
125*890232f2SAndroid Build Coastguard Worker       if (obj->is_struct()) {
126*890232f2SAndroid Build Coastguard Worker         return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
127*890232f2SAndroid Build Coastguard Worker                                      vec_field.required());
128*890232f2SAndroid Build Coastguard Worker       } else {
129*890232f2SAndroid Build Coastguard Worker         auto vec =
130*890232f2SAndroid Build Coastguard Worker             flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
131*890232f2SAndroid Build Coastguard Worker                 table, vec_field);
132*890232f2SAndroid Build Coastguard Worker         if (!v.VerifyVector(vec)) return false;
133*890232f2SAndroid Build Coastguard Worker         if (!vec) return true;
134*890232f2SAndroid Build Coastguard Worker         for (uoffset_t j = 0; j < vec->size(); j++) {
135*890232f2SAndroid Build Coastguard Worker           if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
136*890232f2SAndroid Build Coastguard Worker             return false;
137*890232f2SAndroid Build Coastguard Worker           }
138*890232f2SAndroid Build Coastguard Worker         }
139*890232f2SAndroid Build Coastguard Worker         return true;
140*890232f2SAndroid Build Coastguard Worker       }
141*890232f2SAndroid Build Coastguard Worker     }
142*890232f2SAndroid Build Coastguard Worker     case reflection::Union: {
143*890232f2SAndroid Build Coastguard Worker       auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>(
144*890232f2SAndroid Build Coastguard Worker           table, vec_field);
145*890232f2SAndroid Build Coastguard Worker       if (!v.VerifyVector(vec)) return false;
146*890232f2SAndroid Build Coastguard Worker       if (!vec) return true;
147*890232f2SAndroid Build Coastguard Worker       auto type_vec = table.GetPointer<Vector<uint8_t> *>(vec_field.offset() -
148*890232f2SAndroid Build Coastguard Worker                                                           sizeof(voffset_t));
149*890232f2SAndroid Build Coastguard Worker       if (!v.VerifyVector(type_vec)) return false;
150*890232f2SAndroid Build Coastguard Worker       for (uoffset_t j = 0; j < vec->size(); j++) {
151*890232f2SAndroid Build Coastguard Worker         //  get union type from the prev field
152*890232f2SAndroid Build Coastguard Worker         auto utype = type_vec->Get(j);
153*890232f2SAndroid Build Coastguard Worker         auto elem = vec->Get(j);
154*890232f2SAndroid Build Coastguard Worker         if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false;
155*890232f2SAndroid Build Coastguard Worker       }
156*890232f2SAndroid Build Coastguard Worker       return true;
157*890232f2SAndroid Build Coastguard Worker     }
158*890232f2SAndroid Build Coastguard Worker     case reflection::Vector:
159*890232f2SAndroid Build Coastguard Worker     case reflection::None:
160*890232f2SAndroid Build Coastguard Worker     default: FLATBUFFERS_ASSERT(false); return false;
161*890232f2SAndroid Build Coastguard Worker   }
162*890232f2SAndroid Build Coastguard Worker }
163*890232f2SAndroid Build Coastguard Worker 
VerifyObject(flatbuffers::Verifier & v,const reflection::Schema & schema,const reflection::Object & obj,const flatbuffers::Table * table,bool required)164*890232f2SAndroid Build Coastguard Worker static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
165*890232f2SAndroid Build Coastguard Worker                   const reflection::Object &obj,
166*890232f2SAndroid Build Coastguard Worker                   const flatbuffers::Table *table, bool required) {
167*890232f2SAndroid Build Coastguard Worker   if (!table) return !required;
168*890232f2SAndroid Build Coastguard Worker   if (!table->VerifyTableStart(v)) return false;
169*890232f2SAndroid Build Coastguard Worker   for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
170*890232f2SAndroid Build Coastguard Worker     auto field_def = obj.fields()->Get(i);
171*890232f2SAndroid Build Coastguard Worker     switch (field_def->type()->base_type()) {
172*890232f2SAndroid Build Coastguard Worker       case reflection::None: FLATBUFFERS_ASSERT(false); break;
173*890232f2SAndroid Build Coastguard Worker       case reflection::UType:
174*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<uint8_t>(v, field_def->offset(),
175*890232f2SAndroid Build Coastguard Worker                                          sizeof(uint8_t)))
176*890232f2SAndroid Build Coastguard Worker           return false;
177*890232f2SAndroid Build Coastguard Worker         break;
178*890232f2SAndroid Build Coastguard Worker       case reflection::Bool:
179*890232f2SAndroid Build Coastguard Worker       case reflection::Byte:
180*890232f2SAndroid Build Coastguard Worker       case reflection::UByte:
181*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<int8_t>(v, field_def->offset(), sizeof(int8_t)))
182*890232f2SAndroid Build Coastguard Worker           return false;
183*890232f2SAndroid Build Coastguard Worker         break;
184*890232f2SAndroid Build Coastguard Worker       case reflection::Short:
185*890232f2SAndroid Build Coastguard Worker       case reflection::UShort:
186*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<int16_t>(v, field_def->offset(),
187*890232f2SAndroid Build Coastguard Worker                                          sizeof(int16_t)))
188*890232f2SAndroid Build Coastguard Worker           return false;
189*890232f2SAndroid Build Coastguard Worker         break;
190*890232f2SAndroid Build Coastguard Worker       case reflection::Int:
191*890232f2SAndroid Build Coastguard Worker       case reflection::UInt:
192*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<int32_t>(v, field_def->offset(),
193*890232f2SAndroid Build Coastguard Worker                                          sizeof(int32_t)))
194*890232f2SAndroid Build Coastguard Worker           return false;
195*890232f2SAndroid Build Coastguard Worker         break;
196*890232f2SAndroid Build Coastguard Worker       case reflection::Long:
197*890232f2SAndroid Build Coastguard Worker       case reflection::ULong:
198*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<int64_t>(v, field_def->offset(),
199*890232f2SAndroid Build Coastguard Worker                                          sizeof(int64_t)))
200*890232f2SAndroid Build Coastguard Worker           return false;
201*890232f2SAndroid Build Coastguard Worker         break;
202*890232f2SAndroid Build Coastguard Worker       case reflection::Float:
203*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<float>(v, field_def->offset(), sizeof(float)))
204*890232f2SAndroid Build Coastguard Worker           return false;
205*890232f2SAndroid Build Coastguard Worker         break;
206*890232f2SAndroid Build Coastguard Worker       case reflection::Double:
207*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<double>(v, field_def->offset(), sizeof(double)))
208*890232f2SAndroid Build Coastguard Worker           return false;
209*890232f2SAndroid Build Coastguard Worker         break;
210*890232f2SAndroid Build Coastguard Worker       case reflection::String:
211*890232f2SAndroid Build Coastguard Worker         if (!table->VerifyField<uoffset_t>(v, field_def->offset(),
212*890232f2SAndroid Build Coastguard Worker                                            sizeof(uoffset_t)) ||
213*890232f2SAndroid Build Coastguard Worker             !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) {
214*890232f2SAndroid Build Coastguard Worker           return false;
215*890232f2SAndroid Build Coastguard Worker         }
216*890232f2SAndroid Build Coastguard Worker         break;
217*890232f2SAndroid Build Coastguard Worker       case reflection::Vector:
218*890232f2SAndroid Build Coastguard Worker         if (!VerifyVector(v, schema, *table, *field_def)) return false;
219*890232f2SAndroid Build Coastguard Worker         break;
220*890232f2SAndroid Build Coastguard Worker       case reflection::Obj: {
221*890232f2SAndroid Build Coastguard Worker         auto child_obj = schema.objects()->Get(field_def->type()->index());
222*890232f2SAndroid Build Coastguard Worker         if (child_obj->is_struct()) {
223*890232f2SAndroid Build Coastguard Worker           if (!VerifyStruct(v, *table, field_def->offset(), *child_obj,
224*890232f2SAndroid Build Coastguard Worker                             field_def->required())) {
225*890232f2SAndroid Build Coastguard Worker             return false;
226*890232f2SAndroid Build Coastguard Worker           }
227*890232f2SAndroid Build Coastguard Worker         } else {
228*890232f2SAndroid Build Coastguard Worker           if (!VerifyObject(v, schema, *child_obj,
229*890232f2SAndroid Build Coastguard Worker                             flatbuffers::GetFieldT(*table, *field_def),
230*890232f2SAndroid Build Coastguard Worker                             field_def->required())) {
231*890232f2SAndroid Build Coastguard Worker             return false;
232*890232f2SAndroid Build Coastguard Worker           }
233*890232f2SAndroid Build Coastguard Worker         }
234*890232f2SAndroid Build Coastguard Worker         break;
235*890232f2SAndroid Build Coastguard Worker       }
236*890232f2SAndroid Build Coastguard Worker       case reflection::Union: {
237*890232f2SAndroid Build Coastguard Worker         //  get union type from the prev field
238*890232f2SAndroid Build Coastguard Worker         voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
239*890232f2SAndroid Build Coastguard Worker         auto utype = table->GetField<uint8_t>(utype_offset, 0);
240*890232f2SAndroid Build Coastguard Worker         auto uval = reinterpret_cast<const uint8_t *>(
241*890232f2SAndroid Build Coastguard Worker             flatbuffers::GetFieldT(*table, *field_def));
242*890232f2SAndroid Build Coastguard Worker         if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; }
243*890232f2SAndroid Build Coastguard Worker         break;
244*890232f2SAndroid Build Coastguard Worker       }
245*890232f2SAndroid Build Coastguard Worker       default: FLATBUFFERS_ASSERT(false); break;
246*890232f2SAndroid Build Coastguard Worker     }
247*890232f2SAndroid Build Coastguard Worker   }
248*890232f2SAndroid Build Coastguard Worker 
249*890232f2SAndroid Build Coastguard Worker   if (!v.EndTable()) return false;
250*890232f2SAndroid Build Coastguard Worker 
251*890232f2SAndroid Build Coastguard Worker   return true;
252*890232f2SAndroid Build Coastguard Worker }
253*890232f2SAndroid Build Coastguard Worker 
254*890232f2SAndroid Build Coastguard Worker 
255*890232f2SAndroid Build Coastguard Worker } // namespace
256*890232f2SAndroid Build Coastguard Worker 
GetAnyValueI(reflection::BaseType type,const uint8_t * data)257*890232f2SAndroid Build Coastguard Worker int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
258*890232f2SAndroid Build Coastguard Worker   // clang-format off
259*890232f2SAndroid Build Coastguard Worker   #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
260*890232f2SAndroid Build Coastguard Worker   switch (type) {
261*890232f2SAndroid Build Coastguard Worker     case reflection::UType:
262*890232f2SAndroid Build Coastguard Worker     case reflection::Bool:
263*890232f2SAndroid Build Coastguard Worker     case reflection::UByte:  return FLATBUFFERS_GET(uint8_t);
264*890232f2SAndroid Build Coastguard Worker     case reflection::Byte:   return FLATBUFFERS_GET(int8_t);
265*890232f2SAndroid Build Coastguard Worker     case reflection::Short:  return FLATBUFFERS_GET(int16_t);
266*890232f2SAndroid Build Coastguard Worker     case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
267*890232f2SAndroid Build Coastguard Worker     case reflection::Int:    return FLATBUFFERS_GET(int32_t);
268*890232f2SAndroid Build Coastguard Worker     case reflection::UInt:   return FLATBUFFERS_GET(uint32_t);
269*890232f2SAndroid Build Coastguard Worker     case reflection::Long:   return FLATBUFFERS_GET(int64_t);
270*890232f2SAndroid Build Coastguard Worker     case reflection::ULong:  return FLATBUFFERS_GET(uint64_t);
271*890232f2SAndroid Build Coastguard Worker     case reflection::Float:  return FLATBUFFERS_GET(float);
272*890232f2SAndroid Build Coastguard Worker     case reflection::Double: return FLATBUFFERS_GET(double);
273*890232f2SAndroid Build Coastguard Worker     case reflection::String: {
274*890232f2SAndroid Build Coastguard Worker       auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
275*890232f2SAndroid Build Coastguard Worker                                                 data);
276*890232f2SAndroid Build Coastguard Worker       return s ? StringToInt(s->c_str()) : 0;
277*890232f2SAndroid Build Coastguard Worker     }
278*890232f2SAndroid Build Coastguard Worker     default: return 0;  // Tables & vectors do not make sense.
279*890232f2SAndroid Build Coastguard Worker   }
280*890232f2SAndroid Build Coastguard Worker   #undef FLATBUFFERS_GET
281*890232f2SAndroid Build Coastguard Worker   // clang-format on
282*890232f2SAndroid Build Coastguard Worker }
283*890232f2SAndroid Build Coastguard Worker 
GetAnyValueF(reflection::BaseType type,const uint8_t * data)284*890232f2SAndroid Build Coastguard Worker double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
285*890232f2SAndroid Build Coastguard Worker   switch (type) {
286*890232f2SAndroid Build Coastguard Worker     case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
287*890232f2SAndroid Build Coastguard Worker     case reflection::Double: return ReadScalar<double>(data);
288*890232f2SAndroid Build Coastguard Worker     case reflection::String: {
289*890232f2SAndroid Build Coastguard Worker       auto s =
290*890232f2SAndroid Build Coastguard Worker           reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
291*890232f2SAndroid Build Coastguard Worker       if (s) {
292*890232f2SAndroid Build Coastguard Worker         double d;
293*890232f2SAndroid Build Coastguard Worker         StringToNumber(s->c_str(), &d);
294*890232f2SAndroid Build Coastguard Worker         return d;
295*890232f2SAndroid Build Coastguard Worker       } else {
296*890232f2SAndroid Build Coastguard Worker         return 0.0;
297*890232f2SAndroid Build Coastguard Worker       }
298*890232f2SAndroid Build Coastguard Worker     }
299*890232f2SAndroid Build Coastguard Worker     default: return static_cast<double>(GetAnyValueI(type, data));
300*890232f2SAndroid Build Coastguard Worker   }
301*890232f2SAndroid Build Coastguard Worker }
302*890232f2SAndroid Build Coastguard Worker 
GetAnyValueS(reflection::BaseType type,const uint8_t * data,const reflection::Schema * schema,int type_index)303*890232f2SAndroid Build Coastguard Worker std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
304*890232f2SAndroid Build Coastguard Worker                          const reflection::Schema *schema, int type_index) {
305*890232f2SAndroid Build Coastguard Worker   switch (type) {
306*890232f2SAndroid Build Coastguard Worker     case reflection::Float:
307*890232f2SAndroid Build Coastguard Worker     case reflection::Double: return NumToString(GetAnyValueF(type, data));
308*890232f2SAndroid Build Coastguard Worker     case reflection::String: {
309*890232f2SAndroid Build Coastguard Worker       auto s =
310*890232f2SAndroid Build Coastguard Worker           reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
311*890232f2SAndroid Build Coastguard Worker       return s ? s->c_str() : "";
312*890232f2SAndroid Build Coastguard Worker     }
313*890232f2SAndroid Build Coastguard Worker     case reflection::Obj:
314*890232f2SAndroid Build Coastguard Worker       if (schema) {
315*890232f2SAndroid Build Coastguard Worker         // Convert the table to a string. This is mostly for debugging purposes,
316*890232f2SAndroid Build Coastguard Worker         // and does NOT promise to be JSON compliant.
317*890232f2SAndroid Build Coastguard Worker         // Also prefixes the type.
318*890232f2SAndroid Build Coastguard Worker         auto &objectdef = *schema->objects()->Get(type_index);
319*890232f2SAndroid Build Coastguard Worker         auto s = objectdef.name()->str();
320*890232f2SAndroid Build Coastguard Worker         if (objectdef.is_struct()) {
321*890232f2SAndroid Build Coastguard Worker           s += "(struct)";  // TODO: implement this as well.
322*890232f2SAndroid Build Coastguard Worker         } else {
323*890232f2SAndroid Build Coastguard Worker           auto table_field = reinterpret_cast<const Table *>(
324*890232f2SAndroid Build Coastguard Worker               ReadScalar<uoffset_t>(data) + data);
325*890232f2SAndroid Build Coastguard Worker           s += " { ";
326*890232f2SAndroid Build Coastguard Worker           auto fielddefs = objectdef.fields();
327*890232f2SAndroid Build Coastguard Worker           for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
328*890232f2SAndroid Build Coastguard Worker             auto &fielddef = **it;
329*890232f2SAndroid Build Coastguard Worker             if (!table_field->CheckField(fielddef.offset())) continue;
330*890232f2SAndroid Build Coastguard Worker             auto val = GetAnyFieldS(*table_field, fielddef, schema);
331*890232f2SAndroid Build Coastguard Worker             if (fielddef.type()->base_type() == reflection::String) {
332*890232f2SAndroid Build Coastguard Worker               std::string esc;
333*890232f2SAndroid Build Coastguard Worker               flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true,
334*890232f2SAndroid Build Coastguard Worker                                         false);
335*890232f2SAndroid Build Coastguard Worker               val = esc;
336*890232f2SAndroid Build Coastguard Worker             }
337*890232f2SAndroid Build Coastguard Worker             s += fielddef.name()->str();
338*890232f2SAndroid Build Coastguard Worker             s += ": ";
339*890232f2SAndroid Build Coastguard Worker             s += val;
340*890232f2SAndroid Build Coastguard Worker             s += ", ";
341*890232f2SAndroid Build Coastguard Worker           }
342*890232f2SAndroid Build Coastguard Worker           s += "}";
343*890232f2SAndroid Build Coastguard Worker         }
344*890232f2SAndroid Build Coastguard Worker         return s;
345*890232f2SAndroid Build Coastguard Worker       } else {
346*890232f2SAndroid Build Coastguard Worker         return "(table)";
347*890232f2SAndroid Build Coastguard Worker       }
348*890232f2SAndroid Build Coastguard Worker     case reflection::Vector:
349*890232f2SAndroid Build Coastguard Worker       return "[(elements)]";                   // TODO: implement this as well.
350*890232f2SAndroid Build Coastguard Worker     case reflection::Union: return "(union)";  // TODO: implement this as well.
351*890232f2SAndroid Build Coastguard Worker     default: return NumToString(GetAnyValueI(type, data));
352*890232f2SAndroid Build Coastguard Worker   }
353*890232f2SAndroid Build Coastguard Worker }
354*890232f2SAndroid Build Coastguard Worker 
ForAllFields(const reflection::Object * object,bool reverse,std::function<void (const reflection::Field *)> func)355*890232f2SAndroid Build Coastguard Worker void ForAllFields(const reflection::Object *object, bool reverse,
356*890232f2SAndroid Build Coastguard Worker                   std::function<void(const reflection::Field *)> func) {
357*890232f2SAndroid Build Coastguard Worker   std::vector<uint32_t> field_to_id_map;
358*890232f2SAndroid Build Coastguard Worker   field_to_id_map.resize(object->fields()->size());
359*890232f2SAndroid Build Coastguard Worker 
360*890232f2SAndroid Build Coastguard Worker   // Create the mapping of field ID to the index into the vector.
361*890232f2SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < object->fields()->size(); ++i) {
362*890232f2SAndroid Build Coastguard Worker     auto field = object->fields()->Get(i);
363*890232f2SAndroid Build Coastguard Worker     field_to_id_map[field->id()] = i;
364*890232f2SAndroid Build Coastguard Worker   }
365*890232f2SAndroid Build Coastguard Worker 
366*890232f2SAndroid Build Coastguard Worker   for (size_t i = 0; i < field_to_id_map.size(); ++i) {
367*890232f2SAndroid Build Coastguard Worker     func(object->fields()->Get(
368*890232f2SAndroid Build Coastguard Worker         field_to_id_map[reverse ? field_to_id_map.size() - i + 1 : i]));
369*890232f2SAndroid Build Coastguard Worker   }
370*890232f2SAndroid Build Coastguard Worker }
371*890232f2SAndroid Build Coastguard Worker 
SetAnyValueI(reflection::BaseType type,uint8_t * data,int64_t val)372*890232f2SAndroid Build Coastguard Worker void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
373*890232f2SAndroid Build Coastguard Worker   // clang-format off
374*890232f2SAndroid Build Coastguard Worker   #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
375*890232f2SAndroid Build Coastguard Worker   switch (type) {
376*890232f2SAndroid Build Coastguard Worker     case reflection::UType:
377*890232f2SAndroid Build Coastguard Worker     case reflection::Bool:
378*890232f2SAndroid Build Coastguard Worker     case reflection::UByte:  FLATBUFFERS_SET(uint8_t ); break;
379*890232f2SAndroid Build Coastguard Worker     case reflection::Byte:   FLATBUFFERS_SET(int8_t  ); break;
380*890232f2SAndroid Build Coastguard Worker     case reflection::Short:  FLATBUFFERS_SET(int16_t ); break;
381*890232f2SAndroid Build Coastguard Worker     case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
382*890232f2SAndroid Build Coastguard Worker     case reflection::Int:    FLATBUFFERS_SET(int32_t ); break;
383*890232f2SAndroid Build Coastguard Worker     case reflection::UInt:   FLATBUFFERS_SET(uint32_t); break;
384*890232f2SAndroid Build Coastguard Worker     case reflection::Long:   FLATBUFFERS_SET(int64_t ); break;
385*890232f2SAndroid Build Coastguard Worker     case reflection::ULong:  FLATBUFFERS_SET(uint64_t); break;
386*890232f2SAndroid Build Coastguard Worker     case reflection::Float:  FLATBUFFERS_SET(float   ); break;
387*890232f2SAndroid Build Coastguard Worker     case reflection::Double: FLATBUFFERS_SET(double  ); break;
388*890232f2SAndroid Build Coastguard Worker     // TODO: support strings
389*890232f2SAndroid Build Coastguard Worker     default: break;
390*890232f2SAndroid Build Coastguard Worker   }
391*890232f2SAndroid Build Coastguard Worker   #undef FLATBUFFERS_SET
392*890232f2SAndroid Build Coastguard Worker   // clang-format on
393*890232f2SAndroid Build Coastguard Worker }
394*890232f2SAndroid Build Coastguard Worker 
SetAnyValueF(reflection::BaseType type,uint8_t * data,double val)395*890232f2SAndroid Build Coastguard Worker void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
396*890232f2SAndroid Build Coastguard Worker   switch (type) {
397*890232f2SAndroid Build Coastguard Worker     case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
398*890232f2SAndroid Build Coastguard Worker     case reflection::Double: WriteScalar(data, val); break;
399*890232f2SAndroid Build Coastguard Worker     // TODO: support strings.
400*890232f2SAndroid Build Coastguard Worker     default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
401*890232f2SAndroid Build Coastguard Worker   }
402*890232f2SAndroid Build Coastguard Worker }
403*890232f2SAndroid Build Coastguard Worker 
SetAnyValueS(reflection::BaseType type,uint8_t * data,const char * val)404*890232f2SAndroid Build Coastguard Worker void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
405*890232f2SAndroid Build Coastguard Worker   switch (type) {
406*890232f2SAndroid Build Coastguard Worker     case reflection::Float:
407*890232f2SAndroid Build Coastguard Worker     case reflection::Double: {
408*890232f2SAndroid Build Coastguard Worker       double d;
409*890232f2SAndroid Build Coastguard Worker       StringToNumber(val, &d);
410*890232f2SAndroid Build Coastguard Worker       SetAnyValueF(type, data, d);
411*890232f2SAndroid Build Coastguard Worker       break;
412*890232f2SAndroid Build Coastguard Worker     }
413*890232f2SAndroid Build Coastguard Worker     // TODO: support strings.
414*890232f2SAndroid Build Coastguard Worker     default: SetAnyValueI(type, data, StringToInt(val)); break;
415*890232f2SAndroid Build Coastguard Worker   }
416*890232f2SAndroid Build Coastguard Worker }
417*890232f2SAndroid Build Coastguard Worker 
418*890232f2SAndroid Build Coastguard Worker // Resize a FlatBuffer in-place by iterating through all offsets in the buffer
419*890232f2SAndroid Build Coastguard Worker // and adjusting them by "delta" if they straddle the start offset.
420*890232f2SAndroid Build Coastguard Worker // Once that is done, bytes can now be inserted/deleted safely.
421*890232f2SAndroid Build Coastguard Worker // "delta" may be negative (shrinking).
422*890232f2SAndroid Build Coastguard Worker // Unless "delta" is a multiple of the largest alignment, you'll create a small
423*890232f2SAndroid Build Coastguard Worker // amount of garbage space in the buffer (usually 0..7 bytes).
424*890232f2SAndroid Build Coastguard Worker // If your FlatBuffer's root table is not the schema's root table, you should
425*890232f2SAndroid Build Coastguard Worker // pass in your root_table type as well.
426*890232f2SAndroid Build Coastguard Worker class ResizeContext {
427*890232f2SAndroid Build Coastguard Worker  public:
ResizeContext(const reflection::Schema & schema,uoffset_t start,int delta,std::vector<uint8_t> * flatbuf,const reflection::Object * root_table=nullptr)428*890232f2SAndroid Build Coastguard Worker   ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
429*890232f2SAndroid Build Coastguard Worker                 std::vector<uint8_t> *flatbuf,
430*890232f2SAndroid Build Coastguard Worker                 const reflection::Object *root_table = nullptr)
431*890232f2SAndroid Build Coastguard Worker       : schema_(schema),
432*890232f2SAndroid Build Coastguard Worker         startptr_(flatbuf->data() + start),
433*890232f2SAndroid Build Coastguard Worker         delta_(delta),
434*890232f2SAndroid Build Coastguard Worker         buf_(*flatbuf),
435*890232f2SAndroid Build Coastguard Worker         dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
436*890232f2SAndroid Build Coastguard Worker     auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
437*890232f2SAndroid Build Coastguard Worker     delta_ = (delta_ + mask) & ~mask;
438*890232f2SAndroid Build Coastguard Worker     if (!delta_) return;  // We can't shrink by less than largest_scalar_t.
439*890232f2SAndroid Build Coastguard Worker     // Now change all the offsets by delta_.
440*890232f2SAndroid Build Coastguard Worker     auto root = GetAnyRoot(buf_.data());
441*890232f2SAndroid Build Coastguard Worker     Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
442*890232f2SAndroid Build Coastguard Worker     ResizeTable(root_table ? *root_table : *schema.root_table(), root);
443*890232f2SAndroid Build Coastguard Worker     // We can now add or remove bytes at start.
444*890232f2SAndroid Build Coastguard Worker     if (delta_ > 0)
445*890232f2SAndroid Build Coastguard Worker       buf_.insert(buf_.begin() + start, delta_, 0);
446*890232f2SAndroid Build Coastguard Worker     else
447*890232f2SAndroid Build Coastguard Worker       buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start);
448*890232f2SAndroid Build Coastguard Worker   }
449*890232f2SAndroid Build Coastguard Worker 
450*890232f2SAndroid Build Coastguard Worker   // Check if the range between first (lower address) and second straddles
451*890232f2SAndroid Build Coastguard Worker   // the insertion point. If it does, change the offset at offsetloc (of
452*890232f2SAndroid Build Coastguard Worker   // type T, with direction D).
453*890232f2SAndroid Build Coastguard Worker   template<typename T, int D>
Straddle(const void * first,const void * second,void * offsetloc)454*890232f2SAndroid Build Coastguard Worker   void Straddle(const void *first, const void *second, void *offsetloc) {
455*890232f2SAndroid Build Coastguard Worker     if (first <= startptr_ && second >= startptr_) {
456*890232f2SAndroid Build Coastguard Worker       WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
457*890232f2SAndroid Build Coastguard Worker       DagCheck(offsetloc) = true;
458*890232f2SAndroid Build Coastguard Worker     }
459*890232f2SAndroid Build Coastguard Worker   }
460*890232f2SAndroid Build Coastguard Worker 
461*890232f2SAndroid Build Coastguard Worker   // This returns a boolean that records if the corresponding offset location
462*890232f2SAndroid Build Coastguard Worker   // has been modified already. If so, we can't even read the corresponding
463*890232f2SAndroid Build Coastguard Worker   // offset, since it is pointing to a location that is illegal until the
464*890232f2SAndroid Build Coastguard Worker   // resize actually happens.
465*890232f2SAndroid Build Coastguard Worker   // This must be checked for every offset, since we can't know which offsets
466*890232f2SAndroid Build Coastguard Worker   // will straddle and which won't.
DagCheck(const void * offsetloc)467*890232f2SAndroid Build Coastguard Worker   uint8_t &DagCheck(const void *offsetloc) {
468*890232f2SAndroid Build Coastguard Worker     auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
469*890232f2SAndroid Build Coastguard Worker                    reinterpret_cast<const uoffset_t *>(buf_.data());
470*890232f2SAndroid Build Coastguard Worker     return dag_check_[dag_idx];
471*890232f2SAndroid Build Coastguard Worker   }
472*890232f2SAndroid Build Coastguard Worker 
ResizeTable(const reflection::Object & objectdef,Table * table)473*890232f2SAndroid Build Coastguard Worker   void ResizeTable(const reflection::Object &objectdef, Table *table) {
474*890232f2SAndroid Build Coastguard Worker     if (DagCheck(table)) return;  // Table already visited.
475*890232f2SAndroid Build Coastguard Worker     auto vtable = table->GetVTable();
476*890232f2SAndroid Build Coastguard Worker     // Early out: since all fields inside the table must point forwards in
477*890232f2SAndroid Build Coastguard Worker     // memory, if the insertion point is before the table we can stop here.
478*890232f2SAndroid Build Coastguard Worker     auto tableloc = reinterpret_cast<uint8_t *>(table);
479*890232f2SAndroid Build Coastguard Worker     if (startptr_ <= tableloc) {
480*890232f2SAndroid Build Coastguard Worker       // Check if insertion point is between the table and a vtable that
481*890232f2SAndroid Build Coastguard Worker       // precedes it. This can't happen in current construction code, but check
482*890232f2SAndroid Build Coastguard Worker       // just in case we ever change the way flatbuffers are built.
483*890232f2SAndroid Build Coastguard Worker       Straddle<soffset_t, -1>(vtable, table, table);
484*890232f2SAndroid Build Coastguard Worker     } else {
485*890232f2SAndroid Build Coastguard Worker       // Check each field.
486*890232f2SAndroid Build Coastguard Worker       auto fielddefs = objectdef.fields();
487*890232f2SAndroid Build Coastguard Worker       for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
488*890232f2SAndroid Build Coastguard Worker         auto &fielddef = **it;
489*890232f2SAndroid Build Coastguard Worker         auto base_type = fielddef.type()->base_type();
490*890232f2SAndroid Build Coastguard Worker         // Ignore scalars.
491*890232f2SAndroid Build Coastguard Worker         if (base_type <= reflection::Double) continue;
492*890232f2SAndroid Build Coastguard Worker         // Ignore fields that are not stored.
493*890232f2SAndroid Build Coastguard Worker         auto offset = table->GetOptionalFieldOffset(fielddef.offset());
494*890232f2SAndroid Build Coastguard Worker         if (!offset) continue;
495*890232f2SAndroid Build Coastguard Worker         // Ignore structs.
496*890232f2SAndroid Build Coastguard Worker         auto subobjectdef =
497*890232f2SAndroid Build Coastguard Worker             base_type == reflection::Obj
498*890232f2SAndroid Build Coastguard Worker                 ? schema_.objects()->Get(fielddef.type()->index())
499*890232f2SAndroid Build Coastguard Worker                 : nullptr;
500*890232f2SAndroid Build Coastguard Worker         if (subobjectdef && subobjectdef->is_struct()) continue;
501*890232f2SAndroid Build Coastguard Worker         // Get this fields' offset, and read it if safe.
502*890232f2SAndroid Build Coastguard Worker         auto offsetloc = tableloc + offset;
503*890232f2SAndroid Build Coastguard Worker         if (DagCheck(offsetloc)) continue;  // This offset already visited.
504*890232f2SAndroid Build Coastguard Worker         auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
505*890232f2SAndroid Build Coastguard Worker         Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
506*890232f2SAndroid Build Coastguard Worker         // Recurse.
507*890232f2SAndroid Build Coastguard Worker         switch (base_type) {
508*890232f2SAndroid Build Coastguard Worker           case reflection::Obj: {
509*890232f2SAndroid Build Coastguard Worker             ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
510*890232f2SAndroid Build Coastguard Worker             break;
511*890232f2SAndroid Build Coastguard Worker           }
512*890232f2SAndroid Build Coastguard Worker           case reflection::Vector: {
513*890232f2SAndroid Build Coastguard Worker             auto elem_type = fielddef.type()->element();
514*890232f2SAndroid Build Coastguard Worker             if (elem_type != reflection::Obj && elem_type != reflection::String)
515*890232f2SAndroid Build Coastguard Worker               break;
516*890232f2SAndroid Build Coastguard Worker             auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
517*890232f2SAndroid Build Coastguard Worker             auto elemobjectdef =
518*890232f2SAndroid Build Coastguard Worker                 elem_type == reflection::Obj
519*890232f2SAndroid Build Coastguard Worker                     ? schema_.objects()->Get(fielddef.type()->index())
520*890232f2SAndroid Build Coastguard Worker                     : nullptr;
521*890232f2SAndroid Build Coastguard Worker             if (elemobjectdef && elemobjectdef->is_struct()) break;
522*890232f2SAndroid Build Coastguard Worker             for (uoffset_t i = 0; i < vec->size(); i++) {
523*890232f2SAndroid Build Coastguard Worker               auto loc = vec->Data() + i * sizeof(uoffset_t);
524*890232f2SAndroid Build Coastguard Worker               if (DagCheck(loc)) continue;  // This offset already visited.
525*890232f2SAndroid Build Coastguard Worker               auto dest = loc + vec->Get(i);
526*890232f2SAndroid Build Coastguard Worker               Straddle<uoffset_t, 1>(loc, dest, loc);
527*890232f2SAndroid Build Coastguard Worker               if (elemobjectdef)
528*890232f2SAndroid Build Coastguard Worker                 ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
529*890232f2SAndroid Build Coastguard Worker             }
530*890232f2SAndroid Build Coastguard Worker             break;
531*890232f2SAndroid Build Coastguard Worker           }
532*890232f2SAndroid Build Coastguard Worker           case reflection::Union: {
533*890232f2SAndroid Build Coastguard Worker             ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
534*890232f2SAndroid Build Coastguard Worker                         reinterpret_cast<Table *>(ref));
535*890232f2SAndroid Build Coastguard Worker             break;
536*890232f2SAndroid Build Coastguard Worker           }
537*890232f2SAndroid Build Coastguard Worker           case reflection::String: break;
538*890232f2SAndroid Build Coastguard Worker           default: FLATBUFFERS_ASSERT(false);
539*890232f2SAndroid Build Coastguard Worker         }
540*890232f2SAndroid Build Coastguard Worker       }
541*890232f2SAndroid Build Coastguard Worker       // Check if the vtable offset points beyond the insertion point.
542*890232f2SAndroid Build Coastguard Worker       // Must do this last, since GetOptionalFieldOffset above still reads
543*890232f2SAndroid Build Coastguard Worker       // this value.
544*890232f2SAndroid Build Coastguard Worker       Straddle<soffset_t, -1>(table, vtable, table);
545*890232f2SAndroid Build Coastguard Worker     }
546*890232f2SAndroid Build Coastguard Worker   }
547*890232f2SAndroid Build Coastguard Worker 
548*890232f2SAndroid Build Coastguard Worker  private:
549*890232f2SAndroid Build Coastguard Worker   const reflection::Schema &schema_;
550*890232f2SAndroid Build Coastguard Worker   uint8_t *startptr_;
551*890232f2SAndroid Build Coastguard Worker   int delta_;
552*890232f2SAndroid Build Coastguard Worker   std::vector<uint8_t> &buf_;
553*890232f2SAndroid Build Coastguard Worker   std::vector<uint8_t> dag_check_;
554*890232f2SAndroid Build Coastguard Worker };
555*890232f2SAndroid Build Coastguard Worker 
SetString(const reflection::Schema & schema,const std::string & val,const String * str,std::vector<uint8_t> * flatbuf,const reflection::Object * root_table)556*890232f2SAndroid Build Coastguard Worker void SetString(const reflection::Schema &schema, const std::string &val,
557*890232f2SAndroid Build Coastguard Worker                const String *str, std::vector<uint8_t> *flatbuf,
558*890232f2SAndroid Build Coastguard Worker                const reflection::Object *root_table) {
559*890232f2SAndroid Build Coastguard Worker   auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size());
560*890232f2SAndroid Build Coastguard Worker   auto str_start = static_cast<uoffset_t>(
561*890232f2SAndroid Build Coastguard Worker       reinterpret_cast<const uint8_t *>(str) - flatbuf->data());
562*890232f2SAndroid Build Coastguard Worker   auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
563*890232f2SAndroid Build Coastguard Worker   if (delta) {
564*890232f2SAndroid Build Coastguard Worker     // Clear the old string, since we don't want parts of it remaining.
565*890232f2SAndroid Build Coastguard Worker     memset(flatbuf->data() + start, 0, str->size());
566*890232f2SAndroid Build Coastguard Worker     // Different size, we must expand (or contract).
567*890232f2SAndroid Build Coastguard Worker     ResizeContext(schema, start, delta, flatbuf, root_table);
568*890232f2SAndroid Build Coastguard Worker     // Set the new length.
569*890232f2SAndroid Build Coastguard Worker     WriteScalar(flatbuf->data() + str_start,
570*890232f2SAndroid Build Coastguard Worker                 static_cast<uoffset_t>(val.size()));
571*890232f2SAndroid Build Coastguard Worker   }
572*890232f2SAndroid Build Coastguard Worker   // Copy new data. Safe because we created the right amount of space.
573*890232f2SAndroid Build Coastguard Worker   memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
574*890232f2SAndroid Build Coastguard Worker }
575*890232f2SAndroid Build Coastguard Worker 
ResizeAnyVector(const reflection::Schema & schema,uoffset_t newsize,const VectorOfAny * vec,uoffset_t num_elems,uoffset_t elem_size,std::vector<uint8_t> * flatbuf,const reflection::Object * root_table)576*890232f2SAndroid Build Coastguard Worker uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
577*890232f2SAndroid Build Coastguard Worker                          const VectorOfAny *vec, uoffset_t num_elems,
578*890232f2SAndroid Build Coastguard Worker                          uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
579*890232f2SAndroid Build Coastguard Worker                          const reflection::Object *root_table) {
580*890232f2SAndroid Build Coastguard Worker   auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
581*890232f2SAndroid Build Coastguard Worker   auto delta_bytes = delta_elem * static_cast<int>(elem_size);
582*890232f2SAndroid Build Coastguard Worker   auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
583*890232f2SAndroid Build Coastguard Worker   auto start = static_cast<uoffset_t>(vec_start) +
584*890232f2SAndroid Build Coastguard Worker                static_cast<uoffset_t>(sizeof(uoffset_t)) +
585*890232f2SAndroid Build Coastguard Worker                elem_size * num_elems;
586*890232f2SAndroid Build Coastguard Worker   if (delta_bytes) {
587*890232f2SAndroid Build Coastguard Worker     if (delta_elem < 0) {
588*890232f2SAndroid Build Coastguard Worker       // Clear elements we're throwing away, since some might remain in the
589*890232f2SAndroid Build Coastguard Worker       // buffer.
590*890232f2SAndroid Build Coastguard Worker       auto size_clear = -delta_elem * elem_size;
591*890232f2SAndroid Build Coastguard Worker       memset(flatbuf->data() + start - size_clear, 0, size_clear);
592*890232f2SAndroid Build Coastguard Worker     }
593*890232f2SAndroid Build Coastguard Worker     ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
594*890232f2SAndroid Build Coastguard Worker     WriteScalar(flatbuf->data() + vec_start, newsize);  // Length field.
595*890232f2SAndroid Build Coastguard Worker     // Set new elements to 0.. this can be overwritten by the caller.
596*890232f2SAndroid Build Coastguard Worker     if (delta_elem > 0) {
597*890232f2SAndroid Build Coastguard Worker       memset(flatbuf->data() + start, 0,
598*890232f2SAndroid Build Coastguard Worker              static_cast<size_t>(delta_elem) * elem_size);
599*890232f2SAndroid Build Coastguard Worker     }
600*890232f2SAndroid Build Coastguard Worker   }
601*890232f2SAndroid Build Coastguard Worker   return flatbuf->data() + start;
602*890232f2SAndroid Build Coastguard Worker }
603*890232f2SAndroid Build Coastguard Worker 
AddFlatBuffer(std::vector<uint8_t> & flatbuf,const uint8_t * newbuf,size_t newlen)604*890232f2SAndroid Build Coastguard Worker const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
605*890232f2SAndroid Build Coastguard Worker                              const uint8_t *newbuf, size_t newlen) {
606*890232f2SAndroid Build Coastguard Worker   // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
607*890232f2SAndroid Build Coastguard Worker   // going to chop off the root offset.
608*890232f2SAndroid Build Coastguard Worker   while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
609*890232f2SAndroid Build Coastguard Worker          !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
610*890232f2SAndroid Build Coastguard Worker     flatbuf.push_back(0);
611*890232f2SAndroid Build Coastguard Worker   }
612*890232f2SAndroid Build Coastguard Worker   auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
613*890232f2SAndroid Build Coastguard Worker   // Insert the entire FlatBuffer minus the root pointer.
614*890232f2SAndroid Build Coastguard Worker   flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
615*890232f2SAndroid Build Coastguard Worker   auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
616*890232f2SAndroid Build Coastguard Worker   return flatbuf.data() + insertion_point + root_offset;
617*890232f2SAndroid Build Coastguard Worker }
618*890232f2SAndroid Build Coastguard Worker 
619*890232f2SAndroid Build Coastguard Worker 
620*890232f2SAndroid Build Coastguard Worker 
621*890232f2SAndroid Build Coastguard Worker 
CopyTable(FlatBufferBuilder & fbb,const reflection::Schema & schema,const reflection::Object & objectdef,const Table & table,bool use_string_pooling)622*890232f2SAndroid Build Coastguard Worker Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
623*890232f2SAndroid Build Coastguard Worker                                 const reflection::Schema &schema,
624*890232f2SAndroid Build Coastguard Worker                                 const reflection::Object &objectdef,
625*890232f2SAndroid Build Coastguard Worker                                 const Table &table, bool use_string_pooling) {
626*890232f2SAndroid Build Coastguard Worker   // Before we can construct the table, we have to first generate any
627*890232f2SAndroid Build Coastguard Worker   // subobjects, and collect their offsets.
628*890232f2SAndroid Build Coastguard Worker   std::vector<uoffset_t> offsets;
629*890232f2SAndroid Build Coastguard Worker   auto fielddefs = objectdef.fields();
630*890232f2SAndroid Build Coastguard Worker   for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
631*890232f2SAndroid Build Coastguard Worker     auto &fielddef = **it;
632*890232f2SAndroid Build Coastguard Worker     // Skip if field is not present in the source.
633*890232f2SAndroid Build Coastguard Worker     if (!table.CheckField(fielddef.offset())) continue;
634*890232f2SAndroid Build Coastguard Worker     uoffset_t offset = 0;
635*890232f2SAndroid Build Coastguard Worker     switch (fielddef.type()->base_type()) {
636*890232f2SAndroid Build Coastguard Worker       case reflection::String: {
637*890232f2SAndroid Build Coastguard Worker         offset = use_string_pooling
638*890232f2SAndroid Build Coastguard Worker                      ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
639*890232f2SAndroid Build Coastguard Worker                      : fbb.CreateString(GetFieldS(table, fielddef)).o;
640*890232f2SAndroid Build Coastguard Worker         break;
641*890232f2SAndroid Build Coastguard Worker       }
642*890232f2SAndroid Build Coastguard Worker       case reflection::Obj: {
643*890232f2SAndroid Build Coastguard Worker         auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
644*890232f2SAndroid Build Coastguard Worker         if (!subobjectdef.is_struct()) {
645*890232f2SAndroid Build Coastguard Worker           offset = CopyTable(fbb, schema, subobjectdef,
646*890232f2SAndroid Build Coastguard Worker                              *GetFieldT(table, fielddef), use_string_pooling)
647*890232f2SAndroid Build Coastguard Worker                        .o;
648*890232f2SAndroid Build Coastguard Worker         }
649*890232f2SAndroid Build Coastguard Worker         break;
650*890232f2SAndroid Build Coastguard Worker       }
651*890232f2SAndroid Build Coastguard Worker       case reflection::Union: {
652*890232f2SAndroid Build Coastguard Worker         auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
653*890232f2SAndroid Build Coastguard Worker         offset = CopyTable(fbb, schema, subobjectdef,
654*890232f2SAndroid Build Coastguard Worker                            *GetFieldT(table, fielddef), use_string_pooling)
655*890232f2SAndroid Build Coastguard Worker                      .o;
656*890232f2SAndroid Build Coastguard Worker         break;
657*890232f2SAndroid Build Coastguard Worker       }
658*890232f2SAndroid Build Coastguard Worker       case reflection::Vector: {
659*890232f2SAndroid Build Coastguard Worker         auto vec =
660*890232f2SAndroid Build Coastguard Worker             table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset());
661*890232f2SAndroid Build Coastguard Worker         auto element_base_type = fielddef.type()->element();
662*890232f2SAndroid Build Coastguard Worker         auto elemobjectdef =
663*890232f2SAndroid Build Coastguard Worker             element_base_type == reflection::Obj
664*890232f2SAndroid Build Coastguard Worker                 ? schema.objects()->Get(fielddef.type()->index())
665*890232f2SAndroid Build Coastguard Worker                 : nullptr;
666*890232f2SAndroid Build Coastguard Worker         switch (element_base_type) {
667*890232f2SAndroid Build Coastguard Worker           case reflection::String: {
668*890232f2SAndroid Build Coastguard Worker             std::vector<Offset<const String *>> elements(vec->size());
669*890232f2SAndroid Build Coastguard Worker             auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
670*890232f2SAndroid Build Coastguard Worker             for (uoffset_t i = 0; i < vec_s->size(); i++) {
671*890232f2SAndroid Build Coastguard Worker               elements[i] = use_string_pooling
672*890232f2SAndroid Build Coastguard Worker                                 ? fbb.CreateSharedString(vec_s->Get(i)).o
673*890232f2SAndroid Build Coastguard Worker                                 : fbb.CreateString(vec_s->Get(i)).o;
674*890232f2SAndroid Build Coastguard Worker             }
675*890232f2SAndroid Build Coastguard Worker             offset = fbb.CreateVector(elements).o;
676*890232f2SAndroid Build Coastguard Worker             break;
677*890232f2SAndroid Build Coastguard Worker           }
678*890232f2SAndroid Build Coastguard Worker           case reflection::Obj: {
679*890232f2SAndroid Build Coastguard Worker             if (!elemobjectdef->is_struct()) {
680*890232f2SAndroid Build Coastguard Worker               std::vector<Offset<const Table *>> elements(vec->size());
681*890232f2SAndroid Build Coastguard Worker               for (uoffset_t i = 0; i < vec->size(); i++) {
682*890232f2SAndroid Build Coastguard Worker                 elements[i] = CopyTable(fbb, schema, *elemobjectdef,
683*890232f2SAndroid Build Coastguard Worker                                         *vec->Get(i), use_string_pooling);
684*890232f2SAndroid Build Coastguard Worker               }
685*890232f2SAndroid Build Coastguard Worker               offset = fbb.CreateVector(elements).o;
686*890232f2SAndroid Build Coastguard Worker               break;
687*890232f2SAndroid Build Coastguard Worker             }
688*890232f2SAndroid Build Coastguard Worker           }
689*890232f2SAndroid Build Coastguard Worker             FLATBUFFERS_FALLTHROUGH();  // fall thru
690*890232f2SAndroid Build Coastguard Worker           default: {                    // Scalars and structs.
691*890232f2SAndroid Build Coastguard Worker             auto element_size = GetTypeSize(element_base_type);
692*890232f2SAndroid Build Coastguard Worker             if (elemobjectdef && elemobjectdef->is_struct())
693*890232f2SAndroid Build Coastguard Worker               element_size = elemobjectdef->bytesize();
694*890232f2SAndroid Build Coastguard Worker             fbb.StartVector(vec->size(), element_size);
695*890232f2SAndroid Build Coastguard Worker             fbb.PushBytes(vec->Data(), element_size * vec->size());
696*890232f2SAndroid Build Coastguard Worker             offset = fbb.EndVector(vec->size());
697*890232f2SAndroid Build Coastguard Worker             break;
698*890232f2SAndroid Build Coastguard Worker           }
699*890232f2SAndroid Build Coastguard Worker         }
700*890232f2SAndroid Build Coastguard Worker         break;
701*890232f2SAndroid Build Coastguard Worker       }
702*890232f2SAndroid Build Coastguard Worker       default:  // Scalars.
703*890232f2SAndroid Build Coastguard Worker         break;
704*890232f2SAndroid Build Coastguard Worker     }
705*890232f2SAndroid Build Coastguard Worker     if (offset) { offsets.push_back(offset); }
706*890232f2SAndroid Build Coastguard Worker   }
707*890232f2SAndroid Build Coastguard Worker   // Now we can build the actual table from either offsets or scalar data.
708*890232f2SAndroid Build Coastguard Worker   auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign())
709*890232f2SAndroid Build Coastguard Worker                                      : fbb.StartTable();
710*890232f2SAndroid Build Coastguard Worker   size_t offset_idx = 0;
711*890232f2SAndroid Build Coastguard Worker   for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
712*890232f2SAndroid Build Coastguard Worker     auto &fielddef = **it;
713*890232f2SAndroid Build Coastguard Worker     if (!table.CheckField(fielddef.offset())) continue;
714*890232f2SAndroid Build Coastguard Worker     auto base_type = fielddef.type()->base_type();
715*890232f2SAndroid Build Coastguard Worker     switch (base_type) {
716*890232f2SAndroid Build Coastguard Worker       case reflection::Obj: {
717*890232f2SAndroid Build Coastguard Worker         auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
718*890232f2SAndroid Build Coastguard Worker         if (subobjectdef.is_struct()) {
719*890232f2SAndroid Build Coastguard Worker           CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
720*890232f2SAndroid Build Coastguard Worker                      subobjectdef.bytesize());
721*890232f2SAndroid Build Coastguard Worker           break;
722*890232f2SAndroid Build Coastguard Worker         }
723*890232f2SAndroid Build Coastguard Worker       }
724*890232f2SAndroid Build Coastguard Worker         FLATBUFFERS_FALLTHROUGH();  // fall thru
725*890232f2SAndroid Build Coastguard Worker       case reflection::Union:
726*890232f2SAndroid Build Coastguard Worker       case reflection::String:
727*890232f2SAndroid Build Coastguard Worker       case reflection::Vector:
728*890232f2SAndroid Build Coastguard Worker         fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
729*890232f2SAndroid Build Coastguard Worker         break;
730*890232f2SAndroid Build Coastguard Worker       default: {  // Scalars.
731*890232f2SAndroid Build Coastguard Worker         auto size = GetTypeSize(base_type);
732*890232f2SAndroid Build Coastguard Worker         CopyInline(fbb, fielddef, table, size, size);
733*890232f2SAndroid Build Coastguard Worker         break;
734*890232f2SAndroid Build Coastguard Worker       }
735*890232f2SAndroid Build Coastguard Worker     }
736*890232f2SAndroid Build Coastguard Worker   }
737*890232f2SAndroid Build Coastguard Worker   FLATBUFFERS_ASSERT(offset_idx == offsets.size());
738*890232f2SAndroid Build Coastguard Worker   if (objectdef.is_struct()) {
739*890232f2SAndroid Build Coastguard Worker     fbb.ClearOffsets();
740*890232f2SAndroid Build Coastguard Worker     return fbb.EndStruct();
741*890232f2SAndroid Build Coastguard Worker   } else {
742*890232f2SAndroid Build Coastguard Worker     return fbb.EndTable(start);
743*890232f2SAndroid Build Coastguard Worker   }
744*890232f2SAndroid Build Coastguard Worker }
745*890232f2SAndroid Build Coastguard Worker 
746*890232f2SAndroid Build Coastguard Worker 
Verify(const reflection::Schema & schema,const reflection::Object & root,const uint8_t * const buf,const size_t length,const uoffset_t max_depth,const uoffset_t max_tables)747*890232f2SAndroid Build Coastguard Worker bool Verify(const reflection::Schema &schema, const reflection::Object &root,
748*890232f2SAndroid Build Coastguard Worker             const uint8_t *const buf, const size_t length,
749*890232f2SAndroid Build Coastguard Worker             const uoffset_t max_depth, const uoffset_t max_tables) {
750*890232f2SAndroid Build Coastguard Worker   Verifier v(buf, length, max_depth, max_tables);
751*890232f2SAndroid Build Coastguard Worker   return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf),
752*890232f2SAndroid Build Coastguard Worker                       /*required=*/true);
753*890232f2SAndroid Build Coastguard Worker }
754*890232f2SAndroid Build Coastguard Worker 
VerifySizePrefixed(const reflection::Schema & schema,const reflection::Object & root,const uint8_t * const buf,const size_t length,const uoffset_t max_depth,const uoffset_t max_tables)755*890232f2SAndroid Build Coastguard Worker bool VerifySizePrefixed(const reflection::Schema &schema,
756*890232f2SAndroid Build Coastguard Worker                         const reflection::Object &root,
757*890232f2SAndroid Build Coastguard Worker                         const uint8_t *const buf, const size_t length,
758*890232f2SAndroid Build Coastguard Worker                         const uoffset_t max_depth, const uoffset_t max_tables) {
759*890232f2SAndroid Build Coastguard Worker   Verifier v(buf, length, max_depth, max_tables);
760*890232f2SAndroid Build Coastguard Worker   return VerifyObject(v, schema, root, flatbuffers::GetAnySizePrefixedRoot(buf),
761*890232f2SAndroid Build Coastguard Worker                       /*required=*/true);
762*890232f2SAndroid Build Coastguard Worker }
763*890232f2SAndroid Build Coastguard Worker 
764*890232f2SAndroid Build Coastguard Worker }  // namespace flatbuffers
765