xref: /aosp_15_r20/external/flatbuffers/src/binary_annotator.h (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2021 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 #ifndef FLATBUFFERS_BINARY_ANNOTATOR_H_
18*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_BINARY_ANNOTATOR_H_
19*890232f2SAndroid Build Coastguard Worker 
20*890232f2SAndroid Build Coastguard Worker #include <map>
21*890232f2SAndroid Build Coastguard Worker #include <string>
22*890232f2SAndroid Build Coastguard Worker #include <vector>
23*890232f2SAndroid Build Coastguard Worker 
24*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/base.h"
25*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/reflection.h"
26*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/stl_emulation.h"
27*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
28*890232f2SAndroid Build Coastguard Worker 
29*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
30*890232f2SAndroid Build Coastguard Worker 
31*890232f2SAndroid Build Coastguard Worker enum class BinaryRegionType {
32*890232f2SAndroid Build Coastguard Worker   Unknown = 0,
33*890232f2SAndroid Build Coastguard Worker   UOffset = 1,
34*890232f2SAndroid Build Coastguard Worker   SOffset = 2,
35*890232f2SAndroid Build Coastguard Worker   VOffset = 3,
36*890232f2SAndroid Build Coastguard Worker   Bool = 4,
37*890232f2SAndroid Build Coastguard Worker   Byte = 5,
38*890232f2SAndroid Build Coastguard Worker   Char = 6,
39*890232f2SAndroid Build Coastguard Worker   Uint8 = 7,
40*890232f2SAndroid Build Coastguard Worker   Int8 = 8,
41*890232f2SAndroid Build Coastguard Worker   Uint16 = 9,
42*890232f2SAndroid Build Coastguard Worker   Int16 = 10,
43*890232f2SAndroid Build Coastguard Worker   Uint32 = 11,
44*890232f2SAndroid Build Coastguard Worker   Int32 = 12,
45*890232f2SAndroid Build Coastguard Worker   Uint64 = 13,
46*890232f2SAndroid Build Coastguard Worker   Int64 = 14,
47*890232f2SAndroid Build Coastguard Worker   Float = 15,
48*890232f2SAndroid Build Coastguard Worker   Double = 16,
49*890232f2SAndroid Build Coastguard Worker   UType = 17,
50*890232f2SAndroid Build Coastguard Worker };
51*890232f2SAndroid Build Coastguard Worker 
52*890232f2SAndroid Build Coastguard Worker template<typename T>
53*890232f2SAndroid Build Coastguard Worker static inline std::string ToHex(T i, size_t width = sizeof(T)) {
54*890232f2SAndroid Build Coastguard Worker   std::stringstream stream;
55*890232f2SAndroid Build Coastguard Worker   stream << std::hex << std::uppercase << std::setfill('0') << std::setw(width)
56*890232f2SAndroid Build Coastguard Worker          << i;
57*890232f2SAndroid Build Coastguard Worker   return stream.str();
58*890232f2SAndroid Build Coastguard Worker }
59*890232f2SAndroid Build Coastguard Worker 
60*890232f2SAndroid Build Coastguard Worker // Specialized version for uint8_t that don't work well with std::hex.
ToHex(uint8_t i)61*890232f2SAndroid Build Coastguard Worker static inline std::string ToHex(uint8_t i) {
62*890232f2SAndroid Build Coastguard Worker   return ToHex(static_cast<int>(i), 2);
63*890232f2SAndroid Build Coastguard Worker }
64*890232f2SAndroid Build Coastguard Worker 
65*890232f2SAndroid Build Coastguard Worker enum class BinaryRegionStatus {
66*890232f2SAndroid Build Coastguard Worker   OK = 0,
67*890232f2SAndroid Build Coastguard Worker   WARN = 100,
68*890232f2SAndroid Build Coastguard Worker   WARN_NO_REFERENCES,
69*890232f2SAndroid Build Coastguard Worker   WARN_CORRUPTED_PADDING,
70*890232f2SAndroid Build Coastguard Worker   WARN_PADDING_LENGTH,
71*890232f2SAndroid Build Coastguard Worker   ERROR = 200,
72*890232f2SAndroid Build Coastguard Worker   // An offset is pointing outside the binary bounds.
73*890232f2SAndroid Build Coastguard Worker   ERROR_OFFSET_OUT_OF_BINARY,
74*890232f2SAndroid Build Coastguard Worker   // Expecting to read N bytes but not enough remain in the binary.
75*890232f2SAndroid Build Coastguard Worker   ERROR_INCOMPLETE_BINARY,
76*890232f2SAndroid Build Coastguard Worker   // When a length of a vtable/vector is longer than possible.
77*890232f2SAndroid Build Coastguard Worker   ERROR_LENGTH_TOO_LONG,
78*890232f2SAndroid Build Coastguard Worker   // When a length of a vtable/vector is shorter than possible.
79*890232f2SAndroid Build Coastguard Worker   ERROR_LENGTH_TOO_SHORT,
80*890232f2SAndroid Build Coastguard Worker   // A field mark required is not present in the vtable.
81*890232f2SAndroid Build Coastguard Worker   ERROR_REQUIRED_FIELD_NOT_PRESENT,
82*890232f2SAndroid Build Coastguard Worker   // A realized union type is not within the enum bounds.
83*890232f2SAndroid Build Coastguard Worker   ERROR_INVALID_UNION_TYPE,
84*890232f2SAndroid Build Coastguard Worker   // Occurs when there is a cycle in offsets.
85*890232f2SAndroid Build Coastguard Worker   ERROR_CYCLE_DETECTED,
86*890232f2SAndroid Build Coastguard Worker };
87*890232f2SAndroid Build Coastguard Worker 
88*890232f2SAndroid Build Coastguard Worker enum class BinaryRegionCommentType {
89*890232f2SAndroid Build Coastguard Worker   Unknown = 0,
90*890232f2SAndroid Build Coastguard Worker   SizePrefix,
91*890232f2SAndroid Build Coastguard Worker   // The offset to the root table.
92*890232f2SAndroid Build Coastguard Worker   RootTableOffset,
93*890232f2SAndroid Build Coastguard Worker   // The optional 4-char file identifier.
94*890232f2SAndroid Build Coastguard Worker   FileIdentifier,
95*890232f2SAndroid Build Coastguard Worker   // Generic 0-filled padding
96*890232f2SAndroid Build Coastguard Worker   Padding,
97*890232f2SAndroid Build Coastguard Worker   // The size of the vtable.
98*890232f2SAndroid Build Coastguard Worker   VTableSize,
99*890232f2SAndroid Build Coastguard Worker   // The size of the referring table.
100*890232f2SAndroid Build Coastguard Worker   VTableRefferingTableLength,
101*890232f2SAndroid Build Coastguard Worker   // Offsets to vtable fields.
102*890232f2SAndroid Build Coastguard Worker   VTableFieldOffset,
103*890232f2SAndroid Build Coastguard Worker   // Offsets to unknown vtable fields.
104*890232f2SAndroid Build Coastguard Worker   VTableUnknownFieldOffset,
105*890232f2SAndroid Build Coastguard Worker   // The vtable offset of a table.
106*890232f2SAndroid Build Coastguard Worker   TableVTableOffset,
107*890232f2SAndroid Build Coastguard Worker   // A "inline" table field value.
108*890232f2SAndroid Build Coastguard Worker   TableField,
109*890232f2SAndroid Build Coastguard Worker   // A table field that is unknown.
110*890232f2SAndroid Build Coastguard Worker   TableUnknownField,
111*890232f2SAndroid Build Coastguard Worker   // A table field value that points to another section.
112*890232f2SAndroid Build Coastguard Worker   TableOffsetField,
113*890232f2SAndroid Build Coastguard Worker   // A struct field value.
114*890232f2SAndroid Build Coastguard Worker   StructField,
115*890232f2SAndroid Build Coastguard Worker   // A array field value.
116*890232f2SAndroid Build Coastguard Worker   ArrayField,
117*890232f2SAndroid Build Coastguard Worker   // The length of the string.
118*890232f2SAndroid Build Coastguard Worker   StringLength,
119*890232f2SAndroid Build Coastguard Worker   // The string contents.
120*890232f2SAndroid Build Coastguard Worker   StringValue,
121*890232f2SAndroid Build Coastguard Worker   // The explicit string terminator.
122*890232f2SAndroid Build Coastguard Worker   StringTerminator,
123*890232f2SAndroid Build Coastguard Worker   // The length of the vector (# of items).
124*890232f2SAndroid Build Coastguard Worker   VectorLength,
125*890232f2SAndroid Build Coastguard Worker   // A "inline" value of a vector.
126*890232f2SAndroid Build Coastguard Worker   VectorValue,
127*890232f2SAndroid Build Coastguard Worker   // A vector value that points to another section.
128*890232f2SAndroid Build Coastguard Worker   VectorTableValue,
129*890232f2SAndroid Build Coastguard Worker   VectorStringValue,
130*890232f2SAndroid Build Coastguard Worker   VectorUnionValue,
131*890232f2SAndroid Build Coastguard Worker };
132*890232f2SAndroid Build Coastguard Worker 
133*890232f2SAndroid Build Coastguard Worker struct BinaryRegionComment {
134*890232f2SAndroid Build Coastguard Worker   BinaryRegionStatus status = BinaryRegionStatus::OK;
135*890232f2SAndroid Build Coastguard Worker 
136*890232f2SAndroid Build Coastguard Worker   // If status is non OK, this may be filled in with additional details.
137*890232f2SAndroid Build Coastguard Worker   std::string status_message;
138*890232f2SAndroid Build Coastguard Worker 
139*890232f2SAndroid Build Coastguard Worker   BinaryRegionCommentType type = BinaryRegionCommentType::Unknown;
140*890232f2SAndroid Build Coastguard Worker 
141*890232f2SAndroid Build Coastguard Worker   std::string name;
142*890232f2SAndroid Build Coastguard Worker 
143*890232f2SAndroid Build Coastguard Worker   std::string default_value;
144*890232f2SAndroid Build Coastguard Worker 
145*890232f2SAndroid Build Coastguard Worker   size_t index = 0;
146*890232f2SAndroid Build Coastguard Worker };
147*890232f2SAndroid Build Coastguard Worker 
148*890232f2SAndroid Build Coastguard Worker struct BinaryRegion {
149*890232f2SAndroid Build Coastguard Worker   // Offset into the binary where this region begins.
150*890232f2SAndroid Build Coastguard Worker   uint64_t offset = 0;
151*890232f2SAndroid Build Coastguard Worker 
152*890232f2SAndroid Build Coastguard Worker   // The length of this region in bytes.
153*890232f2SAndroid Build Coastguard Worker   uint64_t length = 0;
154*890232f2SAndroid Build Coastguard Worker 
155*890232f2SAndroid Build Coastguard Worker   // The underlying datatype of this region
156*890232f2SAndroid Build Coastguard Worker   BinaryRegionType type = BinaryRegionType::Unknown;
157*890232f2SAndroid Build Coastguard Worker 
158*890232f2SAndroid Build Coastguard Worker   // If `type` is an array/vector, this is the number of those types this region
159*890232f2SAndroid Build Coastguard Worker   // encompasses.
160*890232f2SAndroid Build Coastguard Worker   uint64_t array_length = 0;
161*890232f2SAndroid Build Coastguard Worker 
162*890232f2SAndroid Build Coastguard Worker   // If the is an offset to some other region, this is what it points to. The
163*890232f2SAndroid Build Coastguard Worker   // offset is relative to overall binary, not to this region.
164*890232f2SAndroid Build Coastguard Worker   uint64_t points_to_offset = 0;
165*890232f2SAndroid Build Coastguard Worker 
166*890232f2SAndroid Build Coastguard Worker   // The comment on the region.
167*890232f2SAndroid Build Coastguard Worker   BinaryRegionComment comment;
168*890232f2SAndroid Build Coastguard Worker };
169*890232f2SAndroid Build Coastguard Worker 
170*890232f2SAndroid Build Coastguard Worker enum class BinarySectionType {
171*890232f2SAndroid Build Coastguard Worker   Unknown = 0,
172*890232f2SAndroid Build Coastguard Worker   Header = 1,
173*890232f2SAndroid Build Coastguard Worker   Table = 2,
174*890232f2SAndroid Build Coastguard Worker   RootTable = 3,
175*890232f2SAndroid Build Coastguard Worker   VTable = 4,
176*890232f2SAndroid Build Coastguard Worker   Struct = 5,
177*890232f2SAndroid Build Coastguard Worker   String = 6,
178*890232f2SAndroid Build Coastguard Worker   Vector = 7,
179*890232f2SAndroid Build Coastguard Worker   Union = 8,
180*890232f2SAndroid Build Coastguard Worker   Padding = 9,
181*890232f2SAndroid Build Coastguard Worker };
182*890232f2SAndroid Build Coastguard Worker 
183*890232f2SAndroid Build Coastguard Worker // A section of the binary that is grouped together in some logical manner, and
184*890232f2SAndroid Build Coastguard Worker // often is pointed too by some other offset BinaryRegion. Sections include
185*890232f2SAndroid Build Coastguard Worker // `tables`, `vtables`, `strings`, `vectors`, etc..
186*890232f2SAndroid Build Coastguard Worker struct BinarySection {
187*890232f2SAndroid Build Coastguard Worker   // User-specified name of the section, if applicable.
188*890232f2SAndroid Build Coastguard Worker   std::string name;
189*890232f2SAndroid Build Coastguard Worker 
190*890232f2SAndroid Build Coastguard Worker   // The type of this section.
191*890232f2SAndroid Build Coastguard Worker   BinarySectionType type = BinarySectionType::Unknown;
192*890232f2SAndroid Build Coastguard Worker 
193*890232f2SAndroid Build Coastguard Worker   // The binary regions that make up this section, in order of their offsets.
194*890232f2SAndroid Build Coastguard Worker   std::vector<BinaryRegion> regions;
195*890232f2SAndroid Build Coastguard Worker };
196*890232f2SAndroid Build Coastguard Worker 
GetRegionType(reflection::BaseType base_type)197*890232f2SAndroid Build Coastguard Worker inline static BinaryRegionType GetRegionType(reflection::BaseType base_type) {
198*890232f2SAndroid Build Coastguard Worker   switch (base_type) {
199*890232f2SAndroid Build Coastguard Worker     case reflection::UType: return BinaryRegionType::UType;
200*890232f2SAndroid Build Coastguard Worker     case reflection::Bool: return BinaryRegionType::Uint8;
201*890232f2SAndroid Build Coastguard Worker     case reflection::Byte: return BinaryRegionType::Uint8;
202*890232f2SAndroid Build Coastguard Worker     case reflection::UByte: return BinaryRegionType::Uint8;
203*890232f2SAndroid Build Coastguard Worker     case reflection::Short: return BinaryRegionType::Int16;
204*890232f2SAndroid Build Coastguard Worker     case reflection::UShort: return BinaryRegionType::Uint16;
205*890232f2SAndroid Build Coastguard Worker     case reflection::Int: return BinaryRegionType::Uint32;
206*890232f2SAndroid Build Coastguard Worker     case reflection::UInt: return BinaryRegionType::Uint32;
207*890232f2SAndroid Build Coastguard Worker     case reflection::Long: return BinaryRegionType::Int64;
208*890232f2SAndroid Build Coastguard Worker     case reflection::ULong: return BinaryRegionType::Uint64;
209*890232f2SAndroid Build Coastguard Worker     case reflection::Float: return BinaryRegionType::Float;
210*890232f2SAndroid Build Coastguard Worker     case reflection::Double: return BinaryRegionType::Double;
211*890232f2SAndroid Build Coastguard Worker     default: return BinaryRegionType::Unknown;
212*890232f2SAndroid Build Coastguard Worker   }
213*890232f2SAndroid Build Coastguard Worker }
214*890232f2SAndroid Build Coastguard Worker 
ToString(const BinaryRegionType type)215*890232f2SAndroid Build Coastguard Worker inline static std::string ToString(const BinaryRegionType type) {
216*890232f2SAndroid Build Coastguard Worker   switch (type) {
217*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::UOffset: return "UOffset32";
218*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::SOffset: return "SOffset32";
219*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::VOffset: return "VOffset16";
220*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Bool: return "bool";
221*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Char: return "char";
222*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Byte: return "int8_t";
223*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Uint8: return "uint8_t";
224*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Uint16: return "uint16_t";
225*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Uint32: return "uint32_t";
226*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Uint64: return "uint64_t"; ;
227*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Int8: return "int8_t";
228*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Int16: return "int16_t";
229*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Int32: return "int32_t";
230*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Int64: return "int64_t";
231*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Double: return "double";
232*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Float: return "float";
233*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::UType: return "UType8";
234*890232f2SAndroid Build Coastguard Worker     case BinaryRegionType::Unknown: return "?uint8_t";
235*890232f2SAndroid Build Coastguard Worker     default: return "todo";
236*890232f2SAndroid Build Coastguard Worker   }
237*890232f2SAndroid Build Coastguard Worker }
238*890232f2SAndroid Build Coastguard Worker 
239*890232f2SAndroid Build Coastguard Worker class BinaryAnnotator {
240*890232f2SAndroid Build Coastguard Worker  public:
BinaryAnnotator(const uint8_t * const bfbs,const uint64_t bfbs_length,const uint8_t * const binary,const uint64_t binary_length)241*890232f2SAndroid Build Coastguard Worker   explicit BinaryAnnotator(const uint8_t *const bfbs,
242*890232f2SAndroid Build Coastguard Worker                            const uint64_t bfbs_length,
243*890232f2SAndroid Build Coastguard Worker                            const uint8_t *const binary,
244*890232f2SAndroid Build Coastguard Worker                            const uint64_t binary_length)
245*890232f2SAndroid Build Coastguard Worker       : bfbs_(bfbs),
246*890232f2SAndroid Build Coastguard Worker         bfbs_length_(bfbs_length),
247*890232f2SAndroid Build Coastguard Worker         schema_(reflection::GetSchema(bfbs)),
248*890232f2SAndroid Build Coastguard Worker         binary_(binary),
249*890232f2SAndroid Build Coastguard Worker         binary_length_(binary_length) {}
250*890232f2SAndroid Build Coastguard Worker 
251*890232f2SAndroid Build Coastguard Worker   std::map<uint64_t, BinarySection> Annotate();
252*890232f2SAndroid Build Coastguard Worker 
253*890232f2SAndroid Build Coastguard Worker  private:
254*890232f2SAndroid Build Coastguard Worker   struct VTable {
255*890232f2SAndroid Build Coastguard Worker     struct Entry {
256*890232f2SAndroid Build Coastguard Worker       const reflection::Field *field = nullptr;
257*890232f2SAndroid Build Coastguard Worker       uint16_t offset_from_table = 0;
258*890232f2SAndroid Build Coastguard Worker     };
259*890232f2SAndroid Build Coastguard Worker 
260*890232f2SAndroid Build Coastguard Worker     // Field ID -> {field def, offset from table}
261*890232f2SAndroid Build Coastguard Worker     std::map<uint16_t, Entry> fields;
262*890232f2SAndroid Build Coastguard Worker 
263*890232f2SAndroid Build Coastguard Worker     uint16_t vtable_size = 0;
264*890232f2SAndroid Build Coastguard Worker     uint16_t table_size = 0;
265*890232f2SAndroid Build Coastguard Worker   };
266*890232f2SAndroid Build Coastguard Worker 
267*890232f2SAndroid Build Coastguard Worker   uint64_t BuildHeader(uint64_t offset);
268*890232f2SAndroid Build Coastguard Worker 
269*890232f2SAndroid Build Coastguard Worker   void BuildVTable(uint64_t offset, const reflection::Object *table,
270*890232f2SAndroid Build Coastguard Worker                    uint64_t offset_of_referring_table);
271*890232f2SAndroid Build Coastguard Worker 
272*890232f2SAndroid Build Coastguard Worker   void BuildTable(uint64_t offset, const BinarySectionType type,
273*890232f2SAndroid Build Coastguard Worker                   const reflection::Object *table);
274*890232f2SAndroid Build Coastguard Worker 
275*890232f2SAndroid Build Coastguard Worker   uint64_t BuildStruct(uint64_t offset, std::vector<BinaryRegion> &regions,
276*890232f2SAndroid Build Coastguard Worker                        const reflection::Object *structure);
277*890232f2SAndroid Build Coastguard Worker 
278*890232f2SAndroid Build Coastguard Worker   void BuildString(uint64_t offset, const reflection::Object *table,
279*890232f2SAndroid Build Coastguard Worker                    const reflection::Field *field);
280*890232f2SAndroid Build Coastguard Worker 
281*890232f2SAndroid Build Coastguard Worker   void BuildVector(uint64_t offset, const reflection::Object *table,
282*890232f2SAndroid Build Coastguard Worker                    const reflection::Field *field, uint64_t parent_table_offset,
283*890232f2SAndroid Build Coastguard Worker                    const VTable &vtable);
284*890232f2SAndroid Build Coastguard Worker 
285*890232f2SAndroid Build Coastguard Worker   std::string BuildUnion(uint64_t offset, uint8_t realized_type,
286*890232f2SAndroid Build Coastguard Worker                          const reflection::Field *field);
287*890232f2SAndroid Build Coastguard Worker 
288*890232f2SAndroid Build Coastguard Worker   void FixMissingRegions();
289*890232f2SAndroid Build Coastguard Worker   void FixMissingSections();
290*890232f2SAndroid Build Coastguard Worker 
IsValidOffset(const uint64_t offset)291*890232f2SAndroid Build Coastguard Worker   inline bool IsValidOffset(const uint64_t offset) const {
292*890232f2SAndroid Build Coastguard Worker     return offset < binary_length_;
293*890232f2SAndroid Build Coastguard Worker   }
294*890232f2SAndroid Build Coastguard Worker 
295*890232f2SAndroid Build Coastguard Worker   // Determines if performing a GetScalar request for `T` at `offset` would read
296*890232f2SAndroid Build Coastguard Worker   // passed the end of the binary.
IsValidRead(const uint64_t offset)297*890232f2SAndroid Build Coastguard Worker   template<typename T> inline bool IsValidRead(const uint64_t offset) const {
298*890232f2SAndroid Build Coastguard Worker     return IsValidRead(offset, sizeof(T));
299*890232f2SAndroid Build Coastguard Worker   }
300*890232f2SAndroid Build Coastguard Worker 
IsValidRead(const uint64_t offset,const uint64_t length)301*890232f2SAndroid Build Coastguard Worker   inline bool IsValidRead(const uint64_t offset, const uint64_t length) const {
302*890232f2SAndroid Build Coastguard Worker     return length < binary_length_ && IsValidOffset(offset + length - 1);
303*890232f2SAndroid Build Coastguard Worker   }
304*890232f2SAndroid Build Coastguard Worker 
305*890232f2SAndroid Build Coastguard Worker   // Calculate the number of bytes remaining from the given offset. If offset is
306*890232f2SAndroid Build Coastguard Worker   // > binary_length, 0 is returned.
RemainingBytes(const uint64_t offset)307*890232f2SAndroid Build Coastguard Worker   uint64_t RemainingBytes(const uint64_t offset) const {
308*890232f2SAndroid Build Coastguard Worker     return IsValidOffset(offset) ? binary_length_ - offset : 0;
309*890232f2SAndroid Build Coastguard Worker   }
310*890232f2SAndroid Build Coastguard Worker 
311*890232f2SAndroid Build Coastguard Worker   template<typename T>
ReadScalar(const uint64_t offset)312*890232f2SAndroid Build Coastguard Worker   flatbuffers::Optional<T> ReadScalar(const uint64_t offset) const {
313*890232f2SAndroid Build Coastguard Worker     if (!IsValidRead<T>(offset)) { return flatbuffers::nullopt; }
314*890232f2SAndroid Build Coastguard Worker 
315*890232f2SAndroid Build Coastguard Worker     return flatbuffers::ReadScalar<T>(binary_ + offset);
316*890232f2SAndroid Build Coastguard Worker   }
317*890232f2SAndroid Build Coastguard Worker 
318*890232f2SAndroid Build Coastguard Worker   // Adds the provided `section` keyed by the `offset` it occurs at. If a
319*890232f2SAndroid Build Coastguard Worker   // section is already added at that offset, it doesn't replace the exisiting
320*890232f2SAndroid Build Coastguard Worker   // one.
AddSection(const uint64_t offset,const BinarySection & section)321*890232f2SAndroid Build Coastguard Worker   void AddSection(const uint64_t offset, const BinarySection &section) {
322*890232f2SAndroid Build Coastguard Worker     sections_.insert(std::make_pair(offset, section));
323*890232f2SAndroid Build Coastguard Worker   }
324*890232f2SAndroid Build Coastguard Worker 
IsInlineField(const reflection::Field * const field)325*890232f2SAndroid Build Coastguard Worker   bool IsInlineField(const reflection::Field *const field) {
326*890232f2SAndroid Build Coastguard Worker     if (field->type()->base_type() == reflection::BaseType::Obj) {
327*890232f2SAndroid Build Coastguard Worker       return schema_->objects()->Get(field->type()->index())->is_struct();
328*890232f2SAndroid Build Coastguard Worker     }
329*890232f2SAndroid Build Coastguard Worker     return IsScalar(field->type()->base_type());
330*890232f2SAndroid Build Coastguard Worker   }
331*890232f2SAndroid Build Coastguard Worker 
IsUnionType(const reflection::BaseType type)332*890232f2SAndroid Build Coastguard Worker   bool IsUnionType(const reflection::BaseType type) {
333*890232f2SAndroid Build Coastguard Worker     return (type == reflection::BaseType::UType ||
334*890232f2SAndroid Build Coastguard Worker             type == reflection::BaseType::Union);
335*890232f2SAndroid Build Coastguard Worker   }
336*890232f2SAndroid Build Coastguard Worker 
IsUnionType(const reflection::Field * const field)337*890232f2SAndroid Build Coastguard Worker   bool IsUnionType(const reflection::Field *const field) {
338*890232f2SAndroid Build Coastguard Worker     return IsUnionType(field->type()->base_type()) &&
339*890232f2SAndroid Build Coastguard Worker            field->type()->index() >= 0;
340*890232f2SAndroid Build Coastguard Worker   }
341*890232f2SAndroid Build Coastguard Worker 
IsValidUnionValue(const reflection::Field * const field,const uint8_t value)342*890232f2SAndroid Build Coastguard Worker   bool IsValidUnionValue(const reflection::Field *const field,
343*890232f2SAndroid Build Coastguard Worker                          const uint8_t value) {
344*890232f2SAndroid Build Coastguard Worker     return IsUnionType(field) &&
345*890232f2SAndroid Build Coastguard Worker            IsValidUnionValue(field->type()->index(), value);
346*890232f2SAndroid Build Coastguard Worker   }
347*890232f2SAndroid Build Coastguard Worker 
IsValidUnionValue(const uint32_t enum_id,const uint8_t value)348*890232f2SAndroid Build Coastguard Worker   bool IsValidUnionValue(const uint32_t enum_id, const uint8_t value) {
349*890232f2SAndroid Build Coastguard Worker     if (enum_id >= schema_->enums()->size()) { return false; }
350*890232f2SAndroid Build Coastguard Worker 
351*890232f2SAndroid Build Coastguard Worker     const reflection::Enum *enum_def = schema_->enums()->Get(enum_id);
352*890232f2SAndroid Build Coastguard Worker 
353*890232f2SAndroid Build Coastguard Worker     if (enum_def == nullptr) { return false; }
354*890232f2SAndroid Build Coastguard Worker 
355*890232f2SAndroid Build Coastguard Worker     return value < enum_def->values()->size();
356*890232f2SAndroid Build Coastguard Worker   }
357*890232f2SAndroid Build Coastguard Worker 
GetElementSize(const reflection::Field * const field)358*890232f2SAndroid Build Coastguard Worker   uint64_t GetElementSize(const reflection::Field *const field) {
359*890232f2SAndroid Build Coastguard Worker     if (IsScalar(field->type()->element())) {
360*890232f2SAndroid Build Coastguard Worker       return GetTypeSize(field->type()->element());
361*890232f2SAndroid Build Coastguard Worker     }
362*890232f2SAndroid Build Coastguard Worker 
363*890232f2SAndroid Build Coastguard Worker     switch (field->type()->element()) {
364*890232f2SAndroid Build Coastguard Worker       case reflection::BaseType::Obj: {
365*890232f2SAndroid Build Coastguard Worker         auto obj = schema_->objects()->Get(field->type()->index());
366*890232f2SAndroid Build Coastguard Worker         return obj->is_struct() ? obj->bytesize() : sizeof(uint32_t);
367*890232f2SAndroid Build Coastguard Worker       }
368*890232f2SAndroid Build Coastguard Worker       default: return sizeof(uint32_t);
369*890232f2SAndroid Build Coastguard Worker     }
370*890232f2SAndroid Build Coastguard Worker   }
371*890232f2SAndroid Build Coastguard Worker 
372*890232f2SAndroid Build Coastguard Worker   bool ContainsSection(const uint64_t offset);
373*890232f2SAndroid Build Coastguard Worker 
374*890232f2SAndroid Build Coastguard Worker   // The schema for the binary file
375*890232f2SAndroid Build Coastguard Worker   const uint8_t *bfbs_;
376*890232f2SAndroid Build Coastguard Worker   const uint64_t bfbs_length_;
377*890232f2SAndroid Build Coastguard Worker   const reflection::Schema *schema_;
378*890232f2SAndroid Build Coastguard Worker 
379*890232f2SAndroid Build Coastguard Worker   // The binary data itself.
380*890232f2SAndroid Build Coastguard Worker   const uint8_t *binary_;
381*890232f2SAndroid Build Coastguard Worker   const uint64_t binary_length_;
382*890232f2SAndroid Build Coastguard Worker 
383*890232f2SAndroid Build Coastguard Worker   // Map of binary offset to vtables, to dedupe vtables.
384*890232f2SAndroid Build Coastguard Worker   std::map<uint64_t, VTable> vtables_;
385*890232f2SAndroid Build Coastguard Worker 
386*890232f2SAndroid Build Coastguard Worker   // The annotated binary sections, index by their absolute offset.
387*890232f2SAndroid Build Coastguard Worker   std::map<uint64_t, BinarySection> sections_;
388*890232f2SAndroid Build Coastguard Worker };
389*890232f2SAndroid Build Coastguard Worker 
390*890232f2SAndroid Build Coastguard Worker }  // namespace flatbuffers
391*890232f2SAndroid Build Coastguard Worker 
392*890232f2SAndroid Build Coastguard Worker #endif  // FLATBUFFERS_BINARY_ANNOTATOR_H_