1 /* 2 * Copyright 2021 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FLATBUFFERS_TABLE_H_ 18 #define FLATBUFFERS_TABLE_H_ 19 20 #include "flatbuffers/base.h" 21 #include "flatbuffers/verifier.h" 22 23 namespace flatbuffers { 24 25 // "tables" use an offset table (possibly shared) that allows fields to be 26 // omitted and added at will, but uses an extra indirection to read. 27 class Table { 28 public: GetVTable()29 const uint8_t *GetVTable() const { 30 return data_ - ReadScalar<soffset_t>(data_); 31 } 32 33 // This gets the field offset for any of the functions below it, or 0 34 // if the field was not present. GetOptionalFieldOffset(voffset_t field)35 voffset_t GetOptionalFieldOffset(voffset_t field) const { 36 // The vtable offset is always at the start. 37 auto vtable = GetVTable(); 38 // The first element is the size of the vtable (fields + type id + itself). 39 auto vtsize = ReadScalar<voffset_t>(vtable); 40 // If the field we're accessing is outside the vtable, we're reading older 41 // data, so it's the same as if the offset was 0 (not present). 42 return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0; 43 } 44 GetField(voffset_t field,T defaultval)45 template<typename T> T GetField(voffset_t field, T defaultval) const { 46 auto field_offset = GetOptionalFieldOffset(field); 47 return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval; 48 } 49 50 template<typename P, typename OffsetSize = uoffset_t> GetPointer(voffset_t field)51 P GetPointer(voffset_t field) { 52 auto field_offset = GetOptionalFieldOffset(field); 53 auto p = data_ + field_offset; 54 return field_offset ? reinterpret_cast<P>(p + ReadScalar<OffsetSize>(p)) 55 : nullptr; 56 } 57 template<typename P, typename OffsetSize = uoffset_t> GetPointer(voffset_t field)58 P GetPointer(voffset_t field) const { 59 return const_cast<Table *>(this)->GetPointer<P, OffsetSize>(field); 60 } 61 GetPointer64(voffset_t field)62 template<typename P> P GetPointer64(voffset_t field) { 63 return GetPointer<P, uoffset64_t>(field); 64 } 65 GetPointer64(voffset_t field)66 template<typename P> P GetPointer64(voffset_t field) const { 67 return GetPointer<P, uoffset64_t>(field); 68 } 69 GetStruct(voffset_t field)70 template<typename P> P GetStruct(voffset_t field) const { 71 auto field_offset = GetOptionalFieldOffset(field); 72 auto p = const_cast<uint8_t *>(data_ + field_offset); 73 return field_offset ? reinterpret_cast<P>(p) : nullptr; 74 } 75 76 template<typename Raw, typename Face> GetOptional(voffset_t field)77 flatbuffers::Optional<Face> GetOptional(voffset_t field) const { 78 auto field_offset = GetOptionalFieldOffset(field); 79 auto p = data_ + field_offset; 80 return field_offset ? Optional<Face>(static_cast<Face>(ReadScalar<Raw>(p))) 81 : Optional<Face>(); 82 } 83 SetField(voffset_t field,T val,T def)84 template<typename T> bool SetField(voffset_t field, T val, T def) { 85 auto field_offset = GetOptionalFieldOffset(field); 86 if (!field_offset) return IsTheSameAs(val, def); 87 WriteScalar(data_ + field_offset, val); 88 return true; 89 } SetField(voffset_t field,T val)90 template<typename T> bool SetField(voffset_t field, T val) { 91 auto field_offset = GetOptionalFieldOffset(field); 92 if (!field_offset) return false; 93 WriteScalar(data_ + field_offset, val); 94 return true; 95 } 96 SetPointer(voffset_t field,const uint8_t * val)97 bool SetPointer(voffset_t field, const uint8_t *val) { 98 auto field_offset = GetOptionalFieldOffset(field); 99 if (!field_offset) return false; 100 WriteScalar(data_ + field_offset, 101 static_cast<uoffset_t>(val - (data_ + field_offset))); 102 return true; 103 } 104 GetAddressOf(voffset_t field)105 uint8_t *GetAddressOf(voffset_t field) { 106 auto field_offset = GetOptionalFieldOffset(field); 107 return field_offset ? data_ + field_offset : nullptr; 108 } GetAddressOf(voffset_t field)109 const uint8_t *GetAddressOf(voffset_t field) const { 110 return const_cast<Table *>(this)->GetAddressOf(field); 111 } 112 CheckField(voffset_t field)113 bool CheckField(voffset_t field) const { 114 return GetOptionalFieldOffset(field) != 0; 115 } 116 117 // Verify the vtable of this table. 118 // Call this once per table, followed by VerifyField once per field. VerifyTableStart(Verifier & verifier)119 bool VerifyTableStart(Verifier &verifier) const { 120 return verifier.VerifyTableStart(data_); 121 } 122 123 // Verify a particular field. 124 template<typename T> VerifyField(const Verifier & verifier,voffset_t field,size_t align)125 bool VerifyField(const Verifier &verifier, voffset_t field, 126 size_t align) const { 127 // Calling GetOptionalFieldOffset should be safe now thanks to 128 // VerifyTable(). 129 auto field_offset = GetOptionalFieldOffset(field); 130 // Check the actual field. 131 return !field_offset || verifier.VerifyField<T>(data_, field_offset, align); 132 } 133 134 // VerifyField for required fields. 135 template<typename T> VerifyFieldRequired(const Verifier & verifier,voffset_t field,size_t align)136 bool VerifyFieldRequired(const Verifier &verifier, voffset_t field, 137 size_t align) const { 138 auto field_offset = GetOptionalFieldOffset(field); 139 return verifier.Check(field_offset != 0) && 140 verifier.VerifyField<T>(data_, field_offset, align); 141 } 142 143 // Versions for offsets. 144 template<typename OffsetT = uoffset_t> VerifyOffset(const Verifier & verifier,voffset_t field)145 bool VerifyOffset(const Verifier &verifier, voffset_t field) const { 146 auto field_offset = GetOptionalFieldOffset(field); 147 return !field_offset || verifier.VerifyOffset<OffsetT>(data_, field_offset); 148 } 149 150 template<typename OffsetT = uoffset_t> VerifyOffsetRequired(const Verifier & verifier,voffset_t field)151 bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const { 152 auto field_offset = GetOptionalFieldOffset(field); 153 return verifier.Check(field_offset != 0) && 154 verifier.VerifyOffset<OffsetT>(data_, field_offset); 155 } 156 VerifyOffset64(const Verifier & verifier,voffset_t field)157 bool VerifyOffset64(const Verifier &verifier, voffset_t field) const { 158 return VerifyOffset<uoffset64_t>(verifier, field); 159 } 160 VerifyOffset64Required(const Verifier & verifier,voffset_t field)161 bool VerifyOffset64Required(const Verifier &verifier, voffset_t field) const { 162 return VerifyOffsetRequired<uoffset64_t>(verifier, field); 163 } 164 165 private: 166 // private constructor & copy constructor: you obtain instances of this 167 // class by pointing to existing data only 168 Table(); 169 Table(const Table &other); 170 Table &operator=(const Table &); 171 172 uint8_t data_[1]; 173 }; 174 175 // This specialization allows avoiding warnings like: 176 // MSVC C4800: type: forcing value to bool 'true' or 'false'. 177 template<> 178 inline flatbuffers::Optional<bool> Table::GetOptional<uint8_t, bool>( 179 voffset_t field) const { 180 auto field_offset = GetOptionalFieldOffset(field); 181 auto p = data_ + field_offset; 182 return field_offset ? Optional<bool>(ReadScalar<uint8_t>(p) != 0) 183 : Optional<bool>(); 184 } 185 186 } // namespace flatbuffers 187 188 #endif // FLATBUFFERS_TABLE_H_ 189