diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | composer.json | 18 | ||||
-rw-r--r-- | include/flatbuffers/idl.h | 7 | ||||
-rw-r--r-- | php/ByteBuffer.php | 495 | ||||
-rw-r--r-- | php/Constants.php | 25 | ||||
-rw-r--r-- | php/FlatbufferBuilder.php | 918 | ||||
-rw-r--r-- | php/Struct.php | 31 | ||||
-rw-r--r-- | php/Table.php | 129 | ||||
-rw-r--r-- | src/flatc.cpp | 4 | ||||
-rw-r--r-- | src/idl_gen_php.cpp | 980 | ||||
-rw-r--r-- | tests/MyGame/Example/Any.php | 25 | ||||
-rw-r--r-- | tests/MyGame/Example/Color.php | 25 | ||||
-rw-r--r-- | tests/MyGame/Example/Monster.php | 759 | ||||
-rw-r--r-- | tests/MyGame/Example/Stat.php | 136 | ||||
-rw-r--r-- | tests/MyGame/Example/Test.php | 53 | ||||
-rw-r--r-- | tests/MyGame/Example/TestSimpleTableWithEnum.php | 99 | ||||
-rw-r--r-- | tests/MyGame/Example/Vec3.php | 96 | ||||
-rw-r--r-- | tests/generate_code.bat | 2 | ||||
-rw-r--r-- | tests/generate_code.sh | 2 | ||||
-rw-r--r-- | tests/phpTest.php | 609 |
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)); + } + } + } +} |