...

Text file src/github.com/google/flatbuffers/net/FlatBuffers/FlatBufferVerify.cs

Documentation: github.com/google/flatbuffers/net/FlatBuffers

     1/*
     2 * Copyright 2014 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 */
    16using System;
    17using System.Reflection;using System.Collections.Generic;
    18using System.IO;
    19
    20namespace Google.FlatBuffers
    21{
    22
    23  /// <summary>
    24  /// The Class of the Verifier Options
    25  /// </summary>
    26  public class Options
    27  {
    28    public const int DEFAULT_MAX_DEPTH = 64;
    29    public const int DEFAULT_MAX_TABLES = 1000000;
    30
    31    private int max_depth = 0;
    32    private int max_tables = 0;
    33    private bool string_end_check = false;
    34    private bool alignment_check = false;
    35
    36    public Options()
    37    {
    38      max_depth = DEFAULT_MAX_DEPTH;
    39      max_tables = DEFAULT_MAX_TABLES;
    40      string_end_check = true;
    41      alignment_check = true;
    42    }
    43
    44    public Options(int maxDepth, int maxTables, bool stringEndCheck, bool alignmentCheck)
    45    {
    46      max_depth = maxDepth;
    47      max_tables = maxTables;
    48      string_end_check = stringEndCheck;
    49      alignment_check = alignmentCheck;
    50    }
    51    /// <summary> Maximum depth of nested tables allowed in a valid flatbuffer. </summary>
    52    public int maxDepth
    53    {
    54      get { return max_depth; }
    55      set { max_depth = value; }
    56    }
    57    /// <summary> Maximum number of tables allowed in a valid flatbuffer. </summary>
    58    public int maxTables
    59    {
    60      get { return max_tables; }
    61      set { max_tables = value; }
    62    }
    63    /// <summary> Check that string contains its null terminator </summary>
    64    public bool stringEndCheck
    65    {
    66      get { return string_end_check; }
    67      set { string_end_check = value; }
    68    }
    69    /// <summary> Check alignment of elements </summary>
    70    public bool alignmentCheck
    71    {
    72      get { return alignment_check; }
    73      set { alignment_check = value; }
    74    }
    75  }
    76
    77  public struct checkElementStruct
    78  {
    79    public bool elementValid;
    80    public uint elementOffset;
    81  }
    82
    83  public delegate bool VerifyTableAction(Verifier verifier, uint tablePos);
    84  public delegate bool VerifyUnionAction(Verifier verifier, byte typeId, uint tablePos);
    85
    86  /// <summary>
    87  /// The Main Class of the FlatBuffer Verifier
    88  /// </summary>
    89  public class Verifier
    90  {
    91    private ByteBuffer verifier_buffer = null;
    92    private Options verifier_options = null;
    93    private int depth_cnt = 0;
    94    private int num_tables_cnt = 0;
    95
    96    public const int SIZE_BYTE = 1;
    97    public const int SIZE_INT = 4;
    98    public const int SIZE_U_OFFSET = 4;
    99    public const int SIZE_S_OFFSET = 4;
   100    public const int SIZE_V_OFFSET = 2;
   101    public const int SIZE_PREFIX_LENGTH = FlatBufferConstants.SizePrefixLength;         // default size = 4
   102    public const int FLATBUFFERS_MAX_BUFFER_SIZE = System.Int32.MaxValue;               // default size = 2147483647
   103    public const int FILE_IDENTIFIER_LENGTH = FlatBufferConstants.FileIdentifierLength; // default size = 4
   104
   105    /// <summary> The Base Constructor of the Verifier object </summary>
   106    public Verifier()
   107    {
   108      // Verifier buffer
   109      verifier_buffer = null;
   110      // Verifier settings 
   111      verifier_options = null;
   112      // Depth counter
   113      depth_cnt = 0;
   114      // Tables counter
   115      num_tables_cnt = 0;
   116    }
   117
   118    /// <summary> The Constructor of the Verifier object with input parameters: ByteBuffer and/or Options </summary>
   119    /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type</param>
   120    /// <param name="options"> Options object with settings for the coniguration the Verifier </param>
   121    public Verifier(ByteBuffer buf, Options options = null)
   122    {
   123      verifier_buffer = buf;
   124      verifier_options = options ?? new Options();
   125      depth_cnt = 0;
   126      num_tables_cnt = 0;
   127    }
   128
   129    /// <summary> Bytes Buffer for Verify</summary>
   130    public ByteBuffer Buf
   131    {
   132      get { return verifier_buffer; }
   133      set { verifier_buffer = value; }
   134    }
   135    /// <summary> Options of the Verifier </summary>
   136    public Options options
   137    {
   138      get { return verifier_options; }
   139      set { verifier_options = value; }
   140    }
   141    /// <summary> Counter of tables depth in a tested flatbuffer  </summary>
   142    public int depth
   143    {
   144      get { return depth_cnt; }
   145      set { depth_cnt = value; }
   146    }
   147    /// <summary> Counter of tables in a tested flatbuffer </summary>
   148    public int numTables
   149    {
   150      get { return num_tables_cnt; }
   151      set { num_tables_cnt = value; }
   152    }
   153
   154
   155    /// <summary> Method set maximum tables depth of valid structure</summary>
   156    /// <param name="value"> Specify Value of the maximum depth of the structure</param>
   157    public Verifier SetMaxDepth(int value)
   158    {
   159      verifier_options.maxDepth = value;
   160      return this;
   161    }
   162    /// <summary> Specify maximum number of tables in structure </summary>
   163    /// <param name="value"> Specify Value of the maximum number of the tables in the structure</param>
   164    public Verifier SetMaxTables(int value)
   165    {
   166      verifier_options.maxTables = value;
   167      return this;
   168    }
   169    /// <summary> Enable/disable buffer content alignment check </summary>
   170    /// <param name="value"> Value of the State for buffer content alignment check (Enable = true) </param>
   171    public Verifier SetAlignmentCheck(bool value)
   172    {
   173      verifier_options.alignmentCheck = value;
   174      return this;
   175    }
   176    /// <summary> Enable/disable checking of string termination '0' character </summary>
   177    /// <param name="value"> Value of the option for string termination '0' character check (Enable = true)</param>
   178    public Verifier SetStringCheck(bool value)
   179    {
   180      verifier_options.stringEndCheck = value;
   181      return this;
   182    }
   183
   184    /// <summary> Check if there is identifier in buffer </summary>
   185    /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param>
   186    /// <param name="startPos">Start position of data in the Byte Buffer</param>
   187    /// <param name="identifier"> Identifier for the Byte Buffer</param>
   188    /// <returns> Return True when the Byte Buffer Identifier is present</returns>
   189    private bool BufferHasIdentifier(ByteBuffer buf, uint startPos, string identifier)
   190    {
   191      if (identifier.Length != FILE_IDENTIFIER_LENGTH)
   192      {
   193        throw new ArgumentException("FlatBuffers: file identifier must be length" + Convert.ToString(FILE_IDENTIFIER_LENGTH));
   194      }
   195      for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++)
   196      {
   197        if ((sbyte)identifier[i] != verifier_buffer.GetSbyte(Convert.ToInt32(SIZE_S_OFFSET + i + startPos)))
   198        {
   199          return false;
   200        }
   201      }
   202
   203      return true;
   204    }
   205
   206    /// <summary> Get UOffsetT from buffer at given position - it must be verified before read </summary>
   207    /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param>
   208    /// <param name="pos"> Position of data in the Byte Buffer</param>
   209    /// <returns> Return the UOffset Value (Unsigned Integer type - 4 bytes) in pos </returns>
   210    private uint ReadUOffsetT(ByteBuffer buf, uint pos)
   211    {
   212      return buf.GetUint(Convert.ToInt32(pos));
   213    }
   214    /// <summary> Get SOffsetT from buffer at given position - it must be verified before read </summary>
   215    /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param>
   216    /// <param name="pos"> Position of data in the Byte Buffer</param>
   217    /// <returns> Return the SOffset Value (Signed Integer type - 4 bytes) in pos </returns>
   218    private int ReadSOffsetT(ByteBuffer buf, int pos)
   219    {
   220      return buf.GetInt(pos);
   221    }
   222    /// <summary> Get VOffsetT from buffer at given position - it must be verified before read </summary>
   223    /// <param name="buf"> Input flat byte buffer defined as ByteBuffer type </param>
   224    /// <param name="pos"> Position of data in the Byte Buffer</param>
   225    /// <returns> Return the VOffset Value (Short type - 2 bytes) in pos </returns>
   226    private short ReadVOffsetT(ByteBuffer buf, int pos)
   227    {
   228      return buf.GetShort(pos);
   229    }
   230
   231    /// <summary> Get table data area relative offset from vtable. Result is relative to table start
   232    ///           Fields which are deprecated are ignored by checking against the vtable's length. </summary>
   233    /// <param name="pos"> Position of data in the Byte Buffer </param>
   234    /// <param name="vtableOffset"> offset of value in the Table</param>
   235    /// <returns> Return the relative VOffset Value (Short type - 2 bytes) in calculated offset </returns>
   236    private short GetVRelOffset(int pos, short vtableOffset)
   237    {
   238      short VOffset = 0;
   239      // Used try/catch because pos typa as int 32bit
   240      try
   241      {
   242        // First, get vtable offset
   243        short vtable = Convert.ToInt16(pos - ReadSOffsetT(verifier_buffer, pos));
   244        // Check that offset points to vtable area (is smaller than vtable size)
   245        if (vtableOffset < ReadVOffsetT(verifier_buffer, vtable))
   246        {
   247          // Now, we can read offset value - TODO check this value against size of table data
   248          VOffset = ReadVOffsetT(verifier_buffer, vtable + vtableOffset);
   249        }
   250        else
   251        {
   252          VOffset = 0;
   253        }
   254      }
   255      catch (Exception e)
   256      {
   257        Console.WriteLine("Exception: {0}", e);
   258        return VOffset;
   259      }
   260      return VOffset;
   261
   262    }
   263    /// <summary> Get table data area absolute offset from vtable. Result is the absolute buffer offset.
   264    /// The result value offset cannot be '0' (pointing to itself) so after validation this method returnes '0'
   265    /// value as a marker for missing optional entry </summary>
   266    /// <param name="tablePos"> Table Position value in the Byte Buffer </param>
   267    /// <param name="vtableOffset"> offset value in the Table</param>
   268    /// <returns> Return the absolute UOffset Value </returns>
   269    private uint GetVOffset(uint tablePos, short vtableOffset)
   270    {
   271      uint UOffset = 0;
   272      // First, get vtable relative offset
   273      short relPos = GetVRelOffset(Convert.ToInt32(tablePos), vtableOffset);
   274      if (relPos != 0)
   275      {
   276        // Calculate offset based on table postion
   277        UOffset = Convert.ToUInt32(tablePos + relPos);
   278      }
   279      else
   280      {
   281        UOffset = 0;
   282      }
   283      return UOffset;
   284    }
   285
   286    /// <summary> Check flatbuffer complexity (tables depth, elements counter and so on) </summary>
   287    /// <returns> If complexity is too high function returns false as verification error </returns>
   288    private bool CheckComplexity()
   289    {
   290      return ((depth <= options.maxDepth) && (numTables <= options.maxTables));
   291    }
   292
   293    /// <summary> Check alignment of element. </summary>
   294    /// <returns> Return True when alignment of the element is correct</returns>
   295    private bool CheckAlignment(uint element, ulong align)
   296    {
   297      return (((element & (align - 1)) == 0) || (!options.alignmentCheck));
   298    }
   299
   300    /// <summary> Check if element is valid in buffer area. </summary> 
   301    /// <param name="pos"> Value defines the offset/position to element</param>
   302    /// <param name="elementSize"> Size of element</param>
   303    /// <returns> Return True when Element is correct </returns>
   304    private bool CheckElement(uint pos, ulong elementSize)
   305    {
   306      return ((elementSize < Convert.ToUInt64(verifier_buffer.Length)) && (pos <= (Convert.ToUInt32(verifier_buffer.Length) - elementSize)));
   307    }
   308    /// <summary> Check if element is a valid scalar. </summary>
   309    /// <param name="pos"> Value defines the offset to scalar</param>
   310    /// <param name="elementSize"> Size of element</param>
   311    /// <returns> Return True when Scalar Element is correct </returns>
   312    private bool CheckScalar(uint pos, ulong elementSize)
   313    {
   314      return ((CheckAlignment(pos, elementSize)) && (CheckElement(pos, elementSize)));
   315    }
   316    /// <summary> Check offset. It is a scalar with size of UOffsetT. </summary>
   317    private bool CheckOffset(uint offset)
   318    {
   319      return (CheckScalar(offset, SIZE_U_OFFSET));
   320    }
   321
   322    private checkElementStruct CheckVectorOrString(uint pos, ulong elementSize)
   323    {
   324      var result = new checkElementStruct
   325      {
   326        elementValid = false,
   327        elementOffset = 0
   328      };
   329
   330      uint vectorPos = pos;
   331      // Check we can read the vector/string size field (it is of uoffset size)
   332      if (!CheckScalar(vectorPos, SIZE_U_OFFSET))
   333      {
   334        // result.elementValid = false; result.elementOffset = 0;
   335        return result;
   336      }
   337      // Check the whole array. If this is a string, the byte past the array
   338      // must be 0.
   339      uint size = ReadUOffsetT(verifier_buffer, vectorPos);
   340      ulong max_elements = (FLATBUFFERS_MAX_BUFFER_SIZE / elementSize);
   341      if (size >= max_elements)
   342      {
   343        // Protect against byte_size overflowing. 
   344        // result.elementValid = false; result.elementOffset = 0;
   345        return result;
   346      }
   347
   348      uint bytes_size = SIZE_U_OFFSET + (Convert.ToUInt32(elementSize) * size);
   349      uint buffer_end_pos = vectorPos + bytes_size;
   350      result.elementValid = CheckElement(vectorPos, bytes_size);
   351      result.elementOffset = buffer_end_pos;
   352      return (result);
   353    }
   354
   355    /// <summary>Verify a string at given position.</summary>
   356    private bool CheckString(uint pos)
   357    {
   358      var result = CheckVectorOrString(pos, SIZE_BYTE);
   359      if (options.stringEndCheck)
   360      {
   361        result.elementValid = result.elementValid && CheckScalar(result.elementOffset, 1); // Must have terminator
   362        result.elementValid = result.elementValid && (verifier_buffer.GetSbyte(Convert.ToInt32(result.elementOffset)) == 0); // Terminating byte must be 0.
   363      }
   364      return result.elementValid;
   365    }
   366
   367    /// <summary> Verify the vector of elements of given size </summary>
   368    private bool CheckVector(uint pos, ulong elementSize)
   369    {
   370      var result = CheckVectorOrString(pos, elementSize);
   371      return result.elementValid;
   372    }
   373    /// <summary> Verify table content using structure dependent generated function </summary>
   374    private bool CheckTable(uint tablePos, VerifyTableAction verifyAction)
   375    {
   376      return verifyAction(this, tablePos);
   377    }
   378
   379    /// <summary> String check wrapper function to be used in vector of strings check </summary>
   380    private bool CheckStringFunc(Verifier verifier, uint pos)
   381    {
   382      return verifier.CheckString(pos);
   383    }
   384
   385    /// <summary> Check vector of objects. Use generated object verification function </summary>
   386    private bool CheckVectorOfObjects(uint pos, VerifyTableAction verifyAction)
   387    {
   388      if (!CheckVector(pos, SIZE_U_OFFSET))
   389      {
   390        return false;
   391      }
   392      uint size = ReadUOffsetT(verifier_buffer, pos);
   393      // Vector data starts just after vector size/length
   394      uint vecStart = pos + SIZE_U_OFFSET;
   395      uint vecOff = 0;
   396      // Iterate offsets and verify referenced objects
   397      for (uint i = 0; i < size; i++)
   398      {
   399        vecOff = vecStart + (i * SIZE_U_OFFSET);
   400        if (!CheckIndirectOffset(vecOff))
   401        {
   402          return false;
   403        }
   404        uint objOffset = GetIndirectOffset(vecOff);
   405        if (!verifyAction(this, objOffset))
   406        {
   407          return false;
   408        }
   409      }
   410      return true;
   411    }
   412
   413    /// <summary> Check if the offset referenced by offsetPos is the valid offset pointing to buffer</summary>
   414    //  offsetPos - offset to offset data
   415    private bool CheckIndirectOffset(uint pos)
   416    {
   417      // Check the input offset is valid
   418      if(!CheckScalar(pos, SIZE_U_OFFSET))
   419      {
   420        return false;
   421      }
   422      // Get indirect offset
   423      uint offset = ReadUOffsetT(verifier_buffer, pos);
   424      // May not point to itself neither wrap around  (buffers are max 2GB)
   425      if ((offset == 0) || (offset >= FLATBUFFERS_MAX_BUFFER_SIZE))
   426      {
   427        return false;
   428      }
   429      // Must be inside the buffer
   430      return CheckElement(pos + offset, 1);
   431    }
   432
   433    /// <summary> Check flatbuffer content using generated object verification function </summary>
   434    private bool CheckBufferFromStart(string identifier, uint startPos, VerifyTableAction verifyAction)
   435    {
   436      if ((identifier != null) &&
   437          (identifier.Length == 0) &&
   438          ((verifier_buffer.Length < (SIZE_U_OFFSET + FILE_IDENTIFIER_LENGTH)) || (!BufferHasIdentifier(verifier_buffer, startPos, identifier))))
   439      {
   440        return false;
   441      }
   442      if(!CheckIndirectOffset(startPos))
   443      {
   444        return false;
   445      }
   446      uint offset = GetIndirectOffset(startPos);
   447      return CheckTable(offset, verifyAction); //  && GetComputedSize()
   448    }
   449
   450    /// <summary> Get indirect offset. It is an offset referenced by offset Pos </summary>
   451    private uint GetIndirectOffset(uint pos)
   452    {
   453      // Get indirect offset referenced by offsetPos
   454      uint offset = pos + ReadUOffsetT(verifier_buffer, pos);
   455      return offset;
   456    }
   457
   458    /// <summary> Verify beginning of table </summary>
   459    /// <param name="tablePos"> Position in the Table </param>
   460    /// <returns> Return True when the verification of the beginning of the table is passed</returns> 
   461    // (this method is used internally by generated verification functions)
   462    public bool VerifyTableStart(uint tablePos)
   463    {
   464      // Starting new table verification increases complexity of structure
   465      depth_cnt++;
   466      num_tables_cnt++;
   467
   468      if (!CheckScalar(tablePos, SIZE_S_OFFSET))
   469      {
   470        return false;
   471      }
   472      uint vtable = (uint)(tablePos - ReadSOffsetT(verifier_buffer, Convert.ToInt32(tablePos)));
   473      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))))));
   474    }
   475
   476    /// <summary> Verify end of table. In practice, this function does not check buffer but handles
   477    /// verification statistics update </summary>
   478    // (this method is used internally by generated verification functions)
   479    public bool VerifyTableEnd(uint tablePos)
   480    {
   481      depth--;
   482      return true;
   483    }
   484
   485    /// <summary> Verifiy static/inlined data area field </summary>
   486    /// <param name="tablePos"> Position in the Table</param>
   487    /// <param name="offsetId"> Offset to the static/inlined data element </param>
   488    /// <param name="elementSize"> Size of the element </param>
   489    /// <param name="align"> Alignment bool value </param>
   490    /// <param name="required"> Required Value when the offset == 0 </param>
   491    /// <returns>Return True when the verification of the static/inlined data element is passed</returns>
   492    // (this method is used internally by generated verification functions)
   493    public bool VerifyField(uint tablePos, short offsetId, ulong elementSize, ulong align, bool required)
   494    {
   495      uint offset = GetVOffset(tablePos, offsetId);
   496      if (offset != 0)
   497      {
   498        return ((CheckAlignment(offset, align)) && (CheckElement(offset, elementSize)));
   499      }
   500      return !required; // it is OK if field is not required
   501    }
   502
   503    /// <summary> Verify string </summary> 
   504    /// <param name="tablePos"> Position in the Table</param>
   505    /// <param name="vOffset"> Offset to the String element </param>
   506    /// <param name="required"> Required Value when the offset == 0 </param>
   507    /// <returns>Return True when the verification of the String is passed</returns>
   508    // (this method is used internally by generated verification functions)
   509    public bool VerifyString(uint tablePos, short vOffset, bool required)
   510    {
   511      var offset = GetVOffset(tablePos, vOffset);
   512      if (offset == 0)
   513      {
   514        return !required;
   515      }
   516      if (!CheckIndirectOffset(offset))
   517      {
   518        return false;
   519      }
   520      var strOffset = GetIndirectOffset(offset);
   521      return CheckString(strOffset);
   522    }
   523
   524    /// <summary> Verify vector of fixed size structures and scalars </summary>
   525    /// <param name="tablePos"> Position in the Table</param>
   526    /// <param name="vOffset"> Offset to the Vector of Data </param>
   527    /// <param name="elementSize"> Size of the element</param>
   528    /// <param name="required"> Required Value when the offset == 0 </param>
   529    /// <returns>Return True when the verification of the Vector of Data passed</returns>
   530    // (this method is used internally by generated verification functions)
   531    public bool VerifyVectorOfData(uint tablePos, short vOffset, ulong elementSize, bool required)
   532    {
   533      var offset = GetVOffset(tablePos, vOffset);
   534      if (offset == 0)
   535      {
   536        return !required;
   537      }
   538      if (!CheckIndirectOffset(offset))
   539      {
   540        return false;
   541      }
   542      var vecOffset = GetIndirectOffset(offset);
   543      return  CheckVector(vecOffset, elementSize);
   544    }
   545
   546    /// <summary> Verify array of strings </summary>
   547    /// <param name="tablePos"> Position in the Table</param>
   548    /// <param name="offsetId"> Offset to the Vector of String </param>
   549    /// <param name="required"> Required Value when the offset == 0 </param>
   550    /// <returns>Return True when the verification of the Vector of String passed</returns>
   551    // (this method is used internally by generated verification functions)
   552    public bool VerifyVectorOfStrings(uint tablePos, short offsetId, bool required)
   553    {
   554      var offset = GetVOffset(tablePos, offsetId);
   555      if (offset == 0)
   556      {
   557        return !required;
   558      }
   559      if (!CheckIndirectOffset(offset))
   560      {
   561        return false;
   562      }
   563      var vecOffset = GetIndirectOffset(offset);
   564      return CheckVectorOfObjects(vecOffset, CheckStringFunc); 
   565    }
   566
   567    /// <summary> Verify vector of tables (objects). Tables are verified using generated verifyObjFunc </summary>
   568    /// <param name="tablePos"> Position in the Table</param>
   569    /// <param name="offsetId"> Offset to the Vector of Table </param>
   570    /// <param name="verifyAction"> Method used to the verification Table </param>
   571    /// <param name="required"> Required Value when the offset == 0 </param>
   572    /// <returns>Return True when the verification of the Vector of Table passed</returns>
   573    // (this method is used internally by generated verification functions)
   574    public bool VerifyVectorOfTables(uint tablePos, short offsetId, VerifyTableAction verifyAction, bool required)
   575    {
   576      var offset = GetVOffset(tablePos, offsetId);
   577      if (offset == 0)
   578      {
   579        return !required;
   580      }
   581      if (!CheckIndirectOffset(offset))
   582      {
   583        return false;
   584      }
   585      var vecOffset = GetIndirectOffset(offset);
   586      return CheckVectorOfObjects(vecOffset, verifyAction);
   587    }
   588
   589    /// <summary> Verify table object using generated verification function. </summary>
   590    /// <param name="tablePos"> Position in the Table</param>
   591    /// <param name="offsetId"> Offset to the Table </param>
   592    /// <param name="verifyAction"> Method used to the verification Table </param>
   593    /// <param name="required"> Required Value when the offset == 0 </param>
   594    /// <returns>Return True when the verification of the Table passed</returns>
   595    // (this method is used internally by generated verification functions)
   596    public bool VerifyTable(uint tablePos, short offsetId, VerifyTableAction verifyAction, bool required)
   597    {
   598      var offset = GetVOffset(tablePos, offsetId);
   599      if (offset == 0)
   600      {
   601        return !required;
   602      }
   603      if (!CheckIndirectOffset(offset))
   604      {
   605        return false;
   606      }
   607      var tabOffset = GetIndirectOffset(offset);
   608      return CheckTable(tabOffset, verifyAction);
   609    }
   610
   611    /// <summary> Verify nested buffer object. When verifyObjFunc is provided, it is used to verify object structure. </summary>
   612    /// <param name="tablePos"> Position in the Table </param>
   613    /// <param name="offsetId"> Offset to the Table </param>
   614    /// <param name="verifyAction">  Method used to the verification Table </param>
   615    /// <param name="required"> Required Value when the offset == 0  </param>
   616    // (this method is used internally by generated verification functions)
   617    public bool VerifyNestedBuffer(uint tablePos, short offsetId, VerifyTableAction verifyAction, bool required)
   618    {
   619      var offset = GetVOffset(tablePos, offsetId);
   620      if (offset == 0)
   621      {
   622        return !required;
   623      }
   624      uint vecOffset = GetIndirectOffset(offset);
   625      if (!CheckVector(vecOffset, SIZE_BYTE))
   626      {
   627        return false;
   628      }
   629      if (verifyAction != null)
   630      {
   631        var vecLength = ReadUOffsetT(verifier_buffer, vecOffset);
   632        // Buffer begins after vector length
   633        var vecStart = vecOffset + SIZE_U_OFFSET;
   634        // Create and Copy nested buffer bytes from part of Verify Buffer
   635        var nestedByteBuffer = new ByteBuffer(verifier_buffer.ToArray(Convert.ToInt32(vecStart), Convert.ToInt32(vecLength)));
   636        var nestedVerifyier = new Verifier(nestedByteBuffer, options);
   637        // There is no internal identifier - use empty one
   638        if (!nestedVerifyier.CheckBufferFromStart("", 0, verifyAction))
   639        {
   640          return false;
   641        }
   642      }
   643      return true;
   644    }
   645
   646    /// <summary> Verifiy static/inlined data area at absolute offset </summary>
   647    /// <param name="pos"> Position of static/inlined data area in the Byte Buffer</param>
   648    /// <param name="elementSize"> Size of the union data</param>
   649    /// <param name="align"> Alignment bool value </param>
   650    /// <returns>Return True when the verification of the Union Data is passed</returns>
   651    // (this method is used internally by generated verification functions)
   652    public bool VerifyUnionData(uint pos, ulong elementSize, ulong align)
   653    {
   654      bool result = ((CheckAlignment(pos, align)) && (CheckElement(pos, elementSize)));
   655      return result;
   656    }
   657
   658    /// <summary> Verify string referenced by absolute offset value </summary>
   659    /// <param name="pos"> Position of Union String in the Byte Buffer</param>
   660    /// <returns>Return True when the verification of the Union String is passed</returns> 
   661    // (this method is used internally by generated verification functions)
   662    public bool VerifyUnionString(uint pos)
   663    {
   664      bool result = CheckString(pos);
   665      return result;
   666    }
   667
   668    /// <summary> Method verifies union object using generated verification function </summary>
   669    /// <param name="tablePos"> Position in the Table</param>
   670    /// <param name="typeIdVOffset"> Offset in the Table</param>
   671    /// <param name="valueVOffset"> Offset to Element</param>
   672    /// <param name="verifyAction"> Verification Method used for Union</param>
   673    /// <param name="required"> Required Value when the offset == 0 </param>
   674    // (this method is used internally by generated verification functions)
   675    public bool VerifyUnion(uint tablePos, short typeIdVOffset, short valueVOffset, VerifyUnionAction verifyAction, bool required)
   676    {
   677      // Check the union type index
   678      var offset = GetVOffset(tablePos, typeIdVOffset);
   679      if (offset == 0)
   680      {
   681        return !required;
   682      }
   683      if (!((CheckAlignment(offset, SIZE_BYTE)) && (CheckElement(offset, SIZE_BYTE))))
   684      {
   685        return false;
   686      }
   687      // Check union data
   688      offset = GetVOffset(tablePos, valueVOffset);
   689      // Take type id
   690      var typeId = verifier_buffer.Get(Convert.ToInt32(offset));
   691      if (offset == 0)
   692      {
   693        // When value data is not present, allow union verification function to deal with illegal offset
   694        return verifyAction(this, typeId, Convert.ToUInt32(verifier_buffer.Length));
   695      }
   696      if (!CheckIndirectOffset(offset))
   697      {
   698        return false;
   699      }
   700      // Take value offset and validate union structure
   701      uint unionOffset = GetIndirectOffset(offset);
   702      return verifyAction(this, typeId, unionOffset);
   703    }
   704
   705    /// <summary> Verify vector of unions (objects). Unions are verified using generated verifyObjFunc </summary>
   706    /// <param name="tablePos"> Position of the Table</param>
   707    /// <param name="typeOffsetId"> Offset in the Table (Union type id)</param>
   708    /// <param name="offsetId"> Offset to vector of Data Stucture offset</param>
   709    /// <param name="verifyAction"> Verification Method used for Union</param>
   710    /// <param name="required"> Required Value when the offset == 0 </param>
   711    /// <returns>Return True when the verification of the Vector of Unions passed</returns>
   712    // (this method is used internally by generated verification functions)
   713    public bool VerifyVectorOfUnion(uint tablePos, short typeOffsetId, short offsetId, VerifyUnionAction verifyAction, bool required)
   714    {
   715      // type id offset must be valid
   716      var offset = GetVOffset(tablePos, typeOffsetId);
   717      if (offset == 0)
   718      {
   719        return !required;
   720      }
   721      if (!CheckIndirectOffset(offset))
   722      {
   723        return false;
   724      }
   725      // Get type id table absolute offset
   726      var typeIdVectorOffset = GetIndirectOffset(offset);
   727      // values offset must be valid
   728      offset = GetVOffset(tablePos, offsetId);
   729      if (!CheckIndirectOffset(offset))
   730      {
   731        return false;
   732      }
   733      var valueVectorOffset = GetIndirectOffset(offset);
   734      // validate referenced vectors
   735      if(!CheckVector(typeIdVectorOffset, SIZE_BYTE) ||
   736         !CheckVector(valueVectorOffset, SIZE_U_OFFSET))
   737      {
   738        return false;
   739      }
   740      // Both vectors should have the same length
   741      var typeIdVectorLength = ReadUOffsetT(verifier_buffer, typeIdVectorOffset);
   742      var valueVectorLength = ReadUOffsetT(verifier_buffer, valueVectorOffset);
   743      if (typeIdVectorLength != valueVectorLength)
   744      {
   745        return false;
   746      }
   747      // Verify each union from vectors
   748      var typeIdStart = typeIdVectorOffset + SIZE_U_OFFSET;
   749      var valueStart = valueVectorOffset + SIZE_U_OFFSET;
   750      for (uint i = 0; i < typeIdVectorLength; i++)
   751      {
   752        // Get type id
   753        byte typeId = verifier_buffer.Get(Convert.ToInt32(typeIdStart + i * SIZE_U_OFFSET));
   754        // get offset to vector item
   755        uint off = valueStart + i * SIZE_U_OFFSET;
   756        // Check the vector item has a proper offset
   757        if (!CheckIndirectOffset(off))
   758        {
   759          return false;
   760        }
   761        uint valueOffset = GetIndirectOffset(off);
   762        // Verify object
   763        if (!verifyAction(this, typeId, valueOffset))
   764        {
   765          return false;
   766        }
   767      }
   768      return true;
   769    }
   770
   771    // Method verifies flatbuffer data using generated Table verification function.
   772    // The data buffer is already provided when creating [Verifier] object (see [NewVerifier])
   773    //
   774    //   - identifier - the expected identifier of buffer data.
   775    //     When empty identifier is provided the identifier validation is skipped.
   776    //   - sizePrefixed - this flag should be true when buffer is prefixed with content size
   777    //   - verifyObjFunc - function to be used for verification. This function is generated by compiler and included in each table definition file with name "<Tablename>Verify"
   778    //
   779    // Example:
   780    //
   781    //  /* Verify Monster table. Ignore buffer name and assume buffer does not contain data length prefix */
   782    //  isValid = verifier.verifyBuffer(bb, false, MonsterVerify)
   783    //
   784    //  /* Verify Monster table. Buffer name is 'MONS' and contains data length prefix */
   785    //  isValid = verifier.verifyBuffer("MONS", true, MonsterVerify)
   786    /// <summary> Method verifies flatbuffer data using generated Table verification function </summary>
   787    /// 
   788    /// <param name="identifier"> The expected identifier of buffer data</param>
   789    /// <param name="sizePrefixed"> Flag should be true when buffer is prefixed with content size</param>
   790    /// <param name="verifyAction"> Function to be used for verification. This function is generated by compiler and included in each table definition file</param>
   791    /// <returns> Return True when verification of FlatBuffer passed</returns>
   792    /// <example>
   793    /// Example 1. Verify Monster table. Ignore buffer name and assume buffer does not contain data length prefix 
   794    /// <code>  isValid = verifier.VerifyBuffer(bb, false, MonsterVerify)</code>
   795    /// Example 2. Verify Monster table. Buffer name is 'MONS' and contains data length prefix 
   796    /// <code>  isValid = verifier.VerifyBuffer("MONS", true, MonsterVerify)</code>
   797    /// </example>
   798    public bool VerifyBuffer(string identifier, bool sizePrefixed, VerifyTableAction verifyAction)
   799    {
   800      // Reset counters - starting verification from beginning
   801      depth = 0;
   802      numTables = 0;
   803
   804      var start = (uint)(verifier_buffer.Position);
   805      if (sizePrefixed) 
   806      {
   807        start = (uint)(verifier_buffer.Position) + SIZE_PREFIX_LENGTH;
   808        if(!CheckScalar((uint)(verifier_buffer.Position), SIZE_PREFIX_LENGTH))
   809        {
   810          return false;
   811        }
   812        uint size = ReadUOffsetT(verifier_buffer, (uint)(verifier_buffer.Position));
   813        if (size != ((uint)(verifier_buffer.Length) - start))
   814        {
   815          return false;
   816        }
   817      } 
   818      return CheckBufferFromStart(identifier, start, verifyAction);
   819    }
   820  }
   821
   822}

View as plain text