/* * Copyright 2021 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FLATBUFFERS_TABLE_H_ #define FLATBUFFERS_TABLE_H_ #include "flatbuffers/base.h" #include "flatbuffers/vector.h" #include "flatbuffers/verifier.h" namespace flatbuffers { // "tables" use an offset table (possibly shared) that allows fields to be // omitted and added at will, but uses an extra indirection to read. class Table { public: const uint8_t* GetVTable() const { return data_ - ReadScalar(data_); } // This gets the field offset for any of the functions below it, or 0 // if the field was not present. voffset_t GetOptionalFieldOffset(voffset_t field) const { // The vtable offset is always at the start. auto vtable = GetVTable(); // The first element is the size of the vtable (fields + type id + itself). auto vtsize = ReadScalar(vtable); // If the field we're accessing is outside the vtable, we're reading older // data, so it's the same as if the offset was 0 (not present). return field < vtsize ? ReadScalar(vtable + field) : 0; } template T GetField(voffset_t field, T defaultval) const { auto field_offset = GetOptionalFieldOffset(field); return field_offset ? ReadScalar(data_ + field_offset) : defaultval; } template P GetPointer(voffset_t field) { auto field_offset = GetOptionalFieldOffset(field); auto p = data_ + field_offset; return field_offset ? reinterpret_cast

(p + ReadScalar(p)) : nullptr; } template P GetPointer(voffset_t field) const { return const_cast(this)->GetPointer(field); } template P GetPointer64(voffset_t field) { return GetPointer(field); } template P GetPointer64(voffset_t field) const { return GetPointer(field); } template const Vector* GetVectorPointerOrEmpty(voffset_t field) const { auto* ptr = GetPointer*, OffsetSize>(field); return ptr ? ptr : EmptyVector(); } template const Vector* GetVectorPointer64OrEmpty(voffset_t field) const { return GetVectorPointerOrEmpty(field); } template Vector* GetMutableVectorPointerOrEmpty(voffset_t field) { auto* ptr = GetPointer*, OffsetSize>(field); // This is a const_cast, but safe, since all mutable operations on an // empty vector are NOPs. return ptr ? ptr : const_cast*>(EmptyVector()); } template Vector* GetMutableVectorPointer64OrEmpty(voffset_t field) { return GetMutableVectorPointerOrEmpty(field); } template P GetStruct(voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); auto p = const_cast(data_ + field_offset); return field_offset ? reinterpret_cast

(p) : nullptr; } template flatbuffers::Optional GetOptional(voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); auto p = data_ + field_offset; return field_offset ? Optional(static_cast(ReadScalar(p))) : Optional(); } template bool SetField(voffset_t field, T val, T def) { auto field_offset = GetOptionalFieldOffset(field); if (!field_offset) return IsTheSameAs(val, def); WriteScalar(data_ + field_offset, val); return true; } template bool SetField(voffset_t field, T val) { auto field_offset = GetOptionalFieldOffset(field); if (!field_offset) return false; WriteScalar(data_ + field_offset, val); return true; } bool SetPointer(voffset_t field, const uint8_t* val) { auto field_offset = GetOptionalFieldOffset(field); if (!field_offset) return false; WriteScalar(data_ + field_offset, static_cast(val - (data_ + field_offset))); return true; } uint8_t* GetAddressOf(voffset_t field) { auto field_offset = GetOptionalFieldOffset(field); return field_offset ? data_ + field_offset : nullptr; } const uint8_t* GetAddressOf(voffset_t field) const { return const_cast(this)->GetAddressOf(field); } bool CheckField(voffset_t field) const { return GetOptionalFieldOffset(field) != 0; } // Verify the vtable of this table. // Call this once per table, followed by VerifyField once per field. template bool VerifyTableStart(VerifierTemplate& verifier) const { return verifier.VerifyTableStart(data_); } // Verify a particular field. template bool VerifyField(const VerifierTemplate& verifier, voffset_t field, size_t align) const { // Calling GetOptionalFieldOffset should be safe now thanks to // VerifyTable(). auto field_offset = GetOptionalFieldOffset(field); // Check the actual field. return !field_offset || verifier.template VerifyField(data_, field_offset, align); } // VerifyField for required fields. template bool VerifyFieldRequired(const VerifierTemplate& verifier, voffset_t field, size_t align) const { auto field_offset = GetOptionalFieldOffset(field); return verifier.Check(field_offset != 0) && verifier.template VerifyField(data_, field_offset, align); } // Versions for offsets. template bool VerifyOffset(const VerifierTemplate& verifier, voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); return !field_offset || verifier.template VerifyOffset(data_, field_offset); } template bool VerifyOffsetRequired(const VerifierTemplate& verifier, voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); return verifier.Check(field_offset != 0) && verifier.template VerifyOffset(data_, field_offset); } template bool VerifyOffset64(const VerifierTemplate& verifier, voffset_t field) const { return VerifyOffset(verifier, field); } template bool VerifyOffset64Required(const VerifierTemplate& verifier, voffset_t field) const { return VerifyOffsetRequired(verifier, field); } // Verify a string that may have a default value. template bool VerifyStringWithDefault(const Verifier& verifier, voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); return field_offset == 0 || verifier.VerifyString(GetPointer(field)); } // Verify a vector that has a default empty value. template bool VerifyVectorWithDefault(const Verifier& verifier, voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); return field_offset == 0 || verifier.VerifyVector( GetPointer*, OffsetSize>(field)); } template bool VerifyVector64WithDefault(const Verifier& verifier, voffset_t field) const { return VerifyVectorWithDefault(verifier, field); } protected: template static const Vector* EmptyVector() { static const SizeT empty_vector_length = 0; return reinterpret_cast*>(&empty_vector_length); } private: // private constructor & copy constructor: you obtain instances of this // class by pointing to existing data only Table(); Table(const Table& other); Table& operator=(const Table&); uint8_t data_[1]; }; // This specialization allows avoiding warnings like: // MSVC C4800: type: forcing value to bool 'true' or 'false'. template <> inline flatbuffers::Optional Table::GetOptional( voffset_t field) const { auto field_offset = GetOptionalFieldOffset(field); auto p = data_ + field_offset; return field_offset ? Optional(ReadScalar(p) != 0) : Optional(); } } // namespace flatbuffers #endif // FLATBUFFERS_TABLE_H_