aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--composer.json18
-rw-r--r--include/flatbuffers/idl.h7
-rw-r--r--php/ByteBuffer.php495
-rw-r--r--php/Constants.php25
-rw-r--r--php/FlatbufferBuilder.php918
-rw-r--r--php/Struct.php31
-rw-r--r--php/Table.php129
-rw-r--r--src/flatc.cpp4
-rw-r--r--src/idl_gen_php.cpp980
-rw-r--r--tests/MyGame/Example/Any.php25
-rw-r--r--tests/MyGame/Example/Color.php25
-rw-r--r--tests/MyGame/Example/Monster.php759
-rw-r--r--tests/MyGame/Example/Stat.php136
-rw-r--r--tests/MyGame/Example/Test.php53
-rw-r--r--tests/MyGame/Example/TestSimpleTableWithEnum.php99
-rw-r--r--tests/MyGame/Example/Vec3.php96
-rw-r--r--tests/generate_code.bat2
-rw-r--r--tests/generate_code.sh2
-rw-r--r--tests/phpTest.php609
20 files changed, 4413 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f0691dd9..5a49cf3e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,7 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_general.cpp
src/idl_gen_go.cpp
src/idl_gen_js.cpp
+ src/idl_gen_php.cpp
src/idl_gen_python.cpp
src/idl_gen_fbs.cpp
src/flatc.cpp
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000..807709c1
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,18 @@
+{
+ "name": "google/flatbuffers",
+ "type": "library",
+ "description": "FlatBuffers for PHP",
+ "keywords": ["google", "flatbuffers", "serialization"],
+ "homepage": "https://github.com/google/flatbuffers",
+ "license": "Apache-2.0",
+ "require": {
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ },
+ "autoload": {
+ "psr-4": {
+ "Google\\FlatBuffers\\": "php"
+ }
+ }
+} \ No newline at end of file
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index ffd612a1..ad755f8c 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -528,6 +528,13 @@ extern bool GenerateJava(const Parser &parser,
const std::string &file_name,
const GeneratorOptions &opts);
+// Generate Php code from the definitions in the Parser object.
+// See idl_gen_php.
+extern bool GeneratePhp(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name,
+ const GeneratorOptions &opts);
+
// Generate Python files from the definitions in the Parser object.
// See idl_gen_python.cpp.
extern bool GeneratePython(const Parser &parser,
diff --git a/php/ByteBuffer.php b/php/ByteBuffer.php
new file mode 100644
index 00000000..4a583b7a
--- /dev/null
+++ b/php/ByteBuffer.php
@@ -0,0 +1,495 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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.
+ */
+
+namespace Google\FlatBuffers;
+
+class ByteBuffer
+{
+ /**
+ * @var string $_buffer;
+ */
+ public $_buffer;
+
+ /**
+ * @var int $_pos;
+ */
+ private $_pos;
+
+ /**
+ * @var bool $_is_little_endian
+ */
+ private static $_is_little_endian = null;
+
+ public static function wrap($bytes)
+ {
+ $bb = new ByteBuffer(0);
+ $bb->_buffer = $bytes;
+
+ return $bb;
+ }
+
+ /**
+ * @param $size
+ */
+ public function __construct($size)
+ {
+ $this->_buffer = str_repeat("\0", $size);
+ }
+
+ /**
+ * @return int
+ */
+ public function capacity()
+ {
+ return strlen($this->_buffer);
+ }
+
+ /**
+ * @return int
+ */
+ public function getPosition()
+ {
+ return $this->_pos;
+ }
+
+ /**
+ * @param $pos
+ */
+ public function setPosition($pos)
+ {
+ $this->_pos = $pos;
+ }
+
+ /**
+ *
+ */
+ public function reset()
+ {
+ $this->_pos = 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function length()
+ {
+ return strlen($this->_buffer);
+ }
+
+ /**
+ * @return string
+ */
+ public function data()
+ {
+ return substr($this->_buffer, $this->_pos);
+ }
+
+ /**
+ * @return bool
+ */
+ public static function isLittleEndian()
+ {
+ if (ByteBuffer::$_is_little_endian === null) {
+ ByteBuffer::$_is_little_endian = unpack('S', "\x01\x00")[1] === 1;
+ }
+
+ return ByteBuffer::$_is_little_endian;
+ }
+
+ /**
+ * write little endian value to the buffer.
+ *
+ * @param $offset
+ * @param $count byte length
+ * @param $data actual values
+ */
+ public function writeLittleEndian($offset, $count, $data)
+ {
+ if (ByteBuffer::isLittleEndian()) {
+ for ($i = 0; $i < $count; $i++) {
+ $this->_buffer[$offset + $i] = chr($data >> $i * 8);
+ }
+ } else {
+ for ($i = 0; $i < $count; $i++) {
+ $this->_buffer[$offset + $count - 1 - $i] = chr($data >> $i * 8);
+ }
+ }
+ }
+
+ /**
+ * read little endian value from the buffer
+ *
+ * @param $offset
+ * @param $count acutal size
+ * @return int
+ */
+ public function readLittleEndian($offset, $count, $force_bigendian = false)
+ {
+ $this->assertOffsetAndLength($offset, $count);
+ $r = 0;
+
+ if (ByteBuffer::isLittleEndian() && $force_bigendian == false) {
+ for ($i = 0; $i < $count; $i++) {
+ $r |= ord($this->_buffer[$offset + $i]) << $i * 8;
+ }
+ } else {
+ for ($i = 0; $i < $count; $i++) {
+ $r |= ord($this->_buffer[$offset + $count -1 - $i]) << $i * 8;
+ }
+ }
+
+ return $r;
+ }
+
+ /**
+ * @param $offset
+ * @param $length
+ */
+ public function assertOffsetAndLength($offset, $length)
+ {
+ if ($offset < 0 ||
+ $offset >= strlen($this->_buffer) ||
+ $offset + $length > strlen($this->_buffer)) {
+ throw new \OutOfRangeException(sprintf("offset: %d, length: %d, buffer; %d", $offset, $length, strlen($this->_buffer)));
+ }
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ * @return mixed
+ */
+ public function putSbyte($offset, $value)
+ {
+ self::validateValue(-128, 127, $value, "sbyte");
+
+ $length = strlen($value);
+ $this->assertOffsetAndLength($offset, $length);
+ return $this->_buffer[$offset] = $value;
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ * @return mixed
+ */
+ public function putByte($offset, $value)
+ {
+ self::validateValue(0, 255, $value, "byte");
+
+ $length = strlen($value);
+ $this->assertOffsetAndLength($offset, $length);
+ return $this->_buffer[$offset] = $value;
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function put($offset, $value)
+ {
+ $length = strlen($value);
+ $this->assertOffsetAndLength($offset, $length);
+ for ($i = 0; $i < $length; $i++) {
+ $this->_buffer[$offset + $i] = $value[$i];
+ }
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putShort($offset, $value)
+ {
+ self::validateValue(-32768, 32767, $value, "short");
+
+ $this->assertOffsetAndLength($offset, 2);
+ $this->writeLittleEndian($offset, 2, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putUshort($offset, $value)
+ {
+ self::validateValue(0, 65535, $value, "short");
+
+ $this->assertOffsetAndLength($offset, 2);
+ $this->writeLittleEndian($offset, 2, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putInt($offset, $value)
+ {
+ self::validateValue(~PHP_INT_MAX, PHP_INT_MAX, $value, "int");
+
+ $this->assertOffsetAndLength($offset, 4);
+ $this->writeLittleEndian($offset, 4, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putUint($offset, $value)
+ {
+ // NOTE: We can't put big integer value. this is PHP limitation.
+ self::validateValue(0, PHP_INT_MAX, $value, "uint", " php has big numbers limitation. check your PHP_INT_MAX");
+
+ $this->assertOffsetAndLength($offset, 4);
+ $this->writeLittleEndian($offset, 4, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putLong($offset, $value)
+ {
+ // NOTE: We can't put big integer value. this is PHP limitation.
+ self::validateValue(~PHP_INT_MAX, PHP_INT_MAX, $value, "long", " php has big numbers limitation. check your PHP_INT_MAX");
+
+ $this->assertOffsetAndLength($offset, 8);
+ $this->writeLittleEndian($offset, 8, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putUlong($offset, $value)
+ {
+ // NOTE: We can't put big integer value. this is PHP limitation.
+ self::validateValue(0, PHP_INT_MAX, $value, "long", " php has big numbers limitation. check your PHP_INT_MAX");
+
+ $this->assertOffsetAndLength($offset, 8);
+ $this->writeLittleEndian($offset, 8, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putFloat($offset, $value)
+ {
+ $this->assertOffsetAndLength($offset, 4);
+
+ $floathelper = pack("f", $value);
+ $v = unpack("V", $floathelper);
+ $this->writeLittleEndian($offset, 4, $v[1]);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putDouble($offset, $value)
+ {
+ $this->assertOffsetAndLength($offset, 8);
+
+ $floathelper = pack("d", $value);
+ $v = unpack("V*", $floathelper);
+
+ $this->writeLittleEndian($offset, 4, $v[1]);
+ $this->writeLittleEndian($offset + 4, 4, $v[2]);
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getByte($index)
+ {
+ return ord($this->_buffer[$index]);
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getSbyte($index)
+ {
+ $v = unpack("c", $this->_buffer[$index]);
+ return $v[1];
+ }
+
+ /**
+ * @param $buffer
+ */
+ public function getX(&$buffer)
+ {
+ for ($i = $this->_pos, $j = 0; $j < strlen($buffer); $i++, $j++) {
+ $buffer[$j] = $this->_buffer[$i];
+ }
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function get($index)
+ {
+ $this->assertOffsetAndLength($index, 1);
+ return $this->_buffer[$index];
+ }
+
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getBool($index)
+ {
+ return (bool)ord($this->_buffer[$index]);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getShort($index)
+ {
+ $result = $this->readLittleEndian($index, 2);
+
+ return self::convertHelper(self::__SHORT, $result);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getUShort($index)
+ {
+ return $this->readLittleEndian($index, 2);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getInt($index)
+ {
+ $result = $this->readLittleEndian($index, 4);
+
+ return self::convertHelper(self::__INT, $result);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getUint($index)
+ {
+ return $this->readLittleEndian($index, 4);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getLong($index)
+ {
+ $result = $this->readLittleEndian($index, 8);
+
+ return self::convertHelper(self::__LONG, $result);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getUlong($index)
+ {
+ return $this->readLittleEndian($index, 8);
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getFloat($index)
+ {
+ $i = $this->readLittleEndian($index, 4);
+
+ return self::convertHelper(self::__FLOAT, $i);
+ }
+
+ /**
+ * @param $index
+ * @return float
+ */
+ public function getDouble($index)
+ {
+ $i = $this->readLittleEndian($index, 4);
+ $i2 = $this->readLittleEndian($index + 4, 4);
+
+ return self::convertHelper(self::__DOUBLE, $i, $i2);
+ }
+
+ const __SHORT = 1;
+ const __INT = 2;
+ const __LONG = 3;
+ const __FLOAT = 4;
+ const __DOUBLE = 5;
+ private static function convertHelper($type, $value, $value2 = null) {
+ // readLittleEndian construct unsigned integer value from bytes. we have to encode this value to
+ // correct bytes, and decode as expected types with `unpack` function.
+ // then it returns correct type value.
+ // see also: http://php.net/manual/en/function.pack.php
+
+ switch ($type) {
+ case self::__SHORT:
+ $helper = pack("v", $value);
+ $v = unpack("s", $helper);
+
+ return $v[1];
+ break;
+ case self::__INT:
+ $helper = pack("V", $value);
+ $v = unpack("l", $helper);
+ return $v[1];
+ break;
+ case self::__LONG:
+ $helper = pack("P", $value);
+ $v = unpack("q", $helper);
+ return $v[1];
+ break;
+ case self::__FLOAT:
+ $inthelper = pack("V", $value);
+ $v = unpack("f", $inthelper);
+ return $v[1];
+ break;
+ case self::__DOUBLE:
+ $inthelper = pack("VV", $value, $value2);
+ $v = unpack("d", $inthelper);
+ return $v[1];
+ break;
+ default:
+ throw new \Exception(sprintf("unexpected type %d specified", $type));
+ }
+ }
+
+ private static function validateValue($min, $max, $value, $type, $additional_notes = "") {
+ if(!($min <= $value && $value <= $max)) {
+ throw new \InvalidArgumentException(sprintf("bad number %s for type %s.%s", $value, $type, $additional_notes));
+ }
+ }
+}
diff --git a/php/Constants.php b/php/Constants.php
new file mode 100644
index 00000000..ef3730d4
--- /dev/null
+++ b/php/Constants.php
@@ -0,0 +1,25 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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.
+ */
+
+namespace Google\FlatBuffers;
+
+class Constants
+{
+ const SIZEOF_SHORT = 2;
+ const SIZEOF_INT = 4;
+ const FILE_IDENTIFIER_LENGTH = 4;
+}
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
new file mode 100644
index 00000000..b72a6d65
--- /dev/null
+++ b/php/FlatbufferBuilder.php
@@ -0,0 +1,918 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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.
+ */
+
+namespace Google\FlatBuffers;
+
+class FlatbufferBuilder
+{
+ /**
+ * @var ByteBuffer $bb
+ */
+ public $bb;
+
+ /**
+ * @var int $space
+ */
+ protected $space;
+
+ /**
+ * @var int $minalign
+ */
+ protected $minalign = 1;
+
+ /**
+ * @var array $vtable
+ */
+ protected $vtable;
+
+ /**
+ * @var int $vtable_in_use
+ */
+ protected $vtable_in_use = 0;
+
+ /**
+ * @var bool $nested
+ */
+ protected $nested = false;
+
+ /**
+ * @var int $object_start
+ */
+ protected $object_start;
+
+ /**
+ * @var array $vtables
+ */
+ protected $vtables = array();
+
+ /**
+ * @var int $num_vtables
+ */
+ protected $num_vtables = 0;
+
+ /**
+ * @var int $vector_num_elems
+ */
+ protected $vector_num_elems = 0;
+
+ /**
+ * @var bool $force_defaults
+ */
+ protected $force_defaults = false;
+
+ /**
+ * create flatbuffers builder
+ *
+ * @param $initial_size initial byte buffer size.
+ */
+ public function __construct($initial_size)
+ {
+ if ($initial_size <= 0) {
+ $initial_size = 1;
+ }
+ $this->space = $initial_size;
+ $this->bb = $this->newByteBuffer($initial_size);
+ }
+
+ /**
+ * create new bytebuffer
+ *
+ * @param $size
+ * @return ByteBuffer
+ */
+ private function newByteBuffer($size)
+ {
+ return new ByteBuffer($size);
+ }
+
+ /**
+ * returns current bytebuffer offset
+ *
+ * @return int
+ */
+ public function offset()
+ {
+ return $this->bb->capacity() - $this->space;
+ }
+
+ /**
+ * padding buffer
+ *
+ * @param $byte_size
+ */
+ public function pad($byte_size)
+ {
+ for ($i = 0; $i < $byte_size; $i++) {
+ $this->bb->putByte(--$this->space, "\0");
+ }
+ }
+
+ /**
+ * prepare bytebuffer
+ *
+ * @param $size
+ * @param $additional_bytes
+ * @throws \Exception
+ */
+ public function prep($size, $additional_bytes)
+ {
+ if ($size > $this->minalign) {
+ $this->minalign = $size;
+ }
+
+ $align_size = ((~($this->bb->capacity() - $this->space + $additional_bytes)) + 1) & ($size - 1);
+ while ($this->space < $align_size + $size + $additional_bytes) {
+ $old_buf_size = $this->bb->capacity();
+ $this->bb = $this->growByteBuffer($this->bb);
+ $this->space += $this->bb->capacity() - $old_buf_size;
+ }
+
+ $this->pad($align_size);
+ }
+
+ /**
+ * @param ByteBuffer $bb
+ * @return ByteBuffer
+ * @throws \Exception
+ */
+ private static function growByteBuffer(ByteBuffer $bb)
+ {
+ $old_buf_size = $bb->capacity();
+ if (($old_buf_size & 0xC0000000) != 0) {
+ throw new \Exception("FlatBuffers: cannot grow buffer beyond 2 gigabytes");
+ }
+ $new_buf_size = $old_buf_size << 1;
+
+ $bb->setPosition(0);
+ $nbb = new ByteBuffer($new_buf_size);
+
+ $nbb->setPosition($new_buf_size - $old_buf_size);
+
+ // TODO(chobie): is this little bit faster?
+ //$nbb->_buffer = substr_replace($nbb->_buffer, $bb->_buffer, $new_buf_size - $old_buf_size, strlen($bb->_buffer));
+ for ($i = $new_buf_size - $old_buf_size, $j = 0; $j < strlen($bb->_buffer); $i++, $j++) {
+ $nbb->_buffer[$i] = $bb->_buffer[$j];
+ }
+
+ return $nbb;
+ }
+
+ /**
+ * @param $x
+ */
+ public function putBool($x)
+ {
+ $this->bb->put($this->space -= 1, chr((int)(bool)($x)));
+ }
+
+ /**
+ * @param $x
+ */
+ public function putByte($x)
+ {
+ $this->bb->put($this->space -= 1, chr($x));
+ }
+
+ /**
+ * @param $x
+ */
+ public function putSbyte($x)
+ {
+ $this->bb->put($this->space -= 1, chr($x));
+ }
+
+ /**
+ * @param $x
+ */
+ public function putShort($x)
+ {
+ $this->bb->putShort($this->space -= 2, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putUshort($x)
+ {
+ $this->bb->putUshort($this->space -= 2, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putInt($x)
+ {
+ $this->bb->putInt($this->space -= 4, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putUint($x)
+ {
+ if ($x > PHP_INT_MAX) {
+ throw new \InvalidArgumentException("your platform can't handling uint correctly. use 64bit machine.");
+ }
+
+ $this->bb->putUint($this->space -= 4, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putLong($x)
+ {
+ if ($x > PHP_INT_MAX) {
+ throw new \InvalidArgumentException("your platform can't handling long correctly. use 64bit machine.");
+ }
+
+ $this->bb->putLong($this->space -= 8, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putUlong($x)
+ {
+ if ($x > PHP_INT_MAX) {
+ throw new \InvalidArgumentException("your platform can't handling ulong correctly. this is php limitations. please wait extension release.");
+ }
+
+ $this->bb->putUlong($this->space -= 8, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putFloat($x)
+ {
+ $this->bb->putFloat($this->space -= 4, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putDouble($x)
+ {
+ $this->bb->putDouble($this->space -= 8, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addBool($x)
+ {
+ $this->prep(1, 0);
+ $this->putBool($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addByte($x)
+ {
+ $this->prep(1, 0);
+ $this->putByte($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addSbyte($x)
+ {
+ $this->prep(1, 0);
+ $this->putSbyte($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addShort($x)
+ {
+ $this->prep(2, 0);
+ $this->putShort($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addUshort($x)
+ {
+ $this->prep(2, 0);
+ $this->putUshort($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addInt($x)
+ {
+ $this->prep(4, 0);
+ $this->putInt($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addUint($x)
+ {
+ $this->prep(4, 0);
+ $this->putUint($x);
+ }
+
+
+ /**
+ * @param $x
+ */
+ public function addLong($x)
+ {
+ $this->prep(8, 0);
+ $this->putLong($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addUlong($x)
+ {
+ $this->prep(8, 0);
+ $this->putUlong($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addFloat($x)
+ {
+ $this->prep(4, 0);
+ $this->putFloat($x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function addDouble($x)
+ {
+ $this->prep(8, 0);
+ $this->putDouble($x);
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addBoolX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addBool($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addByteX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addByte($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addSbyteX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addSbyte($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addShortX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addShort($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addUshortX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addUshort($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addIntX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addInt($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addUintX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addUint($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addLongX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addLong($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addUlongX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addUlong($x);
+ $this->slot($o);
+ }
+ }
+
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addFloatX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addFloat($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addDoubleX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addDouble($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ * @throws \Exception
+ */
+ public function addOffsetX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addOffset($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $off
+ * @throws \Exception
+ */
+ public function addOffset($off)
+ {
+ $this->prep(Constants::SIZEOF_INT, 0); // Ensure alignment is already done
+ if ($off > $this->offset()) {
+ throw new \Exception("");
+ }
+
+ $off = $this->offset() - $off + Constants::SIZEOF_INT;
+ $this->putInt($off);
+ }
+
+ /**
+ * @param $elem_size
+ * @param $num_elems
+ * @param $alignment
+ * @throws \Exception
+ */
+ public function startVector($elem_size, $num_elems, $alignment)
+ {
+ $this->notNested();
+ $this->vector_num_elems = $num_elems;
+ $this->prep(Constants::SIZEOF_INT, $elem_size * $num_elems);
+ $this->prep($alignment, $elem_size * $num_elems); // Just in case alignemnt > int;
+ }
+
+ /**
+ * @return int
+ */
+ public function endVector()
+ {
+ $this->putUint($this->vector_num_elems);
+ return $this->offset();
+ }
+
+ protected function is_utf8($bytes)
+ {
+ $len = strlen($bytes);
+ if ($len < 1) {
+ /* NOTE: always return 1 when passed string is null */
+ return true;
+ }
+
+ for ($j = 0, $i = 0; $i < $len; $i++) {
+ // check ACII
+ if ($bytes[$j] == "\x09" ||
+ $bytes[$j] == "\x0A" ||
+ $bytes[$j] == "\x0D" ||
+ ($bytes[$j] >= "\x20" && $bytes[$j] <= "\x7E")) {
+ $j++;
+ continue;
+ }
+
+ /* non-overlong 2-byte */
+ if ((($i+1) <= $len) &&
+ ($bytes[$j] >= "\xC2" && $bytes[$j] <= "\xDF" &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF"))) {
+ $j += 2;
+ $i++;
+ continue;
+ }
+
+ /* excluding overlongs */
+ if ((($i + 2) <= $len) &&
+ $bytes[$j] == "\xE0" &&
+ ($bytes[$j+1] >= "\xA0" && $bytes[$j+1] <= "\xBF" &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
+ $bytes += 3;
+ $i +=2;
+ continue;
+ }
+
+ /* straight 3-byte */
+ if ((($i+2) <= $len) &&
+ (($bytes[$j] >= "\xE1" && $bytes[$j] <= "\xEC") ||
+ $bytes[$j] == "\xEE" ||
+ $bytes[$j] = "\xEF") &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF") &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF")) {
+ $j += 3;
+ $i += 2;
+ continue;
+ }
+
+ /* excluding surrogates */
+ if ((($i+2) <= $len) &&
+ $bytes[$j] == "\xED" &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x9f" &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
+ $j += 3;
+ $i += 2;
+ continue;
+ }
+
+ /* planes 1-3 */
+ if ((($i + 3) <= $len) &&
+ $bytes[$j] == "\xF0" &&
+ ($bytes[$j+1] >= "\x90" && $bytes[$j+1] <= "\xBF") &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
+ ($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")) {
+ $j += 4;
+ $i += 3;
+ continue;
+ }
+
+
+ /* planes 4-15 */
+ if ((($i+3) <= $len) &&
+ $bytes[$j] >= "\xF1" && $bytes[$j] <= "\xF3" &&
+ $bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF" &&
+ $bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF" &&
+ $bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF"
+ ) {
+ $j += 4;
+ $i += 3;
+ continue;
+ }
+
+ /* plane 16 */
+ if ((($i+3) <= $len) &&
+ $bytes[$j] == "\xF4" &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x8F") &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
+ ($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")
+ ) {
+ $bytes += 4;
+ $i += 3;
+ continue;
+ }
+
+
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param $s
+ * @return int
+ * @throws \Exception
+ */
+ public function createString($s)
+ {
+ if (!$this->is_utf8($s)) {
+ throw new \InvalidArgumentException("string must be utf-8 encoded value.");
+ }
+
+ $this->notNested();
+ $this->addByte(0); // null terminated
+ $this->startVector(1, strlen($s), 1);
+ $this->space -= strlen($s);
+ for ($i = $this->space, $j = 0 ; $j < strlen($s) ; $i++, $j++) {
+ $this->bb->_buffer[$i] = $s[$j];
+ }
+ return $this->endVector();
+ }
+
+ /**
+ * @throws \Exception
+ */
+ public function notNested()
+ {
+ if ($this->nested) {
+ throw new \Exception("FlatBuffers; object serialization must not be nested");
+ }
+ }
+
+ /**
+ * @param $obj
+ * @throws \Exception
+ */
+ public function nested($obj)
+ {
+ if ($obj != $this->offset()) {
+ throw new \Exception("FlatBuffers: struct must be serialized inline");
+ }
+ }
+
+ /**
+ * @param $numfields
+ * @throws \Exception
+ */
+ public function startObject($numfields)
+ {
+ $this->notNested();
+ if ($this->vtable == null || count($this->vtable) < $numfields) {
+ $this->vtable = array();
+ }
+
+ $this->vtable_in_use = $numfields;
+ for ($i = 0; $i < $numfields; $i++) {
+ $this->vtable[$i] = 0;
+ }
+
+ $this->nested = true;
+ $this->object_start = $this->offset();
+ }
+
+ /**
+ * @param $voffset
+ * @param $x
+ * @param $d
+ * @throws \Exception
+ */
+ public function addStructX($voffset, $x, $d)
+ {
+ if ($x != $d) {
+ $this->nested($x);
+ $this->slot($voffset);
+ }
+ }
+
+ /**
+ * @param $voffset
+ * @param $x
+ * @param $d
+ * @throws \Exception
+ */
+ public function addStruct($voffset, $x, $d)
+ {
+ if ($x != $d) {
+ $this->nested($x);
+ $this->slot($voffset);
+ }
+ }
+
+ /**
+ * @param $voffset
+ */
+ public function slot($voffset)
+ {
+ $this->vtable[$voffset] = $this->offset();
+ }
+
+ /**
+ * @return int
+ * @throws \Exception
+ */
+ public function endObject()
+ {
+ if ($this->vtable == null || !$this->nested) {
+ throw new \Exception("FlatBuffers: endObject called without startObject");
+ }
+
+ $this->addInt(0);
+ $vtableloc = $this->offset();
+
+ for ($i = $this->vtable_in_use -1; $i >= 0; $i--) {
+ $off = ($this->vtable[$i] != 0) ? $vtableloc - $this->vtable[$i] : 0;
+ $this->addShort($off);
+ }
+
+ $standard_fields = 2; // the fields below
+ $this->addShort($vtableloc - $this->object_start);
+ $this->addShort(($this->vtable_in_use + $standard_fields) * Constants::SIZEOF_SHORT);
+
+ // search for an existing vtable that matches the current one.
+ $existing_vtable = 0;
+
+ for ($i = 0; $i < $this->num_vtables; $i++) {
+ $vt1 = $this->bb->capacity() - $this->vtables[$i];
+ $vt2 = $this->space;
+
+ $len = $this->bb->getShort($vt1);
+
+ if ($len == $this->bb->getShort($vt2)) {
+ for ($j = Constants::SIZEOF_SHORT; $j < $len; $j += Constants::SIZEOF_SHORT) {
+ if ($this->bb->getShort($vt1 + $j) != $this->bb->getShort($vt2 + $j)) {
+ continue 2;
+ }
+ }
+ $existing_vtable = $this->vtables[$i];
+ break;
+ }
+ }
+
+ if ($existing_vtable != 0) {
+ // Found a match:
+ // Remove the current vtable
+ $this->space = $this->bb->capacity() - $vtableloc;
+ $this->bb->putInt($this->space, $existing_vtable - $vtableloc);
+ } else {
+ // No Match:
+ // Add the location of the current vtable to the list of vtables
+ if ($this->num_vtables == count($this->vtables)) {
+ $vtables = $this->vtables;
+ $this->vtables = array();
+ // copy of
+ for ($i = 0; $i < count($vtables) * 2; $i++) {
+ $this->vtables[$i] = ($i < count($vtables)) ? $vtables[$i] : 0;
+ }
+ }
+ $this->vtables[$this->num_vtables++] = $this->offset();
+ $this->bb->putInt($this->bb->capacity() - $vtableloc, $this->offset() - $vtableloc);
+ }
+
+ $this->nested = false;
+ $this->vtable = null;
+ return $vtableloc;
+ }
+
+ /**
+ * @param $table
+ * @param $field
+ * @throws \Exception
+ */
+ public function required($table, $field)
+ {
+ $table_start = $this->bb->capacity() - $table;
+ $vtable_start = $table_start - $this->bb->getInt($table_start);
+ $ok = $this->bb->getShort($vtable_start + $field) != 0;
+
+ if (!$ok) {
+ throw new \Exception("FlatBuffers: field " . $field . " must be set");
+ }
+ }
+
+ /**
+ * @param $root_table
+ * @throws \Exception
+ */
+ public function finish($root_table, $identifier = null)
+ {
+ if ($identifier == null) {
+ $this->prep($this->minalign, Constants::SIZEOF_INT);
+ $this->addOffset($root_table);
+ $this->bb->setPosition($this->space);
+ } else {
+ $this->prep($this->minalign, Constants::SIZEOF_INT + Constants::FILE_IDENTIFIER_LENGTH);
+ if (strlen($identifier) != Constants::FILE_IDENTIFIER_LENGTH) {
+ throw new \InvalidArgumentException(
+ sprintf("FlatBuffers: file identifier must be length %d",
+ Constants::FILE_IDENTIFIER_LENGTH));
+ }
+
+ for ($i = Constants::FILE_IDENTIFIER_LENGTH - 1; $i >= 0;
+ $i--) {
+ $this->addByte(ord($identifier[$i]));
+ }
+ $this->finish($root_table);
+ }
+ }
+
+ /**
+ * @param bool $forceDefaults
+ */
+ public function forceDefaults($forceDefaults)
+ {
+ $this->force_defaults = $forceDefaults;
+ }
+
+ /**
+ * @return ByteBuffer
+ */
+ public function dataBuffer()
+ {
+ return $this->bb;
+ }
+
+ /**
+ * @return int
+ */
+ public function dataStart()
+ {
+ return $this->space;
+ }
+
+ /**
+ * @return string
+ */
+ public function sizedByteArray()
+ {
+ $start = $this->space;
+ $length = $this->bb->capacity() - $this->space;
+
+ $result = str_repeat("\0", $length);
+ $this->bb->setPosition($start);
+ $this->bb->getX($result);
+
+ return $result;
+ }
+}
diff --git a/php/Struct.php b/php/Struct.php
new file mode 100644
index 00000000..94e712b2
--- /dev/null
+++ b/php/Struct.php
@@ -0,0 +1,31 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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.
+ */
+
+namespace Google\FlatBuffers;
+
+abstract class Struct
+{
+ /**
+ * @var int $bb_pos
+ */
+ protected $bb_pos;
+
+ /**
+ * @var ByteBuffer $bb
+ */
+ protected $bb;
+}
diff --git a/php/Table.php b/php/Table.php
new file mode 100644
index 00000000..7f611456
--- /dev/null
+++ b/php/Table.php
@@ -0,0 +1,129 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * 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.
+ */
+
+namespace Google\FlatBuffers;
+
+abstract class Table
+{
+ /**
+ * @var int $bb_pos
+ */
+ protected $bb_pos;
+ /**
+ * @var ByteBuffer $bb
+ */
+ protected $bb;
+
+ public function __construct()
+ {
+ }
+
+ /**
+ * returns actual vtable offset
+ *
+ * @param $vtable_offset
+ * @return int offset > 0 means exist value. 0 means not exist
+ */
+ protected function __offset($vtable_offset)
+ {
+ $vtable = $this->bb_pos - $this->bb->getInt($this->bb_pos);
+ return $vtable_offset < $this->bb->getShort($vtable) ? $this->bb->getShort($vtable + $vtable_offset) : 0;
+ }
+
+ /**
+ * @param $offset
+ * @return mixed
+ */
+ protected function __indirect($offset)
+ {
+ return $offset + $this->bb->getInt($offset);
+ }
+
+ /**
+ * fetch utf8 encoded string.
+ *
+ * @param $offset
+ * @return string
+ */
+ protected function __string($offset)
+ {
+ $offset += $this->bb->getInt($offset);
+ $len = $this->bb->getInt($offset);
+ $startPos = $offset + Constants::SIZEOF_INT;
+ return substr($this->bb->_buffer, $startPos, $len);
+ }
+
+ /**
+ * @param $offset
+ * @return int
+ */
+ protected function __vector_len($offset)
+ {
+ $offset += $this->bb_pos;
+ $offset += $this->bb->getInt($offset);
+ return $this->bb->getInt($offset);
+ }
+
+ /**
+ * @param $offset
+ * @return int
+ */
+ protected function __vector($offset)
+ {
+ $offset += $this->bb_pos;
+ // data starts after the length
+ return $offset + $this->bb->getInt($offset) + Constants::SIZEOF_INT;
+ }
+
+// protected function __vector_as_bytebuffer($vector_offset, $elem_size)
+// {
+// }
+
+ /**
+ * @param Table $table
+ * @param int $offset
+ * @return Table
+ */
+ protected function __union($table, $offset)
+ {
+ $offset += $this->bb_pos;
+ $table->bb_pos = $offset + $this->bb->getInt($offset);
+ $table->bb = $this->bb;
+ return $table;
+ }
+
+ /**
+ * @param ByteBuffer $bb
+ * @param string $ident
+ * @return bool
+ * @throws \ArgumentException
+ */
+ protected static function __has_identifier($bb, $ident)
+ {
+ if (strlen($ident) != Constants::FILE_IDENTIFIER_LENGTH) {
+ throw new \ArgumentException("FlatBuffers: file identifier must be length " . Constants::FILE_IDENTIFIER_LENGTH);
+ }
+
+ for ($i = 0; $i < 4; $i++) {
+ if ($ident[$i] != $bb->get($bb->getPosition() + Constants::SIZEOF_INT + $i)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/flatc.cpp b/src/flatc.cpp
index b7bc7d9a..337ce5d8 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -72,6 +72,10 @@ const Generator generators[] = {
flatbuffers::GeneratorOptions::kMAX,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
+ { flatbuffers::GeneratePhp, "--php", "PHP",
+ flatbuffers::GeneratorOptions::kMAX,
+ "Generate Php files for tables/structs",
+ flatbuffers::GeneralMakeRule },
};
const char *program_name = NULL;
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
new file mode 100644
index 00000000..aba16507
--- /dev/null
+++ b/src/idl_gen_php.cpp
@@ -0,0 +1,980 @@
+/*
+* 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.
+*/
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace php {
+
+ static std::string GenGetter(const Type &type);
+ static std::string GenDefaultValue(const Value &value);
+ static std::string GenMethod(const FieldDef &field);
+ static void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr);
+ static std::string GenTypeBasic(const Type &type);
+ static std::string GenTypeGet(const Type &type);
+
+ // Ensure that a type is prefixed with its namespace whenever it is used
+ // outside of its namespace.
+ static std::string WrapInNameSpace(const Namespace *ns,
+ const std::string &name) {
+ std::string qualified_name = "\\";
+ for (auto it = ns->components.begin();
+ it != ns->components.end(); ++it) {
+ qualified_name += *it + "\\";
+ }
+ return qualified_name + name;
+ }
+
+ static std::string WrapInNameSpace(const Definition &def) {
+ return WrapInNameSpace(def.defined_namespace, def.name);
+ }
+
+
+ // Hardcode spaces per indentation.
+ const std::string Indent = " ";
+
+ // Begin by declaring namespace and imports.
+ static void BeginFile(const std::string name_space_name,
+ const bool needs_imports,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "<?php\n";
+ code += "// automatically generated, do not modify\n\n";
+ code += "namespace " + name_space_name + ";\n\n";
+
+ if (needs_imports) {
+ code += "use \\Google\\FlatBuffers\\Struct;\n";
+ code += "use \\Google\\FlatBuffers\\Table;\n";
+ code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
+ code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
+ code += "\n";
+ }
+ }
+
+ // Begin a class declaration.
+ static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ if (struct_def.fixed) {
+ code += "class " + struct_def.name + " extends Struct\n";
+ } else {
+ code += "class " + struct_def.name + " extends Table\n";
+ }
+ code += "{\n";
+ }
+
+ static void EndClass(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ // Begin enum code with a class declaration.
+ static void BeginEnum(const std::string class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "class " + class_name + "\n{\n";
+ }
+
+ // A single enum member.
+ static void EnumMember(const EnumVal ev, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "const ";
+ code += ev.name;
+ code += " = ";
+ code += NumToString(ev.value) + ";\n";
+ }
+
+ // End enum code.
+ static void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ // Initialize a new struct or table from existing data.
+ static void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param ByteBuffer $bb\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function getRootAs";
+ code += struct_def.name;
+ code += "(ByteBuffer $bb)\n";
+ code += Indent + "{\n";
+
+ code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
+ code += Indent + Indent;
+ code += "return ($obj->init($bb->getInt($bb->getPosition())";
+ code += " + $bb->getPosition(), $bb));\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ static void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int $_i offset\n";
+ code += Indent + " * @param ByteBuffer $_bb\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " **/\n";
+ code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$this->bb_pos = $_i;\n";
+ code += Indent + Indent + "$this->bb = $_bb;\n";
+ code += Indent + Indent + "return $this;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the length of a vector.
+ static void GetVectorLen(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return int\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "Length()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(";
+ code += NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a struct's scalar.
+ static void GetScalarFieldOfStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return ";
+ code += GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function " + getter;
+ code += MakeCamel(field.name) + "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return ";
+
+ code += "$this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "($this->bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += ";\n";
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a table's scalar.
+ static void GetScalarFieldOfTable(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent +
+ "$o = $this->__offset(" +
+ NumToString(field.value.offset) +
+ ");\n" + Indent + Indent + "return $o != 0 ? ";
+ code += "$this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
+ code += " : " + GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ static void GetStructFieldOfStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$obj = new ";
+ code += GenTypeGet(field.value.type) + "();\n";
+ code += Indent + Indent + "$obj->init($this->bb_pos + ";
+ code += NumToString(field.value.offset) + ", $this->bb);";
+ code += "\n" + Indent + Indent + "return $obj;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ static void GetStructFieldOfTable(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$obj = new ";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+ code += Indent + Indent +
+ "$o = $this->__offset(" +
+ NumToString(field.value.offset) +
+ ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : ";
+ code += GenDefaultValue(field.value) + ";\n";
+
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a string.
+ static void GetStringField(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent +
+ "$o = $this->__offset(" +
+ NumToString(field.value.offset) +
+ ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a union from an object.
+ static void GetUnionField(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "($obj)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent +
+ "$o = $this->__offset(" +
+ NumToString(field.value.offset) +
+ ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's struct member.
+ static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent +
+ "$o = $this->__offset(" +
+ NumToString(field.value.offset) +
+ ");\n";
+ code += Indent + Indent + "$obj = new ";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ code += Indent + Indent;
+ code += "return $o != 0 ? $obj->init($this->bb_pos +"
+ + NumToString(field.value.offset) + ", $this->bb) : null;\n";
+ } else {
+ code += Indent + Indent + "return $o != 0 ? $obj->init(";
+ code += field.value.type.struct_def->fixed
+ ? "$o + $this->bb_pos"
+ : "$this->__indirect($o + $this->bb_pos)";
+ code += ", $this->bb) : null;\n";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += "// base_type_string\n";
+ // TODO(chobie): do we need this?
+ break;
+ case BASE_TYPE_VECTOR:
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += Indent + Indent + "return $o != 0 ? $obj->init(";
+ if (vectortype.struct_def->fixed) {
+ code += "$this->__vector($o) + $j *";
+ code += NumToString(InlineSize(vectortype));
+ } else {
+ code += "$this->__indirect($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ")";
+ }
+ code += ", $this->bb) : null;\n";
+ }
+ break;
+ case BASE_TYPE_UNION:
+ code += Indent + Indent + "return $o != 0 ? $this->";
+ code += GenGetter(field.value.type) + "($obj, $o); null;\n";
+ break;
+ default:
+ break;
+ }
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ static void GetMemberOfVectorOfNonStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int offset\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent +
+ "$o = $this->__offset(" +
+ NumToString(field.value.offset) +
+ ");\n";
+
+ if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ") : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ } else {
+ code += Indent + Indent + "return $o != 0 ? $this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ") : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ }
+ code += Indent + "}\n\n";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ static void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix,
+ std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious
+ // these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(),
+ code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += (std::string)", $" + nameprefix;
+ code += MakeCamel(field.name, false);
+ }
+ }
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ static void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + Indent + "$builder->prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend();
+ ++it) {
+ auto &field = **it;
+ if (field.padding) {
+ code += Indent + Indent + "$builder->pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(),
+ code_ptr);
+ } else {
+ code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
+ code += nameprefix + MakeCamel(field.name, false) + ");\n";
+ }
+ }
+ }
+
+ // Get the value of a table's starting offset.
+ static void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function start" + struct_def.name;
+ code += "(FlatBufferBuilder $builder)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ");\n";
+ code += Indent + "}\n\n";
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create" + struct_def.name;
+ code += "(FlatBufferBuilder $builder, ";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+ code += "$" + field.name;
+ if (!(it == (--struct_def.fields.vec.end()))) {
+ code += ", ";
+ }
+ }
+ code += ")\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ");\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ code += Indent + Indent + "self::add";
+ code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
+ }
+
+ code += Indent + Indent + "$o = $builder->endObject();\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += Indent + Indent + "$builder->required($o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += Indent + Indent + "return $o;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Set the value of a table's field.
+ static void BuildFieldOfTable(const FieldDef &field,
+ const size_t offset,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function ";
+ code += "add" + MakeCamel(field.name);
+ code += "(FlatBufferBuilder $builder, ";
+ code += "$" + MakeCamel(field.name, false);
+ code += ")\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->add";
+ code += GenMethod(field) + "X(";
+ code += NumToString(offset) + ", ";
+
+
+ code += "$" + MakeCamel(field.name, false);
+ code += ", ";
+
+ if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ code += "false";
+ } else {
+ code += field.value.constant;
+ }
+ code += ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ static void BuildVectorOfTable(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param array offset array\n";
+ code += Indent + " * @return int vector offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder $builder, array $data)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startVector(";
+ code += NumToString(elem_size);
+ code += ", count($data), " + NumToString(alignment);
+ code += ");\n";
+ code += Indent + Indent;
+ code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
+ if (IsScalar(field.value.type.VectorType().base_type)) {
+ code += Indent + Indent + Indent;
+ code += "$builder->add";
+ code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
+ code += "($data[$i]);\n";
+ } else {
+ code += Indent + Indent + Indent;
+ code += "$builder->addOffset($data[$i]);\n";
+ }
+ code += Indent + Indent + "}\n";
+ code += Indent + Indent + "return $builder->endVector();\n";
+ code += Indent + "}\n\n";
+
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param int $numElems\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startVector(";
+ code += NumToString(elem_size);
+ code += ", $numElems, " + NumToString(alignment);
+ code += ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the offset of the end of a table.
+ static void GetEndOffsetOnTable(const Parser &parser,
+ const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return int table offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function end" + struct_def.name;
+ code += "(FlatBufferBuilder $builder)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $builder->endObject();\n";
+
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += Indent + Indent + "$builder->required($o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += Indent + Indent + "return $o;\n";
+ code += Indent + "}\n";
+
+ if (parser.root_struct_def_ == &struct_def) {
+ code += "\n";
+ code += Indent + "public static function finish";
+ code += struct_def.name;
+ code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->finish($offset";
+
+ if (parser.file_identifier_.length())
+ code += ", \"" + parser.file_identifier_ + "\"";
+ code += ");\n";
+ code += Indent + "}\n";
+ }
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ static void GenStructAccessor(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr);
+
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(field, code_ptr);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(field, code_ptr);
+ } else {
+ GetStructFieldOfTable(field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING:
+ GetStringField(field, code_ptr);
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION:
+ GetUnionField(field, code_ptr);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ GetVectorLen(field, code_ptr);
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ static void GenTableBuilders(const Parser &parser,
+ const StructDef &struct_def,
+ std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ if (field.value.type.base_type == BASE_TYPE_UNION) {
+ std::string &code = *code_ptr;
+ code += Indent + "public static function add";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder $builder, $offset)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->addOffsetX(";
+ code += NumToString(offset) + ", $offset, 0);\n";
+ code += Indent + "}\n\n";
+ } else {
+ BuildFieldOfTable(field, offset, code_ptr);
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ BuildVectorOfTable(field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(parser, struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ static void GenStruct(const Parser &parser, const StructDef &struct_def,
+ std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ BeginClass(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+
+ std::string &code = *code_ptr;
+ if (!struct_def.fixed) {
+ if (parser.file_identifier_.length()) {
+ // Return the identifier
+ code += Indent + "public static function " + struct_def.name;
+ code += "Identifier()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return \"";
+ code += parser.file_identifier_ + "\";\n";
+ code += Indent + "}\n\n";
+
+ // Check if a buffer has the identifier.
+ code += Indent + "public static function " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer $buf)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return self::";
+ code += "__has_identifier($buf, self::";
+ code += struct_def.name + "Identifier());\n";
+ code += Indent + "}\n\n";
+ }
+
+ if (parser.file_extension_.length()) {
+ // Return the extension
+ code += Indent + "public static function " + struct_def.name;
+ code += "Extension()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return \"" + parser.file_extension_;
+ code += "\";\n";
+ code += Indent + "}\n\n";
+ }
+ }
+
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end();
+ ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(parser, struct_def, code_ptr);
+ }
+ EndClass(code_ptr);
+ }
+
+ // Generate enum declarations.
+ static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, nullptr);
+ BeginEnum(enum_def.name, code_ptr);
+ for (auto it = enum_def.vals.vec.begin();
+ it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr);
+ EnumMember(ev, code_ptr);
+ }
+
+ std::string &code = *code_ptr;
+ code += "\n";
+ code += Indent + "private static $names = array(\n";
+ for (auto it = enum_def.vals.vec.begin();
+ it != enum_def.vals.vec.end(); ++it) {
+ auto &ev = **it;
+ code += Indent + Indent + "\"" + ev.name + "\",\n";
+ }
+
+ code += Indent + ");\n\n";
+ code += Indent + "public static function Name($e)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
+ code += Indent + Indent + Indent + "throw new \\Exception();\n";
+ code += Indent + Indent + "}\n";
+ code += Indent + Indent + "return self::$names[$e];\n";
+ code += Indent + "}\n";
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ static std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default:
+ return "Get";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ static std::string GenMethod(const FieldDef &field) {
+ return IsScalar(field.value.type.base_type)
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "Offset");
+ }
+
+
+ // Save out the generated code for a Php Table type.
+ static bool SaveType(const Parser &parser, const Definition &def,
+ const std::string &classcode, const std::string &path,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string namespace_name;
+ std::string namespace_dir = path;
+
+ auto &namespaces = parser.namespaces_.back()->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (namespace_name.length()) {
+ namespace_name += "\\";
+ namespace_dir += kPathSeparator;
+ }
+ namespace_name += *it;
+ namespace_dir += *it;
+ EnsureDirExists(namespace_dir.c_str());
+ }
+
+ std::string code = "";
+ BeginFile(namespace_name, needs_imports, &code);
+ code += classcode;
+
+ std::string filename = namespace_dir + kPathSeparator + def.name + ".php";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ static std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+#undef FLATBUFFERS_TD
+ };
+ return ctypename[type.base_type];
+ }
+
+ static std::string GenDefaultValue(const Value &value) {
+ if (value.type.enum_def) {
+ if (auto val = value.type.enum_def->ReverseLookup(
+ atoi(value.constant.c_str()), false)) {
+ return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
+ }
+ }
+
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL:
+ return value.constant == "0" ? "false" : "true";
+
+ case BASE_TYPE_STRING:
+ return "null";
+
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ if (value.constant != "0") {
+ int64_t constant = StringToInt(value.constant.c_str());
+ return NumToString(constant);
+ }
+ return "0";
+
+ default:
+ return value.constant;
+ }
+ }
+
+ static std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return "string";
+ case BASE_TYPE_VECTOR:
+ return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT:
+ return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default:
+ return "Table";
+ }
+ }
+
+ static std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : GenTypePointer(type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ static void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\n";
+ code += Indent + "/**\n";
+ code += Indent + " * @return int offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create" + struct_def.name;
+ code += "(FlatBufferBuilder $builder";
+ StructBuilderArgs(struct_def, "", code_ptr);
+ code += ")\n";
+ code += Indent + "{\n";
+
+ StructBuilderBody(struct_def, "", code_ptr);
+
+ code += Indent + Indent + "return $builder->offset();\n";
+ code += Indent + "}\n";
+ }
+
+} // namespace php
+
+ bool GeneratePhp(const Parser &parser,
+ const std::string &path,
+ const std::string & /*file_name*/,
+ const GeneratorOptions & /*opts*/) {
+ for (auto it = parser.enums_.vec.begin();
+ it != parser.enums_.vec.end(); ++it) {
+ std::string enumcode;
+ php::GenEnum(**it, &enumcode);
+
+ if (!php::SaveType(parser, **it, enumcode, path, false))
+ return false;
+ }
+
+ for (auto it = parser.structs_.vec.begin();
+ it != parser.structs_.vec.end(); ++it) {
+ std::string declcode;
+ php::GenStruct(parser, **it, &declcode);
+
+ if (!php::SaveType(parser, **it, declcode, path, true))
+ return false;
+ }
+
+ return true;
+}
+} // namespace flatbuffers
diff --git a/tests/MyGame/Example/Any.php b/tests/MyGame/Example/Any.php
new file mode 100644
index 00000000..d35bfd63
--- /dev/null
+++ b/tests/MyGame/Example/Any.php
@@ -0,0 +1,25 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+class Any
+{
+ const NONE = 0;
+ const Monster = 1;
+ const TestSimpleTableWithEnum = 2;
+
+ private static $names = array(
+ "NONE",
+ "Monster",
+ "TestSimpleTableWithEnum",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/MyGame/Example/Color.php b/tests/MyGame/Example/Color.php
new file mode 100644
index 00000000..9de0e68f
--- /dev/null
+++ b/tests/MyGame/Example/Color.php
@@ -0,0 +1,25 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+class Color
+{
+ const Red = 1;
+ const Green = 2;
+ const Blue = 8;
+
+ private static $names = array(
+ "Red",
+ "Green",
+ "Blue",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php
new file mode 100644
index 00000000..94a0df7d
--- /dev/null
+++ b/tests/MyGame/Example/Monster.php
@@ -0,0 +1,759 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+/// an example documentation comment: monster object
+class Monster extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Monster
+ */
+ public static function getRootAsMonster(ByteBuffer $bb)
+ {
+ $obj = new Monster();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function MonsterIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function MonsterBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::MonsterIdentifier());
+ }
+
+ public static function MonsterExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Monster
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getPos()
+ {
+ $obj = new Vec3();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0;
+ }
+
+ /**
+ * @return short
+ */
+ public function getMana()
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->bb->getShort($o + $this->bb_pos) : 150;
+ }
+
+ /**
+ * @return short
+ */
+ public function getHp()
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->bb->getShort($o + $this->bb_pos) : 100;
+ }
+
+ public function getName()
+ {
+ $o = $this->__offset(10);
+ return $o != 0 ? $this->__string($o + $this->bb_pos) : null;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getInventory($j)
+ {
+ $o = $this->__offset(14);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getInventoryLength()
+ {
+ $o = $this->__offset(14);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function getColor()
+ {
+ $o = $this->__offset(16);
+ return $o != 0 ? $this->bb->getSbyte($o + $this->bb_pos) : \MyGame\Example\Color::Blue;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getTestType()
+ {
+ $o = $this->__offset(18);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \MyGame\Example\Any::NONE;
+ }
+
+ /**
+ * @returnint
+ */
+ public function getTest($obj)
+ {
+ $o = $this->__offset(20);
+ return $o != 0 ? $this->__union($obj, $o) : null;
+ }
+
+ /**
+ * @returnVectorOffset
+ */
+ public function getTest4($j)
+ {
+ $o = $this->__offset(22);
+ $obj = new Test();
+ return $o != 0 ? $obj->init($this->__vector($o) + $j *4, $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTest4Length()
+ {
+ $o = $this->__offset(22);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return string
+ */
+ public function getTestarrayofstring($j)
+ {
+ $o = $this->__offset(24);
+ return $o != 0 ? $this->__string($this->__vector($o) + $j * 4) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofstringLength()
+ {
+ $o = $this->__offset(24);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+/// an example documentation comment: this will end up in the generated code
+/// multiline too
+ /**
+ * @returnVectorOffset
+ */
+ public function getTestarrayoftables($j)
+ {
+ $o = $this->__offset(26);
+ $obj = new Monster();
+ return $o != 0 ? $obj->init($this->__indirect($this->__vector($o) + $j * 4), $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayoftablesLength()
+ {
+ $o = $this->__offset(26);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ public function getEnemy()
+ {
+ $obj = new Monster();
+ $o = $this->__offset(28);
+ return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getTestnestedflatbuffer($j)
+ {
+ $o = $this->__offset(30);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestnestedflatbufferLength()
+ {
+ $o = $this->__offset(30);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ public function getTestempty()
+ {
+ $obj = new Stat();
+ $o = $this->__offset(32);
+ return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getTestbool()
+ {
+ $o = $this->__offset(34);
+ return $o != 0 ? $this->bb->getBool($o + $this->bb_pos) : false;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTesthashs32Fnv1()
+ {
+ $o = $this->__offset(36);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return uint
+ */
+ public function getTesthashu32Fnv1()
+ {
+ $o = $this->__offset(38);
+ return $o != 0 ? $this->bb->getUint($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return long
+ */
+ public function getTesthashs64Fnv1()
+ {
+ $o = $this->__offset(40);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getTesthashu64Fnv1()
+ {
+ $o = $this->__offset(42);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTesthashs32Fnv1a()
+ {
+ $o = $this->__offset(44);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return uint
+ */
+ public function getTesthashu32Fnv1a()
+ {
+ $o = $this->__offset(46);
+ return $o != 0 ? $this->bb->getUint($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return long
+ */
+ public function getTesthashs64Fnv1a()
+ {
+ $o = $this->__offset(48);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getTesthashu64Fnv1a()
+ {
+ $o = $this->__offset(50);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return bool
+ */
+ public function getTestarrayofbools($j)
+ {
+ $o = $this->__offset(52);
+ return $o != 0 ? $this->bb->getBool($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofboolsLength()
+ {
+ $o = $this->__offset(52);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startMonster(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(25);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Monster
+ */
+ public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools)
+ {
+ $builder->startObject(25);
+ self::addPos($builder, $pos);
+ self::addMana($builder, $mana);
+ self::addHp($builder, $hp);
+ self::addName($builder, $name);
+ self::addInventory($builder, $inventory);
+ self::addColor($builder, $color);
+ self::addTestType($builder, $test_type);
+ self::addTest($builder, $test);
+ self::addTest4($builder, $test4);
+ self::addTestarrayofstring($builder, $testarrayofstring);
+ self::addTestarrayoftables($builder, $testarrayoftables);
+ self::addEnemy($builder, $enemy);
+ self::addTestnestedflatbuffer($builder, $testnestedflatbuffer);
+ self::addTestempty($builder, $testempty);
+ self::addTestbool($builder, $testbool);
+ self::addTesthashs32Fnv1($builder, $testhashs32_fnv1);
+ self::addTesthashu32Fnv1($builder, $testhashu32_fnv1);
+ self::addTesthashs64Fnv1($builder, $testhashs64_fnv1);
+ self::addTesthashu64Fnv1($builder, $testhashu64_fnv1);
+ self::addTesthashs32Fnv1a($builder, $testhashs32_fnv1a);
+ self::addTesthashu32Fnv1a($builder, $testhashu32_fnv1a);
+ self::addTesthashs64Fnv1a($builder, $testhashs64_fnv1a);
+ self::addTesthashu64Fnv1a($builder, $testhashu64_fnv1a);
+ self::addTestarrayofbools($builder, $testarrayofbools);
+ $o = $builder->endObject();
+ $builder->required($o, 10); // name
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addPos(FlatBufferBuilder $builder, $pos)
+ {
+ $builder->addStructX(0, $pos, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param short
+ * @return void
+ */
+ public static function addMana(FlatBufferBuilder $builder, $mana)
+ {
+ $builder->addShortX(1, $mana, 150);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param short
+ * @return void
+ */
+ public static function addHp(FlatBufferBuilder $builder, $hp)
+ {
+ $builder->addShortX(2, $hp, 100);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param StringOffset
+ * @return void
+ */
+ public static function addName(FlatBufferBuilder $builder, $name)
+ {
+ $builder->addOffsetX(3, $name, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addInventory(FlatBufferBuilder $builder, $inventory)
+ {
+ $builder->addOffsetX(5, $inventory, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createInventoryVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startInventoryVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param sbyte
+ * @return void
+ */
+ public static function addColor(FlatBufferBuilder $builder, $color)
+ {
+ $builder->addSbyteX(6, $color, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addTestType(FlatBufferBuilder $builder, $testType)
+ {
+ $builder->addByteX(7, $testType, 0);
+ }
+
+ public static function addTest(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->addOffsetX(8, $offset, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTest4(FlatBufferBuilder $builder, $test4)
+ {
+ $builder->addOffsetX(9, $test4, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTest4Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 2);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTest4Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofstring(FlatBufferBuilder $builder, $testarrayofstring)
+ {
+ $builder->addOffsetX(10, $testarrayofstring, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofstringVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofstringVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayoftables(FlatBufferBuilder $builder, $testarrayoftables)
+ {
+ $builder->addOffsetX(11, $testarrayoftables, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayoftablesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayoftablesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addEnemy(FlatBufferBuilder $builder, $enemy)
+ {
+ $builder->addOffsetX(12, $enemy, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestnestedflatbuffer(FlatBufferBuilder $builder, $testnestedflatbuffer)
+ {
+ $builder->addOffsetX(13, $testnestedflatbuffer, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestnestedflatbufferVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestnestedflatbufferVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addTestempty(FlatBufferBuilder $builder, $testempty)
+ {
+ $builder->addOffsetX(14, $testempty, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param bool
+ * @return void
+ */
+ public static function addTestbool(FlatBufferBuilder $builder, $testbool)
+ {
+ $builder->addBoolX(15, $testbool, false);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addTesthashs32Fnv1(FlatBufferBuilder $builder, $testhashs32Fnv1)
+ {
+ $builder->addIntX(16, $testhashs32Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param uint
+ * @return void
+ */
+ public static function addTesthashu32Fnv1(FlatBufferBuilder $builder, $testhashu32Fnv1)
+ {
+ $builder->addUintX(17, $testhashu32Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addTesthashs64Fnv1(FlatBufferBuilder $builder, $testhashs64Fnv1)
+ {
+ $builder->addLongX(18, $testhashs64Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addTesthashu64Fnv1(FlatBufferBuilder $builder, $testhashu64Fnv1)
+ {
+ $builder->addUlongX(19, $testhashu64Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addTesthashs32Fnv1a(FlatBufferBuilder $builder, $testhashs32Fnv1a)
+ {
+ $builder->addIntX(20, $testhashs32Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param uint
+ * @return void
+ */
+ public static function addTesthashu32Fnv1a(FlatBufferBuilder $builder, $testhashu32Fnv1a)
+ {
+ $builder->addUintX(21, $testhashu32Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addTesthashs64Fnv1a(FlatBufferBuilder $builder, $testhashs64Fnv1a)
+ {
+ $builder->addLongX(22, $testhashs64Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addTesthashu64Fnv1a(FlatBufferBuilder $builder, $testhashu64Fnv1a)
+ {
+ $builder->addUlongX(23, $testhashu64Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofbools(FlatBufferBuilder $builder, $testarrayofbools)
+ {
+ $builder->addOffsetX(24, $testarrayofbools, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofboolsVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->addBool($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofboolsVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endMonster(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ $builder->required($o, 10); // name
+ return $o;
+ }
+
+ public static function finishMonsterBuffer(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->finish($offset, "MONS");
+ }
+}
diff --git a/tests/MyGame/Example/Stat.php b/tests/MyGame/Example/Stat.php
new file mode 100644
index 00000000..c959ac7b
--- /dev/null
+++ b/tests/MyGame/Example/Stat.php
@@ -0,0 +1,136 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Stat extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Stat
+ */
+ public static function getRootAsStat(ByteBuffer $bb)
+ {
+ $obj = new Stat();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function StatIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function StatBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::StatIdentifier());
+ }
+
+ public static function StatExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Stat
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getId()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->__string($o + $this->bb_pos) : null;
+ }
+
+ /**
+ * @return long
+ */
+ public function getVal()
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ushort
+ */
+ public function getCount()
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->bb->getUshort($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startStat(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(3);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Stat
+ */
+ public static function createStat(FlatBufferBuilder $builder, $id, $val, $count)
+ {
+ $builder->startObject(3);
+ self::addId($builder, $id);
+ self::addVal($builder, $val);
+ self::addCount($builder, $count);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param StringOffset
+ * @return void
+ */
+ public static function addId(FlatBufferBuilder $builder, $id)
+ {
+ $builder->addOffsetX(0, $id, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addVal(FlatBufferBuilder $builder, $val)
+ {
+ $builder->addLongX(1, $val, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ushort
+ * @return void
+ */
+ public static function addCount(FlatBufferBuilder $builder, $count)
+ {
+ $builder->addUshortX(2, $count, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endStat(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example/Test.php b/tests/MyGame/Example/Test.php
new file mode 100644
index 00000000..acc838a3
--- /dev/null
+++ b/tests/MyGame/Example/Test.php
@@ -0,0 +1,53 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Test extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Test
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return short
+ */
+ public function GetA()
+ {
+ return $this->bb->getShort($this->bb_pos + 0);
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function GetB()
+ {
+ return $this->bb->getSbyte($this->bb_pos + 2);
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createTest(FlatBufferBuilder $builder, $a, $b)
+ {
+ $builder->prep(2, 4);
+ $builder->pad(1);
+ $builder->putSbyte($b);
+ $builder->putShort($a);
+ return $builder->offset();
+ }
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.php b/tests/MyGame/Example/TestSimpleTableWithEnum.php
new file mode 100644
index 00000000..6181461e
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.php
@@ -0,0 +1,99 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TestSimpleTableWithEnum extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TestSimpleTableWithEnum
+ */
+ public static function getRootAsTestSimpleTableWithEnum(ByteBuffer $bb)
+ {
+ $obj = new TestSimpleTableWithEnum();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function TestSimpleTableWithEnumIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function TestSimpleTableWithEnumBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::TestSimpleTableWithEnumIdentifier());
+ }
+
+ public static function TestSimpleTableWithEnumExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TestSimpleTableWithEnum
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function getColor()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getSbyte($o + $this->bb_pos) : \MyGame\Example\Color::Green;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTestSimpleTableWithEnum(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TestSimpleTableWithEnum
+ */
+ public static function createTestSimpleTableWithEnum(FlatBufferBuilder $builder, $color)
+ {
+ $builder->startObject(1);
+ self::addColor($builder, $color);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param sbyte
+ * @return void
+ */
+ public static function addColor(FlatBufferBuilder $builder, $color)
+ {
+ $builder->addSbyteX(0, $color, 2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTestSimpleTableWithEnum(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example/Vec3.php b/tests/MyGame/Example/Vec3.php
new file mode 100644
index 00000000..022254ce
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.php
@@ -0,0 +1,96 @@
+<?php
+// automatically generated, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Vec3 extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Vec3
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return float
+ */
+ public function GetX()
+ {
+ return $this->bb->getFloat($this->bb_pos + 0);
+ }
+
+ /**
+ * @return float
+ */
+ public function GetY()
+ {
+ return $this->bb->getFloat($this->bb_pos + 4);
+ }
+
+ /**
+ * @return float
+ */
+ public function GetZ()
+ {
+ return $this->bb->getFloat($this->bb_pos + 8);
+ }
+
+ /**
+ * @return double
+ */
+ public function GetTest1()
+ {
+ return $this->bb->getDouble($this->bb_pos + 16);
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function GetTest2()
+ {
+ return $this->bb->getSbyte($this->bb_pos + 24);
+ }
+
+ /**
+ * @return Test
+ */
+ public function getTest3()
+ {
+ $obj = new Test();
+ $obj->init($this->bb_pos + 26, $this->bb);
+ return $obj;
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createVec3(FlatBufferBuilder $builder, $x, $y, $z, $test1, $test2, $test3_a, $test3_b)
+ {
+ $builder->prep(16, 32);
+ $builder->pad(2);
+ $builder->prep(2, 4);
+ $builder->pad(1);
+ $builder->putSbyte($test3_b);
+ $builder->putShort($test3_a);
+ $builder->pad(1);
+ $builder->putSbyte($test2);
+ $builder->putDouble($test1);
+ $builder->pad(4);
+ $builder->putFloat($z);
+ $builder->putFloat($y);
+ $builder->putFloat($x);
+ return $builder->offset();
+ }
+}
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
new file mode 100644
index 00000000..75ac1433
--- /dev/null
+++ b/tests/generate_code.bat
@@ -0,0 +1,2 @@
+..\flatc.exe -c -j -n -g -b -p --php -s --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
+..\flatc.exe -b --schema monster_test.fbs
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index 3e96712f..91158bff 100644
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -1,2 +1,2 @@
-../flatc -c -j -n -g -b -p -s --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
+../flatc -c -j -n -g -b -p -s --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
../flatc -b --schema monster_test.fbs
diff --git a/tests/phpTest.php b/tests/phpTest.php
new file mode 100644
index 00000000..bace87db
--- /dev/null
+++ b/tests/phpTest.php
@@ -0,0 +1,609 @@
+<?php
+// manual load for testing. please use PSR style autoloader when you use flatbuffers.
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Constants.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "ByteBuffer.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "FlatbufferBuilder.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Table.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Struct.php"));
+foreach (glob(join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "MyGame", "Example", "*.php"))) as $file) {
+ require $file;
+}
+
+function main()
+{
+ /// Begin Test
+ $assert = new Assert();
+
+ // First, let's test reading a FlatBuffer generated by C++ code:
+ // This file was generated from monsterdata_test.json
+
+ // Now test it:
+ $data = file_get_contents('monsterdata_test.mon');
+ $bb = Google\FlatBuffers\ByteBuffer::wrap($data);
+ test_buffer($assert, $bb);
+
+ // Second, let's create a FlatBuffer from scratch in JavaScript, and test it also.
+ // We use an initial size of 1 to exercise the reallocation algorithm,
+ // normally a size larger than the typical FlatBuffer you generate would be
+ // better for performance.
+ $fbb = new Google\FlatBuffers\FlatBufferBuilder(1);
+
+ // We set up the same values as monsterdata.json:
+ $str = $fbb->createString("MyMonster");
+
+ $inv = \MyGame\Example\Monster::CreateInventoryVector($fbb, array(0, 1, 2, 3, 4));
+
+ $fred = $fbb->createString('Fred');
+ \MyGame\Example\Monster::StartMonster($fbb);
+ \MyGame\Example\Monster::AddName($fbb, $fred);
+ $mon2 = \MyGame\Example\Monster::EndMonster($fbb);
+
+ \MyGame\Example\Monster::StartTest4Vector($fbb, 2);
+ \MyGame\Example\Test::CreateTest($fbb, 10, 20);
+ \MyGame\Example\Test::CreateTest($fbb, 30, 40);
+ $test4 = $fbb->endVector();
+
+ $testArrayOfString = \MyGame\Example\Monster::CreateTestarrayofstringVector($fbb, array(
+ $fbb->createString('test1'),
+ $fbb->createString('test2')
+ ));
+
+ \MyGame\Example\Monster::StartMonster($fbb);
+ \MyGame\Example\Monster::AddPos($fbb, \MyGame\Example\Vec3::CreateVec3($fbb,
+ 1.0, 2.0, 3.0, //float
+ 3.0, // double
+ \MyGame\Example\Color::Green,
+ 5, //short
+ 6));
+ \MyGame\Example\Monster::AddHp($fbb, 80);
+ \MyGame\Example\Monster::AddName($fbb, $str);
+ \MyGame\Example\Monster::AddInventory($fbb, $inv);
+ \MyGame\Example\Monster::AddTestType($fbb, \MyGame\Example\Any::Monster);
+ \MyGame\Example\Monster::AddTest($fbb, $mon2);
+ \MyGame\Example\Monster::AddTest4($fbb, $test4);
+ \MyGame\Example\Monster::AddTestarrayofstring($fbb, $testArrayOfString);
+ \MyGame\Example\Monster::AddTestbool($fbb, false);
+ $mon = \MyGame\Example\Monster::EndMonster($fbb);
+
+ \MyGame\Example\Monster::FinishMonsterBuffer($fbb, $mon);
+
+ // Test it:
+ test_buffer($assert, $fbb->dataBuffer());
+
+ testByteBuffer($assert);
+ fuzzTest1($assert);
+// testUnicode($assert);
+
+ echo 'FlatBuffers php test: completed successfully' . PHP_EOL;
+}
+
+try {
+ main();
+ exit(0);
+} catch(Exception $e) {
+ printf("Fatal error: Uncaught exception '%s' with message '%s. in %s:%d\n", get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
+ printf("Stack trace:\n");
+ echo $e->getTraceAsString() . PHP_EOL;
+ printf(" thrown in in %s:%d\n", $e->getFile(), $e->getLine());
+
+ die(-1);
+}
+
+function test_buffer(Assert $assert, Google\FlatBuffers\ByteBuffer $bb) {
+
+ $assert->ok(MyGame\Example\Monster::MonsterBufferHasIdentifier($bb));
+ $monster = \MyGame\Example\Monster::GetRootAsMonster($bb);
+
+ $assert->strictEqual($monster->GetHp(), 80);
+ $assert->strictEqual($monster->GetMana(), 150); // default
+
+ $assert->strictEqual($monster->GetName(), 'MyMonster');
+
+ $pos = $monster->GetPos();
+ $assert->strictEqual($pos->GetX(), 1.0);
+ $assert->strictEqual($pos->GetY(), 2.0);
+ $assert->strictEqual($pos->GetZ(), 3.0);
+
+ $assert->Equal($pos->GetTest1(), 3.0);
+ $assert->strictEqual($pos->GetTest2(), \MyGame\Example\Color::Green);
+
+ $t = $pos->GetTest3();
+ $assert->strictEqual($t->GetA(), 5);
+ $assert->strictEqual($t->GetB(), 6);
+ $assert->strictEqual($monster->GetTestType(), \MyGame\Example\Any::Monster);
+
+ $monster2 = new \MyGame\Example\Monster();
+ $assert->strictEqual($monster->GetTest($monster2) != null, true);
+ $assert->strictEqual($monster2->GetName(), 'Fred');
+
+ $assert->strictEqual($monster->GetInventoryLength(), 5);
+ $invsum = 0;
+ for ($i = 0; $i < $monster->GetInventoryLength(); $i++) {
+ $invsum += $monster->GetInventory($i);
+ }
+ $assert->strictEqual($invsum, 10);
+
+
+ $test_0 = $monster->GetTest4(0);
+ $test_1 = $monster->GetTest4(1);
+ $assert->strictEqual($monster->GetTest4Length(), 2);
+ $assert->strictEqual($test_0->GetA() + $test_0->GetB() + $test_1->GetA() + $test_1->GetB(), 100);
+
+ $assert->strictEqual($monster->GetTestarrayofstringLength(), 2);
+ $assert->strictEqual($monster->GetTestarrayofstring(0), 'test1');
+ $assert->strictEqual($monster->GetTestarrayofstring(1), 'test2');
+ $assert->strictEqual($monster->GetTestbool(), false);
+}
+
+//function testUnicode(Assert $assert) {
+// // missing unicode_test.mon, implemented later
+// $correct = file_get_contents('unicode_test.mon');
+// $json = json_decode(file_get_contents('unicode_test.json'));
+//
+// // Test reading
+// $bb = flatbuffers\ByteBuffer::Wrap($correct);
+// $monster = \MyGame\Example\Monster::GetRootAsMonster($bb);
+// $assert->strictEqual($monster->GetName(), $json["name"]);
+//
+// //$assert->deepEqual(new Buffer(monster.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(json.name));
+// //assert.strictEqual(monster.testarrayoftablesLength(), json.testarrayoftables.length);
+// foreach ($json["testarrayoftables"]as $i => $table) {
+// $value = $monster->GetTestArrayOfTables($i);
+// $assert->strictEqual($value->GetName(), $table["name"]);
+// //assert.deepEqual(new Buffer(value.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(table.name));
+// }
+// $assert->strictEqual($monster->GetTestarrayofstringLength(), $json["testarrayofstring"]["length"]);
+// foreach ($json["testarrayofstring"] as $i => $string) {
+// $assert->strictEqual($monster->GetTestarrayofstring($i), $string);
+// //assert.deepEqual(new Buffer(monster.testarrayofstring(i, flatbuffers.Encoding.UTF8_BYTES)), new Buffer(string));
+// }
+//
+// // Test writing
+// $fbb = new FlatBuffers\FlatBufferBuilder(1);
+// $name = $fbb->CreateString($json["name"]);
+// $testarrayoftablesOffsets = array_map(function($table) use($fbb) {
+// $name = $fbb->CreateString($table["name"]);
+// \MyGame\Example\Monster::StartMonster($fbb);
+// \MyGame\Example\Monster::AddName($fbb, $name);
+// return \MyGame\Example\Monster::EndMonster($fbb);
+// }, $json["testarrayoftables"]);
+// $testarrayoftablesOffset = \MyGame\Example\Monster::CreateTestarrayoftablesVector($fbb,
+// $testarrayoftablesOffsets);
+//// $testarrayofstringOffset = \MyGame\Example\Monster::CreateTestarrayofstringVector($fbb,
+//// $json["testarrayofstring"].map(function(string) { return fbb.createString(string); }));
+//
+// \MyGame\Example\Monster::startMonster($fbb);
+// \MyGame\Example\Monster::addTestarrayofstring($fbb, $testarrayoftablesOffset);
+// \MyGame\Example\Monster::addTestarrayoftables($fbb, $testarrayoftablesOffset);
+// \MyGame\Example\Monster::addName($fbb, $name);
+// \MyGame\Example\Monster::finishMonsterBuffer($fbb, \MyGame\Example\Monster::endMonster($fbb));
+// //;assert.deepEqual(new Buffer(fbb.asUint8Array()), correct);
+//}
+
+// Low level stress/fuzz test: serialize/deserialize a variety of
+// different kinds of data in different combinations
+function fuzzTest1(Assert $assert)
+{
+
+ // Values we're testing against: chosen to ensure no bits get chopped
+ // off anywhere, and also be different from eachother.
+ $bool_val = true;
+ $char_val = -127; // 0x81
+ $uchar_val = 0xFF;
+ $short_val = -32222; // 0x8222;
+ $ushort_val = 0xFEEE;
+ $int_val = 0x83333333 | 0;
+ // for now
+ $uint_val = 1;
+ $long_val = 2;
+ $ulong_val = 3;
+
+// var uint_val = 0xFDDDDDDD;
+// var long_val = new flatbuffers.Long(0x44444444, 0x84444444);
+// var ulong_val = new flatbuffers.Long(0xCCCCCCCC, 0xFCCCCCCC);
+
+ $float_val = 3.14159;
+ $double_val = 3.14159265359;
+
+ $test_values_max = 11;
+ $fields_per_object = 4;
+ // current implementation is not good at encoding.
+ $num_fuzz_objects = 1000;
+ $builder = new Google\FlatBuffers\FlatBufferBuilder(1);
+
+ // can't use same implementation due to PHP_INTMAX overflow issue.
+ // we use mt_rand function to reproduce fuzzy test.
+ mt_srand(48271);
+ $objects = array();
+ // Generate num_fuzz_objects random objects each consisting of
+ // fields_per_object fields, each of a random type.
+ for ($i = 0; $i < $num_fuzz_objects; $i++) {
+ $builder->startObject($fields_per_object);
+ for ($f = 0; $f < $fields_per_object; $f++) {
+ $choice = mt_rand() % $test_values_max;
+ switch ($choice) {
+ case 0:
+ $builder->addBoolX($f, $bool_val, 0);
+ break;
+ case 1:
+ $builder->addByteX($f, $char_val, 0);
+ break;
+ case 2:
+ $builder->addSbyteX($f, $uchar_val, 0);
+ break;
+ case 3:
+ $builder->addShortX($f, $short_val, 0);
+ break;
+ case 4:
+ $builder->addUshortX($f, $ushort_val, 0);
+ break;
+ case 5:
+ $builder->addIntX($f, $int_val, 0);
+ break;
+ case 6:
+ $builder->addUintX($f, $uint_val, 0);
+ break;
+ case 7:
+ $builder->addLongX($f, $long_val, 0);
+ break;
+ case 8:
+ $builder->addUlongX($f, $ulong_val, 0);
+ break;
+ case 9:
+ $builder->addFloatX($f, $float_val, 0);
+ break;
+ case 10:
+ $builder->addDoubleX($f, $double_val, 0);
+ break;
+ }
+ }
+ $objects[] = $builder->endObject();
+ }
+ $builder->prep(8, 0); // Align whole buffer.
+
+ mt_srand(48271); // Reset
+ $builder->finish($objects[count($objects) - 1]);
+
+ $view = Google\FlatBuffers\ByteBuffer::wrap($builder->sizedByteArray());
+ for ($i = 0; $i < $num_fuzz_objects; $i++) {
+ $offset = $view->capacity() - $objects[$i];
+ for ($f = 0; $f < $fields_per_object; $f++) {
+ $choice = mt_rand() % $test_values_max;
+ $vtable_offset = fieldIndexToOffset($f);
+ $vtable = $offset - $view->getInt($offset);
+ $assert->ok($vtable_offset < $view->getShort($vtable));
+ $field_offset = $offset + $view->getShort($vtable + $vtable_offset);
+ switch ($choice) {
+ case 0:
+ $assert->strictEqual(!!$view->getBool($field_offset), $bool_val);
+ break;
+ case 1:
+ $assert->strictEqual($view->getSbyte($field_offset), $char_val);
+ break;
+ case 2:
+ $assert->strictEqual($view->getByte($field_offset), $uchar_val);
+ break;
+ case 3:
+ $assert->strictEqual($view->getShort($field_offset), $short_val);
+ break;
+ case 4:
+ $assert->strictEqual($view->getUShort($field_offset), $ushort_val);
+ break;
+ case 5:
+ $assert->strictEqual($view->getInt($field_offset), $int_val);
+ break;
+ case 6:
+ $assert->strictEqual($view->getUint($field_offset), $uint_val);
+ break;
+ case 7:
+ if (PHP_INT_SIZE <= 4) break;
+ $assert->strictEqual($view->getLong($field_offset), $long_val);
+ break;
+ case 8:
+ if (PHP_INT_SIZE <= 4) break;
+ $assert->strictEqual($view->getUlong($field_offset), $ulong_val);
+ break;
+ case 9:
+ $assert->strictEqual(floor($view->getFloat($field_offset)), floor($float_val));
+ break;
+ case 10:
+ $assert->strictEqual($view->getDouble($field_offset), $double_val);
+ break;
+ }
+ }
+ }
+}
+
+function fieldIndexToOffset($field_id) {
+ // Should correspond to what EndTable() below builds up.
+ $fixed_fields = 2; // Vtable size and Object Size.
+ return ($field_id + $fixed_fields) * 2;
+}
+
+function testByteBuffer(Assert $assert) {
+
+ //Test: ByteBuffer_Length_MatchesBufferLength
+ $buffer = str_repeat("\0", 100);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal($uut->capacity(), strlen($buffer));
+
+ //Test: ByteBuffer_PutBytePopulatesBufferAtZeroOffset
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putByte(0, "\x63"); // 99
+ $assert->Equal("\x63", $uut->_buffer[0]); // don't share buffer as php user might confuse reference.
+
+ //Test: ByteBuffer_PutByteCannotPutAtOffsetPastLength
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putByte(1, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutShortPopulatesBufferCorrectly
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putShort(0, 1);
+
+ // Ensure Endiannes was written correctly
+ $assert->Equal(chr(0x01), $uut->_buffer[0]);
+ $assert->Equal(chr(0x00), $uut->_buffer[1]);
+
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putShort(0, -32768);
+
+ // Ensure Endiannes was written correctly
+ $assert->Equal(chr(0x00), $uut->_buffer[0]);
+ $assert->Equal(chr(0x80), $uut->_buffer[1]);
+
+ //Test: ByteBuffer_PutShortCannotPutAtOffsetPastLength
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putShort(2, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutShortChecksLength
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putShort(0, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutShortChecksLengthAndOffset
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putShort(1, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutIntPopulatesBufferCorrectly
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putInt(0, 0x0A0B0C0D);
+ $assert->Equal(chr(0x0D), $uut->_buffer[0]);
+ $assert->Equal(chr(0x0C), $uut->_buffer[1]);
+ $assert->Equal(chr(0x0B), $uut->_buffer[2]);
+ $assert->Equal(chr(0x0A), $uut->_buffer[3]);
+
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putInt(0, -2147483648);
+ $assert->Equal(chr(0x00), $uut->_buffer[0]);
+ $assert->Equal(chr(0x00), $uut->_buffer[1]);
+ $assert->Equal(chr(0x00), $uut->_buffer[2]);
+ $assert->Equal(chr(0x80), $uut->_buffer[3]);
+
+ //Test: ByteBuffer_PutIntCannotPutAtOffsetPastLength
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putInt(2, 0x0A0B0C0D);
+ });
+
+ //Test: ByteBuffer_PutIntChecksLength
+ $buffer = str_repeat("\0", 1);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putInt(0, 0x0A0B0C0D);
+ });
+
+ //Test: ByteBuffer_PutIntChecksLengthAndOffset
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putInt(2, 0x0A0B0C0D);
+ });
+
+ if (PHP_INT_SIZE > 4) {
+ //Test: ByteBuffer_PutLongPopulatesBufferCorrectly
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putLong(0, 0x010203040A0B0C0D);
+ $assert->Equal(chr(0x0D), $uut->_buffer[0]);
+ $assert->Equal(chr(0x0C), $uut->_buffer[1]);
+ $assert->Equal(chr(0x0B), $uut->_buffer[2]);
+ $assert->Equal(chr(0x0A), $uut->_buffer[3]);
+ $assert->Equal(chr(0x04), $uut->_buffer[4]);
+ $assert->Equal(chr(0x03), $uut->_buffer[5]);
+ $assert->Equal(chr(0x02), $uut->_buffer[6]);
+ $assert->Equal(chr(0x01), $uut->_buffer[7]);
+
+ //Test: ByteBuffer_PutLongCannotPutAtOffsetPastLength
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putLong(2, 0x010203040A0B0C0D);
+ });
+
+ //Test: ByteBuffer_PutLongCannotPutAtOffsetPastLength
+ $buffer = str_repeat("\0", 1);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putLong(0, 0x010203040A0B0C0D);
+ });
+
+
+ //Test: ByteBuffer_PutLongChecksLengthAndOffset
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putLong(2, 0x010203040A0B0C0D);
+ });
+ }
+
+ //Test: ByteBuffer_GetByteReturnsCorrectData
+ $buffer = str_repeat("\0", 1);
+ $buffer[0] = "\x63";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal("\x63", $uut->get(0));
+
+ //Test: ByteBuffer_GetByteChecksOffset
+ $buffer = str_repeat("\0", 1);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->get(1);
+ });
+
+ //Test: ByteBuffer_GetShortReturnsCorrectData
+ $buffer = str_repeat("\0", 2);
+ $buffer[0] = chr(0x01);
+ $buffer[1] = chr(0x00);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(1, $uut->getShort(0));
+
+ //Test: ByteBuffer_GetShortReturnsCorrectData (signed value)
+ $buffer = str_repeat("\0", 2);
+ $buffer[0] = chr(0x00);
+ $buffer[1] = chr(0x80);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(-32768, $uut->getShort(0));
+
+ //Test: ByteBuffer_GetShortChecksOffset
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getShort(2);
+ });
+
+ //Test: ByteBuffer_GetShortChecksLength
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getShort(1);
+ });
+
+ //Test: ByteBuffer_GetIntReturnsCorrectData
+ $buffer = str_repeat("\0", 4);
+ $buffer[0] = chr(0x0D);
+ $buffer[1] = chr(0x0C);
+ $buffer[2] = chr(0x0B);
+ $buffer[3] = chr(0x0A);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(0x0A0B0C0D, $uut->getInt(0));
+
+ $buffer = str_repeat("\0", 4);
+ $buffer[0] = chr(0x00);
+ $buffer[1] = chr(0x00);
+ $buffer[2] = chr(0x00);
+ $buffer[3] = chr(0x80);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(-2147483648, $uut->getInt(0));
+
+ //Test: ByteBuffer_GetIntChecksOffset
+ $buffer = str_repeat("\0", 4);
+
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getInt(4);
+ });
+
+ //Test: ByteBuffer_GetIntChecksLength
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getInt(0);
+ });
+
+ if (PHP_INT_SIZE > 4) {
+ //Test: ByteBuffer_GetLongReturnsCorrectData
+ $buffer = str_repeat("\0", 8);
+ $buffer[0] = chr(0x0D);
+ $buffer[1] = chr(0x0C);
+ $buffer[2] = chr(0x0B);
+ $buffer[3] = chr(0x0A);
+ $buffer[4] = chr(0x04);
+ $buffer[5] = chr(0x03);
+ $buffer[6] = chr(0x02);
+ $buffer[7] = chr(0x01);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(0x010203040A0B0C0D, $uut->getLong(0));
+ }
+
+ //Test: ByteBuffer_GetLongChecksOffset
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getLong(8);
+ });
+
+ //Test: ByteBuffer_GetLongChecksLength
+ $buffer = str_repeat("\0", 7);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getLong(0);
+ });
+
+ //Test: big endian
+ $buffer = str_repeat("\0", 2);
+ // 0xFF 0x00
+ // Little Endian: 255
+ // Big Endian: 65280
+ $buffer[0] = chr(0xff);
+ $buffer[1] = chr(0x00);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(65280, $uut->readLittleEndian(0, 2, true));
+
+ $buffer = str_repeat("\0", 4);
+ $buffer[0] = chr(0x0D);
+ $buffer[1] = chr(0x0C);
+ $buffer[2] = chr(0x0B);
+ $buffer[3] = chr(0x0A);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(0x0D0C0B0A, $uut->readLittleEndian(0, 4, true));
+
+}
+
+class Assert {
+ public function ok($result, $message = "") {
+ if (!$result){
+ throw new Exception(!empty($message) ? $message : "{$result} is not true.");
+ }
+ }
+
+ public function Equal($result, $expected, $message = "") {
+ if ($result != $expected) {
+ throw new Exception(!empty($message) ? $message : "given the result {$result} is not equals as {$expected}");
+ }
+ }
+
+
+ public function strictEqual($result, $expected, $message = "") {
+ if ($result !== $expected) {
+ throw new Exception(!empty($message) ? $message : "given the result {$result} is not strict equals as {$expected}");
+ }
+ }
+
+ public function Throws($class, Callable $callback) {
+ try {
+ $callback();
+
+ throw new \Exception("passed statement don't throw an exception.");
+ } catch (\Exception $e) {
+ if (get_class($e) != get_class($class)) {
+ throw new Exception("passed statement doesn't throw " . get_class($class) . ". throwws " . get_class($e));
+ }
+ }
+ }
+}