| /* | |
| * Copyright 2014 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. | |
| */ | |
| using System; | |
| using System.Reflection;using System.Collections.Generic; | |
| using System.IO; | |
| namespace Google.FlatBuffers | |
| { | |
| /// <summary> | |
| /// The Class of the Verifier Options | |
| /// </summary> | |
| public class Options | |
| { | |
| public const int DEFAULT_MAX_DEPTH = 64; | |
| public const int DEFAULT_MAX_TABLES = 1000000; | |
| private int max_depth = 0; | |
| private int max_tables = 0; | |
| private bool string_end_check = false; | |
| private bool alignment_check = false; | |
| public Options() | |
| { | |
| max_depth = DEFAULT_MAX_DEPTH; | |
| max_tables = DEFAULT_MAX_TABLES; | |
| string_end_check = true; | |
| alignment_check = true; | |
| } | |
| public Options(int maxDepth, int maxTables, bool stringEndCheck, bool alignmentCheck) | |
| { | |
| max_depth = maxDepth; | |
| max_tables = maxTables; | |
| string_end_check = stringEndCheck; | |
| alignment_check = alignmentCheck; | |
| } | |
| /// <summary> Maximum depth of nested tables allowed in a valid flatbuffer. </summary> | |
| public int maxDepth | |
| { | |
| get { return max_depth; } | |
| set { max_depth = value; } | |
| } | |
| /// <summary> Maximum number of tables allowed in a valid flatbuffer. </summary> | |
| public int maxTables | |
| { | |
| get { return max_tables; } | |
| set { max_tables = value; } | |
| } | |
| /// <summary> Check that string contains its null terminator </summary> | |
| public bool stringEndCheck | |
| { | |
| get { return string_end_check; } | |
| set { string_end_check = value; } | |
| } | |
| /// <summary> Check alignment of elements </summary> | |
| public bool alignmentCheck | |
| { | |
| get { return alignment_check; } | |
| set { alignment_check = value; } | |
| } | |
| } | |
| public struct checkElementStruct | |
| { | |
| public bool elementValid; | |
| public uint elementOffset; | |
| } | |
| public delegate bool VerifyTableAction(Verifier verifier, uint tablePos); | |
| public delegate bool VerifyUnionAction(Verifier verifier, byte typeId, uint tablePos); | |
| /// <summary> | |
| /// The Main Class of the FlatBuffer Verifier | |
| /// </summary> | |
| public class Verifier | |
| { | |
| private ByteBuffer verifier_buffer = null; | |
| private Options verifier_options = null; | |
| private int depth_cnt = 0; | |
| private int num_tables_cnt = 0; | |
| public const int SIZE_BYTE = 1; | |
| public const int SIZE_INT = 4; | |
| public const int SIZE_U_OFFSET = 4; | |
| public const int SIZE_S_OFFSET = 4; | |
| public const int SIZE_V_OFFSET = 2; | |
| public const int SIZE_PREFIX_LENGTH = FlatBufferConstants.SizePrefixLength; // default size = 4 | |
| public const int FLATBUFFERS_MAX_BUFFER_SIZE = System.Int32.MaxValue; // default size = 2147483647 | |
| public const int FILE_IDENTIFIER_LENGTH = FlatBufferConstants.FileIdentifierLength; // default size = 4 | |
| /// <summary> The Base Constructor of the Verifier object </summary> | |
| public Verifier() | |
| { | |
| // Verifier buffer | |
| verifier_buffer = null; | |
| // Verifier settings | |
| verifier_options = null; | |
| // Depth counter | |
| depth_cnt = 0; | |
| // Tables counter | |
| num_tables_cnt = 0; | |
| } | |
| /// <summary> The Constructor of the Verifier object with input parameters: ByteBuffer and/or Options </summary> | |
| /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type</param> | |
| /// <param name="options"> Options object with settings for the coniguration the Verifier </param> | |
| public Verifier(ByteBuffer buf, Options options = null) | |
| { | |
| verifier_buffer = buf; | |
| verifier_options = options ?? new Options(); | |
| depth_cnt = 0; | |
| num_tables_cnt = 0; | |
| } | |
| /// <summary> Bytes Buffer for Verify</summary> | |
| public ByteBuffer Buf | |
| { | |
| get { return verifier_buffer; } | |
| set { verifier_buffer = value; } | |
| } | |
| /// <summary> Options of the Verifier </summary> | |
| public Options options | |
| { | |
| get { return verifier_options; } | |
| set { verifier_options = value; } | |
| } | |
| /// <summary> Counter of tables depth in a tested flatbuffer </summary> | |
| public int depth | |
| { | |
| get { return depth_cnt; } | |
| set { depth_cnt = value; } | |
| } | |
| /// <summary> Counter of tables in a tested flatbuffer </summary> | |
| public int numTables | |
| { | |
| get { return num_tables_cnt; } | |
| set { num_tables_cnt = value; } | |
| } | |
| /// <summary> Method set maximum tables depth of valid structure</summary> | |
| /// <param name="value"> Specify Value of the maximum depth of the structure</param> | |
| public Verifier SetMaxDepth(int value) | |
| { | |
| verifier_options.maxDepth = value; | |
| return this; | |
| } | |
| /// <summary> Specify maximum number of tables in structure </summary> | |
| /// <param name="value"> Specify Value of the maximum number of the tables in the structure</param> | |
| public Verifier SetMaxTables(int value) | |
| { | |
| verifier_options.maxTables = value; | |
| return this; | |
| } | |
| /// <summary> Enable/disable buffer content alignment check </summary> | |
| /// <param name="value"> Value of the State for buffer content alignment check (Enable = true) </param> | |
| public Verifier SetAlignmentCheck(bool value) | |
| { | |
| verifier_options.alignmentCheck = value; | |
| return this; | |
| } | |
| /// <summary> Enable/disable checking of string termination '0' character </summary> | |
| /// <param name="value"> Value of the option for string termination '0' character check (Enable = true)</param> | |
| public Verifier SetStringCheck(bool value) | |
| { | |
| verifier_options.stringEndCheck = value; | |
| return this; | |
| } | |
| /// <summary> Check if there is identifier in buffer </summary> | |
| /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param> | |
| /// <param name="startPos">Start position of data in the Byte Buffer</param> | |
| /// <param name="identifier"> Identifier for the Byte Buffer</param> | |
| /// <returns> Return True when the Byte Buffer Identifier is present</returns> | |
| private bool BufferHasIdentifier(ByteBuffer buf, uint startPos, string identifier) | |
| { | |
| if (identifier.Length != FILE_IDENTIFIER_LENGTH) | |
| { | |
| throw new ArgumentException("FlatBuffers: file identifier must be length" + Convert.ToString(FILE_IDENTIFIER_LENGTH)); | |
| } | |
| for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++) | |
| { | |
| if ((sbyte)identifier[i] != verifier_buffer.GetSbyte(Convert.ToInt32(SIZE_S_OFFSET + i + startPos))) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /// <summary> Get UOffsetT from buffer at given position - it must be verified before read </summary> | |
| /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param> | |
| /// <param name="pos"> Position of data in the Byte Buffer</param> | |
| /// <returns> Return the UOffset Value (Unsigned Integer type - 4 bytes) in pos </returns> | |
| private uint ReadUOffsetT(ByteBuffer buf, uint pos) | |
| { | |
| return buf.GetUint(Convert.ToInt32(pos)); | |
| } | |
| /// <summary> Get SOffsetT from buffer at given position - it must be verified before read </summary> | |
| /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param> | |
| /// <param name="pos"> Position of data in the Byte Buffer</param> | |
| /// <returns> Return the SOffset Value (Signed Integer type - 4 bytes) in pos </returns> | |
| private int ReadSOffsetT(ByteBuffer buf, int pos) | |
| { | |
| return buf.GetInt(pos); | |
| } | |
| /// <summary> Get VOffsetT from buffer at given position - it must be verified before read </summary> | |
| /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param> | |
| /// <param name="pos"> Position of data in the Byte Buffer</param> | |
| /// <returns> Return the VOffset Value (Short type - 2 bytes) in pos </returns> | |
| private short ReadVOffsetT(ByteBuffer buf, int pos) | |
| { | |
| return buf.GetShort(pos); | |
| } | |
| /// <summary> Get table data area relative offset from vtable. Result is relative to table start | |
| /// Fields which are deprecated are ignored by checking against the vtable's length. </summary> | |
| /// <param name="pos"> Position of data in the Byte Buffer </param> | |
| /// <param name="vtableOffset"> offset of value in the Table</param> | |
| /// <returns> Return the relative VOffset Value (Short type - 2 bytes) in calculated offset </returns> | |
| private short GetVRelOffset(int pos, short vtableOffset) | |
| { | |
| short VOffset = 0; | |
| // Used try/catch because pos typa as int 32bit | |
| try | |
| { | |
| // First, get vtable offset | |
| short vtable = Convert.ToInt16(pos - ReadSOffsetT(verifier_buffer, pos)); | |
| // Check that offset points to vtable area (is smaller than vtable size) | |
| if (vtableOffset < ReadVOffsetT(verifier_buffer, vtable)) | |
| { | |
| // Now, we can read offset value - TODO check this value against size of table data | |
| VOffset = ReadVOffsetT(verifier_buffer, vtable + vtableOffset); | |
| } | |
| else | |
| { | |
| VOffset = 0; | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| Console.WriteLine("Exception: {0}", e); | |
| return VOffset; | |
| } | |
| return VOffset; | |
| } | |
| /// <summary> Get table data area absolute offset from vtable. Result is the absolute buffer offset. | |
| /// The result value offset cannot be '0' (pointing to itself) so after validation this method returnes '0' | |
| /// value as a marker for missing optional entry </summary> | |
| /// <param name="tablePos"> Table Position value in the Byte Buffer </param> | |
| /// <param name="vtableOffset"> offset value in the Table</param> | |
| /// <returns> Return the absolute UOffset Value </returns> | |
| private uint GetVOffset(uint tablePos, short vtableOffset) | |
| { | |
| uint UOffset = 0; | |
| // First, get vtable relative offset | |
| short relPos = GetVRelOffset(Convert.ToInt32(tablePos), vtableOffset); | |
| if (relPos != 0) | |
| { | |
| // Calculate offset based on table postion | |
| UOffset = Convert.ToUInt32(tablePos + relPos); | |
| } | |
| else | |
| { | |
| UOffset = 0; | |
| } | |
| return UOffset; | |
| } | |
| /// <summary> Check flatbuffer complexity (tables depth, elements counter and so on) </summary> | |
| /// <returns> If complexity is too high function returns false as verification error </returns> | |
| private bool CheckComplexity() | |
| { | |
| return ((depth <= options.maxDepth) && (numTables <= options.maxTables)); | |
| } | |
| /// <summary> Check alignment of element. </summary> | |
| /// <returns> Return True when alignment of the element is correct</returns> | |
| private bool CheckAlignment(uint element, ulong align) | |
| { | |
| return (((element & (align - 1)) == 0) || (!options.alignmentCheck)); | |
| } | |
| /// <summary> Check if element is valid in buffer area. </summary> | |
| /// <param name="pos"> Value defines the offset/position to element</param> | |
| /// <param name="elementSize"> Size of element</param> | |
| /// <returns> Return True when Element is correct </returns> | |
| private bool CheckElement(uint pos, ulong elementSize) | |
| { | |
| return ((elementSize < Convert.ToUInt64(verifier_buffer.Length)) && (pos <= (Convert.ToUInt32(verifier_buffer.Length) - elementSize))); | |
| } | |
| /// <summary> Check if element is a valid scalar. </summary> | |
| /// <param name="pos"> Value defines the offset to scalar</param> | |
| /// <param name="elementSize"> Size of element</param> | |
| /// <returns> Return True when Scalar Element is correct </returns> | |
| private bool CheckScalar(uint pos, ulong elementSize) | |
| { | |
| return ((CheckAlignment(pos, elementSize)) && (CheckElement(pos, elementSize))); | |
| } | |
| /// <summary> Check offset. It is a scalar with size of UOffsetT. </summary> | |
| private bool CheckOffset(uint offset) | |
| { | |
| return (CheckScalar(offset, SIZE_U_OFFSET)); | |
| } | |
| private checkElementStruct CheckVectorOrString(uint pos, ulong elementSize) | |
| { | |
| var result = new checkElementStruct | |
| { | |
| elementValid = false, | |
| elementOffset = 0 | |
| }; | |
| uint vectorPos = pos; | |
| // Check we can read the vector/string size field (it is of uoffset size) | |
| if (!CheckScalar(vectorPos, SIZE_U_OFFSET)) | |
| { | |
| // result.elementValid = false; result.elementOffset = 0; | |
| return result; | |
| } | |
| // Check the whole array. If this is a string, the byte past the array | |
| // must be 0. | |
| uint size = ReadUOffsetT(verifier_buffer, vectorPos); | |
| ulong max_elements = (FLATBUFFERS_MAX_BUFFER_SIZE / elementSize); | |
| if (size >= max_elements) | |
| { | |
| // Protect against byte_size overflowing. | |
| // result.elementValid = false; result.elementOffset = 0; | |
| return result; | |
| } | |
| uint bytes_size = SIZE_U_OFFSET + (Convert.ToUInt32(elementSize) * size); | |
| uint buffer_end_pos = vectorPos + bytes_size; | |
| result.elementValid = CheckElement(vectorPos, bytes_size); | |
| result.elementOffset = buffer_end_pos; | |
| return (result); | |
| } | |
| /// <summary>Verify a string at given position.</summary> | |
| private bool CheckString(uint pos) | |
| { | |
| var result = CheckVectorOrString(pos, SIZE_BYTE); | |
| if (options.stringEndCheck) | |
| { | |
| result.elementValid = result.elementValid && CheckScalar(result.elementOffset, 1); // Must have terminator | |
| result.elementValid = result.elementValid && (verifier_buffer.GetSbyte(Convert.ToInt32(result.elementOffset)) == 0); // Terminating byte must be 0. | |
| } | |
| return result.elementValid; | |
| } | |
| /// <summary> Verify the vector of elements of given size </summary> | |
| private bool CheckVector(uint pos, ulong elementSize) | |
| { | |
| var result = CheckVectorOrString(pos, elementSize); | |
| return result.elementValid; | |
| } | |
| /// <summary> Verify table content using structure dependent generated function </summary> | |
| private bool CheckTable(uint tablePos, VerifyTableAction verifyAction) | |
| { | |
| return verifyAction(this, tablePos); | |
| } | |
| /// <summary> String check wrapper function to be used in vector of strings check </summary> | |
| private bool CheckStringFunc(Verifier verifier, uint pos) | |
| { | |
| return verifier.CheckString(pos); | |
| } | |
| /// <summary> Check vector of objects. Use generated object verification function </summary> | |
| private bool CheckVectorOfObjects(uint pos, VerifyTableAction verifyAction) | |
| { | |
| if (!CheckVector(pos, SIZE_U_OFFSET)) | |
| { | |
| return false; | |
| } | |
| uint size = ReadUOffsetT(verifier_buffer, pos); | |
| // Vector data starts just after vector size/length | |
| uint vecStart = pos + SIZE_U_OFFSET; | |
| uint vecOff = 0; | |
| // Iterate offsets and verify referenced objects | |
| for (uint i = 0; i < size; i++) | |
| { | |
| vecOff = vecStart + (i * SIZE_U_OFFSET); | |
| if (!CheckIndirectOffset(vecOff)) | |
| { | |
| return false; | |
| } | |
| uint objOffset = GetIndirectOffset(vecOff); | |
| if (!verifyAction(this, objOffset)) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /// <summary> Check if the offset referenced by offsetPos is the valid offset pointing to buffer</summary> | |
| // offsetPos - offset to offset data | |
| private bool CheckIndirectOffset(uint pos) | |
| { | |
| // Check the input offset is valid | |
| if(!CheckScalar(pos, SIZE_U_OFFSET)) | |
| { | |
| return false; | |
| } | |
| // Get indirect offset | |
| uint offset = ReadUOffsetT(verifier_buffer, pos); | |
| // May not point to itself neither wrap around (buffers are max 2GB) | |
| if ((offset == 0) || (offset >= FLATBUFFERS_MAX_BUFFER_SIZE)) | |
| { | |
| return false; | |
| } | |
| // Must be inside the buffer | |
| return CheckElement(pos + offset, 1); | |
| } | |
| /// <summary> Check flatbuffer content using generated object verification function </summary> | |
| private bool CheckBufferFromStart(string identifier, uint startPos, VerifyTableAction verifyAction) | |
| { | |
| if ((identifier != null) && | |
| (identifier.Length == 0) && | |
| ((verifier_buffer.Length < (SIZE_U_OFFSET + FILE_IDENTIFIER_LENGTH)) || (!BufferHasIdentifier(verifier_buffer, startPos, identifier)))) | |
| { | |
| return false; | |
| } | |
| if(!CheckIndirectOffset(startPos)) | |
| { | |
| return false; | |
| } | |
| uint offset = GetIndirectOffset(startPos); | |
| return CheckTable(offset, verifyAction); // && GetComputedSize() | |
| } | |
| /// <summary> Get indirect offset. It is an offset referenced by offset Pos </summary> | |
| private uint GetIndirectOffset(uint pos) | |
| { | |
| // Get indirect offset referenced by offsetPos | |
| uint offset = pos + ReadUOffsetT(verifier_buffer, pos); | |
| return offset; | |
| } | |
| /// <summary> Verify beginning of table </summary> | |
| /// <param name="tablePos"> Position in the Table </param> | |
| /// <returns> Return True when the verification of the beginning of the table is passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyTableStart(uint tablePos) | |
| { | |
| // Starting new table verification increases complexity of structure | |
| depth_cnt++; | |
| num_tables_cnt++; | |
| if (!CheckScalar(tablePos, SIZE_S_OFFSET)) | |
| { | |
| return false; | |
| } | |
| uint vtable = (uint)(tablePos - ReadSOffsetT(verifier_buffer, Convert.ToInt32(tablePos))); | |
| return ((CheckComplexity()) && (CheckScalar(vtable, SIZE_V_OFFSET)) && (CheckAlignment(Convert.ToUInt32(ReadVOffsetT(verifier_buffer, Convert.ToInt32(vtable))), SIZE_V_OFFSET)) && (CheckElement(vtable, Convert.ToUInt64(ReadVOffsetT(verifier_buffer, Convert.ToInt32(vtable)))))); | |
| } | |
| /// <summary> Verify end of table. In practice, this function does not check buffer but handles | |
| /// verification statistics update </summary> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyTableEnd(uint tablePos) | |
| { | |
| depth--; | |
| return true; | |
| } | |
| /// <summary> Verifiy static/inlined data area field </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="offsetId"> Offset to the static/inlined data element </param> | |
| /// <param name="elementSize"> Size of the element </param> | |
| /// <param name="align"> Alignment bool value </param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the static/inlined data element is passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyField(uint tablePos, short offsetId, ulong elementSize, ulong align, bool required) | |
| { | |
| uint offset = GetVOffset(tablePos, offsetId); | |
| if (offset != 0) | |
| { | |
| return ((CheckAlignment(offset, align)) && (CheckElement(offset, elementSize))); | |
| } | |
| return !required; // it is OK if field is not required | |
| } | |
| /// <summary> Verify string </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="vOffset"> Offset to the String element </param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the String is passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyString(uint tablePos, short vOffset, bool required) | |
| { | |
| var offset = GetVOffset(tablePos, vOffset); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| var strOffset = GetIndirectOffset(offset); | |
| return CheckString(strOffset); | |
| } | |
| /// <summary> Verify vector of fixed size structures and scalars </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="vOffset"> Offset to the Vector of Data </param> | |
| /// <param name="elementSize"> Size of the element</param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the Vector of Data passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyVectorOfData(uint tablePos, short vOffset, ulong elementSize, bool required) | |
| { | |
| var offset = GetVOffset(tablePos, vOffset); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| var vecOffset = GetIndirectOffset(offset); | |
| return CheckVector(vecOffset, elementSize); | |
| } | |
| /// <summary> Verify array of strings </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="offsetId"> Offset to the Vector of String </param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the Vector of String passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyVectorOfStrings(uint tablePos, short offsetId, bool required) | |
| { | |
| var offset = GetVOffset(tablePos, offsetId); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| var vecOffset = GetIndirectOffset(offset); | |
| return CheckVectorOfObjects(vecOffset, CheckStringFunc); | |
| } | |
| /// <summary> Verify vector of tables (objects). Tables are verified using generated verifyObjFunc </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="offsetId"> Offset to the Vector of Table </param> | |
| /// <param name="verifyAction"> Method used to the verification Table </param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the Vector of Table passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyVectorOfTables(uint tablePos, short offsetId, VerifyTableAction verifyAction, bool required) | |
| { | |
| var offset = GetVOffset(tablePos, offsetId); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| var vecOffset = GetIndirectOffset(offset); | |
| return CheckVectorOfObjects(vecOffset, verifyAction); | |
| } | |
| /// <summary> Verify table object using generated verification function. </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="offsetId"> Offset to the Table </param> | |
| /// <param name="verifyAction"> Method used to the verification Table </param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the Table passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyTable(uint tablePos, short offsetId, VerifyTableAction verifyAction, bool required) | |
| { | |
| var offset = GetVOffset(tablePos, offsetId); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| var tabOffset = GetIndirectOffset(offset); | |
| return CheckTable(tabOffset, verifyAction); | |
| } | |
| /// <summary> Verify nested buffer object. When verifyObjFunc is provided, it is used to verify object structure. </summary> | |
| /// <param name="tablePos"> Position in the Table </param> | |
| /// <param name="offsetId"> Offset to the Table </param> | |
| /// <param name="verifyAction"> Method used to the verification Table </param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyNestedBuffer(uint tablePos, short offsetId, VerifyTableAction verifyAction, bool required) | |
| { | |
| var offset = GetVOffset(tablePos, offsetId); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| uint vecOffset = GetIndirectOffset(offset); | |
| if (!CheckVector(vecOffset, SIZE_BYTE)) | |
| { | |
| return false; | |
| } | |
| if (verifyAction != null) | |
| { | |
| var vecLength = ReadUOffsetT(verifier_buffer, vecOffset); | |
| // Buffer begins after vector length | |
| var vecStart = vecOffset + SIZE_U_OFFSET; | |
| // Create and Copy nested buffer bytes from part of Verify Buffer | |
| var nestedByteBuffer = new ByteBuffer(verifier_buffer.ToArray(Convert.ToInt32(vecStart), Convert.ToInt32(vecLength))); | |
| var nestedVerifyier = new Verifier(nestedByteBuffer, options); | |
| // There is no internal identifier - use empty one | |
| if (!nestedVerifyier.CheckBufferFromStart("", 0, verifyAction)) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /// <summary> Verifiy static/inlined data area at absolute offset </summary> | |
| /// <param name="pos"> Position of static/inlined data area in the Byte Buffer</param> | |
| /// <param name="elementSize"> Size of the union data</param> | |
| /// <param name="align"> Alignment bool value </param> | |
| /// <returns>Return True when the verification of the Union Data is passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyUnionData(uint pos, ulong elementSize, ulong align) | |
| { | |
| bool result = ((CheckAlignment(pos, align)) && (CheckElement(pos, elementSize))); | |
| return result; | |
| } | |
| /// <summary> Verify string referenced by absolute offset value </summary> | |
| /// <param name="pos"> Position of Union String in the Byte Buffer</param> | |
| /// <returns>Return True when the verification of the Union String is passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyUnionString(uint pos) | |
| { | |
| bool result = CheckString(pos); | |
| return result; | |
| } | |
| /// <summary> Method verifies union object using generated verification function </summary> | |
| /// <param name="tablePos"> Position in the Table</param> | |
| /// <param name="typeIdVOffset"> Offset in the Table</param> | |
| /// <param name="valueVOffset"> Offset to Element</param> | |
| /// <param name="verifyAction"> Verification Method used for Union</param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyUnion(uint tablePos, short typeIdVOffset, short valueVOffset, VerifyUnionAction verifyAction, bool required) | |
| { | |
| // Check the union type index | |
| var offset = GetVOffset(tablePos, typeIdVOffset); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!((CheckAlignment(offset, SIZE_BYTE)) && (CheckElement(offset, SIZE_BYTE)))) | |
| { | |
| return false; | |
| } | |
| // Take type id | |
| var typeId = verifier_buffer.Get(Convert.ToInt32(offset)); | |
| // Check union data | |
| offset = GetVOffset(tablePos, valueVOffset); | |
| if (offset == 0) | |
| { | |
| // When value data is not present, allow union verification function to deal with illegal offset | |
| return verifyAction(this, typeId, Convert.ToUInt32(verifier_buffer.Length)); | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| // Take value offset and validate union structure | |
| uint unionOffset = GetIndirectOffset(offset); | |
| return verifyAction(this, typeId, unionOffset); | |
| } | |
| /// <summary> Verify vector of unions (objects). Unions are verified using generated verifyObjFunc </summary> | |
| /// <param name="tablePos"> Position of the Table</param> | |
| /// <param name="typeOffsetId"> Offset in the Table (Union type id)</param> | |
| /// <param name="offsetId"> Offset to vector of Data Stucture offset</param> | |
| /// <param name="verifyAction"> Verification Method used for Union</param> | |
| /// <param name="required"> Required Value when the offset == 0 </param> | |
| /// <returns>Return True when the verification of the Vector of Unions passed</returns> | |
| // (this method is used internally by generated verification functions) | |
| public bool VerifyVectorOfUnion(uint tablePos, short typeOffsetId, short offsetId, VerifyUnionAction verifyAction, bool required) | |
| { | |
| // type id offset must be valid | |
| var offset = GetVOffset(tablePos, typeOffsetId); | |
| if (offset == 0) | |
| { | |
| return !required; | |
| } | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| // Get type id table absolute offset | |
| var typeIdVectorOffset = GetIndirectOffset(offset); | |
| // values offset must be valid | |
| offset = GetVOffset(tablePos, offsetId); | |
| if (!CheckIndirectOffset(offset)) | |
| { | |
| return false; | |
| } | |
| var valueVectorOffset = GetIndirectOffset(offset); | |
| // validate referenced vectors | |
| if(!CheckVector(typeIdVectorOffset, SIZE_BYTE) || | |
| !CheckVector(valueVectorOffset, SIZE_U_OFFSET)) | |
| { | |
| return false; | |
| } | |
| // Both vectors should have the same length | |
| var typeIdVectorLength = ReadUOffsetT(verifier_buffer, typeIdVectorOffset); | |
| var valueVectorLength = ReadUOffsetT(verifier_buffer, valueVectorOffset); | |
| if (typeIdVectorLength != valueVectorLength) | |
| { | |
| return false; | |
| } | |
| // Verify each union from vectors | |
| var typeIdStart = typeIdVectorOffset + SIZE_U_OFFSET; | |
| var valueStart = valueVectorOffset + SIZE_U_OFFSET; | |
| for (uint i = 0; i < typeIdVectorLength; i++) | |
| { | |
| // Get type id | |
| byte typeId = verifier_buffer.Get(Convert.ToInt32(typeIdStart + i * SIZE_U_OFFSET)); | |
| // get offset to vector item | |
| uint off = valueStart + i * SIZE_U_OFFSET; | |
| // Check the vector item has a proper offset | |
| if (!CheckIndirectOffset(off)) | |
| { | |
| return false; | |
| } | |
| uint valueOffset = GetIndirectOffset(off); | |
| // Verify object | |
| if (!verifyAction(this, typeId, valueOffset)) | |
| { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| // Method verifies flatbuffer data using generated Table verification function. | |
| // The data buffer is already provided when creating [Verifier] object (see [NewVerifier]) | |
| // | |
| // - identifier - the expected identifier of buffer data. | |
| // When empty identifier is provided the identifier validation is skipped. | |
| // - sizePrefixed - this flag should be true when buffer is prefixed with content size | |
| // - verifyObjFunc - function to be used for verification. This function is generated by compiler and included in each table definition file with name "<Tablename>Verify" | |
| // | |
| // Example: | |
| // | |
| // /* Verify Monster table. Ignore buffer name and assume buffer does not contain data length prefix */ | |
| // isValid = verifier.verifyBuffer(bb, false, MonsterVerify) | |
| // | |
| // /* Verify Monster table. Buffer name is 'MONS' and contains data length prefix */ | |
| // isValid = verifier.verifyBuffer("MONS", true, MonsterVerify) | |
| /// <summary> Method verifies flatbuffer data using generated Table verification function </summary> | |
| /// | |
| /// <param name="identifier"> The expected identifier of buffer data</param> | |
| /// <param name="sizePrefixed"> Flag should be true when buffer is prefixed with content size</param> | |
| /// <param name="verifyAction"> Function to be used for verification. This function is generated by compiler and included in each table definition file</param> | |
| /// <returns> Return True when verification of FlatBuffer passed</returns> | |
| /// <example> | |
| /// Example 1. Verify Monster table. Ignore buffer name and assume buffer does not contain data length prefix | |
| /// <code> isValid = verifier.VerifyBuffer(bb, false, MonsterVerify)</code> | |
| /// Example 2. Verify Monster table. Buffer name is 'MONS' and contains data length prefix | |
| /// <code> isValid = verifier.VerifyBuffer("MONS", true, MonsterVerify)</code> | |
| /// </example> | |
| public bool VerifyBuffer(string identifier, bool sizePrefixed, VerifyTableAction verifyAction) | |
| { | |
| // Reset counters - starting verification from beginning | |
| depth = 0; | |
| numTables = 0; | |
| var start = (uint)(verifier_buffer.Position); | |
| if (sizePrefixed) | |
| { | |
| start = (uint)(verifier_buffer.Position) + SIZE_PREFIX_LENGTH; | |
| if(!CheckScalar((uint)(verifier_buffer.Position), SIZE_PREFIX_LENGTH)) | |
| { | |
| return false; | |
| } | |
| uint size = ReadUOffsetT(verifier_buffer, (uint)(verifier_buffer.Position)); | |
| if (size != ((uint)(verifier_buffer.Length) - start)) | |
| { | |
| return false; | |
| } | |
| } | |
| return CheckBufferFromStart(identifier, start, verifyAction); | |
| } | |
| } | |
| } |