James Kuszmaul | 8e62b02 | 2022-03-22 09:33:25 -0700 | [diff] [blame^] | 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: |
| 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. |
| 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 | |
| 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> P GetPointer(voffset_t field) { |
| 51 | auto field_offset = GetOptionalFieldOffset(field); |
| 52 | auto p = data_ + field_offset; |
| 53 | return field_offset ? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p)) |
| 54 | : nullptr; |
| 55 | } |
| 56 | template<typename P> P GetPointer(voffset_t field) const { |
| 57 | return const_cast<Table *>(this)->GetPointer<P>(field); |
| 58 | } |
| 59 | |
| 60 | template<typename P> P GetStruct(voffset_t field) const { |
| 61 | auto field_offset = GetOptionalFieldOffset(field); |
| 62 | auto p = const_cast<uint8_t *>(data_ + field_offset); |
| 63 | return field_offset ? reinterpret_cast<P>(p) : nullptr; |
| 64 | } |
| 65 | |
| 66 | template<typename Raw, typename Face> |
| 67 | flatbuffers::Optional<Face> GetOptional(voffset_t field) const { |
| 68 | auto field_offset = GetOptionalFieldOffset(field); |
| 69 | auto p = data_ + field_offset; |
| 70 | return field_offset ? Optional<Face>(static_cast<Face>(ReadScalar<Raw>(p))) |
| 71 | : Optional<Face>(); |
| 72 | } |
| 73 | |
| 74 | template<typename T> bool SetField(voffset_t field, T val, T def) { |
| 75 | auto field_offset = GetOptionalFieldOffset(field); |
| 76 | if (!field_offset) return IsTheSameAs(val, def); |
| 77 | WriteScalar(data_ + field_offset, val); |
| 78 | return true; |
| 79 | } |
| 80 | template<typename T> bool SetField(voffset_t field, T val) { |
| 81 | auto field_offset = GetOptionalFieldOffset(field); |
| 82 | if (!field_offset) return false; |
| 83 | WriteScalar(data_ + field_offset, val); |
| 84 | return true; |
| 85 | } |
| 86 | |
| 87 | bool SetPointer(voffset_t field, const uint8_t *val) { |
| 88 | auto field_offset = GetOptionalFieldOffset(field); |
| 89 | if (!field_offset) return false; |
| 90 | WriteScalar(data_ + field_offset, |
| 91 | static_cast<uoffset_t>(val - (data_ + field_offset))); |
| 92 | return true; |
| 93 | } |
| 94 | |
| 95 | uint8_t *GetAddressOf(voffset_t field) { |
| 96 | auto field_offset = GetOptionalFieldOffset(field); |
| 97 | return field_offset ? data_ + field_offset : nullptr; |
| 98 | } |
| 99 | const uint8_t *GetAddressOf(voffset_t field) const { |
| 100 | return const_cast<Table *>(this)->GetAddressOf(field); |
| 101 | } |
| 102 | |
| 103 | bool CheckField(voffset_t field) const { |
| 104 | return GetOptionalFieldOffset(field) != 0; |
| 105 | } |
| 106 | |
| 107 | // Verify the vtable of this table. |
| 108 | // Call this once per table, followed by VerifyField once per field. |
| 109 | bool VerifyTableStart(Verifier &verifier) const { |
| 110 | return verifier.VerifyTableStart(data_); |
| 111 | } |
| 112 | |
| 113 | // Verify a particular field. |
| 114 | template<typename T> |
| 115 | bool VerifyField(const Verifier &verifier, voffset_t field, |
| 116 | size_t align) const { |
| 117 | // Calling GetOptionalFieldOffset should be safe now thanks to |
| 118 | // VerifyTable(). |
| 119 | auto field_offset = GetOptionalFieldOffset(field); |
| 120 | // Check the actual field. |
| 121 | return !field_offset || verifier.VerifyField<T>(data_, field_offset, align); |
| 122 | } |
| 123 | |
| 124 | // VerifyField for required fields. |
| 125 | template<typename T> |
| 126 | bool VerifyFieldRequired(const Verifier &verifier, voffset_t field, |
| 127 | size_t align) const { |
| 128 | auto field_offset = GetOptionalFieldOffset(field); |
| 129 | return verifier.Check(field_offset != 0) && |
| 130 | verifier.VerifyField<T>(data_, field_offset, align); |
| 131 | } |
| 132 | |
| 133 | // Versions for offsets. |
| 134 | bool VerifyOffset(const Verifier &verifier, voffset_t field) const { |
| 135 | auto field_offset = GetOptionalFieldOffset(field); |
| 136 | return !field_offset || verifier.VerifyOffset(data_, field_offset); |
| 137 | } |
| 138 | |
| 139 | bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const { |
| 140 | auto field_offset = GetOptionalFieldOffset(field); |
| 141 | return verifier.Check(field_offset != 0) && |
| 142 | verifier.VerifyOffset(data_, field_offset); |
| 143 | } |
| 144 | |
| 145 | private: |
| 146 | // private constructor & copy constructor: you obtain instances of this |
| 147 | // class by pointing to existing data only |
| 148 | Table(); |
| 149 | Table(const Table &other); |
| 150 | Table &operator=(const Table &); |
| 151 | |
| 152 | uint8_t data_[1]; |
| 153 | }; |
| 154 | |
| 155 | // This specialization allows avoiding warnings like: |
| 156 | // MSVC C4800: type: forcing value to bool 'true' or 'false'. |
| 157 | template<> |
| 158 | inline flatbuffers::Optional<bool> Table::GetOptional<uint8_t, bool>( |
| 159 | voffset_t field) const { |
| 160 | auto field_offset = GetOptionalFieldOffset(field); |
| 161 | auto p = data_ + field_offset; |
| 162 | return field_offset ? Optional<bool>(ReadScalar<uint8_t>(p) != 0) |
| 163 | : Optional<bool>(); |
| 164 | } |
| 165 | |
| 166 | } // namespace flatbuffers |
| 167 | |
| 168 | #endif // FLATBUFFERS_TABLE_H_ |