...

Text file src/github.com/google/flatbuffers/php/FlatbufferBuilder.php

Documentation: github.com/google/flatbuffers/php

     1<?php
     2/*
     3 * Copyright 2015 Google Inc.
     4 *
     5 * Licensed under the Apache License, Version 2.0 (the "License");
     6 * you may not use this file except in compliance with the License.
     7 * You may obtain a copy of the License at
     8 *
     9 *     http://www.apache.org/licenses/LICENSE-2.0
    10 *
    11 * Unless required by applicable law or agreed to in writing, software
    12 * distributed under the License is distributed on an "AS IS" BASIS,
    13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14 * See the License for the specific language governing permissions and
    15 * limitations under the License.
    16 */
    17
    18/// @file
    19/// @addtogroup flatbuffers_php_api
    20/// @{
    21
    22namespace Google\FlatBuffers;
    23
    24final class FlatbufferBuilder
    25{
    26    /**
    27     * Internal ByteBuffer for the FlatBuffer data.
    28     * @var ByteBuffer $bb
    29     */
    30    public $bb;
    31
    32    /// @cond FLATBUFFERS_INTERNAL
    33    /**
    34     * @var int $space
    35     */
    36    protected $space;
    37
    38    /**
    39     * @var int $minalign
    40     */
    41    protected $minalign = 1;
    42
    43    /**
    44     * @var array $vtable
    45     */
    46    protected $vtable;
    47
    48    /**
    49     * @var int $vtable_in_use
    50     */
    51    protected $vtable_in_use = 0;
    52
    53    /**
    54     * @var bool $nested
    55     */
    56    protected $nested = false;
    57
    58    /**
    59     * @var int $object_start
    60     */
    61    protected $object_start;
    62
    63    /**
    64     * @var array $vtables
    65     */
    66    protected $vtables = array();
    67
    68    /**
    69     * @var int $num_vtables
    70     */
    71    protected $num_vtables = 0;
    72
    73    /**
    74     * @var int $vector_num_elems
    75     */
    76    protected $vector_num_elems = 0;
    77
    78    /**
    79     * @var bool $force_defaults
    80     */
    81    protected $force_defaults = false;
    82    /// @endcond
    83
    84    /**
    85     * Create a FlatBufferBuilder with a given initial size.
    86     *
    87     * @param $initial_size initial byte buffer size.
    88     */
    89    public function __construct($initial_size)
    90    {
    91        if ($initial_size <= 0) {
    92            $initial_size = 1;
    93        }
    94        $this->space = $initial_size;
    95        $this->bb = $this->newByteBuffer($initial_size);
    96    }
    97
    98    /// @cond FLATBUFFERS_INTERNAL
    99    /**
   100     * create new bytebuffer
   101     *
   102     * @param $size
   103     * @return ByteBuffer
   104     */
   105    private function newByteBuffer($size)
   106    {
   107        return new ByteBuffer($size);
   108    }
   109
   110    /**
   111     * Returns the current ByteBuffer offset.
   112     *
   113     * @return int
   114     */
   115    public function offset()
   116    {
   117        return $this->bb->capacity() - $this->space;
   118    }
   119
   120    /**
   121     * padding buffer
   122     *
   123     * @param $byte_size
   124     */
   125    public function pad($byte_size)
   126    {
   127        for ($i = 0; $i < $byte_size; $i++) {
   128            $this->bb->putByte(--$this->space, "\0");
   129        }
   130    }
   131
   132    /**
   133     * prepare bytebuffer
   134     *
   135     * @param $size
   136     * @param $additional_bytes
   137     * @throws \Exception
   138     */
   139    public function prep($size, $additional_bytes)
   140    {
   141        if ($size > $this->minalign) {
   142            $this->minalign = $size;
   143        }
   144
   145        $align_size = ((~($this->bb->capacity() - $this->space + $additional_bytes)) + 1) & ($size - 1);
   146        while ($this->space < $align_size + $size  + $additional_bytes) {
   147            $old_buf_size = $this->bb->capacity();
   148            $this->bb = $this->growByteBuffer($this->bb);
   149            $this->space += $this->bb->capacity() - $old_buf_size;
   150        }
   151
   152        $this->pad($align_size);
   153    }
   154
   155    /**
   156     * @param ByteBuffer $bb
   157     * @return ByteBuffer
   158     * @throws \Exception
   159     */
   160    private static function growByteBuffer(ByteBuffer $bb)
   161    {
   162        $old_buf_size = $bb->capacity();
   163        if (($old_buf_size & 0xC0000000) != 0) {
   164            throw new \Exception("FlatBuffers: cannot grow buffer beyond 2 gigabytes");
   165        }
   166        $new_buf_size = $old_buf_size << 1;
   167
   168        $bb->setPosition(0);
   169        $nbb = new ByteBuffer($new_buf_size);
   170
   171        $nbb->setPosition($new_buf_size - $old_buf_size);
   172
   173        // TODO(chobie): is this little bit faster?
   174        //$nbb->_buffer = substr_replace($nbb->_buffer, $bb->_buffer, $new_buf_size - $old_buf_size, strlen($bb->_buffer));
   175        for ($i = $new_buf_size - $old_buf_size, $j = 0; $j < strlen($bb->_buffer); $i++, $j++) {
   176            $nbb->_buffer[$i] = $bb->_buffer[$j];
   177        }
   178
   179        return $nbb;
   180    }
   181
   182    /**
   183     * @param $x
   184     */
   185    public function putBool($x)
   186    {
   187        $this->bb->put($this->space -= 1, chr((int)(bool)($x)));
   188    }
   189
   190    /**
   191     * @param $x
   192     */
   193    public function putByte($x)
   194    {
   195        $this->bb->put($this->space -= 1, chr($x));
   196    }
   197
   198    /**
   199     * @param $x
   200     */
   201    public function putSbyte($x)
   202    {
   203        $this->bb->put($this->space -= 1, chr($x));
   204    }
   205
   206    /**
   207     * @param $x
   208     */
   209    public function putShort($x)
   210    {
   211        $this->bb->putShort($this->space -= 2, $x);
   212    }
   213
   214    /**
   215     * @param $x
   216     */
   217    public function putUshort($x)
   218    {
   219        $this->bb->putUshort($this->space -= 2, $x);
   220    }
   221
   222    /**
   223     * @param $x
   224     */
   225    public function putInt($x)
   226    {
   227        $this->bb->putInt($this->space -= 4, $x);
   228    }
   229
   230    /**
   231     * @param $x
   232     */
   233    public function putUint($x)
   234    {
   235        if ($x > PHP_INT_MAX) {
   236            throw new \InvalidArgumentException("your platform can't handle uint correctly. use 64bit machine.");
   237        }
   238
   239        $this->bb->putUint($this->space -= 4, $x);
   240    }
   241
   242    /**
   243     * @param $x
   244     */
   245    public function putLong($x)
   246    {
   247        if ($x > PHP_INT_MAX) {
   248            throw new \InvalidArgumentException("Your platform can't handle long correctly. Use a 64bit machine.");
   249        }
   250
   251        $this->bb->putLong($this->space -= 8, $x);
   252    }
   253
   254    /**
   255     * @param $x
   256     */
   257    public function putUlong($x)
   258    {
   259        if ($x > PHP_INT_MAX) {
   260            throw new \InvalidArgumentException("Your platform can't handle ulong correctly. This is a php limitation. Please wait for the extension release.");
   261        }
   262
   263        $this->bb->putUlong($this->space -= 8, $x);
   264    }
   265
   266    /**
   267     * @param $x
   268     */
   269    public function putFloat($x)
   270    {
   271        $this->bb->putFloat($this->space -= 4, $x);
   272    }
   273
   274    /**
   275     * @param $x
   276     */
   277    public function putDouble($x)
   278    {
   279        $this->bb->putDouble($this->space -= 8, $x);
   280    }
   281
   282    /**
   283     * @param $off
   284     */
   285    public function putOffset($off)
   286    {
   287        $new_off = $this->offset() - $off + Constants::SIZEOF_INT;
   288        $this->putInt($new_off);
   289    }
   290    /// @endcond
   291
   292    /**
   293     * Add a `bool` to the buffer, properly aligned, and grows the buffer (if necessary).
   294     * @param $x The `bool` to add to the buffer.
   295     */
   296    public function addBool($x)
   297    {
   298        $this->prep(1, 0);
   299        $this->putBool($x);
   300    }
   301
   302    /**
   303     * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
   304     * @param $x The `byte` to add to the buffer.
   305     */
   306    public function addByte($x)
   307    {
   308        $this->prep(1, 0);
   309        $this->putByte($x);
   310    }
   311
   312    /**
   313     * Add a `signed byte` to the buffer, properly aligned, and grows the buffer (if necessary).
   314     * @param $x The `signed byte` to add to the buffer.
   315     */
   316    public function addSbyte($x)
   317    {
   318        $this->prep(1, 0);
   319        $this->putSbyte($x);
   320    }
   321
   322    /**
   323     * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
   324     * @param $x The `short` to add to the buffer.
   325     */
   326    public function addShort($x)
   327    {
   328        $this->prep(2, 0);
   329        $this->putShort($x);
   330    }
   331
   332    /**
   333     * Add an `unsigned short` to the buffer, properly aligned, and grows the buffer (if necessary).
   334     * @param $x The `unsigned short` to add to the buffer.
   335     */
   336    public function addUshort($x)
   337    {
   338        $this->prep(2, 0);
   339        $this->putUshort($x);
   340    }
   341
   342    /**
   343     * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
   344     * @param $x The `int` to add to the buffer.
   345     */
   346    public function addInt($x)
   347    {
   348        $this->prep(4, 0);
   349        $this->putInt($x);
   350    }
   351
   352    /**
   353     * Add an `unsigned int` to the buffer, properly aligned, and grows the buffer (if necessary).
   354     * @param $x The `unsigned int` to add to the buffer.
   355     */
   356    public function addUint($x)
   357    {
   358        $this->prep(4, 0);
   359        $this->putUint($x);
   360    }
   361
   362    /**
   363     * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
   364     * @param $x The `long` to add to the buffer.
   365     */
   366    public function addLong($x)
   367    {
   368        $this->prep(8, 0);
   369        $this->putLong($x);
   370    }
   371
   372    /**
   373     * Add an `unsigned long` to the buffer, properly aligned, and grows the buffer (if necessary).
   374     * @param $x The `unsigned long` to add to the buffer.
   375     */
   376    public function addUlong($x)
   377    {
   378        $this->prep(8, 0);
   379        $this->putUlong($x);
   380    }
   381
   382    /**
   383     * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
   384     * @param $x The `float` to add to the buffer.
   385     */
   386    public function addFloat($x)
   387    {
   388        $this->prep(4, 0);
   389        $this->putFloat($x);
   390    }
   391
   392    /**
   393     * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
   394     * @param $x The `double` to add to the buffer.
   395     */
   396    public function addDouble($x)
   397    {
   398        $this->prep(8, 0);
   399        $this->putDouble($x);
   400    }
   401
   402    /// @cond FLATBUFFERS_INTERNAL
   403    /**
   404     * @param $o
   405     * @param $x
   406     * @param $d
   407     */
   408    public function addBoolX($o, $x, $d)
   409    {
   410        if ($this->force_defaults || $x != $d) {
   411            $this->addBool($x);
   412            $this->slot($o);
   413        }
   414    }
   415
   416    /**
   417     * @param $o
   418     * @param $x
   419     * @param $d
   420     */
   421    public function addByteX($o, $x, $d)
   422    {
   423        if ($this->force_defaults || $x != $d) {
   424            $this->addByte($x);
   425            $this->slot($o);
   426        }
   427    }
   428
   429    /**
   430     * @param $o
   431     * @param $x
   432     * @param $d
   433     */
   434    public function addSbyteX($o, $x, $d)
   435    {
   436        if ($this->force_defaults || $x != $d) {
   437            $this->addSbyte($x);
   438            $this->slot($o);
   439        }
   440    }
   441
   442    /**
   443     * @param $o
   444     * @param $x
   445     * @param $d
   446     */
   447    public function addShortX($o, $x, $d)
   448    {
   449        if ($this->force_defaults || $x != $d) {
   450            $this->addShort($x);
   451            $this->slot($o);
   452        }
   453    }
   454
   455    /**
   456     * @param $o
   457     * @param $x
   458     * @param $d
   459     */
   460    public function addUshortX($o, $x, $d)
   461    {
   462        if ($this->force_defaults || $x != $d) {
   463            $this->addUshort($x);
   464            $this->slot($o);
   465        }
   466    }
   467
   468    /**
   469     * @param $o
   470     * @param $x
   471     * @param $d
   472     */
   473    public function addIntX($o, $x, $d)
   474    {
   475        if ($this->force_defaults || $x != $d) {
   476            $this->addInt($x);
   477            $this->slot($o);
   478        }
   479    }
   480
   481    /**
   482     * @param $o
   483     * @param $x
   484     * @param $d
   485     */
   486    public function addUintX($o, $x, $d)
   487    {
   488        if ($this->force_defaults || $x != $d) {
   489            $this->addUint($x);
   490            $this->slot($o);
   491        }
   492    }
   493
   494    /**
   495     * @param $o
   496     * @param $x
   497     * @param $d
   498     */
   499    public function addLongX($o, $x, $d)
   500    {
   501        if ($this->force_defaults || $x != $d) {
   502            $this->addLong($x);
   503            $this->slot($o);
   504        }
   505    }
   506
   507    /**
   508     * @param $o
   509     * @param $x
   510     * @param $d
   511     */
   512    public function addUlongX($o, $x, $d)
   513    {
   514        if ($this->force_defaults || $x != $d) {
   515            $this->addUlong($x);
   516            $this->slot($o);
   517        }
   518    }
   519
   520
   521    /**
   522     * @param $o
   523     * @param $x
   524     * @param $d
   525     */
   526    public function addFloatX($o, $x, $d)
   527    {
   528        if ($this->force_defaults || $x != $d) {
   529            $this->addFloat($x);
   530            $this->slot($o);
   531        }
   532    }
   533
   534    /**
   535     * @param $o
   536     * @param $x
   537     * @param $d
   538     */
   539    public function addDoubleX($o, $x, $d)
   540    {
   541        if ($this->force_defaults || $x != $d) {
   542            $this->addDouble($x);
   543            $this->slot($o);
   544        }
   545    }
   546
   547    /**
   548     * @param $o
   549     * @param $x
   550     * @param $d
   551     * @throws \Exception
   552     */
   553    public function addOffsetX($o, $x, $d)
   554    {
   555        if ($this->force_defaults || $x != $d) {
   556            $this->addOffset($x);
   557            $this->slot($o);
   558        }
   559    }
   560    /// @endcond
   561
   562    /**
   563     * Adds on offset, relative to where it will be written.
   564     * @param $off The offset to add to the buffer.
   565     * @throws \Exception Throws an exception if `$off` is greater than the underlying ByteBuffer's
   566     * offest.
   567     */
   568    public function addOffset($off)
   569    {
   570        $this->prep(Constants::SIZEOF_INT, 0); // Ensure alignment is already done
   571        if ($off > $this->offset()) {
   572            throw new \Exception("");
   573        }
   574        $this->putOffset($off);
   575    }
   576
   577    /// @cond FLATBUFFERS_INTERNAL
   578    /**
   579     * @param $elem_size
   580     * @param $num_elems
   581     * @param $alignment
   582     * @throws \Exception
   583     */
   584    public function startVector($elem_size, $num_elems, $alignment)
   585    {
   586        $this->notNested();
   587        $this->vector_num_elems = $num_elems;
   588        $this->prep(Constants::SIZEOF_INT, $elem_size * $num_elems);
   589        $this->prep($alignment, $elem_size * $num_elems); // Just in case alignemnt > int;
   590    }
   591
   592    /**
   593     * @return int
   594     */
   595    public function endVector()
   596    {
   597        $this->putUint($this->vector_num_elems);
   598        return $this->offset();
   599    }
   600
   601    protected function is_utf8($bytes)
   602    {
   603        if (function_exists('mb_detect_encoding')) {
   604            return (bool) mb_detect_encoding($bytes, 'UTF-8', true);
   605        }
   606
   607        $len = strlen($bytes);
   608        if ($len < 1) {
   609            /* NOTE: always return 1 when passed string is null */
   610            return true;
   611        }
   612
   613        for ($j = 0, $i = 0; $i < $len; $i++) {
   614            // check ACII
   615            if ($bytes[$j] == "\x09" ||
   616                $bytes[$j] == "\x0A" ||
   617                $bytes[$j] == "\x0D" ||
   618                ($bytes[$j] >= "\x20" && $bytes[$j] <= "\x7E")) {
   619                $j++;
   620                continue;
   621            }
   622
   623            /* non-overlong 2-byte */
   624            if ((($i+1) <= $len) &&
   625                ($bytes[$j] >= "\xC2" && $bytes[$j] <= "\xDF" &&
   626                    ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF"))) {
   627                $j += 2;
   628                $i++;
   629                continue;
   630            }
   631
   632            /* excluding overlongs */
   633            if ((($i + 2) <= $len) &&
   634                $bytes[$j] == "\xE0" &&
   635                ($bytes[$j+1] >= "\xA0" && $bytes[$j+1] <= "\xBF" &&
   636                    ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
   637                $bytes += 3;
   638                $i +=2;
   639                continue;
   640            }
   641
   642            /* straight 3-byte */
   643            if ((($i+2) <= $len) &&
   644                (($bytes[$j] >= "\xE1" && $bytes[$j] <= "\xEC") ||
   645                    $bytes[$j] == "\xEE" ||
   646                    $bytes[$j] = "\xEF") &&
   647                ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF") &&
   648                ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF")) {
   649                $j += 3;
   650                $i += 2;
   651                continue;
   652            }
   653
   654            /* excluding surrogates */
   655            if ((($i+2) <= $len) &&
   656                $bytes[$j] == "\xED" &&
   657                ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x9f" &&
   658                    ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
   659                $j += 3;
   660                $i += 2;
   661                continue;
   662            }
   663
   664            /* planes 1-3 */
   665            if ((($i + 3) <= $len) &&
   666                $bytes[$j] == "\xF0" &&
   667                ($bytes[$j+1] >= "\x90" && $bytes[$j+1] <= "\xBF") &&
   668                ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
   669                ($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")) {
   670                $j += 4;
   671                $i += 3;
   672                continue;
   673            }
   674
   675
   676            /* planes 4-15 */
   677            if ((($i+3) <= $len) &&
   678                $bytes[$j] >= "\xF1" && $bytes[$j] <= "\xF3" &&
   679                $bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF" &&
   680                $bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF" &&
   681                $bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF"
   682            ) {
   683                $j += 4;
   684                $i += 3;
   685                continue;
   686            }
   687
   688            /* plane 16 */
   689            if ((($i+3) <= $len) &&
   690                $bytes[$j] == "\xF4" &&
   691                ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x8F") &&
   692                ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
   693                ($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")
   694            ) {
   695                $bytes += 4;
   696                $i += 3;
   697                continue;
   698            }
   699
   700
   701            return false;
   702        }
   703
   704        return true;
   705    }
   706    /// @endcond
   707
   708    /**
   709     * Encode the string `$s` in the buffer using UTF-8.
   710     * @param string $s The string to encode.
   711     * @return int The offset in the buffer where the encoded string starts.
   712     * @throws InvalidArgumentException Thrown if the input string `$s` is not
   713     *     UTF-8.
   714     */
   715    public function createString($s)
   716    {
   717        if (!$this->is_utf8($s)) {
   718            throw new \InvalidArgumentException("string must be utf-8 encoded value.");
   719        }
   720
   721        $this->notNested();
   722        $this->addByte(0); // null terminated
   723        $this->startVector(1, strlen($s), 1);
   724        $this->space -= strlen($s);
   725        for ($i =  $this->space, $j = 0 ; $j < strlen($s) ; $i++, $j++) {
   726            $this->bb->_buffer[$i] = $s[$j];
   727        }
   728        return $this->endVector();
   729    }
   730
   731    /// @cond FLATBUFFERS_INTERNAL
   732    /**
   733     * @throws \Exception
   734     */
   735    public function notNested()
   736    {
   737        if ($this->nested) {
   738            throw new \Exception("FlatBuffers; object serialization must not be nested");
   739        }
   740    }
   741
   742    /**
   743     * @param $obj
   744     * @throws \Exception
   745     */
   746    public function nested($obj)
   747    {
   748        if ($obj != $this->offset()) {
   749            throw new \Exception("FlatBuffers: struct must be serialized inline");
   750        }
   751    }
   752
   753    /**
   754     * @param $numfields
   755     * @throws \Exception
   756     */
   757    public function startObject($numfields)
   758    {
   759        $this->notNested();
   760        if ($this->vtable == null || count($this->vtable) < $numfields) {
   761            $this->vtable = array();
   762        }
   763
   764        $this->vtable_in_use = $numfields;
   765        for ($i = 0; $i < $numfields; $i++) {
   766            $this->vtable[$i] = 0;
   767        }
   768
   769        $this->nested = true;
   770        $this->object_start = $this->offset();
   771    }
   772
   773    /**
   774     * @param $voffset
   775     * @param $x
   776     * @param $d
   777     * @throws \Exception
   778     */
   779    public function addStructX($voffset, $x, $d)
   780    {
   781        if ($x != $d) {
   782            $this->nested($x);
   783            $this->slot($voffset);
   784        }
   785    }
   786
   787    /**
   788     * @param $voffset
   789     * @param $x
   790     * @param $d
   791     * @throws \Exception
   792     */
   793    public function addStruct($voffset, $x, $d)
   794    {
   795        if ($x != $d) {
   796            $this->nested($x);
   797            $this->slot($voffset);
   798        }
   799    }
   800
   801    /**
   802     * @param $voffset
   803     */
   804    public function slot($voffset)
   805    {
   806        $this->vtable[$voffset] = $this->offset();
   807    }
   808
   809    /**
   810     * @return int
   811     * @throws \Exception
   812     */
   813    public function endObject()
   814    {
   815        if ($this->vtable == null || !$this->nested) {
   816            throw new \Exception("FlatBuffers: endObject called without startObject");
   817        }
   818
   819        $this->addInt(0);
   820        $vtableloc = $this->offset();
   821
   822        $i = $this->vtable_in_use -1;
   823        // Trim trailing zeroes.
   824        for (; $i >= 0 && $this->vtable[$i] == 0; $i--) {}
   825        $trimmed_size = $i + 1;
   826        for (; $i >= 0; $i--) {
   827            $off = ($this->vtable[$i] != 0) ? $vtableloc - $this->vtable[$i] : 0;
   828            $this->addShort($off);
   829        }
   830
   831        $standard_fields = 2; // the fields below
   832        $this->addShort($vtableloc - $this->object_start);
   833        $this->addShort(($trimmed_size + $standard_fields) * Constants::SIZEOF_SHORT);
   834
   835        // search for an existing vtable that matches the current one.
   836        $existing_vtable = 0;
   837
   838        for ($i = 0; $i < $this->num_vtables; $i++) {
   839            $vt1 = $this->bb->capacity() - $this->vtables[$i];
   840            $vt2 = $this->space;
   841
   842            $len = $this->bb->getShort($vt1);
   843
   844            if ($len == $this->bb->getShort($vt2)) {
   845                for ($j = Constants::SIZEOF_SHORT; $j < $len; $j += Constants::SIZEOF_SHORT) {
   846                    if ($this->bb->getShort($vt1 + $j) != $this->bb->getShort($vt2 + $j)) {
   847                        continue 2;
   848                    }
   849                }
   850                $existing_vtable = $this->vtables[$i];
   851                break;
   852            }
   853        }
   854
   855        if ($existing_vtable != 0) {
   856            // Found a match:
   857            // Remove the current vtable
   858            $this->space = $this->bb->capacity() - $vtableloc;
   859            $this->bb->putInt($this->space, $existing_vtable - $vtableloc);
   860        } else {
   861            // No Match:
   862            // Add the location of the current vtable to the list of vtables
   863            if ($this->num_vtables == count($this->vtables)) {
   864                $vtables = $this->vtables;
   865                $this->vtables = array();
   866                // copy of
   867                for ($i = 0; $i < count($vtables) * 2; $i++) {
   868                    $this->vtables[$i] = ($i < count($vtables)) ? $vtables[$i] : 0;
   869                }
   870            }
   871            $this->vtables[$this->num_vtables++] = $this->offset();
   872            $this->bb->putInt($this->bb->capacity() - $vtableloc, $this->offset() - $vtableloc);
   873        }
   874
   875        $this->nested = false;
   876        $this->vtable = null;
   877        return $vtableloc;
   878    }
   879
   880    /**
   881     * @param $table
   882     * @param $field
   883     * @throws \Exception
   884     */
   885    public function required($table, $field)
   886    {
   887        $table_start = $this->bb->capacity() - $table;
   888        $vtable_start = $table_start - $this->bb->getInt($table_start);
   889        $ok = $this->bb->getShort($vtable_start + $field) != 0;
   890
   891        if (!$ok) {
   892            throw new \Exception("FlatBuffers: field "  . $field  .  " must be set");
   893        }
   894    }
   895    /// @endcond
   896
   897    /**
   898     * Finalize a buffer, pointing to the given `$root_table`.
   899     * @param $root_table An offest to be added to the buffer.
   900     * @param $file_identifier A FlatBuffer file identifier to be added to the
   901     *     buffer before `$root_table`. This defaults to `null`.
   902     * @throws InvalidArgumentException Thrown if an invalid `$identifier` is
   903     *     given, where its length is not equal to
   904     *    `Constants::FILE_IDENTIFIER_LENGTH`.
   905     */
   906    public function finish($root_table, $identifier = null)
   907    {
   908        if ($identifier == null) {
   909            $this->prep($this->minalign, Constants::SIZEOF_INT);
   910            $this->addOffset($root_table);
   911            $this->bb->setPosition($this->space);
   912        } else {
   913            $this->prep($this->minalign, Constants::SIZEOF_INT + Constants::FILE_IDENTIFIER_LENGTH);
   914            if (strlen($identifier) != Constants::FILE_IDENTIFIER_LENGTH) {
   915                throw new \InvalidArgumentException(
   916                    sprintf("FlatBuffers: file identifier must be length %d",
   917                        Constants::FILE_IDENTIFIER_LENGTH));
   918            }
   919
   920            for ($i = Constants::FILE_IDENTIFIER_LENGTH - 1; $i >= 0;
   921                  $i--) {
   922                $this->addByte(ord($identifier[$i]));
   923            }
   924            $this->finish($root_table);
   925        }
   926    }
   927
   928    /**
   929     * In order to save space, fields that are set to their default value don't
   930     * get serialized into the buffer.
   931     * @param bool $forceDefaults When set to `true`, always serializes default
   932     *     values.
   933     */
   934    public function forceDefaults($forceDefaults)
   935    {
   936        $this->force_defaults = $forceDefaults;
   937    }
   938
   939    /**
   940     * Get the ByteBuffer representing the FlatBuffer.
   941     * @return ByteBuffer The ByteBuffer containing the FlatBuffer data.
   942     */
   943    public function dataBuffer()
   944    {
   945        return $this->bb;
   946    }
   947
   948    /// @cond FLATBUFFERS_INTERNAL
   949    /**
   950     * @return int
   951     */
   952    public function dataStart()
   953    {
   954        return $this->space;
   955    }
   956    /// @endcond
   957
   958    /**
   959     * Utility function to copy and return the FlatBuffer data from the
   960     * underlying ByteBuffer.
   961     * @return string A string (representing a byte[]) that contains a copy
   962     * of the FlatBuffer data.
   963     */
   964    public function sizedByteArray()
   965    {
   966        $start = $this->space;
   967        $length = $this->bb->capacity() - $this->space;
   968
   969        $result = str_repeat("\0", $length);
   970        $this->bb->setPosition($start);
   971        $this->bb->getX($result);
   972
   973        return $result;
   974    }
   975}
   976
   977/// @}

View as plain text