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