Check in php implementation. (#2052)
This pull request includes two implementation: C extension and PHP package. Both implementations support encode/decode of singular, repeated and map fields.pull/2122/merge
parent
86fcd879b3
commit
e0e54661f7
58 changed files with 20236 additions and 3906 deletions
@ -0,0 +1,24 @@ |
||||
{ |
||||
"name": "google/protobuf", |
||||
"type": "library", |
||||
"description": "proto library for PHP", |
||||
"keywords": ["proto"], |
||||
"homepage": "https://developers.google.com/protocol-buffers/", |
||||
"license": "BSD-3-Clause", |
||||
"require": { |
||||
"php": ">=5.5.0" |
||||
}, |
||||
"require-dev": { |
||||
"phpunit/phpunit": ">=4.8.0" |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"Google\\": "php/src/Google" |
||||
}, |
||||
"files": [ |
||||
"php/src/Google/Protobuf/descriptor.php", |
||||
"php/src/Google/Protobuf/descriptor_internal.pb.php", |
||||
"php/src/Google/Protobuf/Internal/Type.php" |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,99 @@ |
||||
This directory contains the Protocol Buffers runtime implementation via both a |
||||
pure PHP package and a native c extension. The pure PHP package is intended to |
||||
provide usability to wider range of PHP platforms, while the c extension is |
||||
intended to provide higher performance. Both implementations provide the same |
||||
runtime APIs and share the same generated code. Users don’t need to re-generate |
||||
code for the same proto definition when they want to switch the implementation |
||||
later. |
||||
|
||||
Both implementations make use of generated PHP code that defines message and |
||||
enum types in PHP. We strongly recommend using protoc's PHP generation support |
||||
with .proto files. The build process in this directory only installs the |
||||
extension/package; you need to install protoc as well to have PHP code |
||||
generation functionality. |
||||
|
||||
## Requirements |
||||
|
||||
To use PHP runtime library requires: |
||||
|
||||
- PHP 5.5 or above. |
||||
|
||||
## Installation |
||||
|
||||
### C Extension |
||||
|
||||
#### Prerequirements |
||||
|
||||
To install the c extension, the following tools are needed: |
||||
* autoconf |
||||
* automake |
||||
* libtool |
||||
* make |
||||
* gcc |
||||
* pear |
||||
* pecl |
||||
|
||||
On Ubuntu, you can install them with: |
||||
``` |
||||
sudo apt-get install php-pear php5-dev autoconf automake libtool make gcc |
||||
``` |
||||
On other platforms, please use the corresponding package managing tool to |
||||
install them before proceeding. |
||||
|
||||
#### Installation from Source (Building extension) |
||||
|
||||
To build the c extension, run the following command: |
||||
``` |
||||
cd ext/google/protobuf |
||||
pear package |
||||
sudo pecl install protobuf-{VERSION}.tgz |
||||
``` |
||||
|
||||
#### Installation from PECL |
||||
|
||||
When we release a version of Protocol Buffers, we will upload the extension to |
||||
[PECL](https://pecl.php.net/). To use this pre-packaged extension, simply |
||||
install it as you would any other extension: |
||||
|
||||
``` |
||||
sudo pecl install protobuf-{VERSION} |
||||
``` |
||||
|
||||
### PHP Package |
||||
|
||||
#### Installation from composer |
||||
|
||||
Simply add "google/protobuf" to the 'require' section of composer.json in your |
||||
project. |
||||
|
||||
### Protoc |
||||
|
||||
Once the extension or package is installed, if you wish to generate PHP code |
||||
from a `.proto` file, you will also want to install the Protocol Buffers |
||||
compiler (protoc), as described in this repository's main `README` file. The |
||||
version of `protoc` included in the latest release supports the `--php_out` |
||||
option to generate PHP code: |
||||
``` |
||||
protoc --php_out=out_dir test.proto |
||||
``` |
||||
|
||||
## Usage |
||||
|
||||
For general guide: |
||||
https://developers.google.com/protocol-buffers/phptutorial/ |
||||
For generated code: |
||||
https://developers.google.com/protocol-buffers/docs/reference/php-generated |
||||
|
||||
Known Issues |
||||
------------ |
||||
|
||||
* Missing native support for well known types. |
||||
* Missing support for proto2. |
||||
* No API provided for clear/copy messages. |
||||
* No API provided for encoding/decoding with stream. |
||||
* Map fields may not be garbage-collected if there is cycle reference. |
||||
* No debug information for messages in c extension. |
||||
* HHVM not tested. |
||||
* PHP 7.0 not tested. |
||||
* C extension not tested on windows. |
||||
* Message name cannot be Empty. |
@ -0,0 +1,388 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <ext/spl/spl_iterators.h> |
||||
#include <Zend/zend_API.h> |
||||
#include <Zend/zend_interfaces.h> |
||||
|
||||
#include "protobuf.h" |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) |
||||
ZEND_ARG_INFO(0, index) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) |
||||
ZEND_ARG_INFO(0, index) |
||||
ZEND_ARG_INFO(0, newval) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_void, 0) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
static zend_function_entry repeated_field_methods[] = { |
||||
PHP_ME(RepeatedField, __construct, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(RepeatedField, append, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(RepeatedField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(RepeatedField, count, arginfo_void, ZEND_ACC_PUBLIC) |
||||
ZEND_FE_END |
||||
}; |
||||
|
||||
// Forward declare static functions.
|
||||
|
||||
static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC); |
||||
static void repeated_field_free(void *object TSRMLS_DC); |
||||
static int repeated_field_array_init(zval *array, upb_fieldtype_t type, |
||||
uint size ZEND_FILE_LINE_DC); |
||||
static void repeated_field_free_element(void *object); |
||||
static void repeated_field_write_dimension(zval *object, zval *offset, |
||||
zval *value TSRMLS_DC); |
||||
static int repeated_field_has_dimension(zval *object, zval *offset TSRMLS_DC); |
||||
static HashTable *repeated_field_get_gc(zval *object, zval ***table, |
||||
int *n TSRMLS_DC); |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RepeatedField creation/desctruction
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
zend_class_entry* repeated_field_type; |
||||
zend_object_handlers* repeated_field_handlers; |
||||
|
||||
void repeated_field_init(TSRMLS_D) { |
||||
zend_class_entry class_type; |
||||
const char* class_name = "Google\\Protobuf\\Internal\\RepeatedField"; |
||||
INIT_CLASS_ENTRY_EX(class_type, class_name, strlen(class_name), |
||||
repeated_field_methods); |
||||
|
||||
repeated_field_type = zend_register_internal_class(&class_type TSRMLS_CC); |
||||
repeated_field_type->create_object = repeated_field_create; |
||||
|
||||
zend_class_implements(repeated_field_type TSRMLS_CC, 2, spl_ce_ArrayAccess, |
||||
spl_ce_Countable); |
||||
|
||||
repeated_field_handlers = PEMALLOC(zend_object_handlers); |
||||
memcpy(repeated_field_handlers, zend_get_std_object_handlers(), |
||||
sizeof(zend_object_handlers)); |
||||
repeated_field_handlers->get_gc = repeated_field_get_gc; |
||||
} |
||||
|
||||
static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC) { |
||||
zend_object_value retval = {0}; |
||||
RepeatedField *intern; |
||||
|
||||
intern = emalloc(sizeof(RepeatedField)); |
||||
memset(intern, 0, sizeof(RepeatedField)); |
||||
|
||||
zend_object_std_init(&intern->std, ce TSRMLS_CC); |
||||
object_properties_init(&intern->std, ce); |
||||
|
||||
intern->array = NULL; |
||||
intern->type = 0; |
||||
intern->msg_ce = NULL; |
||||
|
||||
retval.handle = zend_objects_store_put( |
||||
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, |
||||
(zend_objects_free_object_storage_t)repeated_field_free, NULL TSRMLS_CC); |
||||
retval.handlers = repeated_field_handlers; |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
static void repeated_field_free(void *object TSRMLS_DC) { |
||||
RepeatedField *intern = object; |
||||
zend_object_std_dtor(&intern->std TSRMLS_CC); |
||||
zval_ptr_dtor(&intern->array); |
||||
efree(object); |
||||
} |
||||
|
||||
static int repeated_field_array_init(zval *array, upb_fieldtype_t type, |
||||
uint size ZEND_FILE_LINE_DC) { |
||||
ALLOC_HASHTABLE(Z_ARRVAL_P(array)); |
||||
|
||||
switch (type) { |
||||
case UPB_TYPE_STRING: |
||||
case UPB_TYPE_BYTES: |
||||
case UPB_TYPE_MESSAGE: |
||||
zend_hash_init(Z_ARRVAL_P(array), size, NULL, ZVAL_PTR_DTOR, 0); |
||||
break; |
||||
default: |
||||
zend_hash_init(Z_ARRVAL_P(array), size, NULL, repeated_field_free_element, |
||||
0); |
||||
} |
||||
Z_TYPE_P(array) = IS_ARRAY; |
||||
return SUCCESS; |
||||
} |
||||
|
||||
static void repeated_field_free_element(void *object) { |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RepeatedField Handlers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static void repeated_field_write_dimension(zval *object, zval *offset, |
||||
zval *value TSRMLS_DC) { |
||||
uint64_t index; |
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(object TSRMLS_CC); |
||||
HashTable *ht = HASH_OF(intern->array); |
||||
int size = native_slot_size(intern->type); |
||||
|
||||
unsigned char memory[NATIVE_SLOT_MAX_SIZE]; |
||||
memset(memory, 0, NATIVE_SLOT_MAX_SIZE); |
||||
|
||||
if (!native_slot_set(intern->type, intern->msg_ce, memory, value)) { |
||||
return; |
||||
} |
||||
|
||||
if (!offset || Z_TYPE_P(offset) == IS_NULL) { |
||||
index = zend_hash_num_elements(HASH_OF(intern->array)); |
||||
} else { |
||||
if (protobuf_convert_to_uint64(offset, &index)) { |
||||
if (!zend_hash_index_exists(ht, index)) { |
||||
zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index); |
||||
return; |
||||
} |
||||
} else { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
zend_hash_index_update(ht, index, memory, size, NULL); |
||||
} |
||||
|
||||
static HashTable *repeated_field_get_gc(zval *object, zval ***table, |
||||
int *n TSRMLS_DC) { |
||||
*table = NULL; |
||||
*n = 0; |
||||
RepeatedField *intern = zend_object_store_get_object(object TSRMLS_CC); |
||||
return HASH_OF(intern->array); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// C RepeatedField Utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void *repeated_field_index_native(RepeatedField *intern, int index) { |
||||
HashTable *ht = HASH_OF(intern->array); |
||||
void *value; |
||||
|
||||
if (zend_hash_index_find(ht, index, (void **)&value) == FAILURE) { |
||||
zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index); |
||||
return NULL; |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
void repeated_field_push_native(RepeatedField *intern, void *value TSRMLS_DC) { |
||||
HashTable *ht = HASH_OF(intern->array); |
||||
int size = native_slot_size(intern->type); |
||||
zend_hash_next_index_insert(ht, (void **)value, size, NULL); |
||||
} |
||||
|
||||
void repeated_field_create_with_type(zend_class_entry *ce, |
||||
const upb_fielddef *field, |
||||
zval **repeated_field TSRMLS_DC) { |
||||
MAKE_STD_ZVAL(*repeated_field); |
||||
Z_TYPE_PP(repeated_field) = IS_OBJECT; |
||||
Z_OBJVAL_PP(repeated_field) = |
||||
repeated_field_type->create_object(repeated_field_type TSRMLS_CC); |
||||
|
||||
RepeatedField *intern = |
||||
zend_object_store_get_object(*repeated_field TSRMLS_CC); |
||||
intern->type = upb_fielddef_type(field); |
||||
if (intern->type == UPB_TYPE_MESSAGE) { |
||||
upb_msgdef *msg = upb_fielddef_msgsubdef(field); |
||||
zval *desc_php = get_def_obj(msg); |
||||
Descriptor *desc = zend_object_store_get_object(desc_php TSRMLS_CC); |
||||
intern->msg_ce = desc->klass; |
||||
} |
||||
MAKE_STD_ZVAL(intern->array); |
||||
repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC); |
||||
|
||||
// TODO(teboring): Link class entry for message and enum
|
||||
} |
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PHP RepeatedField Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs an instance of RepeatedField. |
||||
* @param long Type of the stored element. |
||||
* @param string Message/Enum class name (message/enum fields only). |
||||
*/ |
||||
PHP_METHOD(RepeatedField, __construct) { |
||||
long type; |
||||
zend_class_entry* klass = NULL; |
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|C", &type, &klass) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
intern->type = to_fieldtype(type); |
||||
intern->msg_ce = klass; |
||||
|
||||
MAKE_STD_ZVAL(intern->array); |
||||
repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC); |
||||
|
||||
if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) { |
||||
zend_error(E_USER_ERROR, "Message type must have concrete class."); |
||||
return; |
||||
} |
||||
|
||||
// TODO(teboring): Consider enum.
|
||||
} |
||||
|
||||
/**
|
||||
* Append element to the end of the repeated field. |
||||
* @param object The element to be added. |
||||
*/ |
||||
PHP_METHOD(RepeatedField, append) { |
||||
zval *value; |
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
repeated_field_write_dimension(getThis(), NULL, value TSRMLS_CC); |
||||
} |
||||
|
||||
/**
|
||||
* Check whether the element at given index exists. |
||||
* @param long The index to be checked. |
||||
* @return bool True if the element at the given index exists. |
||||
*/ |
||||
PHP_METHOD(RepeatedField, offsetExists) { |
||||
long index; |
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
|
||||
RETURN_BOOL(index >= 0 && |
||||
index < zend_hash_num_elements(HASH_OF(intern->array))); |
||||
} |
||||
|
||||
/**
|
||||
* Return the element at the given index. |
||||
* This will also be called for: $ele = $arr[0] |
||||
* @param long The index of the element to be fetched. |
||||
* @return object The stored element at given index. |
||||
* @exception Invalid type for index. |
||||
* @exception Non-existing index. |
||||
*/ |
||||
PHP_METHOD(RepeatedField, offsetGet) { |
||||
long index; |
||||
void *memory; |
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
HashTable *table = HASH_OF(intern->array); |
||||
|
||||
if (zend_hash_index_find(table, index, (void **)&memory) == FAILURE) { |
||||
zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index); |
||||
return; |
||||
} |
||||
|
||||
native_slot_get(intern->type, memory, return_value_ptr TSRMLS_CC); |
||||
} |
||||
|
||||
/**
|
||||
* Assign the element at the given index. |
||||
* This will also be called for: $arr []= $ele and $arr[0] = ele |
||||
* @param long The index of the element to be assigned. |
||||
* @param object The element to be assigned. |
||||
* @exception Invalid type for index. |
||||
* @exception Non-existing index. |
||||
* @exception Incorrect type of the element. |
||||
*/ |
||||
PHP_METHOD(RepeatedField, offsetSet) { |
||||
zval *index, *value; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
repeated_field_write_dimension(getThis(), index, value TSRMLS_CC); |
||||
} |
||||
|
||||
/**
|
||||
* Remove the element at the given index. |
||||
* This will also be called for: unset($arr) |
||||
* @param long The index of the element to be removed. |
||||
* @exception Invalid type for index. |
||||
* @exception The element to be removed is not at the end of the RepeatedField. |
||||
*/ |
||||
PHP_METHOD(RepeatedField, offsetUnset) { |
||||
long index; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
|
||||
// Only the element at the end of the array can be removed.
|
||||
if (index == -1 || |
||||
index != (zend_hash_num_elements(HASH_OF(intern->array)) - 1)) { |
||||
zend_error(E_USER_ERROR, "Cannot remove element at %d.\n", index); |
||||
return; |
||||
} |
||||
|
||||
zend_hash_index_del(HASH_OF(intern->array), index); |
||||
} |
||||
|
||||
/**
|
||||
* Return the number of stored elements. |
||||
* This will also be called for: count($arr) |
||||
* @return long The number of stored elements. |
||||
*/ |
||||
PHP_METHOD(RepeatedField, count) { |
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->array))); |
||||
} |
@ -1,10 +1,10 @@ |
||||
dnl lines starting with "dnl" are comments |
||||
|
||||
PHP_ARG_ENABLE(protobuf, whether to enable Protobuf extension, [ --enable-protobuf Enable Protobuf extension]) |
||||
|
||||
if test "$PHP_PROTOBUF" != "no"; then |
||||
|
||||
dnl this defines the extension |
||||
PHP_NEW_EXTENSION(protobuf, upb.c protobuf.c def.c message.c storage.c, $ext_shared) |
||||
PHP_NEW_EXTENSION( |
||||
protobuf, |
||||
array.c def.c encode_decode.c map.c message.c protobuf.c storage.c type_check.c upb.c utf8.c, |
||||
$ext_shared) |
||||
|
||||
fi |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,470 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <ext/spl/spl_iterators.h> |
||||
#include <Zend/zend_API.h> |
||||
#include <Zend/zend_interfaces.h> |
||||
|
||||
#include "protobuf.h" |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) |
||||
ZEND_ARG_INFO(0, index) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) |
||||
ZEND_ARG_INFO(0, index) |
||||
ZEND_ARG_INFO(0, newval) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_void, 0) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
// Utilities
|
||||
|
||||
void* upb_value_memory(upb_value* v) { |
||||
return (void*)(&v->val); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Basic map operations on top of upb's strtable.
|
||||
//
|
||||
// Note that we roll our own `Map` container here because, as for
|
||||
// `RepeatedField`, we want a strongly-typed container. This is so that any user
|
||||
// errors due to incorrect map key or value types are raised as close as
|
||||
// possible to the error site, rather than at some deferred point (e.g.,
|
||||
// serialization).
|
||||
//
|
||||
// We build our `Map` on top of upb_strtable so that we're able to take
|
||||
// advantage of the native_slot storage abstraction, as RepeatedField does.
|
||||
// (This is not quite a perfect mapping -- see the key conversions below -- but
|
||||
// gives us full support and error-checking for all value types for free.)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Map values are stored using the native_slot abstraction (as with repeated
|
||||
// field values), but keys are a bit special. Since we use a strtable, we need
|
||||
// to store keys as sequences of bytes such that equality of those bytes maps
|
||||
// one-to-one to equality of keys. We store strings directly (i.e., they map to
|
||||
// their own bytes) and integers as native integers (using the native_slot
|
||||
// abstraction).
|
||||
|
||||
// Note that there is another tradeoff here in keeping string keys as native
|
||||
// strings rather than PHP strings: traversing the Map requires conversion to
|
||||
// PHP string values on every traversal, potentially creating more garbage. We
|
||||
// should consider ways to cache a PHP version of the key if this becomes an
|
||||
// issue later.
|
||||
|
||||
// Forms a key to use with the underlying strtable from a PHP key value. |buf|
|
||||
// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
|
||||
// construct a key byte sequence if needed. |out_key| and |out_length| provide
|
||||
// the resulting key data/length.
|
||||
#define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t)
|
||||
static bool table_key(Map* self, zval* key, |
||||
char* buf, |
||||
const char** out_key, |
||||
size_t* out_length) { |
||||
switch (self->key_type) { |
||||
case UPB_TYPE_STRING: |
||||
if (!protobuf_convert_to_string(key)) { |
||||
return false; |
||||
} |
||||
if (!is_structurally_valid_utf8(Z_STRVAL_P(key), Z_STRLEN_P(key))) { |
||||
zend_error(E_USER_ERROR, "Given key is not UTF8 encoded."); |
||||
return false; |
||||
} |
||||
*out_key = Z_STRVAL_P(key); |
||||
*out_length = Z_STRLEN_P(key); |
||||
break; |
||||
|
||||
#define CASE_TYPE(upb_type, type, c_type, php_type) \ |
||||
case UPB_TYPE_##upb_type: { \
|
||||
c_type type##_value; \
|
||||
if (!protobuf_convert_to_##type(key, &type##_value)) { \
|
||||
return false; \
|
||||
} \
|
||||
native_slot_set(self->key_type, NULL, buf, key); \
|
||||
*out_key = buf; \
|
||||
*out_length = native_slot_size(self->key_type); \
|
||||
break; \
|
||||
} |
||||
CASE_TYPE(BOOL, bool, int8_t, BOOL) |
||||
CASE_TYPE(INT32, int32, int32_t, LONG) |
||||
CASE_TYPE(INT64, int64, int64_t, LONG) |
||||
CASE_TYPE(UINT32, uint32, uint32_t, LONG) |
||||
CASE_TYPE(UINT64, uint64, uint64_t, LONG) |
||||
|
||||
#undef CASE_TYPE |
||||
|
||||
default: |
||||
// Map constructor should not allow a Map with another key type to be
|
||||
// constructed.
|
||||
assert(false); |
||||
break; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MapField methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static zend_function_entry map_field_methods[] = { |
||||
PHP_ME(MapField, __construct, NULL, ZEND_ACC_PUBLIC) |
||||
PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(MapField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) |
||||
PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC) |
||||
ZEND_FE_END |
||||
}; |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MapField creation/desctruction
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
zend_class_entry* map_field_type; |
||||
zend_object_handlers* map_field_handlers; |
||||
|
||||
static map_begin_internal(Map *map, MapIter *iter) { |
||||
iter->self = map; |
||||
upb_strtable_begin(&iter->it, &map->table); |
||||
} |
||||
|
||||
static HashTable *map_field_get_gc(zval *object, zval ***table, |
||||
int *n TSRMLS_DC) { |
||||
// TODO(teboring): Unfortunately, zend engine does not support garbage
|
||||
// collection for custom array. We have to use zend engine's native array
|
||||
// instead.
|
||||
*table = NULL; |
||||
*n = 0; |
||||
return NULL; |
||||
} |
||||
|
||||
void map_field_init(TSRMLS_D) { |
||||
zend_class_entry class_type; |
||||
const char* class_name = "Google\\Protobuf\\Internal\\MapField"; |
||||
INIT_CLASS_ENTRY_EX(class_type, class_name, strlen(class_name), |
||||
map_field_methods); |
||||
|
||||
map_field_type = zend_register_internal_class(&class_type TSRMLS_CC); |
||||
map_field_type->create_object = map_field_create; |
||||
|
||||
zend_class_implements(map_field_type TSRMLS_CC, 2, spl_ce_ArrayAccess, |
||||
spl_ce_Countable); |
||||
|
||||
map_field_handlers = PEMALLOC(zend_object_handlers); |
||||
memcpy(map_field_handlers, zend_get_std_object_handlers(), |
||||
sizeof(zend_object_handlers)); |
||||
map_field_handlers->get_gc = map_field_get_gc; |
||||
} |
||||
|
||||
zend_object_value map_field_create(zend_class_entry *ce TSRMLS_DC) { |
||||
zend_object_value retval = {0}; |
||||
Map *intern; |
||||
|
||||
intern = emalloc(sizeof(Map)); |
||||
memset(intern, 0, sizeof(Map)); |
||||
|
||||
zend_object_std_init(&intern->std, ce TSRMLS_CC); |
||||
object_properties_init(&intern->std, ce); |
||||
|
||||
// Table value type is always UINT64: this ensures enough space to store the
|
||||
// native_slot value.
|
||||
if (!upb_strtable_init(&intern->table, UPB_CTYPE_UINT64)) { |
||||
zend_error(E_USER_ERROR, "Could not allocate table."); |
||||
} |
||||
|
||||
retval.handle = zend_objects_store_put( |
||||
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, |
||||
(zend_objects_free_object_storage_t)map_field_free, NULL TSRMLS_CC); |
||||
retval.handlers = map_field_handlers; |
||||
|
||||
return retval; |
||||
} |
||||
|
||||
void map_field_free(void *object TSRMLS_DC) { |
||||
Map *map = (Map *)object; |
||||
|
||||
switch (map->value_type) { |
||||
case UPB_TYPE_MESSAGE: |
||||
case UPB_TYPE_STRING: |
||||
case UPB_TYPE_BYTES: { |
||||
MapIter it; |
||||
int len; |
||||
for (map_begin_internal(map, &it); !map_done(&it); map_next(&it)) { |
||||
upb_value value = map_iter_value(&it, &len); |
||||
void *mem = upb_value_memory(&value); |
||||
zval_ptr_dtor(mem); |
||||
} |
||||
break; |
||||
} |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
upb_strtable_uninit(&map->table); |
||||
zend_object_std_dtor(&map->std TSRMLS_CC); |
||||
efree(object); |
||||
} |
||||
|
||||
void map_field_create_with_type(zend_class_entry *ce, const upb_fielddef *field, |
||||
zval **map_field TSRMLS_DC) { |
||||
MAKE_STD_ZVAL(*map_field); |
||||
Z_TYPE_PP(map_field) = IS_OBJECT; |
||||
Z_OBJVAL_PP(map_field) = |
||||
map_field_type->create_object(map_field_type TSRMLS_CC); |
||||
|
||||
Map* intern = |
||||
(Map*)zend_object_store_get_object(*map_field TSRMLS_CC); |
||||
|
||||
const upb_fielddef *key_field = map_field_key(field); |
||||
const upb_fielddef *value_field = map_field_value(field); |
||||
intern->key_type = upb_fielddef_type(key_field); |
||||
intern->value_type = upb_fielddef_type(value_field); |
||||
intern->msg_ce = field_type_class(value_field); |
||||
} |
||||
|
||||
static void map_field_free_element(void *object) { |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MapField Handlers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static bool *map_field_read_dimension(zval *object, zval *key, int type, |
||||
zval **retval TSRMLS_DC) { |
||||
Map *intern = |
||||
(Map *)zend_object_store_get_object(object TSRMLS_CC); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
upb_value v; |
||||
#ifndef NDEBUG |
||||
v.ctype = UPB_CTYPE_UINT64; |
||||
#endif |
||||
if (!table_key(intern, key, keybuf, &keyval, &length)) { |
||||
return false; |
||||
} |
||||
|
||||
if (upb_strtable_lookup2(&intern->table, keyval, length, &v)) { |
||||
void* mem = upb_value_memory(&v); |
||||
native_slot_get(intern->value_type, mem, retval TSRMLS_CC); |
||||
return true; |
||||
} else { |
||||
zend_error(E_USER_ERROR, "Given key doesn't exist."); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool map_index_set(Map *intern, const char* keyval, int length, upb_value v) { |
||||
// Replace any existing value by issuing a 'remove' operation first.
|
||||
upb_strtable_remove2(&intern->table, keyval, length, NULL); |
||||
if (!upb_strtable_insert2(&intern->table, keyval, length, v)) { |
||||
zend_error(E_USER_ERROR, "Could not insert into table"); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static bool map_field_write_dimension(zval *object, zval *key, |
||||
zval *value TSRMLS_DC) { |
||||
Map *intern = (Map *)zend_object_store_get_object(object TSRMLS_CC); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
upb_value v; |
||||
void* mem; |
||||
if (!table_key(intern, key, keybuf, &keyval, &length)) { |
||||
return false; |
||||
} |
||||
|
||||
mem = upb_value_memory(&v); |
||||
memset(mem, 0, native_slot_size(intern->value_type)); |
||||
if(!native_slot_set(intern->value_type, intern->msg_ce, mem, value)) { |
||||
return false; |
||||
} |
||||
#ifndef NDEBUG |
||||
v.ctype = UPB_CTYPE_UINT64; |
||||
#endif |
||||
|
||||
// Replace any existing value by issuing a 'remove' operation first.
|
||||
upb_strtable_remove2(&intern->table, keyval, length, NULL); |
||||
if (!upb_strtable_insert2(&intern->table, keyval, length, v)) { |
||||
zend_error(E_USER_ERROR, "Could not insert into table"); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static bool map_field_unset_dimension(zval *object, zval *key TSRMLS_DC) { |
||||
Map *intern = (Map *)zend_object_store_get_object(object TSRMLS_CC); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
upb_value v; |
||||
if (!table_key(intern, key, keybuf, &keyval, &length)) { |
||||
return false; |
||||
} |
||||
#ifndef NDEBUG |
||||
v.ctype = UPB_CTYPE_UINT64; |
||||
#endif |
||||
|
||||
upb_strtable_remove2(&intern->table, keyval, length, &v); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PHP MapField Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
PHP_METHOD(MapField, __construct) { |
||||
long key_type, value_type; |
||||
zend_class_entry* klass = NULL; |
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|C", &key_type, |
||||
&value_type, &klass) == FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
Map* intern = |
||||
(Map*)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
intern->key_type = to_fieldtype(key_type); |
||||
intern->value_type = to_fieldtype(value_type); |
||||
intern->msg_ce = klass; |
||||
|
||||
// Check that the key type is an allowed type.
|
||||
switch (intern->key_type) { |
||||
case UPB_TYPE_INT32: |
||||
case UPB_TYPE_INT64: |
||||
case UPB_TYPE_UINT32: |
||||
case UPB_TYPE_UINT64: |
||||
case UPB_TYPE_BOOL: |
||||
case UPB_TYPE_STRING: |
||||
case UPB_TYPE_BYTES: |
||||
// These are OK.
|
||||
break; |
||||
default: |
||||
zend_error(E_USER_ERROR, "Invalid key type for map."); |
||||
} |
||||
} |
||||
|
||||
PHP_METHOD(MapField, offsetExists) { |
||||
zval *key; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
Map *intern = (Map *)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
upb_value v; |
||||
#ifndef NDEBUG |
||||
v.ctype = UPB_CTYPE_UINT64; |
||||
#endif |
||||
if (!table_key(intern, key, keybuf, &keyval, &length)) { |
||||
return false; |
||||
} |
||||
|
||||
RETURN_BOOL(upb_strtable_lookup2(&intern->table, keyval, length, &v)); |
||||
} |
||||
|
||||
PHP_METHOD(MapField, offsetGet) { |
||||
zval *index, *value; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
map_field_read_dimension(getThis(), index, BP_VAR_R, |
||||
return_value_ptr TSRMLS_CC); |
||||
} |
||||
|
||||
PHP_METHOD(MapField, offsetSet) { |
||||
zval *index, *value; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
map_field_write_dimension(getThis(), index, value TSRMLS_CC); |
||||
} |
||||
|
||||
PHP_METHOD(MapField, offsetUnset) { |
||||
zval *index; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
map_field_unset_dimension(getThis(), index TSRMLS_CC); |
||||
} |
||||
|
||||
PHP_METHOD(MapField, count) { |
||||
Map *intern = |
||||
(MapField *)zend_object_store_get_object(getThis() TSRMLS_CC); |
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RETURN_LONG(upb_strtable_count(&intern->table)); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Map Iterator
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void map_begin(zval *map_php, MapIter *iter) { |
||||
Map *self = UNBOX(Map, map_php); |
||||
map_begin_internal(self, iter); |
||||
} |
||||
|
||||
void map_next(MapIter *iter) { |
||||
upb_strtable_next(&iter->it); |
||||
} |
||||
|
||||
bool map_done(MapIter *iter) { |
||||
return upb_strtable_done(&iter->it); |
||||
} |
||||
|
||||
const char *map_iter_key(MapIter *iter, int *len) { |
||||
*len = upb_strtable_iter_keylength(&iter->it); |
||||
return upb_strtable_iter_key(&iter->it); |
||||
} |
||||
|
||||
upb_value map_iter_value(MapIter *iter, int *len) { |
||||
*len = native_slot_size(iter->self->value_type); |
||||
return upb_strtable_iter_value(&iter->it); |
||||
} |
@ -0,0 +1,74 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<package packagerversion="1.9.5" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd"> |
||||
<name>protobuf</name> |
||||
<channel>pecl.php.net</channel> |
||||
<summary>Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.</summary> |
||||
<description>https://developers.google.com/protocol-buffers/</description> |
||||
<lead> |
||||
<name>Bo Yang</name> |
||||
<user>teboring</user> |
||||
<email>protobuf-opensource@google.com</email> |
||||
<active>yes</active> |
||||
</lead> |
||||
<date>2016-09-02</date> |
||||
<time>16:06:07</time> |
||||
<version> |
||||
<release>3.1.0</release> |
||||
<api>3.1.0</api> |
||||
</version> |
||||
<stability> |
||||
<release>alpha</release> |
||||
<api>alpha</api> |
||||
</stability> |
||||
<license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license> |
||||
<notes> |
||||
First alpha release. |
||||
</notes> |
||||
<contents> |
||||
<dir baseinstalldir="/" name="/"> |
||||
<file baseinstalldir="/" name="config.m4" role="src" /> |
||||
<file baseinstalldir="/" name="array.c" role="src" /> |
||||
<file baseinstalldir="/" name="def.c" role="src" /> |
||||
<file baseinstalldir="/" name="encode_decode.c" role="src" /> |
||||
<file baseinstalldir="/" name="map.c" role="src" /> |
||||
<file baseinstalldir="/" name="message.c" role="src" /> |
||||
<file baseinstalldir="/" name="protobuf.c" role="src" /> |
||||
<file baseinstalldir="/" name="protobuf.h" role="src" /> |
||||
<file baseinstalldir="/" name="storage.c" role="src" /> |
||||
<file baseinstalldir="/" name="type_check.c" role="src" /> |
||||
<file baseinstalldir="/" name="upb.c" role="src" /> |
||||
<file baseinstalldir="/" name="upb.h" role="src" /> |
||||
<file baseinstalldir="/" name="utf8.c" role="src" /> |
||||
<file baseinstalldir="/" name="utf8.h" role="src" /> |
||||
</dir> |
||||
</contents> |
||||
<dependencies> |
||||
<required> |
||||
<php> |
||||
<min>5.6.0</min> |
||||
</php> |
||||
<pearinstaller> |
||||
<min>1.4.0</min> |
||||
</pearinstaller> |
||||
</required> |
||||
</dependencies> |
||||
<providesextension>protobuf</providesextension> |
||||
<extsrcrelease /> |
||||
<changelog> |
||||
<release> |
||||
<version> |
||||
<release>3.1.0</release> |
||||
<api>3.1.0</api> |
||||
</version> |
||||
<stability> |
||||
<release>alpha</release> |
||||
<api>alpha</api> |
||||
</stability> |
||||
<date>2016-09-02</date> |
||||
<license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license> |
||||
<notes> |
||||
First alpha release |
||||
</notes> |
||||
</release> |
||||
</changelog> |
||||
</package> |
@ -1,15 +0,0 @@ |
||||
<?php |
||||
|
||||
|
||||
namespace Google\Protobuf; |
||||
|
||||
$pool = get_generated_pool(); |
||||
$pool->addMessage("TestMessage") |
||||
->optional("optional_int32_a", "int32", 1) |
||||
->optional("optional_int32_b", "int32", 2) |
||||
->finalizeToPool() |
||||
->finalize(); |
||||
|
||||
$test_message = new \TestMessage(); |
||||
|
||||
?> |
@ -0,0 +1,310 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <Zend/zend_operators.h> |
||||
|
||||
#include "protobuf.h" |
||||
#include "utf8.h" |
||||
|
||||
static zend_class_entry* util_type; |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1) |
||||
ZEND_ARG_INFO(1, val) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arg_check_message, 0, 0, 2) |
||||
ZEND_ARG_INFO(1, val) |
||||
ZEND_ARG_INFO(0, klass) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arg_check_repeated, 0, 0, 2) |
||||
ZEND_ARG_INFO(1, val) |
||||
ZEND_ARG_INFO(0, type) |
||||
ZEND_ARG_INFO(0, klass) |
||||
ZEND_END_ARG_INFO() |
||||
|
||||
static zend_function_entry util_methods[] = { |
||||
PHP_ME(Util, checkInt32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkUint32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkInt64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkUint64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkEnum, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkFloat, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkDouble, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkBool, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkString, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkBytes, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkMessage, arg_check_message, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
PHP_ME(Util, checkRepeatedField, arg_check_repeated, |
||||
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) |
||||
ZEND_FE_END |
||||
}; |
||||
|
||||
void util_init(TSRMLS_D) { |
||||
zend_class_entry class_type; |
||||
INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBUtil", |
||||
util_methods); |
||||
util_type = zend_register_internal_class(&class_type TSRMLS_CC); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type checking/conversion.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define CONVERT_TO_INTEGER(type) \ |
||||
static bool convert_long_to_##type(long val, type##_t* type##_value) { \
|
||||
*type##_value = (type##_t)val; \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static bool convert_double_to_##type(double val, type##_t* type##_value) { \
|
||||
*type##_value = (type##_t)zend_dval_to_lval(val); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static bool convert_string_to_##type(const char* val, int len, \
|
||||
type##_t* type##_value) { \
|
||||
long lval; \
|
||||
double dval; \
|
||||
\
|
||||
switch (is_numeric_string(val, len, &lval, &dval, 0)) { \
|
||||
case IS_DOUBLE: { \
|
||||
return convert_double_to_##type(dval, type##_value); \
|
||||
} \
|
||||
case IS_LONG: { \
|
||||
return convert_long_to_##type(lval, type##_value); \
|
||||
} \
|
||||
default: \
|
||||
zend_error(E_USER_ERROR, \
|
||||
"Given string value cannot be converted to integer."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool protobuf_convert_to_##type(zval* from, type##_t* to) { \
|
||||
switch (Z_TYPE_P(from)) { \
|
||||
case IS_LONG: { \
|
||||
return convert_long_to_##type(Z_LVAL_P(from), to); \
|
||||
} \
|
||||
case IS_DOUBLE: { \
|
||||
return convert_double_to_##type(Z_DVAL_P(from), to); \
|
||||
} \
|
||||
case IS_STRING: { \
|
||||
return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \
|
||||
to); \
|
||||
} \
|
||||
default: { \
|
||||
zend_error(E_USER_ERROR, \
|
||||
"Given value cannot be converted to integer."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
return false; \
|
||||
} |
||||
|
||||
CONVERT_TO_INTEGER(int32); |
||||
CONVERT_TO_INTEGER(uint32); |
||||
CONVERT_TO_INTEGER(int64); |
||||
CONVERT_TO_INTEGER(uint64); |
||||
|
||||
#undef CONVERT_TO_INTEGER |
||||
|
||||
#define CONVERT_TO_FLOAT(type) \ |
||||
static bool convert_long_to_##type(long val, type* type##_value) { \
|
||||
*type##_value = (type)val; \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static bool convert_double_to_##type(double val, type* type##_value) { \
|
||||
*type##_value = (type)val; \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static bool convert_string_to_##type(const char* val, int len, \
|
||||
type* type##_value) { \
|
||||
long lval; \
|
||||
double dval; \
|
||||
\
|
||||
switch (is_numeric_string(val, len, &lval, &dval, 0)) { \
|
||||
case IS_DOUBLE: { \
|
||||
*type##_value = (type)dval; \
|
||||
return true; \
|
||||
} \
|
||||
case IS_LONG: { \
|
||||
*type##_value = (type)lval; \
|
||||
return true; \
|
||||
} \
|
||||
default: \
|
||||
zend_error(E_USER_ERROR, \
|
||||
"Given string value cannot be converted to integer."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool protobuf_convert_to_##type(zval* from, type* to) { \
|
||||
switch (Z_TYPE_P(from)) { \
|
||||
case IS_LONG: { \
|
||||
return convert_long_to_##type(Z_LVAL_P(from), to); \
|
||||
} \
|
||||
case IS_DOUBLE: { \
|
||||
return convert_double_to_##type(Z_DVAL_P(from), to); \
|
||||
} \
|
||||
case IS_STRING: { \
|
||||
return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \
|
||||
to); \
|
||||
} \
|
||||
default: { \
|
||||
zend_error(E_USER_ERROR, \
|
||||
"Given value cannot be converted to integer."); \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
return false; \
|
||||
} |
||||
|
||||
CONVERT_TO_FLOAT(float); |
||||
CONVERT_TO_FLOAT(double); |
||||
|
||||
#undef CONVERT_TO_FLOAT |
||||
|
||||
bool protobuf_convert_to_bool(zval* from, int8_t* to) { |
||||
switch (Z_TYPE_P(from)) { |
||||
case IS_BOOL: |
||||
*to = (int8_t)Z_BVAL_P(from); |
||||
break; |
||||
case IS_LONG: |
||||
*to = (int8_t)(Z_LVAL_P(from) != 0); |
||||
break; |
||||
case IS_DOUBLE: |
||||
*to = (int8_t)(Z_LVAL_P(from) != 0); |
||||
break; |
||||
case IS_STRING: { |
||||
char* strval = Z_STRVAL_P(from); |
||||
|
||||
if (Z_STRLEN_P(from) == 0 || |
||||
(Z_STRLEN_P(from) == 1 && Z_STRVAL_P(from)[0] == '0')) { |
||||
*to = 0; |
||||
} else { |
||||
*to = 1; |
||||
} |
||||
STR_FREE(strval); |
||||
} break; |
||||
default: { |
||||
zend_error(E_USER_ERROR, "Given value cannot be converted to bool."); |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
bool protobuf_convert_to_string(zval* from) { |
||||
switch (Z_TYPE_P(from)) { |
||||
case IS_STRING: { |
||||
return true; |
||||
} |
||||
case IS_BOOL: |
||||
case IS_LONG: |
||||
case IS_DOUBLE: { |
||||
int use_copy; |
||||
zval tmp; |
||||
zend_make_printable_zval(from, &tmp, &use_copy); |
||||
ZVAL_COPY_VALUE(from, &tmp); |
||||
return true; |
||||
} |
||||
default: |
||||
zend_error(E_USER_ERROR, "Given value cannot be converted to string."); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PHP Functions.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// The implementation of type checking for primitive fields is empty. This is
|
||||
// because type checking is done when direct assigning message fields (e.g.,
|
||||
// foo->a = 1). Functions defined here are place holders in generated code for
|
||||
// pure PHP implementation (c extension and pure PHP share the same generated
|
||||
// code).
|
||||
#define PHP_TYPE_CHECK(type) \ |
||||
PHP_METHOD(Util, check##type) {} |
||||
|
||||
PHP_TYPE_CHECK(Int32) |
||||
PHP_TYPE_CHECK(Uint32) |
||||
PHP_TYPE_CHECK(Int64) |
||||
PHP_TYPE_CHECK(Uint64) |
||||
PHP_TYPE_CHECK(Enum) |
||||
PHP_TYPE_CHECK(Float) |
||||
PHP_TYPE_CHECK(Double) |
||||
PHP_TYPE_CHECK(Bool) |
||||
PHP_TYPE_CHECK(String) |
||||
PHP_TYPE_CHECK(Bytes) |
||||
|
||||
#undef PHP_TYPE_CHECK |
||||
|
||||
PHP_METHOD(Util, checkMessage) { |
||||
zval* val; |
||||
zend_class_entry* klass = NULL; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!C", &val, &klass) == |
||||
FAILURE) { |
||||
return; |
||||
} |
||||
if (val == NULL) { |
||||
RETURN_NULL(); |
||||
} |
||||
if (!instanceof_function(Z_OBJCE_P(val), klass TSRMLS_CC)) { |
||||
zend_error(E_USER_ERROR, "Given value is not an instance of %s.", |
||||
klass->name); |
||||
return; |
||||
} |
||||
RETURN_ZVAL(val, 1, 0); |
||||
} |
||||
|
||||
PHP_METHOD(Util, checkRepeatedField) { |
||||
zval* val; |
||||
long type; |
||||
const zend_class_entry* klass = NULL; |
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|C", &val, |
||||
repeated_field_type, &type, &klass) == FAILURE) { |
||||
return; |
||||
} |
||||
|
||||
RepeatedField *intern = |
||||
(RepeatedField *)zend_object_store_get_object(val TSRMLS_CC); |
||||
if (to_fieldtype(type) != intern->type) { |
||||
zend_error(E_USER_ERROR, "Incorrect repeated field type."); |
||||
return; |
||||
} |
||||
if (klass != NULL && intern->msg_ce != klass) { |
||||
zend_error(E_USER_ERROR, "Expect a repeated field of %s, but %s is given.", |
||||
klass->name, intern->msg_ce->name); |
||||
return; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,68 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "utf8.h" |
||||
|
||||
static const uint8_t utf8_offset[] = { |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
||||
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, |
||||
4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
}; |
||||
|
||||
bool is_structurally_valid_utf8(const char* buf, int len) { |
||||
int i, j; |
||||
uint8_t offset; |
||||
|
||||
i = 0; |
||||
while (i < len) { |
||||
offset = utf8_offset[(uint8_t)buf[i]]; |
||||
if (offset == 0 || i + offset > len) { |
||||
return false; |
||||
} |
||||
for (j = i + 1; j < i + offset; j++) { |
||||
if (buf[j] & 0xc0 != 0x80) { |
||||
return false; |
||||
} |
||||
} |
||||
i += offset; |
||||
} |
||||
return i == len; |
||||
} |
@ -0,0 +1,36 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_UTF8_H_ |
||||
#define GOOGLE_PROTOBUF_UTF8_H_ |
||||
|
||||
bool is_structurally_valid_utf8(const char* buf, int len); |
||||
|
||||
#endif // GOOGLE_PROTOBUF_UTF8_H_
|
@ -0,0 +1,162 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\Descriptor; |
||||
use Google\Protobuf\Internal\FileDescriptor; |
||||
use Google\Protobuf\Internal\FileDescriptorSet; |
||||
use Google\Protobuf\Internal\MessageBuilderContext; |
||||
use Google\Protobuf\Internal\EnumBuilderContext; |
||||
|
||||
class DescriptorPool |
||||
{ |
||||
private static $pool; |
||||
// Map from message names to sub-maps, which are maps from field numbers to |
||||
// field descriptors. |
||||
private $class_to_desc = []; |
||||
private $class_to_enum_desc = []; |
||||
private $proto_to_class = []; |
||||
|
||||
public static function getGeneratedPool() |
||||
{ |
||||
if (!isset(self::$pool)) { |
||||
self::$pool = new DescriptorPool(); |
||||
} |
||||
return self::$pool; |
||||
} |
||||
|
||||
public function internalAddGeneratedFile($data) |
||||
{ |
||||
$files = new FileDescriptorSet(); |
||||
$files->decode($data); |
||||
$file = FileDescriptor::buildFromProto($files->getFile()[0]); |
||||
|
||||
foreach ($file->getMessageType() as &$desc) { |
||||
$this->addDescriptor($desc); |
||||
} |
||||
unset($desc); |
||||
|
||||
foreach ($file->getEnumType() as &$desc) { |
||||
$this->addEnumDescriptor($desc); |
||||
} |
||||
unset($desc); |
||||
|
||||
foreach ($file->getMessageType() as &$desc) { |
||||
$this->crossLink($desc); |
||||
} |
||||
unset($desc); |
||||
} |
||||
|
||||
public function addMessage($name, $klass) |
||||
{ |
||||
return new MessageBuilderContext($name, $klass, $this); |
||||
} |
||||
|
||||
public function addEnum($name, $klass) |
||||
{ |
||||
return new EnumBuilderContext($name, $klass, $this); |
||||
} |
||||
|
||||
public function addDescriptor($descriptor) |
||||
{ |
||||
$this->proto_to_class[$descriptor->getFullName()] = |
||||
$descriptor->getClass(); |
||||
$this->class_to_desc[$descriptor->getClass()] = $descriptor; |
||||
foreach ($descriptor->getNestedType() as $nested_type) { |
||||
$this->addDescriptor($nested_type); |
||||
} |
||||
} |
||||
|
||||
public function addEnumDescriptor($descriptor) |
||||
{ |
||||
$this->proto_to_class[$descriptor->getFullName()] = |
||||
$descriptor->getClass(); |
||||
$this->class_to_enum_desc[$descriptor->getClass()] = $descriptor; |
||||
} |
||||
|
||||
public function getDescriptorByClassName($klass) |
||||
{ |
||||
return $this->class_to_desc[$klass]; |
||||
} |
||||
|
||||
public function getEnumDescriptorByClassName($klass) |
||||
{ |
||||
return $this->class_to_enum_desc[$klass]; |
||||
} |
||||
|
||||
public function getDescriptorByProtoName($proto) |
||||
{ |
||||
$klass = $this->proto_to_class[$proto]; |
||||
return $this->class_to_desc[$klass]; |
||||
} |
||||
|
||||
public function getEnumDescriptorByProtoName($proto) |
||||
{ |
||||
$klass = $this->proto_to_class[$proto]; |
||||
return $this->class_to_enum_desc[$klass]; |
||||
} |
||||
|
||||
private function crossLink(&$desc) |
||||
{ |
||||
foreach ($desc->getField() as &$field) { |
||||
switch ($field->getType()) { |
||||
case GPBType::MESSAGE: |
||||
$proto = $field->getMessageType(); |
||||
$field->setMessageType( |
||||
$this->getDescriptorByProtoName($proto)); |
||||
break; |
||||
case GPBType::ENUM: |
||||
$proto = $field->getEnumType(); |
||||
$field->setEnumType( |
||||
$this->getEnumDescriptorByProtoName($proto)); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
unset($field); |
||||
|
||||
foreach ($desc->getNestedType() as &$nested_type) { |
||||
$this->crossLink($nested_type); |
||||
} |
||||
unset($nested_type); |
||||
} |
||||
|
||||
public function finish() |
||||
{ |
||||
foreach ($this->class_to_desc as $klass => &$desc) { |
||||
$this->crossLink($desc); |
||||
} |
||||
unset($desc); |
||||
} |
||||
} |
@ -0,0 +1,63 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\EnumDescriptor; |
||||
use Google\Protobuf\Internal\EnumValueDescriptor; |
||||
|
||||
class EnumBuilderContext |
||||
{ |
||||
|
||||
private $descriptor; |
||||
private $pool; |
||||
|
||||
public function __construct($full_name, $klass, $pool) |
||||
{ |
||||
$this->descriptor = new EnumDescriptor(); |
||||
$this->descriptor->setFullName($full_name); |
||||
$this->descriptor->setClass($klass); |
||||
$this->pool = $pool; |
||||
} |
||||
|
||||
public function value($name, $number) |
||||
{ |
||||
$value = new EnumValueDescriptor(); |
||||
$this->descriptor->addValue($number, $value); |
||||
return $this; |
||||
} |
||||
|
||||
public function finalizeToPool() |
||||
{ |
||||
$this->pool->addEnumDescriptor($this->descriptor); |
||||
} |
||||
} |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
class GPBLabel |
||||
{ |
||||
const OPTIONAL = 1; |
||||
const REQUIRED = 2; |
||||
const REPEATED = 3; |
||||
} |
@ -0,0 +1,55 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
class GPBType |
||||
{ |
||||
const DOUBLE = 1; |
||||
const FLOAT = 2; |
||||
const INT64 = 3; |
||||
const UINT64 = 4; |
||||
const INT32 = 5; |
||||
const FIXED64 = 6; |
||||
const FIXED32 = 7; |
||||
const BOOL = 8; |
||||
const STRING = 9; |
||||
const GROUP = 10; |
||||
const MESSAGE = 11; |
||||
const BYTES = 12; |
||||
const UINT32 = 13; |
||||
const ENUM = 14; |
||||
const SFIXED32 = 15; |
||||
const SFIXED64 = 16; |
||||
const SINT32 = 17; |
||||
const SINT64 = 18; |
||||
} |
@ -0,0 +1,161 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
|
||||
class GPBUtil |
||||
{ |
||||
|
||||
public static function checkString(&$var, $check_utf8) |
||||
{ |
||||
if (is_array($var) || is_object($var)) { |
||||
trigger_error("Expect string.", E_USER_ERROR); |
||||
return; |
||||
} |
||||
if (!is_string($var)) { |
||||
$var = strval($var); |
||||
} |
||||
if ($check_utf8 && !preg_match('//u', $var)) { |
||||
trigger_error("Expect utf-8 encoding.", E_USER_ERROR); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
public static function checkEnum(&$var) |
||||
{ |
||||
static::checkInt32($var); |
||||
} |
||||
|
||||
public static function checkInt32(&$var) |
||||
{ |
||||
if (is_numeric($var)) { |
||||
$var = intval($var); |
||||
} else { |
||||
trigger_error("Expect integer.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkUint32(&$var) |
||||
{ |
||||
if (is_numeric($var)) { |
||||
$var = intval($var); |
||||
if (PHP_INT_SIZE === 8) { |
||||
$var |= ((-(($var >> 31) & 0x1)) & ~0xFFFFFFFF); |
||||
} |
||||
} else { |
||||
trigger_error("Expect integer.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkInt64(&$var) |
||||
{ |
||||
if (is_numeric($var)) { |
||||
$var = intval($var); |
||||
} else { |
||||
trigger_error("Expect integer.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkUint64(&$var) |
||||
{ |
||||
if (is_numeric($var)) { |
||||
$var = intval($var); |
||||
} else { |
||||
trigger_error("Expect integer.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkFloat(&$var) |
||||
{ |
||||
if (is_float($var) || is_numeric($var)) { |
||||
$var = floatval($var); |
||||
} else { |
||||
trigger_error("Expect float.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkDouble(&$var) |
||||
{ |
||||
if (is_float($var) || is_numeric($var)) { |
||||
$var = floatval($var); |
||||
} else { |
||||
trigger_error("Expect float.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkBool(&$var) |
||||
{ |
||||
if (is_array($var) || is_object($var)) { |
||||
trigger_error("Expect boolean.", E_USER_ERROR); |
||||
return; |
||||
} |
||||
$var = boolval($var); |
||||
} |
||||
|
||||
public static function checkMessage(&$var, $klass) |
||||
{ |
||||
if (!$var instanceof $klass && !is_null($var)) { |
||||
trigger_error("Expect message.", E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function checkRepeatedField(&$var, $type, $klass = null) |
||||
{ |
||||
if (!$var instanceof RepeatedField) { |
||||
trigger_error("Expect repeated field.", E_USER_ERROR); |
||||
} |
||||
if ($var->getType() != $type) { |
||||
trigger_error( |
||||
"Expect repeated field of different type.", |
||||
E_USER_ERROR); |
||||
} |
||||
if ($var->getType() === GPBType::MESSAGE && |
||||
$var->getClass() !== $klass) { |
||||
trigger_error( |
||||
"Expect repeated field of different message.", |
||||
E_USER_ERROR); |
||||
} |
||||
} |
||||
|
||||
public static function Int64($value) |
||||
{ |
||||
return new Int64($value); |
||||
} |
||||
|
||||
public static function Uint64($value) |
||||
{ |
||||
return new Uint64($value); |
||||
} |
||||
} |
@ -0,0 +1,583 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\GPBUtil; |
||||
use Google\Protobuf\Internal\Int64; |
||||
use Google\Protobuf\Internal\Uint64; |
||||
|
||||
class GPBWire |
||||
{ |
||||
|
||||
const TAG_TYPE_BITS = 3; |
||||
|
||||
const WIRETYPE_VARINT = 0; |
||||
const WIRETYPE_FIXED64 = 1; |
||||
const WIRETYPE_LENGTH_DELIMITED = 2; |
||||
const WIRETYPE_START_GROUP = 3; |
||||
const WIRETYPE_END_GROUP = 4; |
||||
const WIRETYPE_FIXED32 = 5; |
||||
|
||||
const UNKNOWN = 0; |
||||
const NORMAL_FORMAT = 1; |
||||
const PACKED_FORMAT = 2; |
||||
|
||||
public static function getTagFieldNumber($tag) |
||||
{ |
||||
return ($tag >> self::TAG_TYPE_BITS) & |
||||
(1 << ((PHP_INT_SIZE * 8) - self::TAG_TYPE_BITS)) - 1; |
||||
} |
||||
|
||||
public static function getTagWireType($tag) |
||||
{ |
||||
return $tag & 0x7; |
||||
} |
||||
|
||||
public static function getWireType($type) |
||||
{ |
||||
switch ($type) { |
||||
case GPBType::FLOAT: |
||||
case GPBType::FIXED32: |
||||
case GPBType::SFIXED32: |
||||
return self::WIRETYPE_FIXED32; |
||||
case GPBType::DOUBLE: |
||||
case GPBType::FIXED64: |
||||
case GPBType::SFIXED64: |
||||
return self::WIRETYPE_FIXED64; |
||||
case GPBType::UINT32: |
||||
case GPBType::UINT64: |
||||
case GPBType::INT32: |
||||
case GPBType::INT64: |
||||
case GPBType::SINT32: |
||||
case GPBType::SINT64: |
||||
case GPBType::ENUM: |
||||
case GPBType::BOOL: |
||||
return self::WIRETYPE_VARINT; |
||||
case GPBType::STRING: |
||||
case GPBType::BYTES: |
||||
case GPBType::MESSAGE: |
||||
return self::WIRETYPE_LENGTH_DELIMITED; |
||||
case GPBType::GROUP: |
||||
user_error("Unsupported type."); |
||||
return 0; |
||||
default: |
||||
user_error("Unsupported type."); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
// ZigZag Transform: Encodes signed integers so that they can be effectively |
||||
// used with varint encoding. |
||||
// |
||||
// varint operates on unsigned integers, encoding smaller numbers into fewer |
||||
// bytes. If you try to use it on a signed integer, it will treat this |
||||
// number as a very large unsigned integer, which means that even small |
||||
// signed numbers like -1 will take the maximum number of bytes (10) to |
||||
// encode. zigZagEncode() maps signed integers to unsigned in such a way |
||||
// that those with a small absolute value will have smaller encoded values, |
||||
// making them appropriate for encoding using varint. |
||||
// |
||||
// int32 -> uint32 |
||||
// ------------------------- |
||||
// 0 -> 0 |
||||
// -1 -> 1 |
||||
// 1 -> 2 |
||||
// -2 -> 3 |
||||
// ... -> ... |
||||
// 2147483647 -> 4294967294 |
||||
// -2147483648 -> 4294967295 |
||||
// |
||||
// >> encode >> |
||||
// << decode << |
||||
public static function zigZagEncode32($int32) |
||||
{ |
||||
// Fill high 32 bits. |
||||
if (PHP_INT_SIZE === 8) { |
||||
$int32 |= ((($int32 << 32) >> 31) & (0xFFFFFFFF << 32)); |
||||
} |
||||
|
||||
$uint32 = ($int32 << 1) ^ ($int32 >> 31); |
||||
|
||||
// Fill high 32 bits. |
||||
if (PHP_INT_SIZE === 8) { |
||||
$uint32 |= ((($uint32 << 32) >> 31) & (0xFFFFFFFF << 32)); |
||||
} |
||||
|
||||
return $uint32; |
||||
} |
||||
|
||||
public static function zigZagDecode32($uint32) |
||||
{ |
||||
// Fill high 32 bits. |
||||
if (PHP_INT_SIZE === 8) { |
||||
$uint32 |= ($uint32 & 0xFFFFFFFF); |
||||
} |
||||
|
||||
$int32 = (($uint32 >> 1) & 0x7FFFFFFF) ^ (-($uint32 & 1)); |
||||
|
||||
return $int32; |
||||
} |
||||
|
||||
public static function zigZagEncode64($int64) |
||||
{ |
||||
$a = $int64->copy()->leftShift(1); |
||||
$b = $int64->copy()->rightShift(63); |
||||
$result = $a->bitXor($b); |
||||
$uint64 = Uint64::newValue($result->high, $result->low); |
||||
return $uint64; |
||||
} |
||||
|
||||
public static function zigZagDecode64($uint64) |
||||
{ |
||||
$a = $uint64->copy()->rightShift(1); |
||||
$b = $uint64->oddMask(); |
||||
$result = $a->bitXor($b); |
||||
$int64 = Int64::newValue($result->high, $result->low); |
||||
return $int64; |
||||
} |
||||
|
||||
public static function readInt32(&$input, &$value) |
||||
{ |
||||
return $input->readVarint32($value); |
||||
} |
||||
|
||||
public static function readInt64(&$input, &$value) |
||||
{ |
||||
return $input->readVarint64($value); |
||||
} |
||||
|
||||
public static function readUint32(&$input, &$value) |
||||
{ |
||||
return self::readInt32($input, $value); |
||||
} |
||||
|
||||
public static function readUint64(&$input, &$value) |
||||
{ |
||||
return self::readInt64($input, $value); |
||||
} |
||||
|
||||
public static function readSint32(&$input, &$value) |
||||
{ |
||||
if (!$input->readVarint32($value)) { |
||||
return false; |
||||
} |
||||
$value = GPBWire::zigZagDecode32($value); |
||||
return true; |
||||
} |
||||
|
||||
public static function readSint64(&$input, &$value) |
||||
{ |
||||
if (!$input->readVarint64($value)) { |
||||
return false; |
||||
} |
||||
$value = GPBWire::zigZagDecode64($value); |
||||
return true; |
||||
} |
||||
|
||||
public static function readFixed32(&$input, &$value) |
||||
{ |
||||
return $input->readLittleEndian32($value); |
||||
} |
||||
|
||||
public static function readFixed64(&$input, &$value) |
||||
{ |
||||
return $input->readLittleEndian64($value); |
||||
} |
||||
|
||||
public static function readSfixed32(&$input, &$value) |
||||
{ |
||||
if (!self::readFixed32($input, $value)) { |
||||
return false; |
||||
} |
||||
if (PHP_INT_SIZE === 8) { |
||||
$value |= (-($value >> 31) << 32); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static function readSfixed64(&$input, &$value) |
||||
{ |
||||
if (!self::readFixed64($input, $value)) { |
||||
return false; |
||||
} |
||||
$value = Int64::newValue($value->high, $value->low); |
||||
return true; |
||||
} |
||||
|
||||
public static function readFloat(&$input, &$value) |
||||
{ |
||||
$data = null; |
||||
if (!$input->readRaw(4, $data)) { |
||||
return false; |
||||
} |
||||
$value = unpack('f', $data)[1]; |
||||
return true; |
||||
} |
||||
|
||||
public static function readDouble(&$input, &$value) |
||||
{ |
||||
$data = null; |
||||
if (!$input->readRaw(8, $data)) { |
||||
return false; |
||||
} |
||||
$value = unpack('d', $data)[1]; |
||||
return true; |
||||
} |
||||
|
||||
public static function readBool(&$input, &$value) |
||||
{ |
||||
if (!$input->readVarint64($value)) { |
||||
return false; |
||||
} |
||||
if ($value->high === 0 && $value->low === 0) { |
||||
$value = false; |
||||
} else { |
||||
$value = true; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static function readString(&$input, &$value) |
||||
{ |
||||
$length = 0; |
||||
return $input->readVarintSizeAsInt($length) && $input->readRaw($length, $value); |
||||
} |
||||
|
||||
public static function readMessage(&$input, &$message) |
||||
{ |
||||
$length = 0; |
||||
if (!$input->readVarintSizeAsInt($length)) { |
||||
return false; |
||||
} |
||||
$old_limit = 0; |
||||
$recursion_limit = 0; |
||||
$input->incrementRecursionDepthAndPushLimit( |
||||
$length, |
||||
$old_limit, |
||||
$recursion_limit); |
||||
if ($recursion_limit < 0 || !$message->parseFromStream($input)) { |
||||
return false; |
||||
} |
||||
return $input->decrementRecursionDepthAndPopLimit($old_limit); |
||||
} |
||||
|
||||
public static function writeTag(&$output, $tag) |
||||
{ |
||||
return $output->writeTag($tag); |
||||
} |
||||
|
||||
public static function writeInt32(&$output, $value) |
||||
{ |
||||
return $output->writeVarint32($value); |
||||
} |
||||
|
||||
public static function writeInt64(&$output, $value) |
||||
{ |
||||
return $output->writeVarint64($value); |
||||
} |
||||
|
||||
public static function writeUint32(&$output, $value) |
||||
{ |
||||
return $output->writeVarint32($value); |
||||
} |
||||
|
||||
public static function writeUint64(&$output, $value) |
||||
{ |
||||
return $output->writeVarint64($value); |
||||
} |
||||
|
||||
public static function writeSint32(&$output, $value) |
||||
{ |
||||
$value = GPBWire::zigZagEncode32($value); |
||||
return $output->writeVarint64($value); |
||||
} |
||||
|
||||
public static function writeSint64(&$output, $value) |
||||
{ |
||||
$value = GPBWire::zigZagEncode64(GPBUtil::Int64($value)); |
||||
return $output->writeVarint64($value->toInteger()); |
||||
} |
||||
|
||||
public static function writeFixed32(&$output, $value) |
||||
{ |
||||
return $output->writeLittleEndian32($value); |
||||
} |
||||
|
||||
public static function writeFixed64(&$output, $value) |
||||
{ |
||||
return $output->writeLittleEndian64($value); |
||||
} |
||||
|
||||
public static function writeSfixed32(&$output, $value) |
||||
{ |
||||
return $output->writeLittleEndian32($value); |
||||
} |
||||
|
||||
public static function writeSfixed64(&$output, $value) |
||||
{ |
||||
return $output->writeLittleEndian64($value); |
||||
} |
||||
|
||||
public static function writeBool(&$output, $value) |
||||
{ |
||||
if ($value) { |
||||
return $output->writeVarint32(1); |
||||
} else { |
||||
return $output->writeVarint32(0); |
||||
} |
||||
} |
||||
|
||||
public static function writeFloat(&$output, $value) |
||||
{ |
||||
$data = pack("f", $value); |
||||
return $output->writeRaw($data, 4); |
||||
} |
||||
|
||||
public static function writeDouble(&$output, $value) |
||||
{ |
||||
$data = pack("d", $value); |
||||
return $output->writeRaw($data, 8); |
||||
} |
||||
|
||||
public static function writeString(&$output, $value) |
||||
{ |
||||
return self::writeBytes($output, $value); |
||||
} |
||||
|
||||
public static function writeBytes(&$output, $value) |
||||
{ |
||||
$size = strlen($value); |
||||
if (!$output->writeVarint32($size)) { |
||||
return false; |
||||
} |
||||
return $output->writeRaw($value, $size); |
||||
} |
||||
|
||||
public static function writeMessage(&$output, $value) |
||||
{ |
||||
$size = $value->byteSize(); |
||||
if (!$output->writeVarint32($size)) { |
||||
return false; |
||||
} |
||||
return $value->serializeToStream($output); |
||||
} |
||||
|
||||
public static function makeTag($number, $type) |
||||
{ |
||||
return ($number << 3) | self::getWireType($type); |
||||
} |
||||
|
||||
public static function tagSize($field) |
||||
{ |
||||
$tag = self::makeTag($field->getNumber(), $field->getType()); |
||||
return self::varint32Size($tag); |
||||
} |
||||
|
||||
public static function varint32Size($value) |
||||
{ |
||||
if ($value < 0) { |
||||
return 5; |
||||
} |
||||
if ($value < (1 << 7)) { |
||||
return 1; |
||||
} |
||||
if ($value < (1 << 14)) { |
||||
return 2; |
||||
} |
||||
if ($value < (1 << 21)) { |
||||
return 3; |
||||
} |
||||
if ($value < (1 << 28)) { |
||||
return 4; |
||||
} |
||||
return 5; |
||||
} |
||||
|
||||
public static function sint32Size($value) |
||||
{ |
||||
$value = self::zigZagEncode32($value); |
||||
return self::varint32Size($value); |
||||
} |
||||
|
||||
public static function sint64Size($value) |
||||
{ |
||||
$value = GPBUtil::Int64($value); |
||||
$value = self::zigZagEncode64($value); |
||||
return self::varint64Size($value->toInteger()); |
||||
} |
||||
|
||||
public static function varint64Size($value) |
||||
{ |
||||
if ($value < 0) { |
||||
return 10; |
||||
} |
||||
if ($value < (1 << 7)) { |
||||
return 1; |
||||
} |
||||
if ($value < (1 << 14)) { |
||||
return 2; |
||||
} |
||||
if ($value < (1 << 21)) { |
||||
return 3; |
||||
} |
||||
if ($value < (1 << 28)) { |
||||
return 4; |
||||
} |
||||
if ($value < (1 << 35)) { |
||||
return 5; |
||||
} |
||||
if ($value < (1 << 42)) { |
||||
return 6; |
||||
} |
||||
if ($value < (1 << 49)) { |
||||
return 7; |
||||
} |
||||
if ($value < (1 << 56)) { |
||||
return 8; |
||||
} |
||||
return 9; |
||||
} |
||||
|
||||
public static function serializeFieldToStream( |
||||
$value, |
||||
$field, |
||||
$need_tag, |
||||
&$output) |
||||
{ |
||||
if ($need_tag) { |
||||
if (!GPBWire::writeTag( |
||||
$output, |
||||
self::makeTag( |
||||
$field->getNumber(), |
||||
$field->getType()))) { |
||||
return false; |
||||
} |
||||
} |
||||
switch ($field->getType()) { |
||||
case GPBType::DOUBLE: |
||||
if (!GPBWire::writeDouble($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::FLOAT: |
||||
if (!GPBWire::writeFloat($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::INT64: |
||||
if (!GPBWire::writeInt64($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::UINT64: |
||||
if (!GPBWire::writeUint64($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::INT32: |
||||
if (!GPBWire::writeInt32($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::FIXED32: |
||||
if (!GPBWire::writeFixed32($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::FIXED64: |
||||
if (!GPBWire::writeFixed64($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::BOOL: |
||||
if (!GPBWire::writeBool($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::STRING: |
||||
if (!GPBWire::writeString($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
// case GPBType::GROUP: |
||||
// echo "GROUP\xA"; |
||||
// trigger_error("Not implemented.", E_ERROR); |
||||
// break; |
||||
case GPBType::MESSAGE: |
||||
if (!GPBWire::writeMessage($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::BYTES: |
||||
if (!GPBWire::writeBytes($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::UINT32: |
||||
if (!GPBWire::writeUint32($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::ENUM: |
||||
if (!GPBWire::writeInt32($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SFIXED32: |
||||
if (!GPBWire::writeSfixed32($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SFIXED64: |
||||
if (!GPBWire::writeSfixed64($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SINT32: |
||||
if (!GPBWire::writeSint32($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SINT64: |
||||
if (!GPBWire::writeSint64($output, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
default: |
||||
user_error("Unsupported type."); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,323 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\Uint64; |
||||
|
||||
class InputStream |
||||
{ |
||||
|
||||
private $buffer; |
||||
private $buffer_size_after_limit; |
||||
private $buffer_end; |
||||
private $current; |
||||
private $current_limit; |
||||
private $legitimate_message_end; |
||||
private $recursion_budget; |
||||
private $recursion_limit; |
||||
private $total_bytes_limit; |
||||
private $total_bytes_read; |
||||
|
||||
const MAX_VARINT_BYTES = 10; |
||||
const MAX_VARINT32_BYTES = 5; |
||||
const DEFAULT_RECURSION_LIMIT = 100; |
||||
const DEFAULT_TOTAL_BYTES_LIMIT = 33554432; // 32 << 20, 32MB |
||||
|
||||
public function __construct($buffer) |
||||
{ |
||||
$start = 0; |
||||
$end = strlen($buffer); |
||||
$this->buffer = $buffer; |
||||
$this->buffer_size_after_limit = 0; |
||||
$this->buffer_end = $end; |
||||
$this->current = $start; |
||||
$this->current_limit = $end; |
||||
$this->legitimate_message_end = false; |
||||
$this->recursion_budget = self::DEFAULT_RECURSION_LIMIT; |
||||
$this->recursion_limit = self::DEFAULT_RECURSION_LIMIT; |
||||
$this->total_bytes_limit = self::DEFAULT_TOTAL_BYTES_LIMIT; |
||||
$this->total_bytes_read = $end - $start; |
||||
} |
||||
|
||||
private function advance($amount) |
||||
{ |
||||
$this->current += $amount; |
||||
} |
||||
|
||||
private function bufferSize() |
||||
{ |
||||
return $this->buffer_end - $this->current; |
||||
} |
||||
|
||||
private function current() |
||||
{ |
||||
return $this->total_bytes_read - |
||||
($this->buffer_end - $this->current + |
||||
$this->buffer_size_after_limit); |
||||
} |
||||
|
||||
private function recomputeBufferLimits() |
||||
{ |
||||
$this->buffer_end += $this->buffer_size_after_limit; |
||||
$closest_limit = min($this->current_limit, $this->total_bytes_limit); |
||||
if ($closest_limit < $this->total_bytes_read) { |
||||
// The limit position is in the current buffer. We must adjust the |
||||
// buffer size accordingly. |
||||
$this->buffer_size_after_limit = $this->total_bytes_read - |
||||
$closest_limit; |
||||
$this->buffer_end -= $this->buffer_size_after_limit; |
||||
} else { |
||||
$this->buffer_size_after_limit = 0; |
||||
} |
||||
} |
||||
|
||||
private function consumedEntireMessage() |
||||
{ |
||||
return $this->legitimate_message_end; |
||||
} |
||||
|
||||
/** |
||||
* Read uint32 into $var. Advance buffer with consumed bytes. If the |
||||
* contained varint is larger than 32 bits, discard the high order bits. |
||||
* @param $var. |
||||
*/ |
||||
public function readVarint32(&$var) |
||||
{ |
||||
if (!$this->readVarint64($var)) { |
||||
return false; |
||||
} |
||||
$var = $var->toInteger() & 0xFFFFFFFF; |
||||
// Convert large uint32 to int32. |
||||
if (PHP_INT_SIZE === 8 && ($var > 0x7FFFFFFF)) { |
||||
$var = $var | (0xFFFFFFFF << 32); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Read Uint64 into $var. Advance buffer with consumed bytes. |
||||
* @param $var. |
||||
*/ |
||||
public function readVarint64(&$var) |
||||
{ |
||||
$result = new Uint64(0); |
||||
$count = 0; |
||||
$b = 0; |
||||
|
||||
do { |
||||
if ($this->current === $this->buffer_end) { |
||||
return false; |
||||
} |
||||
if ($count === self::MAX_VARINT_BYTES) { |
||||
return false; |
||||
} |
||||
$b = ord($this->buffer[$this->current]); |
||||
$result->bitOr((new Uint64($b & 0x7F))->leftShift(7 * $count)); |
||||
$this->advance(1); |
||||
$count += 1; |
||||
} while ($b & 0x80); |
||||
|
||||
$var = $result; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Read int into $var. If the result is larger than the largest integer, $var |
||||
* will be -1. Advance buffer with consumed bytes. |
||||
* @param $var. |
||||
*/ |
||||
public function readVarintSizeAsInt(&$var) |
||||
{ |
||||
if (!$this->readVarint64($var)) { |
||||
return false; |
||||
} |
||||
$var = $var->toInteger(); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Read 32-bit unsiged integer to $var. If the buffer has less than 4 bytes, |
||||
* return false. Advance buffer with consumed bytes. |
||||
* @param $var. |
||||
*/ |
||||
public function readLittleEndian32(&$var) |
||||
{ |
||||
$data = null; |
||||
if (!$this->readRaw(4, $data)) { |
||||
return false; |
||||
} |
||||
$var = unpack('V', $data); |
||||
$var = $var[1]; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Read 64-bit unsiged integer to $var. If the buffer has less than 8 bytes, |
||||
* return false. Advance buffer with consumed bytes. |
||||
* @param $var. |
||||
*/ |
||||
public function readLittleEndian64(&$var) |
||||
{ |
||||
$data = null; |
||||
if (!$this->readRaw(4, $data)) { |
||||
return false; |
||||
} |
||||
$low = unpack('V', $data)[1]; |
||||
if (!$this->readRaw(4, $data)) { |
||||
return false; |
||||
} |
||||
$high = unpack('V', $data)[1]; |
||||
$var = Uint64::newValue($high, $low); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Read tag into $var. Advance buffer with consumed bytes. |
||||
* @param $var. |
||||
*/ |
||||
public function readTag() |
||||
{ |
||||
if ($this->current === $this->buffer_end) { |
||||
// Make sure that it failed due to EOF, not because we hit |
||||
// total_bytes_limit, which, unlike normal limits, is not a valid |
||||
// place to end a message. |
||||
$current_position = $this->total_bytes_read - |
||||
$this->buffer_size_after_limit; |
||||
if ($current_position >= $this->total_bytes_limit) { |
||||
// Hit total_bytes_limit_. But if we also hit the normal limit, |
||||
// we're still OK. |
||||
$this->legitimate_message_end = |
||||
($this->current_limit === $this->total_bytes_limit); |
||||
} else { |
||||
$this->legitimate_message_end = true; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
$result = 0; |
||||
// The larget tag is 2^29 - 1, which can be represented by int32. |
||||
$success = $this->readVarint32($result); |
||||
if ($success) { |
||||
return $result; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public function readRaw($size, &$buffer) |
||||
{ |
||||
$current_buffer_size = 0; |
||||
if ($this->bufferSize() < $size) { |
||||
return false; |
||||
} |
||||
|
||||
$buffer = substr($this->buffer, $this->current, $size); |
||||
$this->advance($size); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/* Places a limit on the number of bytes that the stream may read, starting |
||||
* from the current position. Once the stream hits this limit, it will act |
||||
* like the end of the input has been reached until popLimit() is called. |
||||
* |
||||
* As the names imply, the stream conceptually has a stack of limits. The |
||||
* shortest limit on the stack is always enforced, even if it is not the top |
||||
* limit. |
||||
* |
||||
* The value returned by pushLimit() is opaque to the caller, and must be |
||||
* passed unchanged to the corresponding call to popLimit(). |
||||
* |
||||
* @param integer $byte_limit |
||||
*/ |
||||
public function pushLimit($byte_limit) |
||||
{ |
||||
// Current position relative to the beginning of the stream. |
||||
$current_position = $this->current(); |
||||
$old_limit = $this->current_limit; |
||||
|
||||
// security: byte_limit is possibly evil, so check for negative values |
||||
// and overflow. |
||||
if ($byte_limit >= 0 && $byte_limit <= PHP_INT_MAX - $current_position) { |
||||
$this->current_limit = $current_position + $byte_limit; |
||||
} else { |
||||
// Negative or overflow. |
||||
$this->current_limit = PHP_INT_MAX; |
||||
} |
||||
|
||||
// We need to enforce all limits, not just the new one, so if the previous |
||||
// limit was before the new requested limit, we continue to enforce the |
||||
// previous limit. |
||||
$this->current_limit = min($this->current_limit, $old_limit); |
||||
|
||||
$this->recomputeBufferLimits(); |
||||
return $old_limit; |
||||
} |
||||
|
||||
/* The limit passed in is actually the *old* limit, which we returned from |
||||
* PushLimit(). |
||||
* |
||||
* @param integer $byte_limit |
||||
*/ |
||||
public function popLimit($byte_limit) |
||||
{ |
||||
$this->current_limit = $byte_limit; |
||||
$this->recomputeBufferLimits(); |
||||
// We may no longer be at a legitimate message end. ReadTag() needs to |
||||
// be called again to find out. |
||||
$this->legitimate_message_end = false; |
||||
} |
||||
|
||||
public function incrementRecursionDepthAndPushLimit( |
||||
$byte_limit, &$old_limit, &$recursion_budget) |
||||
{ |
||||
$old_limit = $this->pushLimit($byte_limit); |
||||
$recursion_limit = --$this->recursion_limit; |
||||
} |
||||
|
||||
public function decrementRecursionDepthAndPopLimit($byte_limit) |
||||
{ |
||||
$result = $this->consumedEntireMessage(); |
||||
$this->popLimit($byte_limit); |
||||
++$this->recursion_budget; |
||||
return $result; |
||||
} |
||||
|
||||
public function bytesUntilLimit() |
||||
{ |
||||
if ($this->current_limit === PHP_INT_MAX) { |
||||
return -1; |
||||
} |
||||
return $this->current_limit - $this->current; |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\Message; |
||||
|
||||
class MapEntry extends Message |
||||
{ |
||||
public $key; |
||||
public $value; |
||||
|
||||
public function setKey(&$key) { |
||||
$this->key = $key; |
||||
} |
||||
|
||||
public function getKey() { |
||||
return $this->key; |
||||
} |
||||
|
||||
public function setValue(&$value) { |
||||
$this->value = $value; |
||||
} |
||||
|
||||
public function getValue() { |
||||
return $this->value; |
||||
} |
||||
} |
@ -0,0 +1,321 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
/** |
||||
* MapField and MapFieldIter are used by generated protocol message classes to |
||||
* manipulate map fields. |
||||
*/ |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
/** |
||||
* MapFieldIter is used to iterate MapField. It is also need for the foreach |
||||
* syntax. |
||||
*/ |
||||
class MapFieldIter implements \Iterator |
||||
{ |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $container; |
||||
|
||||
/** |
||||
* Create iterator instance for MapField. |
||||
* |
||||
* @param MapField The MapField instance for which this iterator is |
||||
* created. |
||||
* @ignore |
||||
*/ |
||||
public function __construct($container) |
||||
{ |
||||
$this->container = $container; |
||||
} |
||||
|
||||
/** |
||||
* Reset the status of the iterator |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function rewind() |
||||
{ |
||||
return reset($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Return the element at the current position. |
||||
* |
||||
* @return object The element at the current position. |
||||
*/ |
||||
public function current() |
||||
{ |
||||
return current($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Return the current key. |
||||
* |
||||
* @return object The current key. |
||||
*/ |
||||
public function key() |
||||
{ |
||||
return key($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Move to the next position. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function next() |
||||
{ |
||||
return next($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Check whether there are more elements to iterate. |
||||
* |
||||
* @return bool True if there are more elements to iterate. |
||||
*/ |
||||
public function valid() |
||||
{ |
||||
return key($this->container) !== null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
function checkKey($key_type, &$key) |
||||
{ |
||||
switch ($key_type) { |
||||
case GPBType::INT32: |
||||
GPBUtil::checkInt32($key); |
||||
break; |
||||
case GPBType::UINT32: |
||||
GPBUtil::checkUint32($key); |
||||
break; |
||||
case GPBType::INT64: |
||||
GPBUtil::checkInt64($key); |
||||
break; |
||||
case GPBType::UINT64: |
||||
GPBUtil::checkUint64($key); |
||||
break; |
||||
case GPBType::FIXED64: |
||||
GPBUtil::checkUint64($key); |
||||
break; |
||||
case GPBType::FIXED32: |
||||
GPBUtil::checkUint32($key); |
||||
break; |
||||
case GPBType::SFIXED64: |
||||
GPBUtil::checkInt64($key); |
||||
break; |
||||
case GPBType::SFIXED32: |
||||
GPBUtil::checkInt32($key); |
||||
break; |
||||
case GPBType::SINT64: |
||||
GPBUtil::checkInt64($key); |
||||
break; |
||||
case GPBType::SINT32: |
||||
GPBUtil::checkInt32($key); |
||||
break; |
||||
case GPBType::BOOL: |
||||
GPBUtil::checkBool($key); |
||||
break; |
||||
case GPBType::STRING: |
||||
GPBUtil::checkString($key, true); |
||||
break; |
||||
default: |
||||
var_dump($key_type); |
||||
trigger_error( |
||||
"Given type cannot be map key.", |
||||
E_USER_ERROR); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* MapField is used by generated protocol message classes to manipulate map |
||||
* fields. It can be used like native PHP array. |
||||
*/ |
||||
class MapField implements \ArrayAccess, \IteratorAggregate, \Countable |
||||
{ |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $container; |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $key_type; |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $value_type; |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $value_klass; |
||||
|
||||
/** |
||||
* Constructs an instance of MapField. |
||||
* |
||||
* @param long $key_type Type of the stored key element. |
||||
* @param long $value_type Type of the stored value element. |
||||
* @param string $klass Message/Enum class name of value instance |
||||
* (message/enum fields only). |
||||
* @ignore |
||||
*/ |
||||
public function __construct($key_type, $value_type, $klass = null) |
||||
{ |
||||
$this->container = []; |
||||
$this->key_type = $key_type; |
||||
$this->value_type = $value_type; |
||||
$this->klass = $klass; |
||||
} |
||||
|
||||
/** |
||||
* Return the element at the given key. |
||||
* |
||||
* This will also be called for: $ele = $arr[$key] |
||||
* |
||||
* @param object $key The key of the element to be fetched. |
||||
* @return object The stored element at given key. |
||||
* @throws ErrorException Invalid type for index. |
||||
* @throws ErrorException Non-existing index. |
||||
*/ |
||||
public function offsetGet($key) |
||||
{ |
||||
return $this->container[$key]; |
||||
} |
||||
|
||||
/** |
||||
* Assign the element at the given key. |
||||
* |
||||
* This will also be called for: $arr[$key] = $value |
||||
* |
||||
* @param object $key The key of the element to be fetched. |
||||
* @param object $value The element to be assigned. |
||||
* @return void |
||||
* @throws ErrorException Invalid type for key. |
||||
* @throws ErrorException Invalid type for value. |
||||
* @throws ErrorException Non-existing key. |
||||
*/ |
||||
public function offsetSet($key, $value) |
||||
{ |
||||
checkKey($this->key_type, $key); |
||||
|
||||
switch ($this->value_type) { |
||||
case GPBType::INT32: |
||||
GPBUtil::checkInt32($value); |
||||
break; |
||||
case GPBType::UINT32: |
||||
GPBUtil::checkUint32($value); |
||||
break; |
||||
case GPBType::INT64: |
||||
GPBUtil::checkInt64($value); |
||||
break; |
||||
case GPBType::UINT64: |
||||
GPBUtil::checkUint64($value); |
||||
break; |
||||
case GPBType::FLOAT: |
||||
GPBUtil::checkFloat($value); |
||||
break; |
||||
case GPBType::DOUBLE: |
||||
GPBUtil::checkDouble($value); |
||||
break; |
||||
case GPBType::BOOL: |
||||
GPBUtil::checkBool($value); |
||||
break; |
||||
case GPBType::STRING: |
||||
GPBUtil::checkString($value, true); |
||||
break; |
||||
case GPBType::MESSAGE: |
||||
GPBUtil::checkMessage($value, $this->klass); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
$this->container[$key] = $value; |
||||
} |
||||
|
||||
/** |
||||
* Remove the element at the given key. |
||||
* |
||||
* This will also be called for: unset($arr) |
||||
* |
||||
* @param object $key The key of the element to be removed. |
||||
* @return void |
||||
* @throws ErrorException Invalid type for key. |
||||
*/ |
||||
public function offsetUnset($key) |
||||
{ |
||||
checkKey($this->key_type, $key); |
||||
unset($this->container[$key]); |
||||
} |
||||
|
||||
/** |
||||
* Check the existence of the element at the given key. |
||||
* |
||||
* This will also be called for: isset($arr) |
||||
* |
||||
* @param object $key The key of the element to be removed. |
||||
* @return bool True if the element at the given key exists. |
||||
* @throws ErrorException Invalid type for key. |
||||
*/ |
||||
public function offsetExists($key) |
||||
{ |
||||
checkKey($this->key_type, $key); |
||||
return isset($this->container[$key]); |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function getIterator() |
||||
{ |
||||
return new MapFieldIter($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Return the number of stored elements. |
||||
* |
||||
* This will also be called for: count($arr) |
||||
* |
||||
* @return integer The number of stored elements. |
||||
*/ |
||||
public function count() |
||||
{ |
||||
return count($this->container); |
||||
} |
||||
} |
@ -0,0 +1,671 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
/** |
||||
* Defines Message, the parent class extended by all protocol message classes. |
||||
*/ |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\InputStream; |
||||
use Google\Protobuf\Internal\OutputStream; |
||||
use Google\Protobuf\Internal\DescriptorPool; |
||||
use Google\Protobuf\Internal\GPBLabel; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\GPBWire; |
||||
use Google\Protobuf\Internal\MapEntry; |
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
|
||||
/** |
||||
* Parent class of all proto messages. Users should not instantiate this class |
||||
* or extend this class or its child classes by their own. See the comment of |
||||
* specific functions for more details. |
||||
*/ |
||||
class Message |
||||
{ |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $desc; |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function __construct($desc = NULL) |
||||
{ |
||||
// MapEntry message is shared by all types of map fields, whose |
||||
// descriptors are different from each other. Thus, we cannot find a |
||||
// specific descriptor from the descriptor pool. |
||||
if (get_class($this) === 'Google\Protobuf\Internal\MapEntry') { |
||||
$this->desc = $desc; |
||||
return; |
||||
} |
||||
$pool = DescriptorPool::getGeneratedPool(); |
||||
$this->desc = $pool->getDescriptorByClassName(get_class($this)); |
||||
foreach ($this->desc->getField() as $field) { |
||||
$setter = $field->getSetter(); |
||||
if ($field->isMap()) { |
||||
$message_type = $field->getMessageType(); |
||||
$key_field = $message_type->getFieldByNumber(1); |
||||
$value_field = $message_type->getFieldByNumber(2); |
||||
switch ($value_field->getType()) { |
||||
case GPBType::MESSAGE: |
||||
case GPBType::GROUP: |
||||
$this->$setter( |
||||
new MapField( |
||||
$key_field->getType(), |
||||
$value_field->getType(), |
||||
$value_field->getMessageType()->getClass())); |
||||
break; |
||||
case GPBType::ENUM: |
||||
$this->$setter( |
||||
new MapField( |
||||
$key_field->getType(), |
||||
$value_field->getType(), |
||||
$value_field->getEnumType()->getClass())); |
||||
break; |
||||
default: |
||||
$this->$setter(new MapField($key_field->getType(), |
||||
$value_field->getType())); |
||||
break; |
||||
} |
||||
} else if ($field->getLabel() === GPBLabel::REPEATED) { |
||||
switch ($field->getType()) { |
||||
case GPBType::MESSAGE: |
||||
case GPBType::GROUP: |
||||
$this->$setter( |
||||
new RepeatedField( |
||||
$field->getType(), |
||||
$field->getMessageType()->getClass())); |
||||
break; |
||||
case GPBType::ENUM: |
||||
$this->$setter( |
||||
new RepeatedField( |
||||
$field->getType(), |
||||
$field->getEnumType()->getClass())); |
||||
break; |
||||
default: |
||||
$this->$setter(new RepeatedField($field->getType())); |
||||
break; |
||||
} |
||||
} else if ($field->getOneofIndex() !== -1) { |
||||
$oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; |
||||
$oneof_name = $oneof->getName(); |
||||
$this->$oneof_name = new OneofField($oneof); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected function readOneof($number) |
||||
{ |
||||
$field = $this->desc->getFieldByNumber($number); |
||||
$oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; |
||||
$oneof_name = $oneof->getName(); |
||||
$oneof_field = $this->$oneof_name; |
||||
if ($number === $oneof_field->getNumber()) { |
||||
return $oneof_field->getValue(); |
||||
} else { |
||||
return $this->defaultValue($field); |
||||
} |
||||
} |
||||
|
||||
protected function writeOneof($number, $value) |
||||
{ |
||||
$field = $this->desc->getFieldByNumber($number); |
||||
$oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; |
||||
$oneof_name = $oneof->getName(); |
||||
$oneof_field = $this->$oneof_name; |
||||
$oneof_field->setValue($value); |
||||
$oneof_field->setFieldName($field->getName()); |
||||
$oneof_field->setNumber($number); |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function defaultValue($field) |
||||
{ |
||||
$value = null; |
||||
|
||||
switch ($field->getType()) { |
||||
case GPBType::DOUBLE: |
||||
case GPBType::FLOAT: |
||||
return 0.0; |
||||
case GPBType::UINT32: |
||||
case GPBType::UINT64: |
||||
case GPBType::INT32: |
||||
case GPBType::INT64: |
||||
case GPBType::FIXED32: |
||||
case GPBType::FIXED64: |
||||
case GPBType::SFIXED32: |
||||
case GPBType::SFIXED64: |
||||
case GPBType::SINT32: |
||||
case GPBType::SINT64: |
||||
case GPBType::ENUM: |
||||
return 0; |
||||
case GPBType::BOOL: |
||||
return false; |
||||
case GPBType::STRING: |
||||
case GPBType::BYTES: |
||||
return ""; |
||||
case GPBType::GROUP: |
||||
case GPBType::MESSAGE: |
||||
return null; |
||||
default: |
||||
user_error("Unsupported type."); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private static function parseFieldFromStreamNoTag($input, $field, &$value) |
||||
{ |
||||
switch ($field->getType()) { |
||||
case GPBType::DOUBLE: |
||||
if (!GPBWire::readDouble($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::FLOAT: |
||||
if (!GPBWire::readFloat($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::INT64: |
||||
if (!GPBWire::readInt64($input, $value)) { |
||||
return false; |
||||
} |
||||
$value = $value->toInteger(); |
||||
break; |
||||
case GPBType::UINT64: |
||||
if (!GPBWire::readUint64($input, $value)) { |
||||
return false; |
||||
} |
||||
$value = $value->toInteger(); |
||||
break; |
||||
case GPBType::INT32: |
||||
if (!GPBWire::readInt32($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::FIXED64: |
||||
if (!GPBWire::readFixed64($input, $value)) { |
||||
return false; |
||||
} |
||||
$value = $value->toInteger(); |
||||
break; |
||||
case GPBType::FIXED32: |
||||
if (!GPBWire::readFixed32($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::BOOL: |
||||
if (!GPBWire::readBool($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::STRING: |
||||
// TODO(teboring): Add utf-8 check. |
||||
if (!GPBWire::readString($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::GROUP: |
||||
echo "GROUP\xA"; |
||||
trigger_error("Not implemented.", E_ERROR); |
||||
break; |
||||
case GPBType::MESSAGE: |
||||
if ($field->isMap()) { |
||||
$value = new MapEntry($field->getMessageType()); |
||||
} else { |
||||
$klass = $field->getMessageType()->getClass(); |
||||
$value = new $klass; |
||||
} |
||||
if (!GPBWire::readMessage($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::BYTES: |
||||
if (!GPBWire::readString($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::UINT32: |
||||
if (!GPBWire::readUint32($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::ENUM: |
||||
// TODO(teboring): Check unknown enum value. |
||||
if (!GPBWire::readInt32($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SFIXED32: |
||||
if (!GPBWire::readSfixed32($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SFIXED64: |
||||
if (!GPBWire::readSfixed64($input, $value)) { |
||||
return false; |
||||
} |
||||
$value = $value->toInteger(); |
||||
break; |
||||
case GPBType::SINT32: |
||||
if (!GPBWire::readSint32($input, $value)) { |
||||
return false; |
||||
} |
||||
break; |
||||
case GPBType::SINT64: |
||||
if (!GPBWire::readSint64($input, $value)) { |
||||
return false; |
||||
} |
||||
$value = $value->toInteger(); |
||||
break; |
||||
default: |
||||
user_error("Unsupported type."); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function parseFieldFromStream($tag, $input, $field) |
||||
{ |
||||
$value = null; |
||||
$field_type = $field->getType(); |
||||
|
||||
$value_format = GPBWire::UNKNOWN; |
||||
if (GPBWire::getTagWireType($tag) === |
||||
GPBWire::getWireType($field_type)) { |
||||
$value_format = GPBWire::NORMAL_FORMAT; |
||||
} elseif ($field->isPackable() && |
||||
GPBWire::getTagWireType($tag) === |
||||
GPBWire::WIRETYPE_LENGTH_DELIMITED) { |
||||
$value_format = GPBWire::PACKED_FORMAT; |
||||
} |
||||
|
||||
if ($value_format === GPBWire::NORMAL_FORMAT) { |
||||
if (!self::parseFieldFromStreamNoTag($input, $field, $value)) { |
||||
return false; |
||||
} |
||||
} elseif ($value_format === GPBWire::PACKED_FORMAT) { |
||||
$length = 0; |
||||
if (!GPBWire::readInt32($input, $length)) { |
||||
return false; |
||||
} |
||||
$limit = $input->pushLimit($length); |
||||
$getter = $field->getGetter(); |
||||
while ($input->bytesUntilLimit() > 0) { |
||||
if (!self::parseFieldFromStreamNoTag($input, $field, $value)) { |
||||
return false; |
||||
} |
||||
$this->$getter()[] = $value; |
||||
} |
||||
$input->popLimit($limit); |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
|
||||
if ($field->isMap()) { |
||||
$getter = $field->getGetter(); |
||||
$this->$getter()[$value->getKey()] = $value->getValue(); |
||||
} else if ($field->isRepeated()) { |
||||
$getter = $field->getGetter(); |
||||
$this->$getter()[] = $value; |
||||
} else { |
||||
$setter = $field->getSetter(); |
||||
$this->$setter($value); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Parses a protocol buffer contained in a string. |
||||
* |
||||
* This function takes a string in the (non-human-readable) binary wire |
||||
* format, matching the encoding output by encode(). |
||||
* |
||||
* @param string $data Binary protobuf data. |
||||
* @return bool Return true on success. |
||||
*/ |
||||
public function decode($data) |
||||
{ |
||||
$input = new InputStream($data); |
||||
$this->parseFromStream($input); |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function parseFromStream($input) |
||||
{ |
||||
while (true) { |
||||
$tag = $input->readTag(); |
||||
// End of input. This is a valid place to end, so return true. |
||||
if ($tag === 0) { |
||||
return true; |
||||
} |
||||
|
||||
$number = GPBWire::getTagFieldNumber($tag); |
||||
$field = $this->desc->getFieldByNumber($number); |
||||
|
||||
if (!$this->parseFieldFromStream($tag, $input, $field)) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function serializeSingularFieldToStream($field, &$output) |
||||
{ |
||||
if (!$this->existField($field)) { |
||||
return true; |
||||
} |
||||
$getter = $field->getGetter(); |
||||
$value = $this->$getter(); |
||||
if (!GPBWire::serializeFieldToStream($value, $field, true, $output)) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function serializeRepeatedFieldToStream($field, &$output) |
||||
{ |
||||
$getter = $field->getGetter(); |
||||
$values = $this->$getter(); |
||||
$count = count($values); |
||||
if ($count === 0) { |
||||
return true; |
||||
} |
||||
|
||||
$packed = $field->getPacked(); |
||||
if ($packed) { |
||||
if (!GPBWire::writeTag( |
||||
$output, |
||||
GPBWire::makeTag($field->getNumber(), GPBType::STRING))) { |
||||
return false; |
||||
} |
||||
$size = 0; |
||||
foreach ($values as $value) { |
||||
$size += $this->fieldDataOnlyByteSize($field, $value); |
||||
} |
||||
if (!$output->writeVarint32($size)) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
foreach ($values as $value) { |
||||
if (!GPBWire::serializeFieldToStream( |
||||
$value, |
||||
$field, |
||||
!$packed, |
||||
$output)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function serializeMapFieldToStream($field, $output) |
||||
{ |
||||
$getter = $field->getGetter(); |
||||
$values = $this->$getter(); |
||||
$count = count($values); |
||||
if ($count === 0) { |
||||
return true; |
||||
} |
||||
|
||||
foreach ($values as $key => $value) { |
||||
$map_entry = new MapEntry($field->getMessageType()); |
||||
$map_entry->setKey($key); |
||||
$map_entry->setValue($value); |
||||
if (!GPBWire::serializeFieldToStream( |
||||
$map_entry, |
||||
$field, |
||||
true, |
||||
$output)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function serializeFieldToStream(&$output, $field) |
||||
{ |
||||
if ($field->isMap()) { |
||||
return $this->serializeMapFieldToStream($field, $output); |
||||
} elseif ($field->isRepeated()) { |
||||
return $this->serializeRepeatedFieldToStream($field, $output); |
||||
} else { |
||||
return $this->serializeSingularFieldToStream($field, $output); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function serializeToStream(&$output) |
||||
{ |
||||
$fields = $this->desc->getField(); |
||||
foreach ($fields as $field) { |
||||
if (!$this->serializeFieldToStream($output, $field)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Serialize the message to string. |
||||
* @return string Serialized binary protobuf data. |
||||
*/ |
||||
public function encode() |
||||
{ |
||||
$output = new OutputStream($this->byteSize()); |
||||
$this->serializeToStream($output); |
||||
return $output->getData(); |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function existField($field) |
||||
{ |
||||
$getter = $field->getGetter(); |
||||
$value = $this->$getter(); |
||||
return $value !== $this->defaultValue($field); |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function repeatedFieldDataOnlyByteSize($field) |
||||
{ |
||||
$size = 0; |
||||
|
||||
$getter = $field->getGetter(); |
||||
$values = $this->$getter(); |
||||
$count = count($values); |
||||
if ($count !== 0) { |
||||
$size += $count * GPBWire::tagSize($field); |
||||
foreach ($values as $value) { |
||||
$size += $this->singularFieldDataOnlyByteSize($field); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function fieldDataOnlyByteSize($field, $value) |
||||
{ |
||||
$size = 0; |
||||
|
||||
switch ($field->getType()) { |
||||
case GPBType::BOOL: |
||||
$size += 1; |
||||
break; |
||||
case GPBType::FLOAT: |
||||
case GPBType::FIXED32: |
||||
case GPBType::SFIXED32: |
||||
$size += 4; |
||||
break; |
||||
case GPBType::DOUBLE: |
||||
case GPBType::FIXED64: |
||||
case GPBType::SFIXED64: |
||||
$size += 8; |
||||
break; |
||||
case GPBType::UINT32: |
||||
case GPBType::INT32: |
||||
case GPBType::ENUM: |
||||
$size += GPBWire::varint32Size($value); |
||||
break; |
||||
case GPBType::UINT64: |
||||
case GPBType::INT64: |
||||
$size += GPBWire::varint64Size($value); |
||||
break; |
||||
case GPBType::SINT32: |
||||
$size += GPBWire::sint32Size($value); |
||||
break; |
||||
case GPBType::SINT64: |
||||
$size += GPBWire::sint64Size($value); |
||||
break; |
||||
case GPBType::STRING: |
||||
case GPBType::BYTES: |
||||
$size += strlen($value); |
||||
$size += GPBWire::varint32Size($size); |
||||
break; |
||||
case GPBType::MESSAGE: |
||||
$size += $value->byteSize(); |
||||
$size += GPBWire::varint32Size($size); |
||||
break; |
||||
case GPBType::GROUP: |
||||
// TODO(teboring): Add support. |
||||
user_error("Unsupported type."); |
||||
break; |
||||
default: |
||||
user_error("Unsupported type."); |
||||
return 0; |
||||
} |
||||
|
||||
return $size; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private function fieldByteSize($field) |
||||
{ |
||||
$size = 0; |
||||
if ($field->isMap()) { |
||||
$getter = $field->getGetter(); |
||||
$values = $this->$getter(); |
||||
$count = count($values); |
||||
if ($count !== 0) { |
||||
$size += $count * GPBWire::tagSize($field); |
||||
$message_type = $field->getMessageType(); |
||||
$key_field = $message_type->getFieldByNumber(1); |
||||
$value_field = $message_type->getFieldByNumber(2); |
||||
foreach ($values as $key => $value) { |
||||
$data_size = 0; |
||||
$data_size += $this->fieldDataOnlyByteSize($key_field, $key); |
||||
$data_size += $this->fieldDataOnlyByteSize( |
||||
$value_field, |
||||
$value); |
||||
$data_size += GPBWire::tagSize($key_field); |
||||
$data_size += GPBWire::tagSize($value_field); |
||||
$size += GPBWire::varint32Size($data_size) + $data_size; |
||||
} |
||||
} |
||||
} elseif ($field->isRepeated()) { |
||||
$getter = $field->getGetter(); |
||||
$values = $this->$getter(); |
||||
$count = count($values); |
||||
if ($count !== 0) { |
||||
if ($field->getPacked()) { |
||||
$data_size = 0; |
||||
foreach ($values as $value) { |
||||
$data_size += $this->fieldDataOnlyByteSize($field, $value); |
||||
} |
||||
$size += GPBWire::tagSize($field); |
||||
$size += GPBWire::varint32Size($data_size); |
||||
$size += $data_size; |
||||
} else { |
||||
$size += $count * GPBWire::tagSize($field); |
||||
foreach ($values as $value) { |
||||
$size += $this->fieldDataOnlyByteSize($field, $value); |
||||
} |
||||
} |
||||
} |
||||
} elseif ($this->existField($field)) { |
||||
$size += GPBWire::tagSize($field); |
||||
$getter = $field->getGetter(); |
||||
$value = $this->$getter(); |
||||
$size += $this->fieldDataOnlyByteSize($field, $value); |
||||
} |
||||
return $size; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function byteSize() |
||||
{ |
||||
$size = 0; |
||||
|
||||
$fields = $this->desc->getField(); |
||||
foreach ($fields as $field) { |
||||
$size += $this->fieldByteSize($field); |
||||
} |
||||
return $size; |
||||
} |
||||
} |
@ -0,0 +1,120 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\GPBLabel; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\Descriptor; |
||||
use Google\Protobuf\Internal\FieldDescriptor; |
||||
|
||||
class MessageBuilderContext |
||||
{ |
||||
|
||||
private $descriptor; |
||||
private $pool; |
||||
|
||||
public function __construct($full_name, $klass, $pool) |
||||
{ |
||||
$this->descriptor = new Descriptor(); |
||||
$this->descriptor->setFullName($full_name); |
||||
$this->descriptor->setClass($klass); |
||||
$this->pool = $pool; |
||||
} |
||||
|
||||
private function getFieldDescriptor($name, $label, $type, |
||||
$number, $type_name = null) |
||||
{ |
||||
$field = new FieldDescriptor(); |
||||
$field->setName($name); |
||||
$camel_name = implode('', array_map('ucwords', explode('_', $name))); |
||||
$field->setGetter('get' . $camel_name); |
||||
$field->setSetter('set' . $camel_name); |
||||
$field->setType($type); |
||||
$field->setNumber($number); |
||||
$field->setLabel($label); |
||||
|
||||
// At this time, the message/enum type may have not been added to pool. |
||||
// So we use the type name as place holder and will replace it with the |
||||
// actual descriptor in cross building. |
||||
switch ($type) { |
||||
case GPBType::MESSAGE: |
||||
$field->setMessageType($type_name); |
||||
break; |
||||
case GPBType::ENUM: |
||||
$field->setEnumType($type_name); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return $field; |
||||
} |
||||
|
||||
public function optional($name, $type, $number, $type_name = null) |
||||
{ |
||||
$this->descriptor->addField($this->getFieldDescriptor( |
||||
$name, |
||||
GPBLabel::OPTIONAL, |
||||
$type, |
||||
$number, |
||||
$type_name)); |
||||
return $this; |
||||
} |
||||
|
||||
public function repeated($name, $type, $number, $type_name = null) |
||||
{ |
||||
$this->descriptor->addField($this->getFieldDescriptor( |
||||
$name, |
||||
GPBLabel::REPEATED, |
||||
$type, |
||||
$number, |
||||
$type_name)); |
||||
return $this; |
||||
} |
||||
|
||||
public function required($name, $type, $number, $type_name = null) |
||||
{ |
||||
$this->descriptor->addField($this->getFieldDescriptor( |
||||
$name, |
||||
GPBLabel::REQUIRED, |
||||
$type, |
||||
$number, |
||||
$type_name)); |
||||
return $this; |
||||
} |
||||
|
||||
public function finalizeToPool() |
||||
{ |
||||
$this->pool->addDescriptor($this->descriptor); |
||||
} |
||||
} |
@ -0,0 +1,77 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
class OneofField |
||||
{ |
||||
|
||||
private $desc; |
||||
private $field_name; |
||||
private $number = 0; |
||||
private $value; |
||||
|
||||
public function __construct($desc) |
||||
{ |
||||
$this->desc = $desc; |
||||
} |
||||
|
||||
public function setValue($value) |
||||
{ |
||||
$this->value = $value; |
||||
} |
||||
|
||||
public function getValue() |
||||
{ |
||||
return $this->value; |
||||
} |
||||
|
||||
public function setFieldName($field_name) |
||||
{ |
||||
$this->field_name = $field_name; |
||||
} |
||||
|
||||
public function getFieldName() |
||||
{ |
||||
return $this->field_name; |
||||
} |
||||
|
||||
public function setNumber($number) |
||||
{ |
||||
$this->number = $number; |
||||
} |
||||
|
||||
public function getNumber() |
||||
{ |
||||
return $this->number; |
||||
} |
||||
} |
@ -0,0 +1,143 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
class OutputStream |
||||
{ |
||||
|
||||
private $buffer; |
||||
private $buffer_size; |
||||
private $current; |
||||
|
||||
const MAX_VARINT32_BYTES = 5; |
||||
const MAX_VARINT64_BYTES = 10; |
||||
|
||||
public function __construct($size) |
||||
{ |
||||
$this->current = 0; |
||||
$this->buffer_size = $size; |
||||
$this->buffer = str_repeat(chr(0), $this->buffer_size); |
||||
} |
||||
|
||||
public function getData() |
||||
{ |
||||
return $this->buffer; |
||||
} |
||||
|
||||
public function writeVarint32($value) |
||||
{ |
||||
$bytes = str_repeat(chr(0), self::MAX_VARINT32_BYTES); |
||||
$size = self::writeVarintToArray($value, $bytes, true); |
||||
return $this->writeRaw($bytes, $size); |
||||
} |
||||
|
||||
public function writeVarint64($value) |
||||
{ |
||||
$bytes = str_repeat(chr(0), self::MAX_VARINT64_BYTES); |
||||
$size = self::writeVarintToArray($value, $bytes); |
||||
return $this->writeRaw($bytes, $size); |
||||
} |
||||
|
||||
public function writeLittleEndian32($value) |
||||
{ |
||||
$bytes = str_repeat(chr(0), 4); |
||||
$size = self::writeLittleEndian32ToArray($value, $bytes); |
||||
return $this->writeRaw($bytes, $size); |
||||
} |
||||
|
||||
public function writeLittleEndian64($value) |
||||
{ |
||||
$bytes = str_repeat(chr(0), 8); |
||||
$size = self::writeLittleEndian64ToArray($value, $bytes); |
||||
return $this->writeRaw($bytes, $size); |
||||
} |
||||
|
||||
public function writeTag($tag) |
||||
{ |
||||
return $this->writeVarint32($tag); |
||||
} |
||||
|
||||
public function writeRaw($data, $size) |
||||
{ |
||||
if ($this->buffer_size < $size) { |
||||
var_dump($this->buffer_size); |
||||
var_dump($size); |
||||
trigger_error("Output stream doesn't have enough buffer."); |
||||
return false; |
||||
} |
||||
|
||||
for ($i = 0; $i < $size; $i++) { |
||||
$this->buffer[$this->current] = $data[$i]; |
||||
$this->current++; |
||||
$this->buffer_size--; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private static function writeVarintToArray($value, &$buffer, $trim = false) |
||||
{ |
||||
$current = 0; |
||||
if ($trim) { |
||||
$value &= 0xFFFFFFFF; |
||||
} |
||||
while ($value >= 0x80 || $value < 0) { |
||||
$buffer[$current] = chr($value | 0x80); |
||||
$value = ($value >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7)); |
||||
$current++; |
||||
} |
||||
$buffer[$current] = chr($value); |
||||
return $current + 1; |
||||
} |
||||
|
||||
private static function writeLittleEndian32ToArray($value, &$buffer) |
||||
{ |
||||
$buffer[0] = chr($value & 0x000000FF); |
||||
$buffer[1] = chr(($value >> 8) & 0x000000FF); |
||||
$buffer[2] = chr(($value >> 16) & 0x000000FF); |
||||
$buffer[3] = chr(($value >> 24) & 0x000000FF); |
||||
return 4; |
||||
} |
||||
|
||||
private static function writeLittleEndian64ToArray($value, &$buffer) |
||||
{ |
||||
$buffer[0] = chr($value & 0x000000FF); |
||||
$buffer[1] = chr(($value >> 8) & 0x000000FF); |
||||
$buffer[2] = chr(($value >> 16) & 0x000000FF); |
||||
$buffer[3] = chr(($value >> 24) & 0x000000FF); |
||||
$buffer[4] = chr(($value >> 32) & 0x000000FF); |
||||
$buffer[5] = chr(($value >> 40) & 0x000000FF); |
||||
$buffer[6] = chr(($value >> 48) & 0x000000FF); |
||||
$buffer[7] = chr(($value >> 56) & 0x000000FF); |
||||
return 8; |
||||
} |
||||
} |
@ -0,0 +1,303 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
/** |
||||
* RepeatedField and RepeatedFieldIter are used by generated protocol message |
||||
* classes to manipulate repeated fields. |
||||
*/ |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\GPBUtil; |
||||
|
||||
/** |
||||
* RepeatedFieldIter is used to iterate RepeatedField. It is also need for the |
||||
* foreach syntax. |
||||
*/ |
||||
class RepeatedFieldIter implements \Iterator |
||||
{ |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $position; |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $container; |
||||
|
||||
/** |
||||
* Create iterator instance for RepeatedField. |
||||
* |
||||
* @param RepeatedField The RepeatedField instance for which this iterator |
||||
* is created. |
||||
* @ignore |
||||
*/ |
||||
public function __construct($container) |
||||
{ |
||||
$this->position = 0; |
||||
$this->container = $container; |
||||
} |
||||
|
||||
/** |
||||
* Reset the status of the iterator |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function rewind() |
||||
{ |
||||
$this->position = 0; |
||||
} |
||||
|
||||
/** |
||||
* Return the element at the current position. |
||||
* |
||||
* @return object The element at the current position. |
||||
*/ |
||||
public function current() |
||||
{ |
||||
return $this->container[$this->position]; |
||||
} |
||||
|
||||
/** |
||||
* Return the current position. |
||||
* |
||||
* @return integer The current position. |
||||
*/ |
||||
public function key() |
||||
{ |
||||
return $this->position; |
||||
} |
||||
|
||||
/** |
||||
* Move to the next position. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function next() |
||||
{ |
||||
++$this->position; |
||||
} |
||||
|
||||
/** |
||||
* Check whether there are more elements to iterate. |
||||
* |
||||
* @return bool True if there are more elements to iterate. |
||||
*/ |
||||
public function valid() |
||||
{ |
||||
return isset($this->container[$this->position]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* RepeatedField is used by generated protocol message classes to manipulate |
||||
* repeated fields. It can be used like native PHP array. |
||||
*/ |
||||
class RepeatedField implements \ArrayAccess, \IteratorAggregate, \Countable |
||||
{ |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $container; |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $type; |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
private $klass; |
||||
|
||||
/** |
||||
* Constructs an instance of RepeatedField. |
||||
* |
||||
* @param long $type Type of the stored element. |
||||
* @param string $klass Message/Enum class name (message/enum fields only). |
||||
* @ignore |
||||
*/ |
||||
public function __construct($type, $klass = null) |
||||
{ |
||||
$this->container = []; |
||||
$this->type = $type; |
||||
$this->klass = $klass; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function getType() |
||||
{ |
||||
return $this->type; |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function getClass() |
||||
{ |
||||
return $this->klass; |
||||
} |
||||
|
||||
/** |
||||
* Return the element at the given index. |
||||
* |
||||
* This will also be called for: $ele = $arr[0] |
||||
* |
||||
* @param long $offset The index of the element to be fetched. |
||||
* @return object The stored element at given index. |
||||
* @throws ErrorException Invalid type for index. |
||||
* @throws ErrorException Non-existing index. |
||||
*/ |
||||
public function offsetGet($offset) |
||||
{ |
||||
return $this->container[$offset]; |
||||
} |
||||
|
||||
/** |
||||
* Assign the element at the given index. |
||||
* |
||||
* This will also be called for: $arr []= $ele and $arr[0] = ele |
||||
* |
||||
* @param long $offset The index of the element to be assigned. |
||||
* @param object $value The element to be assigned. |
||||
* @return void |
||||
* @throws ErrorException Invalid type for index. |
||||
* @throws ErrorException Non-existing index. |
||||
* @throws ErrorException Incorrect type of the element. |
||||
*/ |
||||
public function offsetSet($offset, $value) |
||||
{ |
||||
switch ($this->type) { |
||||
case GPBType::INT32: |
||||
GPBUtil::checkInt32($value); |
||||
break; |
||||
case GPBType::UINT32: |
||||
GPBUtil::checkUint32($value); |
||||
break; |
||||
case GPBType::INT64: |
||||
GPBUtil::checkInt64($value); |
||||
break; |
||||
case GPBType::UINT64: |
||||
GPBUtil::checkUint64($value); |
||||
break; |
||||
case GPBType::FLOAT: |
||||
GPBUtil::checkFloat($value); |
||||
break; |
||||
case GPBType::DOUBLE: |
||||
GPBUtil::checkDouble($value); |
||||
break; |
||||
case GPBType::BOOL: |
||||
GPBUtil::checkBool($value); |
||||
break; |
||||
case GPBType::STRING: |
||||
GPBUtil::checkString($value, true); |
||||
break; |
||||
case GPBType::MESSAGE: |
||||
GPBUtil::checkMessage($value, $this->klass); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
if (is_null($offset)) { |
||||
$this->container[] = $value; |
||||
} else { |
||||
$count = count($this->container); |
||||
if (!is_numeric($offset) || $offset < 0 || $offset >= $count) { |
||||
trigger_error( |
||||
"Cannot modify element at the given index", |
||||
E_USER_ERROR); |
||||
return; |
||||
} |
||||
$this->container[$offset] = $value; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove the element at the given index. |
||||
* |
||||
* This will also be called for: unset($arr) |
||||
* |
||||
* @param long $offset The index of the element to be removed. |
||||
* @return void |
||||
* @throws ErrorException Invalid type for index. |
||||
* @throws ErrorException The element to be removed is not at the end of the |
||||
* RepeatedField. |
||||
*/ |
||||
public function offsetUnset($offset) |
||||
{ |
||||
$count = count($this->container); |
||||
if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) { |
||||
trigger_error( |
||||
"Cannot remove element at the given index", |
||||
E_USER_ERROR); |
||||
return; |
||||
} |
||||
array_pop($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Check the existence of the element at the given index. |
||||
* |
||||
* This will also be called for: isset($arr) |
||||
* |
||||
* @param long $offset The index of the element to be removed. |
||||
* @return bool True if the element at the given offset exists. |
||||
* @throws ErrorException Invalid type for index. |
||||
*/ |
||||
public function offsetExists($offset) |
||||
{ |
||||
return isset($this->container[$offset]); |
||||
} |
||||
|
||||
/** |
||||
* @ignore |
||||
*/ |
||||
public function getIterator() |
||||
{ |
||||
return new RepeatedFieldIter($this->container); |
||||
} |
||||
|
||||
/** |
||||
* Return the number of stored elements. |
||||
* |
||||
* This will also be called for: count($arr) |
||||
* |
||||
* @return integer The number of stored elements. |
||||
*/ |
||||
public function count() |
||||
{ |
||||
return count($this->container); |
||||
} |
||||
} |
@ -0,0 +1,175 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
class GPBInteger |
||||
{ |
||||
public $high = 0; |
||||
public $low = 0; |
||||
|
||||
public function __construct($value = 0) |
||||
{ |
||||
$this->low = $value & 0xFFFFFFFF; |
||||
if (PHP_INT_SIZE === 8) { |
||||
$this->high = ($value >> 32) & 0xFFFFFFFF; |
||||
} |
||||
} |
||||
|
||||
// Return 0 for unsigned integers and 1 for signed integers. |
||||
protected function sign() |
||||
{ |
||||
trigger_error("Not implemented", E_ERROR); |
||||
} |
||||
|
||||
public function leftShift($count) |
||||
{ |
||||
if ($count > 63) { |
||||
$this->low = 0; |
||||
$this->high = 0; |
||||
return; |
||||
} |
||||
if ($count > 32) { |
||||
$this->high = $this->low; |
||||
$this->low = 0; |
||||
$count -= 32; |
||||
} |
||||
$mask = (1 << $count) - 1; |
||||
$this->high = (($this->high << $count) & 0xFFFFFFFF) | |
||||
(($this->low >> (32 - $count)) & $mask); |
||||
$this->low = ($this->low << $count) & 0xFFFFFFFF; |
||||
|
||||
$this->high &= 0xFFFFFFFF; |
||||
$this->low &= 0xFFFFFFFF; |
||||
return $this; |
||||
} |
||||
|
||||
public function rightShift($count) |
||||
{ |
||||
$sign = (($this->high & 0x80000000) >> 31) & $this->sign(); |
||||
if ($count > 63) { |
||||
$this->low = -$sign; |
||||
$this->high = -$sign; |
||||
return; |
||||
} |
||||
if ($count > 32) { |
||||
$this->low = $this->high; |
||||
$this->high = -$sign; |
||||
$count -= 32; |
||||
} |
||||
$this->low = (($this->low >> $count) & 0xFFFFFFFF) | |
||||
(($this->high << (32 - $count)) & 0xFFFFFFFF); |
||||
$this->high = (($this->high >> $count) | (-$sign << $count)); |
||||
|
||||
$this->high &= 0xFFFFFFFF; |
||||
$this->low &= 0xFFFFFFFF; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
public function bitOr($var) |
||||
{ |
||||
$this->high |= $var->high; |
||||
$this->low |= $var->low; |
||||
return $this; |
||||
} |
||||
|
||||
public function bitXor($var) |
||||
{ |
||||
$this->high ^= $var->high; |
||||
$this->low ^= $var->low; |
||||
return $this; |
||||
} |
||||
|
||||
public function bitAnd($var) |
||||
{ |
||||
$this->high &= $var->high; |
||||
$this->low &= $var->low; |
||||
return $this; |
||||
} |
||||
|
||||
// Even: all zero; Odd: all one. |
||||
public function oddMask() |
||||
{ |
||||
$low = (-($this->low & 1)) & 0xFFFFFFFF; |
||||
$high = $low; |
||||
return UInt64::newValue($high, $low); |
||||
} |
||||
|
||||
public function toInteger() |
||||
{ |
||||
if (PHP_INT_SIZE === 8) { |
||||
return ($this->high << 32) | $this->low; |
||||
} else { |
||||
return $this->low; |
||||
} |
||||
} |
||||
|
||||
public function copy() |
||||
{ |
||||
return static::newValue($this->high, $this->low); |
||||
} |
||||
} |
||||
|
||||
class Uint64 extends GPBInteger |
||||
{ |
||||
|
||||
public static function newValue($high, $low) |
||||
{ |
||||
$uint64 = new Uint64(0); |
||||
$uint64->high = $high; |
||||
$uint64->low = $low; |
||||
return $uint64; |
||||
} |
||||
|
||||
protected function sign() |
||||
{ |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
class Int64 extends GPBInteger |
||||
{ |
||||
|
||||
public static function newValue($high, $low) |
||||
{ |
||||
$int64 = new Int64(0); |
||||
$int64->high = $high; |
||||
$int64->low = $low; |
||||
return $int64; |
||||
} |
||||
|
||||
protected function sign() |
||||
{ |
||||
return 1; |
||||
} |
||||
} |
@ -0,0 +1,541 @@ |
||||
<?php |
||||
|
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
namespace Google\Protobuf\Internal; |
||||
|
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\MessageOptions; |
||||
|
||||
class FileDescriptor |
||||
{ |
||||
|
||||
private $package; |
||||
private $message_type = []; |
||||
private $enum_type = []; |
||||
|
||||
public function setPackage($package) |
||||
{ |
||||
$this->package = $package; |
||||
} |
||||
|
||||
public function getPackage() |
||||
{ |
||||
return $this->package; |
||||
} |
||||
|
||||
public function getMessageType() |
||||
{ |
||||
return $this->message_type; |
||||
} |
||||
|
||||
public function addMessageType($desc) |
||||
{ |
||||
$this->message_type[] = $desc; |
||||
} |
||||
|
||||
public function getEnumType() |
||||
{ |
||||
return $this->enum_type; |
||||
} |
||||
|
||||
public function addEnumType($desc) |
||||
{ |
||||
$this->enum_type[]= $desc; |
||||
} |
||||
|
||||
public static function buildFromProto($proto) |
||||
{ |
||||
$file = new FileDescriptor(); |
||||
$file->setPackage($proto->getPackage()); |
||||
foreach ($proto->getMessageType() as $message_proto) { |
||||
$file->addMessageType(Descriptor::buildFromProto( |
||||
$message_proto, $file->getPackage(), "")); |
||||
} |
||||
foreach ($proto->getEnumType() as $enum_proto) { |
||||
$file->getEnumType()[] = |
||||
$file->addEnumType( |
||||
EnumDescriptor::buildFromProto( |
||||
$enum_proto, |
||||
$file->getPackage(), |
||||
"")); |
||||
} |
||||
return $file; |
||||
} |
||||
} |
||||
|
||||
class Descriptor |
||||
{ |
||||
|
||||
private $full_name; |
||||
private $field = []; |
||||
private $nested_type = []; |
||||
private $enum_type = []; |
||||
private $klass; |
||||
private $options; |
||||
private $oneof_decl = []; |
||||
|
||||
public function addOneofDecl($oneof) |
||||
{ |
||||
$this->oneof_decl[] = $oneof; |
||||
} |
||||
|
||||
public function getOneofDecl() |
||||
{ |
||||
return $this->oneof_decl; |
||||
} |
||||
|
||||
public function setFullName($full_name) |
||||
{ |
||||
$this->full_name = $full_name; |
||||
} |
||||
|
||||
public function getFullName() |
||||
{ |
||||
return $this->full_name; |
||||
} |
||||
|
||||
public function addField($field) |
||||
{ |
||||
$this->field[$field->getNumber()] = $field; |
||||
} |
||||
|
||||
public function getField() |
||||
{ |
||||
return $this->field; |
||||
} |
||||
|
||||
public function addNestedType($desc) |
||||
{ |
||||
$this->nested_type[] = $desc; |
||||
} |
||||
|
||||
public function getNestedType() |
||||
{ |
||||
return $this->nested_type; |
||||
} |
||||
|
||||
public function addEnumType($desc) |
||||
{ |
||||
$this->enum_type[] = $desc; |
||||
} |
||||
|
||||
public function getEnumType() |
||||
{ |
||||
return $this->enum_type; |
||||
} |
||||
|
||||
public function getFieldByNumber($number) |
||||
{ |
||||
return $this->field[$number]; |
||||
} |
||||
|
||||
public function setClass($klass) |
||||
{ |
||||
$this->klass = $klass; |
||||
} |
||||
|
||||
public function getClass() |
||||
{ |
||||
return $this->klass; |
||||
} |
||||
|
||||
public function setOptions($options) |
||||
{ |
||||
$this->options = $options; |
||||
} |
||||
|
||||
public function getOptions() |
||||
{ |
||||
return $this->options; |
||||
} |
||||
|
||||
public static function buildFromProto($proto, $package, $containing) |
||||
{ |
||||
$desc = new Descriptor(); |
||||
|
||||
$message_name_without_package = ""; |
||||
$classname = ""; |
||||
$fullname = ""; |
||||
getFullClassName( |
||||
$proto, |
||||
$containing, |
||||
$package, |
||||
$message_name_without_package, |
||||
$classname, |
||||
$fullname); |
||||
$desc->setFullName($fullname); |
||||
$desc->setClass($classname); |
||||
$desc->setOptions($proto->getOptions()); |
||||
|
||||
foreach ($proto->getField() as $field_proto) { |
||||
$desc->addField(FieldDescriptor::buildFromProto($field_proto)); |
||||
} |
||||
|
||||
// Handle nested types. |
||||
foreach ($proto->getNestedType() as $nested_proto) { |
||||
$desc->addNestedType(Descriptor::buildFromProto( |
||||
$nested_proto, $package, $message_name_without_package)); |
||||
} |
||||
|
||||
// Handle oneof fields. |
||||
foreach ($proto->getOneofDecl() as $oneof_proto) { |
||||
$desc->addOneofDecl( |
||||
OneofDescriptor::buildFromProto($oneof_proto, $desc)); |
||||
} |
||||
|
||||
return $desc; |
||||
} |
||||
} |
||||
function getFullClassName( |
||||
$proto, |
||||
$containing, |
||||
$package, |
||||
&$message_name_without_package, |
||||
&$classname, |
||||
&$fullname) |
||||
{ |
||||
// Full name needs to start with '.'. |
||||
$message_name_without_package = $proto->getName(); |
||||
if ($containing !== "") { |
||||
$message_name_without_package = |
||||
$containing . "." . $message_name_without_package; |
||||
} |
||||
if ($package === "") { |
||||
$fullname = "." . $message_name_without_package; |
||||
} else { |
||||
$fullname = "." . $package . "." . $message_name_without_package; |
||||
} |
||||
|
||||
// Nested message class names are seperated by '_', and package names are |
||||
// seperated by '\'. |
||||
$class_name_without_package = |
||||
implode('_', array_map('ucwords', |
||||
explode('.', $message_name_without_package))); |
||||
$classname = |
||||
implode('\\', array_map('ucwords', explode('.', $package))). |
||||
"\\".$class_name_without_package; |
||||
} |
||||
|
||||
class OneofDescriptor |
||||
{ |
||||
|
||||
private $name; |
||||
private $fields; |
||||
|
||||
public function setName($name) |
||||
{ |
||||
$this->name = $name; |
||||
} |
||||
|
||||
public function getName() |
||||
{ |
||||
return $this->name; |
||||
} |
||||
|
||||
public function addField(&$field) |
||||
{ |
||||
$this->fields[] = $field; |
||||
} |
||||
|
||||
public function getFields() |
||||
{ |
||||
return $this->fields; |
||||
} |
||||
|
||||
public static function buildFromProto($oneof_proto) |
||||
{ |
||||
$oneof = new OneofDescriptor(); |
||||
$oneof->setName($oneof_proto->getName()); |
||||
return $oneof; |
||||
} |
||||
} |
||||
|
||||
|
||||
class EnumDescriptor |
||||
{ |
||||
|
||||
private $klass; |
||||
private $full_name; |
||||
private $value; |
||||
|
||||
public function setFullName($full_name) |
||||
{ |
||||
$this->full_name = $full_name; |
||||
} |
||||
|
||||
public function getFullName() |
||||
{ |
||||
return $this->full_name; |
||||
} |
||||
|
||||
public function addValue($number, $value) |
||||
{ |
||||
$this->value[$number] = $value; |
||||
} |
||||
|
||||
public function setClass($klass) |
||||
{ |
||||
$this->klass = $klass; |
||||
} |
||||
|
||||
public function getClass() |
||||
{ |
||||
return $this->klass; |
||||
} |
||||
|
||||
public static function buildFromProto($proto, $package, $containing) |
||||
{ |
||||
$desc = new EnumDescriptor(); |
||||
|
||||
$enum_name_without_package = ""; |
||||
$classname = ""; |
||||
$fullname = ""; |
||||
getFullClassName( |
||||
$proto, |
||||
$containing, |
||||
$package, |
||||
$enum_name_without_package, |
||||
$classname, |
||||
$fullname); |
||||
$desc->setFullName($fullname); |
||||
$desc->setClass($classname); |
||||
|
||||
return $desc; |
||||
} |
||||
} |
||||
|
||||
class EnumValueDescriptor |
||||
{ |
||||
} |
||||
|
||||
class FieldDescriptor |
||||
{ |
||||
|
||||
private $name; |
||||
private $setter; |
||||
private $getter; |
||||
private $number; |
||||
private $label; |
||||
private $type; |
||||
private $message_type; |
||||
private $enum_type; |
||||
private $packed; |
||||
private $is_map; |
||||
private $oneof_index = -1; |
||||
|
||||
public function setOneofIndex($index) |
||||
{ |
||||
$this->oneof_index = $index; |
||||
} |
||||
|
||||
public function getOneofIndex() |
||||
{ |
||||
return $this->oneof_index; |
||||
} |
||||
|
||||
public function setName($name) |
||||
{ |
||||
$this->name = $name; |
||||
} |
||||
|
||||
public function getName() |
||||
{ |
||||
return $this->name; |
||||
} |
||||
|
||||
public function setSetter($setter) |
||||
{ |
||||
$this->setter = $setter; |
||||
} |
||||
|
||||
public function getSetter() |
||||
{ |
||||
return $this->setter; |
||||
} |
||||
|
||||
public function setGetter($getter) |
||||
{ |
||||
$this->getter = $getter; |
||||
} |
||||
|
||||
public function getGetter() |
||||
{ |
||||
return $this->getter; |
||||
} |
||||
|
||||
public function setNumber($number) |
||||
{ |
||||
$this->number = $number; |
||||
} |
||||
|
||||
public function getNumber() |
||||
{ |
||||
return $this->number; |
||||
} |
||||
|
||||
public function setLabel($label) |
||||
{ |
||||
$this->label = $label; |
||||
} |
||||
|
||||
public function getLabel() |
||||
{ |
||||
return $this->label; |
||||
} |
||||
|
||||
public function isRepeated() |
||||
{ |
||||
return $this->label === GPBLabel::REPEATED; |
||||
} |
||||
|
||||
public function setType($type) |
||||
{ |
||||
$this->type = $type; |
||||
} |
||||
|
||||
public function getType() |
||||
{ |
||||
return $this->type; |
||||
} |
||||
|
||||
public function setMessageType($message_type) |
||||
{ |
||||
$this->message_type = $message_type; |
||||
} |
||||
|
||||
public function getMessageType() |
||||
{ |
||||
return $this->message_type; |
||||
} |
||||
|
||||
public function setEnumType($enum_type) |
||||
{ |
||||
$this->enum_type = $enum_type; |
||||
} |
||||
|
||||
public function getEnumType() |
||||
{ |
||||
return $this->enum_type; |
||||
} |
||||
|
||||
public function setPacked($packed) |
||||
{ |
||||
$this->packed = $packed; |
||||
} |
||||
|
||||
public function getPacked() |
||||
{ |
||||
return $this->packed; |
||||
} |
||||
|
||||
public function isPackable() |
||||
{ |
||||
return $this->isRepeated() && self::isTypePackable($this->type); |
||||
} |
||||
|
||||
public function isMap() |
||||
{ |
||||
return $this->getType() == GPBType::MESSAGE && |
||||
!is_null($this->getMessageType()->getOptions()) && |
||||
$this->getMessageType()->getOptions()->getMapEntry(); |
||||
} |
||||
|
||||
private static function isTypePackable($field_type) |
||||
{ |
||||
return ($field_type !== GPBType::STRING && |
||||
$field_type !== GPBType::GROUP && |
||||
$field_type !== GPBType::MESSAGE && |
||||
$field_type !== GPBType::BYTES); |
||||
} |
||||
|
||||
public static function getFieldDescriptor( |
||||
$name, |
||||
$label, |
||||
$type, |
||||
$number, |
||||
$oneof_index, |
||||
$packed, |
||||
$type_name = null) |
||||
{ |
||||
$field = new FieldDescriptor(); |
||||
$field->setName($name); |
||||
$camel_name = implode('', array_map('ucwords', explode('_', $name))); |
||||
$field->setGetter('get' . $camel_name); |
||||
$field->setSetter('set' . $camel_name); |
||||
$field->setType($type); |
||||
$field->setNumber($number); |
||||
$field->setLabel($label); |
||||
$field->setPacked($packed); |
||||
$field->setOneofIndex($oneof_index); |
||||
|
||||
// At this time, the message/enum type may have not been added to pool. |
||||
// So we use the type name as place holder and will replace it with the |
||||
// actual descriptor in cross building. |
||||
switch ($type) { |
||||
case GPBType::MESSAGE: |
||||
$field->setMessageType($type_name); |
||||
break; |
||||
case GPBType::ENUM: |
||||
$field->setEnumType($type_name); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
return $field; |
||||
} |
||||
|
||||
public static function buildFromProto($proto) |
||||
{ |
||||
$type_name = null; |
||||
switch ($proto->getType()) { |
||||
case GPBType::MESSAGE: |
||||
case GPBType::GROUP: |
||||
case GPBType::ENUM: |
||||
$type_name = $proto->getTypeName(); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
$oneof_index = $proto->hasOneofIndex() ? $proto->getOneofIndex() : -1; |
||||
$packed = false; |
||||
$options = $proto->getOptions(); |
||||
if ($options !== null) { |
||||
$packed = $options->getPacked(); |
||||
} |
||||
|
||||
return FieldDescriptor::getFieldDescriptor( |
||||
$proto->getName(), $proto->getLabel(), $proto->getType(), |
||||
$proto->getNumber(), $oneof_index, $packed, $type_name); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="UTF-8" ?> |
||||
<!-- Install phpDocumentor to generate docs. --> |
||||
<phpdoc> |
||||
<parser> |
||||
<target>doc</target> |
||||
</parser> |
||||
<transformer> |
||||
<target>doc</target> |
||||
</transformer> |
||||
<files> |
||||
<file>Google/Protobuf/Internal/MapField.php</file> |
||||
<file>Google/Protobuf/Internal/Message.php</file> |
||||
<file>Google/Protobuf/Internal/RepeatedField.php</file> |
||||
</files> |
||||
</phpdoc> |
@ -0,0 +1,888 @@ |
||||
<?php |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_util.php'); |
||||
|
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
|
||||
class RepeatedFieldTest extends PHPUnit_Framework_TestCase |
||||
{ |
||||
|
||||
######################################################### |
||||
# Test int32 field. |
||||
######################################################### |
||||
|
||||
public function testInt32() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
|
||||
// Test append. |
||||
$arr []= MAX_INT32; |
||||
$this->assertSame(MAX_INT32, $arr[0]); |
||||
$arr []= MIN_INT32; |
||||
$this->assertSame(MIN_INT32, $arr[1]); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertSame(1, $arr[2]); |
||||
$arr []= MAX_INT32_FLOAT; |
||||
$this->assertSame(MAX_INT32, $arr[3]); |
||||
$arr []= MAX_INT32_FLOAT; |
||||
$this->assertSame(MAX_INT32, $arr[4]); |
||||
|
||||
$arr []= '2'; |
||||
$this->assertSame(2, $arr[5]); |
||||
$arr []= '3.1'; |
||||
$this->assertSame(3, $arr[6]); |
||||
$arr []= MAX_INT32_STRING; |
||||
$this->assertSame(MAX_INT32, $arr[7]); |
||||
|
||||
$this->assertEquals(8, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(0, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= MAX_INT32; |
||||
$this->assertSame(MAX_INT32, $arr[0]); |
||||
$arr [1]= MIN_INT32; |
||||
$this->assertSame(MIN_INT32, $arr[1]); |
||||
|
||||
$arr [2]= 1.1; |
||||
$this->assertSame(1, $arr[2]); |
||||
$arr [3]= MAX_INT32_FLOAT; |
||||
$this->assertSame(MAX_INT32, $arr[3]); |
||||
$arr [4]= MAX_INT32_FLOAT; |
||||
$this->assertSame(MAX_INT32, $arr[4]); |
||||
|
||||
$arr [5]= '2'; |
||||
$this->assertSame(2, $arr[5]); |
||||
$arr [6]= '3.1'; |
||||
$this->assertSame(3, $arr[6]); |
||||
$arr [7]= MAX_INT32_STRING; |
||||
$this->assertSame(MAX_INT32, $arr[7]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32AppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32SetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= 0; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32AppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32SetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= 0; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test uint32 field. |
||||
######################################################### |
||||
|
||||
public function testUint32() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT32); |
||||
|
||||
// Test append. |
||||
$arr []= MAX_UINT32; |
||||
$this->assertSame(-1, $arr[0]); |
||||
$arr []= -1; |
||||
$this->assertSame(-1, $arr[1]); |
||||
$arr []= MIN_UINT32; |
||||
$this->assertSame(MIN_UINT32, $arr[2]); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertSame(1, $arr[3]); |
||||
$arr []= MAX_UINT32_FLOAT; |
||||
$this->assertSame(-1, $arr[4]); |
||||
$arr []= -1.0; |
||||
$this->assertSame(-1, $arr[5]); |
||||
$arr []= MIN_UINT32_FLOAT; |
||||
$this->assertSame(MIN_UINT32, $arr[6]); |
||||
|
||||
$arr []= '2'; |
||||
$this->assertSame(2, $arr[7]); |
||||
$arr []= '3.1'; |
||||
$this->assertSame(3, $arr[8]); |
||||
$arr []= MAX_UINT32_STRING; |
||||
$this->assertSame(-1, $arr[9]); |
||||
$arr []= '-1.0'; |
||||
$this->assertSame(-1, $arr[10]); |
||||
$arr []= MIN_UINT32_STRING; |
||||
$this->assertSame(MIN_UINT32, $arr[11]); |
||||
|
||||
$this->assertEquals(12, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(0, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= MAX_UINT32; |
||||
$this->assertSame(-1, $arr[0]); |
||||
$arr [1]= -1; |
||||
$this->assertSame(-1, $arr[1]); |
||||
$arr [2]= MIN_UINT32; |
||||
$this->assertSame(MIN_UINT32, $arr[2]); |
||||
|
||||
$arr [3]= 1.1; |
||||
$this->assertSame(1, $arr[3]); |
||||
$arr [4]= MAX_UINT32_FLOAT; |
||||
$this->assertSame(-1, $arr[4]); |
||||
$arr [5]= -1.0; |
||||
$this->assertSame(-1, $arr[5]); |
||||
$arr [6]= MIN_UINT32_FLOAT; |
||||
$this->assertSame(MIN_UINT32, $arr[6]); |
||||
|
||||
$arr [7]= '2'; |
||||
$this->assertSame(2, $arr[7]); |
||||
$arr [8]= '3.1'; |
||||
$this->assertSame(3, $arr[8]); |
||||
$arr [9]= MAX_UINT32_STRING; |
||||
$this->assertSame(-1, $arr[9]); |
||||
$arr [10]= '-1.0'; |
||||
$this->assertSame(-1, $arr[10]); |
||||
$arr [11]= MIN_UINT32_STRING; |
||||
$this->assertSame(MIN_UINT32, $arr[11]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32AppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT32); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32SetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT32); |
||||
$arr []= 0; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32AppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT32); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32SetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT32); |
||||
$arr []= 0; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test int64 field. |
||||
######################################################### |
||||
|
||||
public function testInt64() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT64); |
||||
|
||||
// Test append. |
||||
$arr []= MAX_INT64; |
||||
$this->assertSame(MAX_INT64, $arr[0]); |
||||
$arr []= MIN_INT64; |
||||
$this->assertEquals(MIN_INT64, $arr[1]); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertSame(1, $arr[2]); |
||||
|
||||
$arr []= '2'; |
||||
$this->assertSame(2, $arr[3]); |
||||
$arr []= '3.1'; |
||||
$this->assertSame(3, $arr[4]); |
||||
$arr []= MAX_INT64_STRING; |
||||
$this->assertSame(MAX_INT64, $arr[5]); |
||||
$arr []= MIN_INT64_STRING; |
||||
$this->assertEquals(MIN_INT64, $arr[6]); |
||||
|
||||
$this->assertEquals(7, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(0, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= MAX_INT64; |
||||
$this->assertSame(MAX_INT64, $arr[0]); |
||||
$arr [1]= MIN_INT64; |
||||
$this->assertEquals(MIN_INT64, $arr[1]); |
||||
|
||||
$arr [2]= 1.1; |
||||
$this->assertSame(1, $arr[2]); |
||||
|
||||
$arr [3]= '2'; |
||||
$this->assertSame(2, $arr[3]); |
||||
$arr [4]= '3.1'; |
||||
$this->assertSame(3, $arr[4]); |
||||
$arr [5]= MAX_INT64_STRING; |
||||
$this->assertSame(MAX_INT64, $arr[5]); |
||||
$arr [6]= MIN_INT64_STRING; |
||||
$this->assertEquals(MIN_INT64, $arr[6]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64AppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT64); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64SetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT64); |
||||
$arr []= 0; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64AppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT64); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64SetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT64); |
||||
$arr []= 0; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test uint64 field. |
||||
######################################################### |
||||
|
||||
public function testUint64() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT64); |
||||
|
||||
// Test append. |
||||
$arr []= MAX_UINT64; |
||||
$this->assertEquals(MAX_UINT64, $arr[0]); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertSame(1, $arr[1]); |
||||
|
||||
$arr []= '2'; |
||||
$this->assertSame(2, $arr[2]); |
||||
$arr []= '3.1'; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr []= MAX_UINT64_STRING; |
||||
$this->assertEquals(MAX_UINT64, $arr[4]); |
||||
|
||||
$this->assertEquals(5, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(0, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= MAX_UINT64; |
||||
$this->assertEquals(MAX_UINT64, $arr[0]); |
||||
|
||||
$arr [1]= 1.1; |
||||
$this->assertSame(1, $arr[1]); |
||||
|
||||
$arr [2]= '2'; |
||||
$this->assertSame(2, $arr[2]); |
||||
$arr [3]= '3.1'; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr [4]= MAX_UINT64_STRING; |
||||
$this->assertEquals(MAX_UINT64, $arr[4]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64AppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT64); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64SetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT64); |
||||
$arr []= 0; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64AppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT64); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64SetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::UINT64); |
||||
$arr []= 0; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test float field. |
||||
######################################################### |
||||
|
||||
public function testFloat() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::FLOAT); |
||||
|
||||
// Test append. |
||||
$arr []= 1; |
||||
$this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr []= '2'; |
||||
$this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); |
||||
$arr []= '3.1'; |
||||
$this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); |
||||
|
||||
$this->assertEquals(4, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(0.0, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= 1; |
||||
$this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr [1]= 1.1; |
||||
$this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr [2]= '2'; |
||||
$this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); |
||||
$arr [3]= '3.1'; |
||||
$this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatAppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::FLOAT); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatSetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::FLOAT); |
||||
$arr []= 0.0; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatAppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::FLOAT); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatSetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::FLOAT); |
||||
$arr []= 0.0; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test double field. |
||||
######################################################### |
||||
|
||||
public function testDouble() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::DOUBLE); |
||||
|
||||
// Test append. |
||||
$arr []= 1; |
||||
$this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr []= '2'; |
||||
$this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); |
||||
$arr []= '3.1'; |
||||
$this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); |
||||
|
||||
$this->assertEquals(4, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(0.0, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= 1; |
||||
$this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr [1]= 1.1; |
||||
$this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr [2]= '2'; |
||||
$this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); |
||||
$arr [3]= '3.1'; |
||||
$this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleAppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::DOUBLE); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleSetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::DOUBLE); |
||||
$arr []= 0.0; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleAppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::DOUBLE); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleSetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::DOUBLE); |
||||
$arr []= 0.0; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test bool field. |
||||
######################################################### |
||||
|
||||
public function testBool() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::BOOL); |
||||
|
||||
// Test append. |
||||
$arr []= true; |
||||
$this->assertSame(true, $arr[0]); |
||||
|
||||
$arr []= -1; |
||||
$this->assertSame(true, $arr[1]); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertSame(true, $arr[2]); |
||||
|
||||
$arr []= ''; |
||||
$this->assertSame(false, $arr[3]); |
||||
|
||||
$this->assertEquals(4, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = 0; |
||||
$this->assertSame(false, $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= true; |
||||
$this->assertSame(true, $arr[0]); |
||||
|
||||
$arr [1]= -1; |
||||
$this->assertSame(true, $arr[1]); |
||||
|
||||
$arr [2]= 1.1; |
||||
$this->assertSame(true, $arr[2]); |
||||
|
||||
$arr [3]= ''; |
||||
$this->assertSame(false, $arr[3]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testBoolAppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::BOOL); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testBoolSetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::BOOL); |
||||
$arr []= true; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test string field. |
||||
######################################################### |
||||
|
||||
public function testString() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::STRING); |
||||
|
||||
// Test append. |
||||
$arr []= 'abc'; |
||||
$this->assertSame('abc', $arr[0]); |
||||
|
||||
$arr []= 1; |
||||
$this->assertSame('1', $arr[1]); |
||||
|
||||
$arr []= 1.1; |
||||
$this->assertSame('1.1', $arr[2]); |
||||
|
||||
$arr []= true; |
||||
$this->assertSame('1', $arr[3]); |
||||
|
||||
$this->assertEquals(4, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = ''; |
||||
$this->assertSame('', $arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= 'abc'; |
||||
$this->assertSame('abc', $arr[0]); |
||||
|
||||
$arr [1]= 1; |
||||
$this->assertSame('1', $arr[1]); |
||||
|
||||
$arr [2]= 1.1; |
||||
$this->assertSame('1.1', $arr[2]); |
||||
|
||||
$arr [3]= true; |
||||
$this->assertSame('1', $arr[3]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringAppendMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::STRING); |
||||
$arr []= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringSetMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::STRING); |
||||
$arr []= 'abc'; |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringAppendInvalidUTF8Fail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::STRING); |
||||
$hex = hex2bin("ff"); |
||||
$arr []= $hex; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringSetInvalidUTF8Fail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::STRING); |
||||
$arr []= 'abc'; |
||||
$hex = hex2bin("ff"); |
||||
$arr [0]= $hex; |
||||
} |
||||
|
||||
######################################################### |
||||
# Test message field. |
||||
######################################################### |
||||
|
||||
public function testMessage() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class); |
||||
|
||||
// Test append. |
||||
$sub_m = new TestMessage_Sub(); |
||||
$sub_m->setA(1); |
||||
$arr []= $sub_m; |
||||
$this->assertSame(1, $arr[0]->getA()); |
||||
|
||||
$null = null; |
||||
$arr []= $null; |
||||
$this->assertNull($arr[1]); |
||||
|
||||
$this->assertEquals(2, count($arr)); |
||||
|
||||
for ($i = 0; $i < count($arr); $i++) { |
||||
$arr[$i] = $null; |
||||
$this->assertNull($arr[$i]); |
||||
} |
||||
|
||||
// Test set. |
||||
$arr [0]= $sub_m; |
||||
$this->assertSame(1, $arr[0]->getA()); |
||||
|
||||
$arr [1]= $null; |
||||
$this->assertNull($arr[1]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageAppendIntFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class); |
||||
$arr []= 1; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageSetIntFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class); |
||||
$arr []= new TestMessage_Sub; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageAppendStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class); |
||||
$arr []= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageSetStringFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class); |
||||
$arr []= new TestMessage_Sub; |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageAppendOtherMessageFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class); |
||||
$arr []= new TestMessage; |
||||
} |
||||
|
||||
######################################################### |
||||
# Test offset type |
||||
######################################################### |
||||
|
||||
public function testOffset() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= 0; |
||||
|
||||
$arr [0]= 1; |
||||
$this->assertSame(1, $arr[0]); |
||||
$this->assertSame(1, count($arr)); |
||||
|
||||
$arr ['0']= 2; |
||||
$this->assertSame(2, $arr['0']); |
||||
$this->assertSame(2, $arr[0]); |
||||
$this->assertSame(1, count($arr)); |
||||
|
||||
$arr [0.0]= 3; |
||||
$this->assertSame(3, $arr[0.0]); |
||||
$this->assertSame(1, count($arr)); |
||||
} |
||||
|
||||
public function testInsertRemoval() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
|
||||
$arr []= 0; |
||||
$arr []= 1; |
||||
$arr []= 2; |
||||
$this->assertSame(3, count($arr)); |
||||
|
||||
unset($arr[2]); |
||||
$this->assertSame(2, count($arr)); |
||||
$this->assertSame(0, $arr[0]); |
||||
$this->assertSame(1, $arr[1]); |
||||
|
||||
$arr [] = 3; |
||||
$this->assertSame(3, count($arr)); |
||||
$this->assertSame(0, $arr[0]); |
||||
$this->assertSame(1, $arr[1]); |
||||
$this->assertSame(3, $arr[2]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testRemoveMiddleFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
|
||||
$arr []= 0; |
||||
$arr []= 1; |
||||
$arr []= 2; |
||||
$this->assertSame(3, count($arr)); |
||||
|
||||
unset($arr[1]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testRemoveEmptyFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
|
||||
unset($arr[0]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageOffsetFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= 0; |
||||
$arr [new TestMessage_Sub()]= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringOffsetFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr []= 0; |
||||
$arr ['abc']= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testSetNonExistedOffsetFail() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::INT32); |
||||
$arr [0]= 0; |
||||
} |
||||
|
||||
######################################################### |
||||
# Test memory leak |
||||
######################################################### |
||||
|
||||
public function testCycleLeak() |
||||
{ |
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); |
||||
$arr []= new TestMessage; |
||||
$arr[0]->SetRepeatedRecursive($arr); |
||||
|
||||
// Clean up memory before test. |
||||
gc_collect_cycles(); |
||||
$start = memory_get_usage(); |
||||
unset($arr); |
||||
|
||||
// Explicitly trigger garbage collection. |
||||
gc_collect_cycles(); |
||||
|
||||
$end = memory_get_usage(); |
||||
$this->assertLessThan($start, $end); |
||||
} |
||||
} |
@ -1,4 +0,0 @@ |
||||
<?php |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_util.php'); |
@ -0,0 +1,136 @@ |
||||
<?php |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_base.php'); |
||||
require_once('test_util.php'); |
||||
|
||||
use Google\Protobuf\RepeatedField; |
||||
use Google\Protobuf\GPBType; |
||||
use Foo\TestEnum; |
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
use Foo\TestPackedMessage; |
||||
use Foo\TestUnpackedMessage; |
||||
|
||||
class EncodeDecodeTest extends TestBase |
||||
{ |
||||
|
||||
public function testEncode() |
||||
{ |
||||
$from = new TestMessage(); |
||||
$this->expectEmptyFields($from); |
||||
$this->setFields($from); |
||||
$this->expectFields($from); |
||||
|
||||
$data = $from->encode(); |
||||
$this->assertSame(TestUtil::getGoldenTestMessage(), $data); |
||||
} |
||||
|
||||
public function testDecode() |
||||
{ |
||||
$to = new TestMessage(); |
||||
$to->decode(TestUtil::getGoldenTestMessage()); |
||||
$this->expectFields($to); |
||||
} |
||||
|
||||
public function testEncodeDecode() |
||||
{ |
||||
$from = new TestMessage(); |
||||
$this->expectEmptyFields($from); |
||||
$this->setFields($from); |
||||
$this->expectFields($from); |
||||
|
||||
$data = $from->encode(); |
||||
|
||||
$to = new TestMessage(); |
||||
$to->decode($data); |
||||
$this->expectFields($to); |
||||
} |
||||
|
||||
public function testEncodeDecodeEmpty() |
||||
{ |
||||
$from = new TestMessage(); |
||||
$this->expectEmptyFields($from); |
||||
|
||||
$data = $from->encode(); |
||||
|
||||
$to = new TestMessage(); |
||||
$to->decode($data); |
||||
$this->expectEmptyFields($to); |
||||
} |
||||
|
||||
public function testEncodeDecodeOneof() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
$m->setOneofInt32(1); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
$this->assertSame(1, $n->getOneofInt32()); |
||||
|
||||
$m->setOneofFloat(2.0); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
$this->assertSame(2.0, $n->getOneofFloat()); |
||||
|
||||
$m->setOneofString('abc'); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
$this->assertSame('abc', $n->getOneofString()); |
||||
|
||||
$sub_m = new TestMessage_Sub(); |
||||
$sub_m->setA(1); |
||||
$m->setOneofMessage($sub_m); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
$this->assertSame(1, $n->getOneofMessage()->getA()); |
||||
} |
||||
|
||||
public function testPackedEncode() |
||||
{ |
||||
$from = new TestPackedMessage(); |
||||
TestUtil::setTestPackedMessage($from); |
||||
$this->assertSame(TestUtil::getGoldenTestPackedMessage(), |
||||
$from->encode()); |
||||
} |
||||
|
||||
public function testPackedDecodePacked() |
||||
{ |
||||
$to = new TestPackedMessage(); |
||||
$to->decode(TestUtil::getGoldenTestPackedMessage()); |
||||
TestUtil::assertTestPackedMessage($to); |
||||
} |
||||
|
||||
public function testPackedDecodeUnpacked() |
||||
{ |
||||
$to = new TestPackedMessage(); |
||||
$to->decode(TestUtil::getGoldenTestUnpackedMessage()); |
||||
TestUtil::assertTestPackedMessage($to); |
||||
} |
||||
|
||||
public function testUnpackedEncode() |
||||
{ |
||||
$from = new TestUnpackedMessage(); |
||||
TestUtil::setTestPackedMessage($from); |
||||
$this->assertSame(TestUtil::getGoldenTestUnpackedMessage(), |
||||
$from->encode()); |
||||
} |
||||
|
||||
public function testUnpackedDecodePacked() |
||||
{ |
||||
$to = new TestUnpackedMessage(); |
||||
$to->decode(TestUtil::getGoldenTestPackedMessage()); |
||||
TestUtil::assertTestPackedMessage($to); |
||||
} |
||||
|
||||
public function testUnpackedDecodeUnpacked() |
||||
{ |
||||
$to = new TestUnpackedMessage(); |
||||
$to->decode(TestUtil::getGoldenTestUnpackedMessage()); |
||||
TestUtil::assertTestPackedMessage($to); |
||||
} |
||||
} |
@ -0,0 +1,557 @@ |
||||
<?php |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_util.php'); |
||||
|
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Foo\TestEnum; |
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
|
||||
class GeneratedClassTest extends PHPUnit_Framework_TestCase |
||||
{ |
||||
|
||||
######################################################### |
||||
# Test field accessors. |
||||
######################################################### |
||||
|
||||
public function testSetterGetter() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalInt32(1); |
||||
$this->assertSame(1, $m->getOptionalInt32()); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test int32 field. |
||||
######################################################### |
||||
|
||||
public function testInt32Field() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalInt32(MAX_INT32); |
||||
$this->assertSame(MAX_INT32, $m->getOptionalInt32()); |
||||
$m->setOptionalInt32(MIN_INT32); |
||||
$this->assertSame(MIN_INT32, $m->getOptionalInt32()); |
||||
|
||||
// Set float. |
||||
$m->setOptionalInt32(1.1); |
||||
$this->assertSame(1, $m->getOptionalInt32()); |
||||
$m->setOptionalInt32(MAX_INT32_FLOAT); |
||||
$this->assertSame(MAX_INT32, $m->getOptionalInt32()); |
||||
$m->setOptionalInt32(MIN_INT32_FLOAT); |
||||
$this->assertSame(MIN_INT32, $m->getOptionalInt32()); |
||||
|
||||
// Set string. |
||||
$m->setOptionalInt32('2'); |
||||
$this->assertSame(2, $m->getOptionalInt32()); |
||||
$m->setOptionalInt32('3.1'); |
||||
$this->assertSame(3, $m->getOptionalInt32()); |
||||
$m->setOptionalInt32(MAX_INT32_STRING); |
||||
$this->assertSame(MAX_INT32, $m->getOptionalInt32()); |
||||
$m->setOptionalInt32(MIN_INT32_STRING); |
||||
$this->assertSame(MIN_INT32, $m->getOptionalInt32()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32FieldInvalidTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalInt32(new TestMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32FieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalInt32('abc'); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test uint32 field. |
||||
######################################################### |
||||
|
||||
public function testUint32Field() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalUint32(MAX_UINT32); |
||||
$this->assertSame(-1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(-1); |
||||
$this->assertSame(-1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(MIN_UINT32); |
||||
$this->assertSame(MIN_INT32, $m->getOptionalUint32()); |
||||
|
||||
// Set float. |
||||
$m->setOptionalUint32(1.1); |
||||
$this->assertSame(1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(MAX_UINT32_FLOAT); |
||||
$this->assertSame(-1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(-1.0); |
||||
$this->assertSame(-1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(MIN_UINT32_FLOAT); |
||||
$this->assertSame(MIN_INT32, $m->getOptionalUint32()); |
||||
|
||||
// Set string. |
||||
$m->setOptionalUint32('2'); |
||||
$this->assertSame(2, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32('3.1'); |
||||
$this->assertSame(3, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(MAX_UINT32_STRING); |
||||
$this->assertSame(-1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32('-1.0'); |
||||
$this->assertSame(-1, $m->getOptionalUint32()); |
||||
$m->setOptionalUint32(MIN_UINT32_STRING); |
||||
$this->assertSame(MIN_INT32, $m->getOptionalUint32()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32FieldInvalidTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalUint32(new TestMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32FieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalUint32('abc'); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test int64 field. |
||||
######################################################### |
||||
|
||||
public function testInt64Field() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalInt64(MAX_INT64); |
||||
$this->assertSame(MAX_INT64, $m->getOptionalInt64()); |
||||
$m->setOptionalInt64(MIN_INT64); |
||||
$this->assertEquals(MIN_INT64, $m->getOptionalInt64()); |
||||
|
||||
// Set float. |
||||
$m->setOptionalInt64(1.1); |
||||
$this->assertSame(1, $m->getOptionalInt64()); |
||||
|
||||
// Set string. |
||||
$m->setOptionalInt64('2'); |
||||
$this->assertSame(2, $m->getOptionalInt64()); |
||||
$m->setOptionalInt64('3.1'); |
||||
$this->assertSame(3, $m->getOptionalInt64()); |
||||
$m->setOptionalInt64(MAX_INT64_STRING); |
||||
$this->assertSame(MAX_INT64, $m->getOptionalInt64()); |
||||
$m->setOptionalInt64(MIN_INT64_STRING); |
||||
$this->assertEquals(MIN_INT64, $m->getOptionalInt64()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64FieldInvalidTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalInt64(new TestMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64FieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalInt64('abc'); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test uint64 field. |
||||
######################################################### |
||||
|
||||
public function testUint64Field() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalUint64(MAX_UINT64); |
||||
$this->assertEquals(MAX_UINT64, $m->getOptionalUint64()); |
||||
|
||||
// Set float. |
||||
$m->setOptionalUint64(1.1); |
||||
$this->assertSame(1, $m->getOptionalUint64()); |
||||
|
||||
// Set string. |
||||
$m->setOptionalUint64('2'); |
||||
$this->assertSame(2, $m->getOptionalUint64()); |
||||
$m->setOptionalUint64('3.1'); |
||||
$this->assertSame(3, $m->getOptionalUint64()); |
||||
$m->setOptionalUint64(MAX_UINT64_STRING); |
||||
$this->assertEquals(MAX_UINT64, $m->getOptionalUint64()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64FieldInvalidTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalUint64(new TestMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64FieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalUint64('abc'); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test enum field. |
||||
######################################################### |
||||
|
||||
public function testEnumField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set enum. |
||||
$m->setOptionalEnum(TestEnum::ONE); |
||||
$this->assertEquals(TestEnum::ONE, $m->getOptionalEnum()); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalEnum(1); |
||||
$this->assertEquals(TestEnum::ONE, $m->getOptionalEnum()); |
||||
|
||||
// Set float. |
||||
$m->setOptionalEnum(1.1); |
||||
$this->assertEquals(TestEnum::ONE, $m->getOptionalEnum()); |
||||
|
||||
// Set string. |
||||
$m->setOptionalEnum("1"); |
||||
$this->assertEquals(TestEnum::ONE, $m->getOptionalEnum()); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test float field. |
||||
######################################################### |
||||
|
||||
public function testFloatField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalFloat(1); |
||||
$this->assertEquals(1.0, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF); |
||||
|
||||
// Set float. |
||||
$m->setOptionalFloat(1.1); |
||||
$this->assertEquals(1.1, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF); |
||||
|
||||
// Set string. |
||||
$m->setOptionalFloat('2'); |
||||
$this->assertEquals(2.0, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF); |
||||
$m->setOptionalFloat('3.1'); |
||||
$this->assertEquals(3.1, $m->getOptionalFloat(), '', MAX_FLOAT_DIFF); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatFieldInvalidTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalFloat(new TestMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatFieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalFloat('abc'); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test double field. |
||||
######################################################### |
||||
|
||||
public function testDoubleField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalDouble(1); |
||||
$this->assertEquals(1.0, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF); |
||||
|
||||
// Set float. |
||||
$m->setOptionalDouble(1.1); |
||||
$this->assertEquals(1.1, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF); |
||||
|
||||
// Set string. |
||||
$m->setOptionalDouble('2'); |
||||
$this->assertEquals(2.0, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF); |
||||
$m->setOptionalDouble('3.1'); |
||||
$this->assertEquals(3.1, $m->getOptionalDouble(), '', MAX_FLOAT_DIFF); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleFieldInvalidTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalDouble(new TestMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleFieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalDouble('abc'); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test bool field. |
||||
######################################################### |
||||
|
||||
public function testBoolField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set bool. |
||||
$m->setOptionalBool(true); |
||||
$this->assertSame(true, $m->getOptionalBool()); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalBool(-1); |
||||
$this->assertSame(true, $m->getOptionalBool()); |
||||
|
||||
// Set float. |
||||
$m->setOptionalBool(1.1); |
||||
$this->assertSame(true, $m->getOptionalBool()); |
||||
|
||||
// Set string. |
||||
$m->setOptionalBool(''); |
||||
$this->assertSame(false, $m->getOptionalBool()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testBoolFieldInvalidStringFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalBool(new TestMessage()); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test string field. |
||||
######################################################### |
||||
|
||||
public function testStringField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set string. |
||||
$m->setOptionalString('abc'); |
||||
$this->assertSame('abc', $m->getOptionalString()); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalString(1); |
||||
$this->assertSame('1', $m->getOptionalString()); |
||||
|
||||
// Set double. |
||||
$m->setOptionalString(1.1); |
||||
$this->assertSame('1.1', $m->getOptionalString()); |
||||
|
||||
// Set bool. |
||||
$m->setOptionalString(true); |
||||
$this->assertSame('1', $m->getOptionalString()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringFieldInvalidUTF8Fail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$hex = hex2bin("ff"); |
||||
$m->setOptionalString($hex); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test bytes field. |
||||
######################################################### |
||||
|
||||
public function testBytesField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
// Set string. |
||||
$m->setOptionalBytes('abc'); |
||||
$this->assertSame('abc', $m->getOptionalBytes()); |
||||
|
||||
// Set integer. |
||||
$m->setOptionalBytes(1); |
||||
$this->assertSame('1', $m->getOptionalBytes()); |
||||
|
||||
// Set double. |
||||
$m->setOptionalBytes(1.1); |
||||
$this->assertSame('1.1', $m->getOptionalBytes()); |
||||
|
||||
// Set bool. |
||||
$m->setOptionalBytes(true); |
||||
$this->assertSame('1', $m->getOptionalBytes()); |
||||
} |
||||
|
||||
public function testBytesFieldInvalidUTF8Success() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$hex = hex2bin("ff"); |
||||
$m->setOptionalBytes($hex); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test message field. |
||||
######################################################### |
||||
|
||||
public function testMessageField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
$sub_m = new TestMessage_Sub(); |
||||
$sub_m->setA(1); |
||||
$m->setOptionalMessage($sub_m); |
||||
$this->assertSame(1, $m->getOptionalMessage()->getA()); |
||||
|
||||
$null = null; |
||||
$m->setOptionalMessage($null); |
||||
$this->assertNull($m->getOptionalMessage()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageFieldWrongTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$a = 1; |
||||
$m->setOptionalMessage($a); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageFieldWrongClassFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setOptionalMessage(new TestMessage()); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test repeated field. |
||||
######################################################### |
||||
|
||||
public function testRepeatedField() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
$repeated_int32 = new RepeatedField(GPBType::INT32); |
||||
$m->setRepeatedInt32($repeated_int32); |
||||
$this->assertSame($repeated_int32, $m->getRepeatedInt32()); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testRepeatedFieldWrongTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$a = 1; |
||||
$m->setRepeatedInt32($a); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testRepeatedFieldWrongObjectFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->setRepeatedInt32($m); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testRepeatedFieldWrongRepeatedTypeFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
$repeated_int32 = new RepeatedField(GPBType::UINT32); |
||||
$m->setRepeatedInt32($repeated_int32); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testRepeatedFieldWrongRepeatedMessageClassFail() |
||||
{ |
||||
$m = new TestMessage(); |
||||
|
||||
$repeated_message = new RepeatedField(GPBType::MESSAGE, |
||||
TestMessage::class); |
||||
$m->setRepeatedMessage($repeated_message); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test oneof field. |
||||
######################################################### |
||||
|
||||
public function testOneofField() { |
||||
$m = new TestMessage(); |
||||
|
||||
$m->setOneofInt32(1); |
||||
$this->assertSame(1, $m->getOneofInt32()); |
||||
$this->assertSame(0.0, $m->getOneofFloat()); |
||||
$this->assertSame('', $m->getOneofString()); |
||||
$this->assertSame(NULL, $m->getOneofMessage()); |
||||
|
||||
$m->setOneofFloat(2.0); |
||||
$this->assertSame(0, $m->getOneofInt32()); |
||||
$this->assertSame(2.0, $m->getOneofFloat()); |
||||
$this->assertSame('', $m->getOneofString()); |
||||
$this->assertSame(NULL, $m->getOneofMessage()); |
||||
|
||||
$m->setOneofString('abc'); |
||||
$this->assertSame(0, $m->getOneofInt32()); |
||||
$this->assertSame(0.0, $m->getOneofFloat()); |
||||
$this->assertSame('abc', $m->getOneofString()); |
||||
$this->assertSame(NULL, $m->getOneofMessage()); |
||||
|
||||
$sub_m = new TestMessage_Sub(); |
||||
$sub_m->setA(1); |
||||
$m->setOneofMessage($sub_m); |
||||
$this->assertSame(0, $m->getOneofInt32()); |
||||
$this->assertSame(0.0, $m->getOneofFloat()); |
||||
$this->assertSame('', $m->getOneofString()); |
||||
$this->assertSame(1, $m->getOneofMessage()->getA()); |
||||
} |
||||
} |
@ -0,0 +1,648 @@ |
||||
<?php |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_util.php'); |
||||
|
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\MapField; |
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
|
||||
class MapFieldTest extends PHPUnit_Framework_TestCase { |
||||
|
||||
######################################################### |
||||
# Test int32 field. |
||||
######################################################### |
||||
|
||||
public function testInt32() { |
||||
$arr = new MapField(GPBType::INT32, GPBType::INT32); |
||||
|
||||
// Test integer argument. |
||||
$arr[MAX_INT32] = MAX_INT32; |
||||
$this->assertSame(MAX_INT32, $arr[MAX_INT32]); |
||||
$arr[MIN_INT32] = MIN_INT32; |
||||
$this->assertSame(MIN_INT32, $arr[MIN_INT32]); |
||||
$this->assertEquals(2, count($arr)); |
||||
$this->assertTrue(isset($arr[MAX_INT32])); |
||||
$this->assertTrue(isset($arr[MIN_INT32])); |
||||
unset($arr[MAX_INT32]); |
||||
unset($arr[MIN_INT32]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test float argument. |
||||
$arr[1.9] = 1.9; |
||||
$arr[2.1] = 2.1; |
||||
$this->assertSame(1, $arr[1]); |
||||
$this->assertSame(2, $arr[2]); |
||||
$arr[MAX_INT32_FLOAT] = MAX_INT32_FLOAT; |
||||
$this->assertSame(MAX_INT32, $arr[MAX_INT32]); |
||||
$arr[MIN_INT32_FLOAT] = MIN_INT32_FLOAT; |
||||
$this->assertSame(MIN_INT32, $arr[MIN_INT32]); |
||||
$this->assertEquals(4, count($arr)); |
||||
unset($arr[1.9]); |
||||
unset($arr[2.9]); |
||||
unset($arr[MAX_INT32_FLOAT]); |
||||
unset($arr[MIN_INT32_FLOAT]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test string argument. |
||||
$arr['2'] = '2'; |
||||
$this->assertSame(2, $arr[2]); |
||||
$arr['3.1'] = '3.1'; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr[MAX_INT32_STRING] = MAX_INT32_STRING; |
||||
$this->assertSame(MAX_INT32, $arr[MAX_INT32]); |
||||
$this->assertEquals(3, count($arr)); |
||||
unset($arr['2']); |
||||
unset($arr['3.1']); |
||||
unset($arr[MAX_INT32_STRING]); |
||||
$this->assertEquals(0, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32SetStringKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT32, GPBType::INT32); |
||||
$arr ['abc']= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32SetStringValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT32, GPBType::INT32); |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32SetMessageKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT32, GPBType::INT32); |
||||
$arr [new TestMessage_Sub()]= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt32SetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT32, GPBType::INT32); |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test uint32 field. |
||||
######################################################### |
||||
|
||||
public function testUint32() { |
||||
$arr = new MapField(GPBType::UINT32, GPBType::UINT32); |
||||
|
||||
// Test integer argument. |
||||
$arr[MAX_UINT32] = MAX_UINT32; |
||||
$this->assertSame(-1, $arr[-1]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[MAX_UINT32]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[-1] = -1; |
||||
$this->assertSame(-1, $arr[-1]); |
||||
$arr[MIN_UINT32] = MIN_UINT32; |
||||
$this->assertSame(MIN_UINT32, $arr[MIN_UINT32]); |
||||
$this->assertEquals(2, count($arr)); |
||||
unset($arr[-1]); |
||||
unset($arr[MIN_UINT32]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test float argument. |
||||
$arr[MAX_UINT32_FLOAT] = MAX_UINT32_FLOAT; |
||||
$this->assertSame(-1, $arr[-1]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[MAX_UINT32_FLOAT]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[3.1] = 3.1; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr[-1.0] = -1.0; |
||||
$this->assertSame(-1, $arr[-1]); |
||||
$arr[MIN_UINT32_FLOAT] = MIN_UINT32_FLOAT; |
||||
$this->assertSame(MIN_UINT32, $arr[MIN_UINT32]); |
||||
$this->assertEquals(3, count($arr)); |
||||
unset($arr[3.1]); |
||||
unset($arr[-1.0]); |
||||
unset($arr[MIN_UINT32_FLOAT]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test string argument. |
||||
$arr[MAX_UINT32_STRING] = MAX_UINT32_STRING; |
||||
$this->assertSame(-1, $arr[-1]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[MAX_UINT32_STRING]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr['7'] = '7'; |
||||
$this->assertSame(7, $arr[7]); |
||||
$arr['3.1'] = '3.1'; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr['-1.0'] = '-1.0'; |
||||
$this->assertSame(-1, $arr[-1]); |
||||
$arr[MIN_UINT32_STRING] = MIN_UINT32_STRING; |
||||
$this->assertSame(MIN_UINT32, $arr[MIN_UINT32]); |
||||
$this->assertEquals(4, count($arr)); |
||||
unset($arr['7']); |
||||
unset($arr['3.1']); |
||||
unset($arr['-1.0']); |
||||
unset($arr[MIN_UINT32_STRING]); |
||||
$this->assertEquals(0, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32SetStringKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT32, GPBType::UINT32); |
||||
$arr ['abc']= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32SetStringValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT32, GPBType::UINT32); |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32SetMessageKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT32, GPBType::UINT32); |
||||
$arr [new TestMessage_Sub()]= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint32SetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT32, GPBType::UINT32); |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test int64 field. |
||||
######################################################### |
||||
|
||||
public function testInt64() { |
||||
$arr = new MapField(GPBType::INT64, GPBType::INT64); |
||||
|
||||
// Test integer argument. |
||||
$arr[MAX_INT64] = MAX_INT64; |
||||
$this->assertSame(MAX_INT64, $arr[MAX_INT64]); |
||||
$arr[MIN_INT64] = MIN_INT64; |
||||
$this->assertEquals(MIN_INT64, $arr[MIN_INT64]); |
||||
$this->assertEquals(2, count($arr)); |
||||
unset($arr[MAX_INT64]); |
||||
unset($arr[MIN_INT64]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test float argument. |
||||
$arr[1.1] = 1.1; |
||||
$this->assertSame(1, $arr[1]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[1.1]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test string argument. |
||||
$arr['2'] = '2'; |
||||
$this->assertSame(2, $arr[2]); |
||||
$arr['3.1'] = '3.1'; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr[MAX_INT64_STRING] = MAX_INT64_STRING; |
||||
$this->assertSame(MAX_INT64, $arr[MAX_INT64]); |
||||
$arr[MIN_INT64_STRING] = MIN_INT64_STRING; |
||||
$this->assertEquals(MIN_INT64, $arr[MIN_INT64]); |
||||
$this->assertEquals(4, count($arr)); |
||||
unset($arr['2']); |
||||
unset($arr['3.1']); |
||||
unset($arr[MAX_INT64_STRING]); |
||||
unset($arr[MIN_INT64_STRING]); |
||||
$this->assertEquals(0, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64SetStringKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::INT64); |
||||
$arr ['abc']= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64SetStringValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::INT64); |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64SetMessageKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::INT64); |
||||
$arr [new TestMessage_Sub()]= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testInt64SetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::INT64); |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test uint64 field. |
||||
######################################################### |
||||
|
||||
public function testUint64() { |
||||
$arr = new MapField(GPBType::UINT64, GPBType::UINT64); |
||||
|
||||
// Test integer argument. |
||||
$arr[MAX_UINT64] = MAX_UINT64; |
||||
$this->assertEquals(MAX_UINT64, $arr[MAX_UINT64]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[MAX_UINT64]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test float argument. |
||||
$arr[1.1] = 1.1; |
||||
$this->assertSame(1, $arr[1]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[1.1]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test string argument. |
||||
$arr['2'] = '2'; |
||||
$this->assertSame(2, $arr[2]); |
||||
$arr['3.1'] = '3.1'; |
||||
$this->assertSame(3, $arr[3]); |
||||
$arr[MAX_UINT64_STRING] = MAX_UINT64_STRING; |
||||
$this->assertEquals(MAX_UINT64, $arr[MAX_UINT64]); |
||||
$this->assertEquals(3, count($arr)); |
||||
unset($arr['2']); |
||||
unset($arr['3.1']); |
||||
unset($arr[MAX_UINT64_STRING]); |
||||
$this->assertEquals(0, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64SetStringKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT64, GPBType::UINT64); |
||||
$arr ['abc']= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64SetStringValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT64, GPBType::UINT64); |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64SetMessageKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT64, GPBType::UINT64); |
||||
$arr [new TestMessage_Sub()]= 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testUint64SetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::UINT64, GPBType::UINT64); |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test float field. |
||||
######################################################### |
||||
|
||||
public function testFloat() { |
||||
$arr = new MapField(GPBType::INT32, GPBType::FLOAT); |
||||
|
||||
// Test set. |
||||
$arr[0] = 1; |
||||
$this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr[1] = 1.1; |
||||
$this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr[2] = '2'; |
||||
$this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); |
||||
$arr[3] = '3.1'; |
||||
$this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); |
||||
|
||||
$this->assertEquals(4, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatSetStringValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::FLOAT); |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testFloatSetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::FLOAT); |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test double field. |
||||
######################################################### |
||||
|
||||
public function testDouble() { |
||||
$arr = new MapField(GPBType::INT32, GPBType::DOUBLE); |
||||
|
||||
// Test set. |
||||
$arr[0] = 1; |
||||
$this->assertEquals(1.0, $arr[0], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr[1] = 1.1; |
||||
$this->assertEquals(1.1, $arr[1], '', MAX_FLOAT_DIFF); |
||||
|
||||
$arr[2] = '2'; |
||||
$this->assertEquals(2.0, $arr[2], '', MAX_FLOAT_DIFF); |
||||
$arr[3] = '3.1'; |
||||
$this->assertEquals(3.1, $arr[3], '', MAX_FLOAT_DIFF); |
||||
|
||||
$this->assertEquals(4, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleSetStringValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::DOUBLE); |
||||
$arr [0]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testDoubleSetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::INT64, GPBType::DOUBLE); |
||||
$arr [0]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test bool field. |
||||
######################################################### |
||||
|
||||
public function testBool() { |
||||
$arr = new MapField(GPBType::BOOL, GPBType::BOOL); |
||||
|
||||
// Test boolean. |
||||
$arr[True] = True; |
||||
$this->assertSame(True, $arr[True]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[True]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[False] = False; |
||||
$this->assertSame(False, $arr[False]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[False]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test integer. |
||||
$arr[-1] = -1; |
||||
$this->assertSame(True, $arr[True]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[-1]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[0] = 0; |
||||
$this->assertSame(False, $arr[False]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[0]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test float. |
||||
$arr[1.1] = 1.1; |
||||
$this->assertSame(True, $arr[True]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[1.1]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[0.0] = 0.0; |
||||
$this->assertSame(False, $arr[False]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[0.0]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
// Test string. |
||||
$arr['a'] = 'a'; |
||||
$this->assertSame(True, $arr[True]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr['a']); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[''] = ''; |
||||
$this->assertSame(False, $arr[False]); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr['']); |
||||
$this->assertEquals(0, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testBoolSetMessageKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::BOOL, GPBType::BOOL); |
||||
$arr [new TestMessage_Sub()]= true; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testBoolSetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::BOOL, GPBType::BOOL); |
||||
$arr [true]= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test string field. |
||||
######################################################### |
||||
|
||||
public function testString() { |
||||
$arr = new MapField(GPBType::STRING, GPBType::STRING); |
||||
|
||||
// Test set. |
||||
$arr['abc'] = 'abc'; |
||||
$this->assertSame('abc', $arr['abc']); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr['abc']); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[1] = 1; |
||||
$this->assertSame('1', $arr['1']); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[1]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[1.1] = 1.1; |
||||
$this->assertSame('1.1', $arr['1.1']); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[1.1]); |
||||
$this->assertEquals(0, count($arr)); |
||||
|
||||
$arr[True] = True; |
||||
$this->assertSame('1', $arr['1']); |
||||
$this->assertEquals(1, count($arr)); |
||||
unset($arr[True]); |
||||
$this->assertEquals(0, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringSetInvalidUTF8KeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::STRING, GPBType::STRING); |
||||
$arr[hex2bin("ff")]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringSetInvalidUTF8ValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::STRING, GPBType::STRING); |
||||
$arr ['abc']= hex2bin("ff"); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringSetMessageKeyFail() |
||||
{ |
||||
$arr = new MapField(GPBType::STRING, GPBType::STRING); |
||||
$arr [new TestMessage_Sub()]= 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testStringSetMessageValueFail() |
||||
{ |
||||
$arr = new MapField(GPBType::STRING, GPBType::STRING); |
||||
$arr ['abc']= new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test message field. |
||||
######################################################### |
||||
|
||||
public function testMessage() { |
||||
$arr = new MapField(GPBType::INT32, |
||||
GPBType::MESSAGE, TestMessage_Sub::class); |
||||
|
||||
// Test append. |
||||
$sub_m = new TestMessage_Sub(); |
||||
$sub_m->setA(1); |
||||
$arr[0] = $sub_m; |
||||
$this->assertSame(1, $arr[0]->getA()); |
||||
|
||||
$null = NULL; |
||||
$arr[1] = $null; |
||||
$this->assertNull($arr[1]); |
||||
|
||||
$this->assertEquals(2, count($arr)); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageSetIntValueFail() |
||||
{ |
||||
$arr = |
||||
new MapField(GPBType::INT32, GPBType::MESSAGE, TestMessage::class); |
||||
$arr[0] = 0; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageSetStringValueFail() |
||||
{ |
||||
$arr = |
||||
new MapField(GPBType::INT32, GPBType::MESSAGE, TestMessage::class); |
||||
$arr[0] = 'abc'; |
||||
} |
||||
|
||||
/** |
||||
* @expectedException PHPUnit_Framework_Error |
||||
*/ |
||||
public function testMessageSetOtherMessageValueFail() |
||||
{ |
||||
$arr = |
||||
new MapField(GPBType::INT32, GPBType::MESSAGE, TestMessage::class); |
||||
$arr[0] = new TestMessage_Sub(); |
||||
} |
||||
|
||||
######################################################### |
||||
# Test memory leak |
||||
######################################################### |
||||
|
||||
// TODO(teboring): Add it back. |
||||
// public function testCycleLeak() |
||||
// { |
||||
// $arr = new MapField(GPBType::INT32, |
||||
// GPBType::MESSAGE, TestMessage::class); |
||||
// $arr [0]= new TestMessage; |
||||
// $arr[0]->SetMapRecursive($arr); |
||||
|
||||
// // Clean up memory before test. |
||||
// gc_collect_cycles(); |
||||
// $start = memory_get_usage(); |
||||
// unset($arr); |
||||
|
||||
// // Explicitly trigger garbage collection. |
||||
// gc_collect_cycles(); |
||||
|
||||
// $end = memory_get_usage(); |
||||
// $this->assertLessThan($start, $end); |
||||
// } |
||||
} |
@ -0,0 +1,73 @@ |
||||
<?php |
||||
|
||||
# phpunit has memory leak by itself. Thus, it cannot be used to test memory leak. |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_util.php'); |
||||
|
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
|
||||
$from = new TestMessage(); |
||||
TestUtil::setTestMessage($from); |
||||
TestUtil::assertTestMessage($from); |
||||
|
||||
$data = $from->encode(); |
||||
|
||||
$to = new TestMessage(); |
||||
$to->decode($data); |
||||
|
||||
TestUtil::assertTestMessage($to); |
||||
|
||||
$from->setRecursive($from); |
||||
|
||||
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); |
||||
$arr []= new TestMessage; |
||||
$arr[0]->SetRepeatedRecursive($arr); |
||||
|
||||
// Test oneof fields. |
||||
$m = new TestMessage(); |
||||
|
||||
$m->setOneofInt32(1); |
||||
assert(1 === $m->getOneofInt32()); |
||||
assert(0.0 === $m->getOneofFloat()); |
||||
assert('' === $m->getOneofString()); |
||||
assert(NULL === $m->getOneofMessage()); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
assert(1 === $n->getOneofInt32()); |
||||
|
||||
$m->setOneofFloat(2.0); |
||||
assert(0 === $m->getOneofInt32()); |
||||
assert(2.0 === $m->getOneofFloat()); |
||||
assert('' === $m->getOneofString()); |
||||
assert(NULL === $m->getOneofMessage()); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
assert(2.0 === $n->getOneofFloat()); |
||||
|
||||
$m->setOneofString('abc'); |
||||
assert(0 === $m->getOneofInt32()); |
||||
assert(0.0 === $m->getOneofFloat()); |
||||
assert('abc' === $m->getOneofString()); |
||||
assert(NULL === $m->getOneofMessage()); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
assert('abc' === $n->getOneofString()); |
||||
|
||||
$sub_m = new TestMessage_Sub(); |
||||
$sub_m->setA(1); |
||||
$m->setOneofMessage($sub_m); |
||||
assert(0 === $m->getOneofInt32()); |
||||
assert(0.0 === $m->getOneofFloat()); |
||||
assert('' === $m->getOneofString()); |
||||
assert(1 === $m->getOneofMessage()->getA()); |
||||
$data = $m->encode(); |
||||
$n = new TestMessage(); |
||||
$n->decode($data); |
||||
assert(1 === $n->getOneofMessage()->getA()); |
@ -0,0 +1,443 @@ |
||||
<?php |
||||
|
||||
require_once('test.pb.php'); |
||||
require_once('test_base.php'); |
||||
require_once('test_util.php'); |
||||
|
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
use Foo\TestPackedMessage; |
||||
use Google\Protobuf\Internal\InputStream; |
||||
use Google\Protobuf\Internal\FileDescriptorSet; |
||||
use Google\Protobuf\Internal\GPBUtil; |
||||
use Google\Protobuf\Internal\Int64; |
||||
use Google\Protobuf\Internal\Uint64; |
||||
use Google\Protobuf\Internal\GPBLabel; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\GPBWire; |
||||
use Google\Protobuf\Internal\OutputStream; |
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
|
||||
class ImplementationTest extends TestBase |
||||
{ |
||||
|
||||
public function testReadInt32() |
||||
{ |
||||
$value = null; |
||||
|
||||
// Positive number. |
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readInt32($input, $value); |
||||
$this->assertSame(1, $value); |
||||
|
||||
// Negative number. |
||||
$input = new InputStream(hex2bin("ffffffff0f")); |
||||
GPBWire::readInt32($input, $value); |
||||
$this->assertSame(-1, $value); |
||||
|
||||
// Discard overflow bits. |
||||
$input = new InputStream(hex2bin("ffffffff7f")); |
||||
GPBWire::readInt32($input, $value); |
||||
$this->assertSame(-1, $value); |
||||
} |
||||
|
||||
public function testReadUint32() |
||||
{ |
||||
$value = null; |
||||
|
||||
// Positive number. |
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readUint32($input, $value); |
||||
$this->assertSame(1, $value); |
||||
|
||||
// Max uint32. |
||||
$input = new InputStream(hex2bin("ffffffff0f")); |
||||
GPBWire::readUint32($input, $value); |
||||
$this->assertSame(-1, $value); |
||||
|
||||
// Discard overflow bits. |
||||
$input = new InputStream(hex2bin("ffffffff7f")); |
||||
GPBWire::readUint32($input, $value); |
||||
$this->assertSame(-1, $value); |
||||
} |
||||
|
||||
public function testReadInt64() |
||||
{ |
||||
$value = null; |
||||
|
||||
// Positive number. |
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readInt64($input, $value); |
||||
$this->assertSame(1, $value->toInteger()); |
||||
|
||||
// Negative number. |
||||
$input = new InputStream(hex2bin("ffffffffffffffffff01")); |
||||
GPBWire::readInt64($input, $value); |
||||
$this->assertSame(-1, $value->toInteger()); |
||||
|
||||
// Discard overflow bits. |
||||
$input = new InputStream(hex2bin("ffffffffffffffffff0f")); |
||||
GPBWire::readInt64($input, $value); |
||||
$this->assertSame(-1, $value->toInteger()); |
||||
} |
||||
|
||||
public function testReadUint64() |
||||
{ |
||||
$value = null; |
||||
|
||||
// Positive number. |
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readUint64($input, $value); |
||||
$this->assertSame(1, $value->toInteger()); |
||||
|
||||
// Negative number. |
||||
$input = new InputStream(hex2bin("FFFFFFFFFFFFFFFFFF01")); |
||||
GPBWire::readUint64($input, $value); |
||||
$this->assertSame(-1, $value->toInteger()); |
||||
|
||||
// Discard overflow bits. |
||||
$input = new InputStream(hex2bin("FFFFFFFFFFFFFFFFFF0F")); |
||||
GPBWire::readUint64($input, $value); |
||||
$this->assertSame(-1, $value->toInteger()); |
||||
} |
||||
|
||||
public function testReadSint32() |
||||
{ |
||||
$value = null; |
||||
|
||||
$input = new InputStream(hex2bin("00")); |
||||
GPBWire::readSint32($input, $value); |
||||
$this->assertSame(0, $value); |
||||
|
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readSint32($input, $value); |
||||
$this->assertSame(-1, $value); |
||||
|
||||
$input = new InputStream(hex2bin("02")); |
||||
GPBWire::readSint32($input, $value); |
||||
$this->assertSame(1, $value); |
||||
} |
||||
|
||||
public function testReadSint64() |
||||
{ |
||||
$value = null; |
||||
|
||||
$input = new InputStream(hex2bin("00")); |
||||
GPBWire::readSint64($input, $value); |
||||
$this->assertEquals(GPBUtil::Int64(0), $value); |
||||
|
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readSint64($input, $value); |
||||
$this->assertEquals(GPBUtil::Int64(-1), $value); |
||||
|
||||
$input = new InputStream(hex2bin("02")); |
||||
GPBWire::readSint64($input, $value); |
||||
$this->assertEquals(GPBUtil::Int64(1), $value); |
||||
} |
||||
|
||||
public function testReadFixed32() |
||||
{ |
||||
$value = null; |
||||
$input = new InputStream(hex2bin("12345678")); |
||||
GPBWire::readFixed32($input, $value); |
||||
$this->assertSame(0x78563412, $value); |
||||
} |
||||
|
||||
public function testReadFixed64() |
||||
{ |
||||
$value = null; |
||||
$input = new InputStream(hex2bin("1234567812345678")); |
||||
GPBWire::readFixed64($input, $value); |
||||
$this->assertEquals(Uint64::newValue(0x78563412, 0x78563412), $value); |
||||
} |
||||
|
||||
public function testReadSfixed32() |
||||
{ |
||||
$value = null; |
||||
$input = new InputStream(hex2bin("12345678")); |
||||
GPBWire::readSfixed32($input, $value); |
||||
$this->assertSame(0x78563412, $value); |
||||
} |
||||
|
||||
public function testReadFloat() |
||||
{ |
||||
$value = null; |
||||
$input = new InputStream(hex2bin("0000803F")); |
||||
GPBWire::readFloat($input, $value); |
||||
$this->assertSame(1.0, $value); |
||||
} |
||||
|
||||
public function testReadBool() |
||||
{ |
||||
$value = null; |
||||
|
||||
$input = new InputStream(hex2bin("00")); |
||||
GPBWire::readBool($input, $value); |
||||
$this->assertSame(false, $value); |
||||
|
||||
$input = new InputStream(hex2bin("01")); |
||||
GPBWire::readBool($input, $value); |
||||
$this->assertSame(true, $value); |
||||
} |
||||
|
||||
public function testReadDouble() |
||||
{ |
||||
$value = null; |
||||
$input = new InputStream(hex2bin("000000000000F03F")); |
||||
GPBWire::readDouble($input, $value); |
||||
$this->assertSame(1.0, $value); |
||||
} |
||||
|
||||
public function testReadSfixed64() |
||||
{ |
||||
$value = null; |
||||
$input = new InputStream(hex2bin("1234567812345678")); |
||||
GPBWire::readSfixed64($input, $value); |
||||
$this->assertEquals(Int64::newValue(0x78563412, 0x78563412), $value); |
||||
} |
||||
|
||||
public function testZigZagEncodeDecode() |
||||
{ |
||||
$this->assertSame(0, GPBWire::zigZagEncode32(0)); |
||||
$this->assertSame(1, GPBWire::zigZagEncode32(-1)); |
||||
$this->assertSame(2, GPBWire::zigZagEncode32(1)); |
||||
$this->assertSame(3, GPBWire::zigZagEncode32(-2)); |
||||
$this->assertSame(0x7FFFFFFE, GPBWire::zigZagEncode32(0x3FFFFFFF)); |
||||
$this->assertSame(0x7FFFFFFF, GPBWire::zigZagEncode32(0xC0000000)); |
||||
$this->assertSame(-2, GPBWire::zigZagEncode32(0x7FFFFFFF)); |
||||
$this->assertSame(-1, GPBWire::zigZagEncode32(0x80000000)); |
||||
|
||||
$this->assertSame(0, GPBWire::zigZagDecode32(0)); |
||||
$this->assertSame(-1, GPBWire::zigZagDecode32(1)); |
||||
$this->assertSame(1, GPBWire::zigZagDecode32(2)); |
||||
$this->assertSame(-2, GPBWire::zigZagDecode32(3)); |
||||
$this->assertSame(0x3FFFFFFF, GPBWire::zigZagDecode32(0x7FFFFFFE)); |
||||
$this->assertSame(-1073741824, GPBWire::zigZagDecode32(0x7FFFFFFF)); |
||||
$this->assertSame(0x7FFFFFFF, GPBWire::zigZagDecode32(0xFFFFFFFE)); |
||||
$this->assertSame(-2147483648, GPBWire::zigZagDecode32(0xFFFFFFFF)); |
||||
|
||||
$this->assertEquals(GPBUtil::Uint64(0), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0))); |
||||
$this->assertEquals(GPBUtil::Uint64(1), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(-1))); |
||||
$this->assertEquals(GPBUtil::Uint64(2), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(1))); |
||||
$this->assertEquals(GPBUtil::Uint64(3), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(-2))); |
||||
$this->assertEquals( |
||||
GPBUtil::Uint64(0x000000007FFFFFFE), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0x000000003FFFFFFF))); |
||||
$this->assertEquals( |
||||
GPBUtil::Uint64(0x000000007FFFFFFF), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0xFFFFFFFFC0000000))); |
||||
$this->assertEquals( |
||||
GPBUtil::Uint64(0x00000000FFFFFFFE), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0x000000007FFFFFFF))); |
||||
$this->assertEquals( |
||||
GPBUtil::Uint64(0x00000000FFFFFFFF), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0xFFFFFFFF80000000))); |
||||
$this->assertEquals( |
||||
Uint64::newValue(4294967295, 4294967294), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0x7FFFFFFFFFFFFFFF))); |
||||
$this->assertEquals( |
||||
Uint64::newValue(4294967295, 4294967295), |
||||
GPBWire::zigZagEncode64(GPBUtil::Int64(0x8000000000000000))); |
||||
|
||||
$this->assertEquals(GPBUtil::Int64(0), |
||||
GPBWire::zigZagDecode64(GPBUtil::Uint64(0))); |
||||
$this->assertEquals(GPBUtil::Int64(-1), |
||||
GPBWire::zigZagDecode64(GPBUtil::Uint64(1))); |
||||
$this->assertEquals(GPBUtil::Int64(1), |
||||
GPBWire::zigZagDecode64(GPBUtil::Uint64(2))); |
||||
$this->assertEquals(GPBUtil::Int64(-2), |
||||
GPBWire::zigZagDecode64(GPBUtil::Uint64(3))); |
||||
|
||||
// Round trip |
||||
$this->assertSame(0, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(0))); |
||||
$this->assertSame(1, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(1))); |
||||
$this->assertSame(-1, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(-1))); |
||||
$this->assertSame(14927, |
||||
GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(14927))); |
||||
$this->assertSame(-3612, |
||||
GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(-3612))); |
||||
} |
||||
|
||||
public function testDecode() |
||||
{ |
||||
$m = new TestMessage(); |
||||
$m->decode(TestUtil::getGoldenTestMessage()); |
||||
TestUtil::assertTestMessage($m); |
||||
} |
||||
|
||||
public function testDescriptorDecode() |
||||
{ |
||||
$file_desc_set = new FileDescriptorSet(); |
||||
$file_desc_set->decode(hex2bin( |
||||
"0a3b0a12746573745f696e636c7564652e70726f746f120362617222180a" . |
||||
"0b54657374496e636c75646512090a0161180120012805620670726f746f33")); |
||||
|
||||
$this->assertSame(1, sizeof($file_desc_set->getFile())); |
||||
|
||||
$file_desc = $file_desc_set->getFile()[0]; |
||||
$this->assertSame("test_include.proto", $file_desc->getName()); |
||||
$this->assertSame("bar", $file_desc->getPackage()); |
||||
$this->assertSame(0, sizeof($file_desc->getDependency())); |
||||
$this->assertSame(1, sizeof($file_desc->getMessageType())); |
||||
$this->assertSame(0, sizeof($file_desc->getEnumType())); |
||||
$this->assertSame("proto3", $file_desc->getSyntax()); |
||||
|
||||
$desc = $file_desc->getMessageType()[0]; |
||||
$this->assertSame("TestInclude", $desc->getName()); |
||||
$this->assertSame(1, sizeof($desc->getField())); |
||||
$this->assertSame(0, sizeof($desc->getNestedType())); |
||||
$this->assertSame(0, sizeof($desc->getEnumType())); |
||||
$this->assertSame(0, sizeof($desc->getOneofDecl())); |
||||
|
||||
$field = $desc->getField()[0]; |
||||
$this->assertSame("a", $field->getName()); |
||||
$this->assertSame(1, $field->getNumber()); |
||||
$this->assertSame(GPBLabel::OPTIONAL, $field->getLabel()); |
||||
$this->assertSame(GPBType::INT32, $field->getType()); |
||||
} |
||||
|
||||
public function testReadVarint64() |
||||
{ |
||||
$var = 0; |
||||
|
||||
// Empty buffer. |
||||
$input = new InputStream(hex2bin('')); |
||||
$this->assertFalse($input->readVarint64($var)); |
||||
|
||||
// The largest varint is 10 bytes long. |
||||
$input = new InputStream(hex2bin('8080808080808080808001')); |
||||
$this->assertFalse($input->readVarint64($var)); |
||||
|
||||
// Corrupted varint. |
||||
$input = new InputStream(hex2bin('808080')); |
||||
$this->assertFalse($input->readVarint64($var)); |
||||
|
||||
// Normal case. |
||||
$input = new InputStream(hex2bin('808001')); |
||||
$this->assertTrue($input->readVarint64($var)); |
||||
$this->assertSame(16384, $var->toInteger()); |
||||
$this->assertFalse($input->readVarint64($var)); |
||||
|
||||
// Read two varint. |
||||
$input = new InputStream(hex2bin('808001808002')); |
||||
$this->assertTrue($input->readVarint64($var)); |
||||
$this->assertSame(16384, $var->toInteger()); |
||||
$this->assertTrue($input->readVarint64($var)); |
||||
$this->assertSame(32768, $var->toInteger()); |
||||
$this->assertFalse($input->readVarint64($var)); |
||||
} |
||||
|
||||
public function testReadVarint32() |
||||
{ |
||||
$var = 0; |
||||
|
||||
// Empty buffer. |
||||
$input = new InputStream(hex2bin('')); |
||||
$this->assertFalse($input->readVarint32($var)); |
||||
|
||||
// The largest varint is 10 bytes long. |
||||
$input = new InputStream(hex2bin('8080808080808080808001')); |
||||
$this->assertFalse($input->readVarint32($var)); |
||||
|
||||
// Corrupted varint. |
||||
$input = new InputStream(hex2bin('808080')); |
||||
$this->assertFalse($input->readVarint32($var)); |
||||
|
||||
// Normal case. |
||||
$input = new InputStream(hex2bin('808001')); |
||||
$this->assertTrue($input->readVarint32($var)); |
||||
$this->assertSame(16384, $var); |
||||
$this->assertFalse($input->readVarint32($var)); |
||||
|
||||
// Read two varint. |
||||
$input = new InputStream(hex2bin('808001808002')); |
||||
$this->assertTrue($input->readVarint32($var)); |
||||
$this->assertSame(16384, $var); |
||||
$this->assertTrue($input->readVarint32($var)); |
||||
$this->assertSame(32768, $var); |
||||
$this->assertFalse($input->readVarint32($var)); |
||||
|
||||
// Read a 64-bit integer. High-order bits should be discarded. |
||||
$input = new InputStream(hex2bin('808081808001')); |
||||
$this->assertTrue($input->readVarint32($var)); |
||||
$this->assertSame(16384, $var); |
||||
$this->assertFalse($input->readVarint32($var)); |
||||
} |
||||
|
||||
public function testReadTag() |
||||
{ |
||||
$input = new InputStream(hex2bin('808001')); |
||||
$tag = $input->readTag(); |
||||
$this->assertSame(16384, $tag); |
||||
$tag = $input->readTag(); |
||||
$this->assertSame(0, $tag); |
||||
} |
||||
|
||||
public function testPushPopLimit() |
||||
{ |
||||
$input = new InputStream(hex2bin('808001')); |
||||
$old_limit = $input->pushLimit(0); |
||||
$tag = $input->readTag(); |
||||
$this->assertSame(0, $tag); |
||||
$input->popLimit($old_limit); |
||||
$tag = $input->readTag(); |
||||
$this->assertSame(16384, $tag); |
||||
} |
||||
|
||||
public function testReadRaw() |
||||
{ |
||||
$input = new InputStream(hex2bin('808001')); |
||||
$buffer = null; |
||||
|
||||
$this->assertTrue($input->readRaw(3, $buffer)); |
||||
$this->assertSame(hex2bin('808001'), $buffer); |
||||
|
||||
$this->assertFalse($input->readRaw(1, $buffer)); |
||||
} |
||||
|
||||
public function testWriteVarint32() |
||||
{ |
||||
$output = new OutputStream(3); |
||||
$output->writeVarint32(16384); |
||||
$this->assertSame(hex2bin('808001'), $output->getData()); |
||||
} |
||||
|
||||
public function testWriteVarint64() |
||||
{ |
||||
$output = new OutputStream(10); |
||||
$output->writeVarint64(-43); |
||||
$this->assertSame(hex2bin('D5FFFFFFFFFFFFFFFF01'), $output->getData()); |
||||
} |
||||
|
||||
public function testWriteLittleEndian32() |
||||
{ |
||||
$output = new OutputStream(4); |
||||
$output->writeLittleEndian32(46); |
||||
$this->assertSame(hex2bin('2E000000'), $output->getData()); |
||||
} |
||||
|
||||
public function testWriteLittleEndian64() |
||||
{ |
||||
$output = new OutputStream(8); |
||||
$output->writeLittleEndian64(47); |
||||
$this->assertSame(hex2bin('2F00000000000000'), $output->getData()); |
||||
} |
||||
|
||||
public function testByteSize() |
||||
{ |
||||
$m = new TestMessage(); |
||||
TestUtil::setTestMessage($m); |
||||
$this->assertSame(447, $m->byteSize()); |
||||
} |
||||
|
||||
public function testPackedByteSize() |
||||
{ |
||||
$m = new TestPackedMessage(); |
||||
TestUtil::setTestPackedMessage($m); |
||||
$this->assertSame(156, $m->byteSize()); |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,136 @@ |
||||
syntax = "proto3"; |
||||
|
||||
import 'test_include.proto'; |
||||
|
||||
package foo; |
||||
|
||||
message TestMessage { |
||||
// Singular |
||||
int32 optional_int32 = 1; |
||||
int64 optional_int64 = 2; |
||||
uint32 optional_uint32 = 3; |
||||
uint64 optional_uint64 = 4; |
||||
sint32 optional_sint32 = 5; |
||||
sint64 optional_sint64 = 6; |
||||
fixed32 optional_fixed32 = 7; |
||||
fixed64 optional_fixed64 = 8; |
||||
sfixed32 optional_sfixed32 = 9; |
||||
sfixed64 optional_sfixed64 = 10; |
||||
float optional_float = 11; |
||||
double optional_double = 12; |
||||
bool optional_bool = 13; |
||||
string optional_string = 14; |
||||
bytes optional_bytes = 15; |
||||
|
||||
TestEnum optional_enum = 16; |
||||
Sub optional_message = 17; |
||||
bar.TestInclude optional_included_message = 18; |
||||
TestMessage recursive = 19; |
||||
|
||||
// Repeated |
||||
repeated int32 repeated_int32 = 31; |
||||
repeated int64 repeated_int64 = 32; |
||||
repeated uint32 repeated_uint32 = 33; |
||||
repeated uint64 repeated_uint64 = 34; |
||||
repeated sint32 repeated_sint32 = 35; |
||||
repeated sint64 repeated_sint64 = 36; |
||||
repeated fixed32 repeated_fixed32 = 37; |
||||
repeated fixed64 repeated_fixed64 = 38; |
||||
repeated sfixed32 repeated_sfixed32 = 39; |
||||
repeated sfixed64 repeated_sfixed64 = 40; |
||||
repeated float repeated_float = 41; |
||||
repeated double repeated_double = 42; |
||||
repeated bool repeated_bool = 43; |
||||
repeated string repeated_string = 44; |
||||
repeated bytes repeated_bytes = 45; |
||||
|
||||
repeated TestEnum repeated_enum = 46; |
||||
repeated Sub repeated_message = 47; |
||||
repeated TestMessage repeated_recursive = 48; |
||||
|
||||
oneof my_oneof { |
||||
int32 oneof_int32 = 51; |
||||
int64 oneof_int64 = 52; |
||||
uint32 oneof_uint32 = 53; |
||||
uint64 oneof_uint64 = 54; |
||||
uint32 oneof_sint32 = 55; |
||||
uint64 oneof_sint64 = 56; |
||||
uint32 oneof_fixed32 = 57; |
||||
uint64 oneof_fixed64 = 58; |
||||
uint32 oneof_sfixed32 = 59; |
||||
uint64 oneof_sfixed64 = 60; |
||||
double oneof_double = 61; |
||||
float oneof_float = 62; |
||||
bool oneof_bool = 63; |
||||
string oneof_string = 64; |
||||
bytes oneof_bytes = 65; |
||||
TestEnum oneof_enum = 66; |
||||
Sub oneof_message = 67; |
||||
} |
||||
|
||||
map<int32, int32> map_int32_int32 = 71; |
||||
map<int64, int64> map_int64_int64 = 72; |
||||
map<uint32, uint32> map_uint32_uint32 = 73; |
||||
map<uint64, uint64> map_uint64_uint64 = 74; |
||||
map<sint32, sint32> map_sint32_sint32 = 75; |
||||
map<sint64, sint64> map_sint64_sint64 = 76; |
||||
map<fixed32, fixed32> map_fixed32_fixed32 = 77; |
||||
map<fixed64, fixed64> map_fixed64_fixed64 = 78; |
||||
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 79; |
||||
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 80; |
||||
map<int32, float> map_int32_float = 81; |
||||
map<int32, double> map_int32_double = 82; |
||||
map<bool, bool> map_bool_bool = 83; |
||||
map<string, string> map_string_string = 84; |
||||
map<int32, bytes> map_int32_bytes = 85; |
||||
map<int32, TestEnum> map_int32_enum = 86; |
||||
map<int32, Sub> map_int32_message = 87; |
||||
|
||||
map<int32, TestMessage> map_recursive = 88; |
||||
|
||||
message Sub { |
||||
int32 a = 1; |
||||
} |
||||
|
||||
// NestedMessage nested_message = 90; |
||||
} |
||||
|
||||
enum TestEnum { |
||||
ZERO = 0; |
||||
ONE = 1; |
||||
} |
||||
|
||||
message TestPackedMessage { |
||||
repeated int32 repeated_int32 = 90 [packed = true]; |
||||
repeated int64 repeated_int64 = 91 [packed = true]; |
||||
repeated uint32 repeated_uint32 = 92 [packed = true]; |
||||
repeated uint64 repeated_uint64 = 93 [packed = true]; |
||||
repeated sint32 repeated_sint32 = 94 [packed = true]; |
||||
repeated sint64 repeated_sint64 = 95 [packed = true]; |
||||
repeated fixed32 repeated_fixed32 = 96 [packed = true]; |
||||
repeated fixed64 repeated_fixed64 = 97 [packed = true]; |
||||
repeated sfixed32 repeated_sfixed32 = 98 [packed = true]; |
||||
repeated sfixed64 repeated_sfixed64 = 99 [packed = true]; |
||||
repeated float repeated_float = 100 [packed = true]; |
||||
repeated double repeated_double = 101 [packed = true]; |
||||
repeated bool repeated_bool = 102 [packed = true]; |
||||
repeated TestEnum repeated_enum = 103 [packed = true]; |
||||
} |
||||
|
||||
// Need to be in sync with TestPackedMessage. |
||||
message TestUnpackedMessage { |
||||
repeated int32 repeated_int32 = 90 [packed = false]; |
||||
repeated int64 repeated_int64 = 91 [packed = false]; |
||||
repeated uint32 repeated_uint32 = 92 [packed = false]; |
||||
repeated uint64 repeated_uint64 = 93 [packed = false]; |
||||
repeated sint32 repeated_sint32 = 94 [packed = false]; |
||||
repeated sint64 repeated_sint64 = 95 [packed = false]; |
||||
repeated fixed32 repeated_fixed32 = 96 [packed = false]; |
||||
repeated fixed64 repeated_fixed64 = 97 [packed = false]; |
||||
repeated sfixed32 repeated_sfixed32 = 98 [packed = false]; |
||||
repeated sfixed64 repeated_sfixed64 = 99 [packed = false]; |
||||
repeated float repeated_float = 100 [packed = false]; |
||||
repeated double repeated_double = 101 [packed = false]; |
||||
repeated bool repeated_bool = 102 [packed = false]; |
||||
repeated TestEnum repeated_enum = 103 [packed = false]; |
||||
} |
@ -0,0 +1,23 @@ |
||||
#!/bin/bash |
||||
cd ../ext/google/protobuf/ |
||||
make clean |
||||
set -e |
||||
|
||||
phpize && ./configure --enable-debug CFLAGS='-g -O0' && make |
||||
cd - |
||||
|
||||
tests=( array_test.php encode_decode_test.php generated_class_test.php map_field_test.php ) |
||||
|
||||
for t in "${tests[@]}" |
||||
do |
||||
echo "****************************" |
||||
echo "* $t" |
||||
echo "****************************" |
||||
php -dextension=../ext/google/protobuf/modules/protobuf.so `which phpunit` $t |
||||
echo "" |
||||
done |
||||
|
||||
# Make sure to run the memory test in debug mode. |
||||
php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php |
||||
|
||||
USE_ZEND_ALLOC=0 valgrind --leak-check=yes php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php |
@ -0,0 +1,92 @@ |
||||
<?php |
||||
|
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
|
||||
class TestBase extends PHPUnit_Framework_TestCase |
||||
{ |
||||
|
||||
public function setFields(TestMessage $m) |
||||
{ |
||||
TestUtil::setTestMessage($m); |
||||
} |
||||
|
||||
public function expectFields(TestMessage $m) |
||||
{ |
||||
$this->assertSame(-42, $m->getOptionalInt32()); |
||||
$this->assertSame(42, $m->getOptionalUint32()); |
||||
$this->assertSame(-43, $m->getOptionalInt64()); |
||||
$this->assertSame(43, $m->getOptionalUint64()); |
||||
$this->assertSame(-44, $m->getOptionalSint32()); |
||||
$this->assertSame(-45, $m->getOptionalSint64()); |
||||
$this->assertSame(46, $m->getOptionalFixed32()); |
||||
$this->assertSame(47, $m->getOptionalFixed64()); |
||||
$this->assertSame(-46, $m->getOptionalSfixed32()); |
||||
$this->assertSame(-47, $m->getOptionalSfixed64()); |
||||
$this->assertSame(1.5, $m->getOptionalFloat()); |
||||
$this->assertSame(1.6, $m->getOptionalDouble()); |
||||
$this->assertSame(true, $m->getOptionalBool()); |
||||
$this->assertSame('a', $m->getOptionalString()); |
||||
$this->assertSame('b', $m->getOptionalBytes()); |
||||
$this->assertSame(33, $m->getOptionalMessage()->getA()); |
||||
|
||||
$this->assertEquals(-42, $m->getRepeatedInt32()[0]); |
||||
$this->assertEquals(42, $m->getRepeatedUint32()[0]); |
||||
$this->assertEquals(-43, $m->getRepeatedInt64()[0]); |
||||
$this->assertEquals(43, $m->getRepeatedUint64()[0]); |
||||
$this->assertEquals(-44, $m->getRepeatedSint32()[0]); |
||||
$this->assertEquals(-45, $m->getRepeatedSint64()[0]); |
||||
$this->assertEquals(46, $m->getRepeatedFixed32()[0]); |
||||
$this->assertEquals(47, $m->getRepeatedFixed64()[0]); |
||||
$this->assertEquals(-46, $m->getRepeatedSfixed32()[0]); |
||||
$this->assertEquals(-47, $m->getRepeatedSfixed64()[0]); |
||||
$this->assertEquals(1.5, $m->getRepeatedFloat()[0]); |
||||
$this->assertEquals(1.6, $m->getRepeatedDouble()[0]); |
||||
$this->assertEquals(true, $m->getRepeatedBool()[0]); |
||||
$this->assertEquals('a', $m->getRepeatedString()[0]); |
||||
$this->assertEquals('b', $m->getRepeatedBytes()[0]); |
||||
$this->assertEquals(34, $m->getRepeatedMessage()[0]->GetA()); |
||||
|
||||
$this->assertEquals(-52, $m->getRepeatedInt32()[1]); |
||||
$this->assertEquals(52, $m->getRepeatedUint32()[1]); |
||||
$this->assertEquals(-53, $m->getRepeatedInt64()[1]); |
||||
$this->assertEquals(53, $m->getRepeatedUint64()[1]); |
||||
$this->assertEquals(-54, $m->getRepeatedSint32()[1]); |
||||
$this->assertEquals(-55, $m->getRepeatedSint64()[1]); |
||||
$this->assertEquals(56, $m->getRepeatedFixed32()[1]); |
||||
$this->assertEquals(57, $m->getRepeatedFixed64()[1]); |
||||
$this->assertEquals(-56, $m->getRepeatedSfixed32()[1]); |
||||
$this->assertEquals(-57, $m->getRepeatedSfixed64()[1]); |
||||
$this->assertEquals(2.5, $m->getRepeatedFloat()[1]); |
||||
$this->assertEquals(2.6, $m->getRepeatedDouble()[1]); |
||||
$this->assertEquals(false, $m->getRepeatedBool()[1]); |
||||
$this->assertEquals('c', $m->getRepeatedString()[1]); |
||||
$this->assertEquals('d', $m->getRepeatedBytes()[1]); |
||||
$this->assertEquals(35, $m->getRepeatedMessage()[1]->GetA()); |
||||
} |
||||
|
||||
public function expectEmptyFields(TestMessage $m) |
||||
{ |
||||
$this->assertSame(0, $m->getOptionalInt32()); |
||||
$this->assertSame(0, $m->getOptionalUint32()); |
||||
$this->assertSame(0, $m->getOptionalInt64()); |
||||
$this->assertSame(0, $m->getOptionalUint64()); |
||||
$this->assertSame(0, $m->getOptionalSint32()); |
||||
$this->assertSame(0, $m->getOptionalSint64()); |
||||
$this->assertSame(0, $m->getOptionalFixed32()); |
||||
$this->assertSame(0, $m->getOptionalFixed64()); |
||||
$this->assertSame(0, $m->getOptionalSfixed32()); |
||||
$this->assertSame(0, $m->getOptionalSfixed64()); |
||||
$this->assertSame(0.0, $m->getOptionalFloat()); |
||||
$this->assertSame(0.0, $m->getOptionalDouble()); |
||||
$this->assertSame(false, $m->getOptionalBool()); |
||||
$this->assertSame('', $m->getOptionalString()); |
||||
$this->assertSame('', $m->getOptionalBytes()); |
||||
$this->assertNull($m->getOptionalMessage()); |
||||
} |
||||
|
||||
// This test is to avoid the warning of no test by php unit. |
||||
public function testNone() |
||||
{ |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
<?php |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: test_include.proto |
||||
|
||||
namespace Bar; |
||||
|
||||
use Google\Protobuf\Internal\DescriptorPool; |
||||
use Google\Protobuf\Internal\GPBType; |
||||
use Google\Protobuf\Internal\RepeatedField; |
||||
use Google\Protobuf\Internal\GPBUtil; |
||||
|
||||
class TestInclude extends \Google\Protobuf\Internal\Message |
||||
{ |
||||
private $a = 0; |
||||
|
||||
public function getA() |
||||
{ |
||||
return $this->a; |
||||
} |
||||
|
||||
public function setA($var) |
||||
{ |
||||
GPBUtil::checkInt32($var); |
||||
$this->a = $var; |
||||
} |
||||
|
||||
} |
||||
|
||||
$pool = DescriptorPool::getGeneratedPool(); |
||||
|
||||
$pool->internalAddGeneratedFile(hex2bin( |
||||
"0a3b0a12746573745f696e636c7564652e70726f746f120362617222180a" . |
||||
"0b54657374496e636c75646512090a0161180120012805620670726f746f" . |
||||
"33" |
||||
)); |
||||
|
@ -0,0 +1,393 @@ |
||||
<?php |
||||
|
||||
use Foo\TestEnum; |
||||
use Foo\TestMessage; |
||||
use Foo\TestMessage_Sub; |
||||
use Foo\TestPackedMessage; |
||||
use Foo\TestUnpackedMessage; |
||||
|
||||
define('MAX_FLOAT_DIFF', 0.000001); |
||||
|
||||
if (PHP_INT_SIZE == 8) { |
||||
define('MAX_INT_STRING', '9223372036854775807'); |
||||
define('MAX_INT_UPPER_STRING', '9223372036854775808'); |
||||
} else { |
||||
define('MAX_INT_STRING', '2147483647'); |
||||
define('MAX_INT_UPPER_STRING', '2147483648'); |
||||
} |
||||
|
||||
define('MAX_INT32', 2147483647); |
||||
define('MAX_INT32_FLOAT', 2147483647.0); |
||||
define('MAX_INT32_STRING', '2147483647'); |
||||
|
||||
define('MIN_INT32', -2147483648); |
||||
define('MIN_INT32_FLOAT', -2147483648.0); |
||||
define('MIN_INT32_STRING', '-2147483648'); |
||||
|
||||
define('MAX_UINT32', 4294967295); |
||||
define('MAX_UINT32_FLOAT', 4294967295.0); |
||||
define('MAX_UINT32_STRING', '4294967295'); |
||||
|
||||
define('MIN_UINT32', -2147483648); |
||||
define('MIN_UINT32_FLOAT', -2147483648.0); |
||||
define('MIN_UINT32_STRING', '-2147483648'); |
||||
|
||||
define('MAX_INT64', 9223372036854775807); |
||||
define('MAX_INT64_STRING', '9223372036854775807'); |
||||
|
||||
define('MIN_INT64_STRING', '-9223372036854775808'); |
||||
if (PHP_INT_SIZE === 8) { |
||||
define('MIN_INT64', -9223372036854775808); |
||||
} else { |
||||
define('MIN_INT64', MIN_INT64_STRING); |
||||
} |
||||
|
||||
define('MAX_UINT64_STRING', '-9223372036854775808'); |
||||
define('MAX_UINT64', MAX_UINT64_STRING); |
||||
|
||||
class TestUtil |
||||
{ |
||||
|
||||
public static function setTestMessage(TestMessage $m) |
||||
{ |
||||
$m->setOptionalInt32(-42); |
||||
$m->setOptionalInt64(-43); |
||||
$m->setOptionalUint32(42); |
||||
$m->setOptionalUint64(43); |
||||
$m->setOptionalSint32(-44); |
||||
$m->setOptionalSint64(-45); |
||||
$m->setOptionalFixed32(46); |
||||
$m->setOptionalFixed64(47); |
||||
$m->setOptionalSfixed32(-46); |
||||
$m->setOptionalSfixed64(-47); |
||||
$m->setOptionalFloat(1.5); |
||||
$m->setOptionalDouble(1.6); |
||||
$m->setOptionalBool(true); |
||||
$m->setOptionalString('a'); |
||||
$m->setOptionalBytes('b'); |
||||
$m->setOptionalEnum(TestEnum::ONE); |
||||
$m->setOptionalMessage(new TestMessage_Sub()); |
||||
$m->getOptionalMessage()->SetA(33); |
||||
|
||||
$m->getRepeatedInt32() []= -42; |
||||
$m->getRepeatedInt64() []= -43; |
||||
$m->getRepeatedUint32() []= 42; |
||||
$m->getRepeatedUint64() []= 43; |
||||
$m->getRepeatedSint32() []= -44; |
||||
$m->getRepeatedSint64() []= -45; |
||||
$m->getRepeatedFixed32() []= 46; |
||||
$m->getRepeatedFixed64() []= 47; |
||||
$m->getRepeatedSfixed32() []= -46; |
||||
$m->getRepeatedSfixed64() []= -47; |
||||
$m->getRepeatedFloat() []= 1.5; |
||||
$m->getRepeatedDouble() []= 1.6; |
||||
$m->getRepeatedBool() []= true; |
||||
$m->getRepeatedString() []= 'a'; |
||||
$m->getRepeatedBytes() []= 'b'; |
||||
$m->getRepeatedEnum() []= TestEnum::ZERO; |
||||
$m->getRepeatedMessage() []= new TestMessage_Sub(); |
||||
$m->getRepeatedMessage()[0]->setA(34); |
||||
|
||||
$m->getRepeatedInt32() []= -52; |
||||
$m->getRepeatedInt64() []= -53; |
||||
$m->getRepeatedUint32() []= 52; |
||||
$m->getRepeatedUint64() []= 53; |
||||
$m->getRepeatedSint32() []= -54; |
||||
$m->getRepeatedSint64() []= -55; |
||||
$m->getRepeatedFixed32() []= 56; |
||||
$m->getRepeatedFixed64() []= 57; |
||||
$m->getRepeatedSfixed32() []= -56; |
||||
$m->getRepeatedSfixed64() []= -57; |
||||
$m->getRepeatedFloat() []= 2.5; |
||||
$m->getRepeatedDouble() []= 2.6; |
||||
$m->getRepeatedBool() []= false; |
||||
$m->getRepeatedString() []= 'c'; |
||||
$m->getRepeatedBytes() []= 'd'; |
||||
$m->getRepeatedEnum() []= TestEnum::ONE; |
||||
$m->getRepeatedMessage() []= new TestMessage_Sub(); |
||||
$m->getRepeatedMessage()[1]->SetA(35); |
||||
|
||||
$m->getMapInt32Int32()[-62] = -62; |
||||
$m->getMapInt64Int64()[-63] = -63; |
||||
$m->getMapUint32Uint32()[62] = 62; |
||||
$m->getMapUint64Uint64()[63] = 63; |
||||
$m->getMapSint32Sint32()[-64] = -64; |
||||
$m->getMapSint64Sint64()[-65] = -65; |
||||
$m->getMapFixed32Fixed32()[66] = 66; |
||||
$m->getMapFixed64Fixed64()[67] = 67; |
||||
$m->getMapInt32Float()[1] = 3.5; |
||||
$m->getMapInt32Double()[1] = 3.6; |
||||
$m->getMapBoolBool()[true] = true; |
||||
$m->getMapStringString()['e'] = 'e'; |
||||
$m->getMapInt32Bytes()[1] = 'f'; |
||||
$m->getMapInt32Enum()[1] = TestEnum::ONE; |
||||
$m->getMapInt32Message()[1] = new TestMessage_Sub(); |
||||
$m->getMapInt32Message()[1]->SetA(36); |
||||
} |
||||
|
||||
public static function assertTestMessage(TestMessage $m) |
||||
{ |
||||
assert(-42 === $m->getOptionalInt32()); |
||||
assert(42 === $m->getOptionalUint32()); |
||||
assert(-43 === $m->getOptionalInt64()); |
||||
assert(43 === $m->getOptionalUint64()); |
||||
assert(-44 === $m->getOptionalSint32()); |
||||
assert(-45 === $m->getOptionalSint64()); |
||||
assert(46 === $m->getOptionalFixed32()); |
||||
assert(47 === $m->getOptionalFixed64()); |
||||
assert(-46 === $m->getOptionalSfixed32()); |
||||
assert(-47 === $m->getOptionalSfixed64()); |
||||
assert(1.5 === $m->getOptionalFloat()); |
||||
assert(1.6 === $m->getOptionalDouble()); |
||||
assert(true=== $m->getOptionalBool()); |
||||
assert('a' === $m->getOptionalString()); |
||||
assert('b' === $m->getOptionalBytes()); |
||||
assert(TestEnum::ONE === $m->getOptionalEnum()); |
||||
assert(33 === $m->getOptionalMessage()->getA()); |
||||
|
||||
assert(-42 === $m->getRepeatedInt32()[0]); |
||||
assert(42 === $m->getRepeatedUint32()[0]); |
||||
assert(-43 === $m->getRepeatedInt64()[0]); |
||||
assert(43 === $m->getRepeatedUint64()[0]); |
||||
assert(-44 === $m->getRepeatedSint32()[0]); |
||||
assert(-45 === $m->getRepeatedSint64()[0]); |
||||
assert(46 === $m->getRepeatedFixed32()[0]); |
||||
assert(47 === $m->getRepeatedFixed64()[0]); |
||||
assert(-46 === $m->getRepeatedSfixed32()[0]); |
||||
assert(-47 === $m->getRepeatedSfixed64()[0]); |
||||
assert(1.5 === $m->getRepeatedFloat()[0]); |
||||
assert(1.6 === $m->getRepeatedDouble()[0]); |
||||
assert(true=== $m->getRepeatedBool()[0]); |
||||
assert('a' === $m->getRepeatedString()[0]); |
||||
assert('b' === $m->getRepeatedBytes()[0]); |
||||
assert(TestEnum::ZERO === $m->getRepeatedEnum()[0]); |
||||
assert(34 === $m->getRepeatedMessage()[0]->getA()); |
||||
|
||||
assert(-52 === $m->getRepeatedInt32()[1]); |
||||
assert(52 === $m->getRepeatedUint32()[1]); |
||||
assert(-53 === $m->getRepeatedInt64()[1]); |
||||
assert(53 === $m->getRepeatedUint64()[1]); |
||||
assert(-54 === $m->getRepeatedSint32()[1]); |
||||
assert(-55 === $m->getRepeatedSint64()[1]); |
||||
assert(56 === $m->getRepeatedFixed32()[1]); |
||||
assert(57 === $m->getRepeatedFixed64()[1]); |
||||
assert(-56 === $m->getRepeatedSfixed32()[1]); |
||||
assert(-57 === $m->getRepeatedSfixed64()[1]); |
||||
assert(2.5 === $m->getRepeatedFloat()[1]); |
||||
assert(2.6 === $m->getRepeatedDouble()[1]); |
||||
assert(false === $m->getRepeatedBool()[1]); |
||||
assert('c' === $m->getRepeatedString()[1]); |
||||
assert('d' === $m->getRepeatedBytes()[1]); |
||||
assert(TestEnum::ONE === $m->getRepeatedEnum()[1]); |
||||
assert(35 === $m->getRepeatedMessage()[1]->getA()); |
||||
|
||||
assert(-62 === $m->getMapInt32Int32()[-62]); |
||||
assert(-63 === $m->getMapInt64Int64()[-63]); |
||||
assert(62 === $m->getMapUint32Uint32()[62]); |
||||
assert(63 === $m->getMapUint64Uint64()[63]); |
||||
assert(-64 === $m->getMapSint32Sint32()[-64]); |
||||
assert(-65 === $m->getMapSint64Sint64()[-65]); |
||||
assert(66 === $m->getMapFixed32Fixed32()[66]); |
||||
assert(67 === $m->getMapFixed64Fixed64()[67]); |
||||
assert(3.5 === $m->getMapInt32Float()[1]); |
||||
assert(3.6 === $m->getMapInt32Double()[1]); |
||||
assert(true === $m->getMapBoolBool()[true]); |
||||
assert('e' === $m->getMapStringString()['e']); |
||||
assert('f' === $m->getMapInt32Bytes()[1]); |
||||
assert(TestEnum::ONE === $m->getMapInt32Enum()[1]); |
||||
assert(36 === $m->getMapInt32Message()[1]->GetA()); |
||||
} |
||||
|
||||
public static function getGoldenTestMessage() |
||||
{ |
||||
return hex2bin( |
||||
"08D6FFFFFF0F" . |
||||
"10D5FFFFFFFFFFFFFFFF01" . |
||||
"182A" . |
||||
"202B" . |
||||
"2857" . |
||||
"3059" . |
||||
"3D2E000000" . |
||||
"412F00000000000000" . |
||||
"4DD2FFFFFF" . |
||||
"51D1FFFFFFFFFFFFFF" . |
||||
"5D0000C03F" . |
||||
"619A9999999999F93F" . |
||||
"6801" . |
||||
"720161" . |
||||
"7A0162" . |
||||
"800101" . |
||||
"8A01020821" . |
||||
|
||||
"F801D6FFFFFF0F" . |
||||
"F801CCFFFFFF0F" . |
||||
"8002D5FFFFFFFFFFFFFFFF01" . |
||||
"8002CBFFFFFFFFFFFFFFFF01" . |
||||
"88022A" . |
||||
"880234" . |
||||
"90022B" . |
||||
"900235" . |
||||
"980257" . |
||||
"98026B" . |
||||
"A00259" . |
||||
"A0026D" . |
||||
"AD022E000000" . |
||||
"AD0238000000" . |
||||
"B1022F00000000000000" . |
||||
"B1023900000000000000" . |
||||
"BD02D2FFFFFF" . |
||||
"BD02C8FFFFFF" . |
||||
"C102D1FFFFFFFFFFFFFF" . |
||||
"C102C7FFFFFFFFFFFFFF" . |
||||
"CD020000C03F" . |
||||
"CD0200002040" . |
||||
"D1029A9999999999F93F" . |
||||
"D102CDCCCCCCCCCC0440" . |
||||
"D80201" . |
||||
"D80200" . |
||||
"E2020161" . |
||||
"E2020163" . |
||||
"EA020162" . |
||||
"EA020164" . |
||||
"F00200" . |
||||
"F00201" . |
||||
"FA02020822" . |
||||
"FA02020823" . |
||||
|
||||
"BA040C08C2FFFFFF0F10C2FFFFFF0F" . |
||||
"C2041608C1FFFFFFFFFFFFFFFF0110C1FFFFFFFFFFFFFFFF01" . |
||||
"CA0404083E103E" . |
||||
"D20404083F103F" . |
||||
"DA0404087f107F" . |
||||
"E20406088101108101" . |
||||
"EA040A0D420000001542000000" . |
||||
"F20412094300000000000000114300000000000000" . |
||||
"8A050708011500006040" . |
||||
"92050B080111CDCCCCCCCCCC0C40" . |
||||
"9A050408011001" . |
||||
"A205060a0165120165" . |
||||
"AA05050801120166" . |
||||
"B2050408011001" . |
||||
"Ba0506080112020824" |
||||
); |
||||
} |
||||
|
||||
public static function setTestPackedMessage($m) |
||||
{ |
||||
$m->getRepeatedInt32()[] = -42; |
||||
$m->getRepeatedInt32()[] = -52; |
||||
$m->getRepeatedInt64()[] = -43; |
||||
$m->getRepeatedInt64()[] = -53; |
||||
$m->getRepeatedUint32()[] = 42; |
||||
$m->getRepeatedUint32()[] = 52; |
||||
$m->getRepeatedUint64()[] = 43; |
||||
$m->getRepeatedUint64()[] = 53; |
||||
$m->getRepeatedSint32()[] = -44; |
||||
$m->getRepeatedSint32()[] = -54; |
||||
$m->getRepeatedSint64()[] = -45; |
||||
$m->getRepeatedSint64()[] = -55; |
||||
$m->getRepeatedFixed32()[] = 46; |
||||
$m->getRepeatedFixed32()[] = 56; |
||||
$m->getRepeatedFixed64()[] = 47; |
||||
$m->getRepeatedFixed64()[] = 57; |
||||
$m->getRepeatedSfixed32()[] = -46; |
||||
$m->getRepeatedSfixed32()[] = -56; |
||||
$m->getRepeatedSfixed64()[] = -47; |
||||
$m->getRepeatedSfixed64()[] = -57; |
||||
$m->getRepeatedFloat()[] = 1.5; |
||||
$m->getRepeatedFloat()[] = 2.5; |
||||
$m->getRepeatedDouble()[] = 1.6; |
||||
$m->getRepeatedDouble()[] = 2.6; |
||||
$m->getRepeatedBool()[] = true; |
||||
$m->getRepeatedBool()[] = false; |
||||
$m->getRepeatedEnum()[] = TestEnum::ONE; |
||||
$m->getRepeatedEnum()[] = TestEnum::ZERO; |
||||
} |
||||
|
||||
public static function assertTestPackedMessage($m) |
||||
{ |
||||
assert(2 === count($m->getRepeatedInt32())); |
||||
assert(2 === count($m->getRepeatedInt64())); |
||||
assert(2 === count($m->getRepeatedUint32())); |
||||
assert(2 === count($m->getRepeatedUint64())); |
||||
assert(2 === count($m->getRepeatedSint32())); |
||||
assert(2 === count($m->getRepeatedSint64())); |
||||
assert(2 === count($m->getRepeatedFixed32())); |
||||
assert(2 === count($m->getRepeatedFixed64())); |
||||
assert(2 === count($m->getRepeatedSfixed32())); |
||||
assert(2 === count($m->getRepeatedSfixed64())); |
||||
assert(2 === count($m->getRepeatedFloat())); |
||||
assert(2 === count($m->getRepeatedDouble())); |
||||
assert(2 === count($m->getRepeatedBool())); |
||||
assert(2 === count($m->getRepeatedEnum())); |
||||
|
||||
assert(-42 === $m->getRepeatedInt32()[0]); |
||||
assert(-52 === $m->getRepeatedInt32()[1]); |
||||
assert(-43 === $m->getRepeatedInt64()[0]); |
||||
assert(-53 === $m->getRepeatedInt64()[1]); |
||||
assert(42 === $m->getRepeatedUint32()[0]); |
||||
assert(52 === $m->getRepeatedUint32()[1]); |
||||
assert(43 === $m->getRepeatedUint64()[0]); |
||||
assert(53 === $m->getRepeatedUint64()[1]); |
||||
assert(-44 === $m->getRepeatedSint32()[0]); |
||||
assert(-54 === $m->getRepeatedSint32()[1]); |
||||
assert(-45 === $m->getRepeatedSint64()[0]); |
||||
assert(-55 === $m->getRepeatedSint64()[1]); |
||||
assert(46 === $m->getRepeatedFixed32()[0]); |
||||
assert(56 === $m->getRepeatedFixed32()[1]); |
||||
assert(47 === $m->getRepeatedFixed64()[0]); |
||||
assert(57 === $m->getRepeatedFixed64()[1]); |
||||
assert(-46 === $m->getRepeatedSfixed32()[0]); |
||||
assert(-56 === $m->getRepeatedSfixed32()[1]); |
||||
assert(-47 === $m->getRepeatedSfixed64()[0]); |
||||
assert(-57 === $m->getRepeatedSfixed64()[1]); |
||||
assert(1.5 === $m->getRepeatedFloat()[0]); |
||||
assert(2.5 === $m->getRepeatedFloat()[1]); |
||||
assert(1.6 === $m->getRepeatedDouble()[0]); |
||||
assert(2.6 === $m->getRepeatedDouble()[1]); |
||||
assert(true === $m->getRepeatedBool()[0]); |
||||
assert(false === $m->getRepeatedBool()[1]); |
||||
assert(TestEnum::ONE === $m->getRepeatedEnum()[0]); |
||||
assert(TestEnum::ZERO === $m->getRepeatedEnum()[1]); |
||||
} |
||||
|
||||
public static function getGoldenTestPackedMessage() |
||||
{ |
||||
return hex2bin( |
||||
"D2050AD6FFFFFF0FCCFFFFFF0F" . |
||||
"DA0514D5FFFFFFFFFFFFFFFF01CBFFFFFFFFFFFFFFFF01" . |
||||
"E205022A34" . |
||||
"EA05022B35" . |
||||
"F20502576B" . |
||||
"FA0502596D" . |
||||
"8206082E00000038000000" . |
||||
"8A06102F000000000000003900000000000000" . |
||||
"920608D2FFFFFFC8FFFFFF" . |
||||
"9A0610D1FFFFFFFFFFFFFFC7FFFFFFFFFFFFFF" . |
||||
"A206080000C03F00002040" . |
||||
"AA06109A9999999999F93FCDCCCCCCCCCC0440" . |
||||
"B206020100" . |
||||
"BA06020100" |
||||
); |
||||
} |
||||
|
||||
public static function getGoldenTestUnpackedMessage() |
||||
{ |
||||
return hex2bin( |
||||
"D005D6FFFFFF0FD005CCFFFFFF0F" . |
||||
"D805D5FFFFFFFFFFFFFFFF01D805CBFFFFFFFFFFFFFFFF01" . |
||||
"E0052AE00534" . |
||||
"E8052BE80535" . |
||||
"F00557F0056B" . |
||||
"F80559F8056D" . |
||||
"85062E000000850638000000" . |
||||
"89062F0000000000000089063900000000000000" . |
||||
"9506D2FFFFFF9506C8FFFFFF" . |
||||
"9906D1FFFFFFFFFFFFFF9906C7FFFFFFFFFFFFFF" . |
||||
"A5060000C03FA50600002040" . |
||||
"A9069A9999999999F93FA906CDCCCCCCCCCC0440" . |
||||
"B00601B00600" . |
||||
"B80601B80600" |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<phpunit bootstrap="./vendor/autoload.php" |
||||
colors="true"> |
||||
<testsuites> |
||||
<testsuite name="protobuf-tests"> |
||||
<file>php/tests/php_implementation_test.php</file> |
||||
<file>php/tests/array_test.php</file> |
||||
<file>php/tests/encode_decode_test.php</file> |
||||
<file>php/tests/generated_class_test.php</file> |
||||
<file>php/tests/map_field_test.php</file> |
||||
</testsuite> |
||||
</testsuites> |
||||
</phpunit> |
@ -0,0 +1,781 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/compiler/php/php_generator.h> |
||||
|
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
#include <google/protobuf/compiler/plugin.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
#include <sstream> |
||||
|
||||
using google::protobuf::internal::scoped_ptr; |
||||
|
||||
const std::string kDescriptorFile = "google/protobuf/descriptor.proto"; |
||||
const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal"; |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace php { |
||||
|
||||
// Forward decls.
|
||||
std::string PhpName(const std::string& full_name, bool is_descriptor); |
||||
std::string DefaultForField(google::protobuf::FieldDescriptor* field); |
||||
std::string IntToString(int32 value); |
||||
std::string GeneratedFileName(const std::string& proto_file, |
||||
bool is_descriptor); |
||||
std::string LabelForField(google::protobuf::FieldDescriptor* field); |
||||
std::string TypeName(google::protobuf::FieldDescriptor* field); |
||||
std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter); |
||||
std::string EscapeDollor(const string& to_escape); |
||||
std::string BinaryToHex(const string& binary); |
||||
void GenerateMessage(const string& name_prefix, |
||||
const google::protobuf::Descriptor* message, |
||||
bool is_descriptor, |
||||
google::protobuf::io::Printer* printer); |
||||
void GenerateEnum(const google::protobuf::EnumDescriptor* en, |
||||
google::protobuf::io::Printer* printer); |
||||
void Indent(google::protobuf::io::Printer* printer); |
||||
void Outdent(google::protobuf::io::Printer* printer); |
||||
|
||||
std::string MessageName(const google::protobuf::Descriptor* message, |
||||
bool is_descriptor) { |
||||
string message_name = message->name(); |
||||
const google::protobuf::Descriptor* descriptor = message->containing_type(); |
||||
while (descriptor != NULL) { |
||||
message_name = descriptor->name() + '_' + message_name; |
||||
descriptor = descriptor->containing_type(); |
||||
} |
||||
return PhpName(message->file()->package(), is_descriptor) + '\\' + |
||||
message_name; |
||||
} |
||||
|
||||
std::string MessageFullName(const google::protobuf::Descriptor* message, |
||||
bool is_descriptor) { |
||||
if (is_descriptor) { |
||||
return StringReplace(message->full_name(), |
||||
"google.protobuf", |
||||
"google.protobuf.internal", false); |
||||
} else { |
||||
return message->full_name(); |
||||
} |
||||
} |
||||
|
||||
std::string EnumFullName(const google::protobuf::EnumDescriptor* envm, |
||||
bool is_descriptor) { |
||||
if (is_descriptor) { |
||||
return StringReplace(envm->full_name(), |
||||
"google.protobuf", |
||||
"google.protobuf.internal", false); |
||||
} else { |
||||
return envm->full_name(); |
||||
} |
||||
} |
||||
|
||||
std::string EnumClassName(const google::protobuf::EnumDescriptor* envm) { |
||||
string enum_class_name = envm->name(); |
||||
const google::protobuf::Descriptor* descriptor = envm->containing_type(); |
||||
while (descriptor != NULL) { |
||||
enum_class_name = descriptor->name() + '_' + enum_class_name; |
||||
descriptor = descriptor->containing_type(); |
||||
} |
||||
return enum_class_name; |
||||
} |
||||
|
||||
std::string EnumName(const google::protobuf::EnumDescriptor* envm, |
||||
bool is_descriptor) { |
||||
string enum_name = EnumClassName(envm); |
||||
return PhpName(envm->file()->package(), is_descriptor) + '\\' + enum_name; |
||||
} |
||||
|
||||
std::string PhpName(const std::string& full_name, bool is_descriptor) { |
||||
if (is_descriptor) { |
||||
return kDescriptorPackageName; |
||||
} |
||||
|
||||
std::string result; |
||||
bool cap_next_letter = true; |
||||
for (int i = 0; i < full_name.size(); i++) { |
||||
if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) { |
||||
result += full_name[i] + ('A' - 'a'); |
||||
cap_next_letter = false; |
||||
} else if (full_name[i] == '.') { |
||||
result += '\\'; |
||||
cap_next_letter = true; |
||||
} else { |
||||
result += full_name[i]; |
||||
cap_next_letter = false; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
std::string DefaultForField(const google::protobuf::FieldDescriptor* field) { |
||||
switch (field->type()) { |
||||
case FieldDescriptor::TYPE_INT32: |
||||
case FieldDescriptor::TYPE_INT64: |
||||
case FieldDescriptor::TYPE_UINT32: |
||||
case FieldDescriptor::TYPE_UINT64: |
||||
case FieldDescriptor::TYPE_SINT32: |
||||
case FieldDescriptor::TYPE_SINT64: |
||||
case FieldDescriptor::TYPE_FIXED32: |
||||
case FieldDescriptor::TYPE_FIXED64: |
||||
case FieldDescriptor::TYPE_SFIXED32: |
||||
case FieldDescriptor::TYPE_SFIXED64: |
||||
case FieldDescriptor::TYPE_ENUM: return "0"; |
||||
case FieldDescriptor::TYPE_DOUBLE: |
||||
case FieldDescriptor::TYPE_FLOAT: return "0.0"; |
||||
case FieldDescriptor::TYPE_BOOL: return "false"; |
||||
case FieldDescriptor::TYPE_STRING: |
||||
case FieldDescriptor::TYPE_BYTES: return "''"; |
||||
case FieldDescriptor::TYPE_MESSAGE: |
||||
case FieldDescriptor::TYPE_GROUP: return "null"; |
||||
default: assert(false); return ""; |
||||
} |
||||
} |
||||
|
||||
std::string GeneratedFileName(const std::string& proto_file, |
||||
bool is_descriptor) { |
||||
if (is_descriptor) { |
||||
return "descriptor_internal.pb.php"; |
||||
} else { |
||||
int lastindex = proto_file.find_last_of("."); |
||||
return proto_file.substr(0, lastindex) + ".pb.php"; |
||||
} |
||||
} |
||||
|
||||
std::string IntToString(int32 value) { |
||||
std::ostringstream os; |
||||
os << value; |
||||
return os.str(); |
||||
} |
||||
|
||||
std::string LabelForField(const google::protobuf::FieldDescriptor* field) { |
||||
switch (field->label()) { |
||||
case FieldDescriptor::LABEL_OPTIONAL: return "optional"; |
||||
case FieldDescriptor::LABEL_REQUIRED: return "required"; |
||||
case FieldDescriptor::LABEL_REPEATED: return "repeated"; |
||||
default: assert(false); return ""; |
||||
} |
||||
} |
||||
|
||||
std::string TypeName(const google::protobuf::FieldDescriptor* field) { |
||||
switch (field->type()) { |
||||
case FieldDescriptor::TYPE_INT32: return "int32"; |
||||
case FieldDescriptor::TYPE_INT64: return "int64"; |
||||
case FieldDescriptor::TYPE_UINT32: return "uint32"; |
||||
case FieldDescriptor::TYPE_UINT64: return "uint64"; |
||||
case FieldDescriptor::TYPE_SINT32: return "sint32"; |
||||
case FieldDescriptor::TYPE_SINT64: return "sint64"; |
||||
case FieldDescriptor::TYPE_FIXED32: return "fixed32"; |
||||
case FieldDescriptor::TYPE_FIXED64: return "fixed64"; |
||||
case FieldDescriptor::TYPE_SFIXED32: return "sfixed32"; |
||||
case FieldDescriptor::TYPE_SFIXED64: return "sfixed64"; |
||||
case FieldDescriptor::TYPE_DOUBLE: return "double"; |
||||
case FieldDescriptor::TYPE_FLOAT: return "float"; |
||||
case FieldDescriptor::TYPE_BOOL: return "bool"; |
||||
case FieldDescriptor::TYPE_ENUM: return "enum"; |
||||
case FieldDescriptor::TYPE_STRING: return "string"; |
||||
case FieldDescriptor::TYPE_BYTES: return "bytes"; |
||||
case FieldDescriptor::TYPE_MESSAGE: return "message"; |
||||
case FieldDescriptor::TYPE_GROUP: return "group"; |
||||
default: assert(false); return ""; |
||||
} |
||||
} |
||||
|
||||
std::string EnumOrMessageSuffix( |
||||
const google::protobuf::FieldDescriptor* field, bool is_descriptor) { |
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
||||
return ", '" + MessageFullName(field->message_type(), is_descriptor) + "'"; |
||||
} |
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
||||
return ", '" + EnumFullName(field->enum_type(), is_descriptor) + "'"; |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
// Converts a name to camel-case. If cap_first_letter is true, capitalize the
|
||||
// first letter.
|
||||
std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) { |
||||
std::string result; |
||||
for (int i = 0; i < input.size(); i++) { |
||||
if ('a' <= input[i] && input[i] <= 'z') { |
||||
if (cap_first_letter) { |
||||
result += input[i] + ('A' - 'a'); |
||||
} else { |
||||
result += input[i]; |
||||
} |
||||
cap_first_letter = false; |
||||
} else if ('A' <= input[i] && input[i] <= 'Z') { |
||||
if (i == 0 && !cap_first_letter) { |
||||
// Force first letter to lower-case unless explicitly told to
|
||||
// capitalize it.
|
||||
result += input[i] + ('a' - 'A'); |
||||
} else { |
||||
// Capital letters after the first are left as-is.
|
||||
result += input[i]; |
||||
} |
||||
cap_first_letter = false; |
||||
} else if ('0' <= input[i] && input[i] <= '9') { |
||||
result += input[i]; |
||||
cap_first_letter = true; |
||||
} else { |
||||
cap_first_letter = true; |
||||
} |
||||
} |
||||
// Add a trailing "_" if the name should be altered.
|
||||
if (input[input.size() - 1] == '#') { |
||||
result += '_'; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
std::string EscapeDollor(const string& to_escape) { |
||||
return StringReplace(to_escape, "$", "\\$", true); |
||||
} |
||||
|
||||
std::string BinaryToHex(const string& src) { |
||||
string dest; |
||||
size_t i; |
||||
unsigned char symbol[16] = { |
||||
'0', '1', '2', '3', |
||||
'4', '5', '6', '7', |
||||
'8', '9', 'a', 'b', |
||||
'c', 'd', 'e', 'f', |
||||
}; |
||||
|
||||
dest.resize(src.size() * 2); |
||||
char* append_ptr = &dest[0]; |
||||
|
||||
for (i = 0; i < src.size(); i++) { |
||||
*append_ptr++ = symbol[(src[i] & 0xf0) >> 4]; |
||||
*append_ptr++ = symbol[src[i] & 0x0f]; |
||||
} |
||||
|
||||
return dest; |
||||
} |
||||
|
||||
void Indent(google::protobuf::io::Printer* printer) { |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
} |
||||
void Outdent(google::protobuf::io::Printer* printer) { |
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
} |
||||
|
||||
void GenerateField(const google::protobuf::FieldDescriptor* field, |
||||
google::protobuf::io::Printer* printer, bool is_descriptor) { |
||||
if (field->is_repeated()) { |
||||
printer->Print( |
||||
"private $@name@;\n", |
||||
"name", field->name()); |
||||
} else if (field->containing_oneof()) { |
||||
// Oneof fields are handled by GenerateOneofField.
|
||||
return; |
||||
} else { |
||||
printer->Print( |
||||
"private $@name@ = @default@;\n", |
||||
"name", field->name(), |
||||
"default", DefaultForField(field)); |
||||
} |
||||
|
||||
if (is_descriptor) { |
||||
printer->Print( |
||||
"private $has_@name@ = false;\n", |
||||
"name", field->name()); |
||||
} |
||||
} |
||||
|
||||
void GenerateOneofField(const google::protobuf::OneofDescriptor* oneof, |
||||
google::protobuf::io::Printer* printer) { |
||||
// Oneof property needs to be protected in order to be accessed by parent
|
||||
// class in implementation.
|
||||
printer->Print( |
||||
"protected $@name@;\n", |
||||
"name", oneof->name()); |
||||
} |
||||
|
||||
void GenerateFieldAccessor(const google::protobuf::FieldDescriptor* field, |
||||
bool is_descriptor, |
||||
google::protobuf::io::Printer* printer) { |
||||
const OneofDescriptor* oneof = field->containing_oneof(); |
||||
|
||||
// Generate getter.
|
||||
if (oneof != NULL) { |
||||
printer->Print( |
||||
"public function get@camel_name@()\n" |
||||
"{\n" |
||||
" return $this->readOneof(@number@);\n" |
||||
"}\n\n", |
||||
"camel_name", UnderscoresToCamelCase(field->name(), true), |
||||
"number", IntToString(field->number())); |
||||
} else { |
||||
printer->Print( |
||||
"public function get@camel_name@()\n" |
||||
"{\n" |
||||
" return $this->@name@;\n" |
||||
"}\n\n", |
||||
"camel_name", UnderscoresToCamelCase(field->name(), true), "name", |
||||
field->name()); |
||||
} |
||||
|
||||
// Generate setter.
|
||||
printer->Print( |
||||
"public function set@camel_name@(@var@)\n" |
||||
"{\n", |
||||
"camel_name", UnderscoresToCamelCase(field->name(), true), |
||||
"var", (field->is_repeated() || |
||||
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? |
||||
"&$var": "$var"); |
||||
|
||||
Indent(printer); |
||||
|
||||
// Type check.
|
||||
if (field->is_map()) { |
||||
} else if (field->is_repeated()) { |
||||
printer->Print( |
||||
"GPBUtil::checkRepeatedField($var, GPBType::@type@", |
||||
"type", ToUpper(field->type_name())); |
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
||||
printer->Print( |
||||
", \\@class_name@);\n", |
||||
"class_name", |
||||
MessageName(field->message_type(), is_descriptor) + "::class"); |
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
||||
printer->Print( |
||||
", @class_name@);\n", |
||||
"class_name", |
||||
EnumName(field->enum_type(), is_descriptor) + "::class"); |
||||
} else { |
||||
printer->Print(");\n"); |
||||
} |
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
||||
printer->Print( |
||||
"GPBUtil::checkMessage($var, \\@class_name@::class);\n", |
||||
"class_name", MessageName(field->message_type(), is_descriptor)); |
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
||||
printer->Print( |
||||
"GPBUtil::checkEnum($var, \\@class_name@::class);\n", |
||||
"class_name", EnumName(field->enum_type(), is_descriptor)); |
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { |
||||
printer->Print( |
||||
"GPBUtil::checkString($var, @utf8@);\n", |
||||
"utf8", |
||||
field->type() == FieldDescriptor::TYPE_STRING ? "True": "False"); |
||||
} else { |
||||
printer->Print( |
||||
"GPBUtil::check@type@($var);\n", |
||||
"type", UnderscoresToCamelCase(field->cpp_type_name(), true)); |
||||
} |
||||
|
||||
if (oneof != NULL) { |
||||
printer->Print( |
||||
"$this->writeOneof(@number@, $var);\n", |
||||
"number", IntToString(field->number())); |
||||
} else { |
||||
printer->Print( |
||||
"$this->@name@ = $var;\n", |
||||
"name", field->name()); |
||||
} |
||||
|
||||
// Set has bit for proto2 only.
|
||||
if (is_descriptor) { |
||||
printer->Print( |
||||
"$this->has_@field_name@ = true;\n", |
||||
"field_name", field->name()); |
||||
} |
||||
|
||||
Outdent(printer); |
||||
|
||||
printer->Print( |
||||
"}\n\n"); |
||||
|
||||
// Generate has method for proto2 only.
|
||||
if (is_descriptor) { |
||||
printer->Print( |
||||
"public function has@camel_name@()\n" |
||||
"{\n" |
||||
" return $this->has_@field_name@;\n" |
||||
"}\n\n", |
||||
"camel_name", UnderscoresToCamelCase(field->name(), true), |
||||
"field_name", field->name()); |
||||
} |
||||
} |
||||
|
||||
void GenerateRepeatedFieldDecode( |
||||
const google::protobuf::FieldDescriptor* field, |
||||
google::protobuf::io::Printer* printer) { |
||||
printer->Print( |
||||
"if ($input->read@cap_wire_type@($var)) return False;\n" |
||||
"$this->get@cap_field_name@() []= $var;\n", |
||||
"cap_field_name", UnderscoresToCamelCase(field->name(), true), |
||||
"cap_wire_type", UnderscoresToCamelCase(field->type_name(), true)); |
||||
} |
||||
|
||||
void GeneratePrimitiveFieldDecode( |
||||
const google::protobuf::FieldDescriptor* field, |
||||
google::protobuf::io::Printer* printer) { |
||||
printer->Print( |
||||
"if ($input->read@cap_wire_type@($var)) return False;\n" |
||||
"$this->set@cap_field_name@($var);\n", |
||||
"cap_field_name", UnderscoresToCamelCase(field->name(), true), |
||||
"cap_wire_type", UnderscoresToCamelCase(field->type_name(), true)); |
||||
} |
||||
|
||||
void GenerateFieldDecode(const google::protobuf::FieldDescriptor* field, |
||||
google::protobuf::io::Printer* printer) { |
||||
printer->Print( |
||||
"case @number@:\n", |
||||
"number", IntToString(field->number())); |
||||
Indent(printer); |
||||
|
||||
if (field->is_repeated()) { |
||||
GenerateRepeatedFieldDecode(field, printer); |
||||
} else { |
||||
GeneratePrimitiveFieldDecode(field, printer); |
||||
} |
||||
|
||||
printer->Print( |
||||
"break;\n"); |
||||
Outdent(printer); |
||||
} |
||||
|
||||
void GenerateMessage(const string& name_prefix, |
||||
const google::protobuf::Descriptor* message, |
||||
bool is_descriptor, |
||||
google::protobuf::io::Printer* printer) { |
||||
// Don't generate MapEntry messages -- we use the PHP extension's native
|
||||
// support for map fields instead.
|
||||
if (message->options().map_entry()) { |
||||
return; |
||||
} |
||||
|
||||
string message_name = name_prefix.empty()? |
||||
message->name() : name_prefix + "_" + message->name(); |
||||
|
||||
printer->Print( |
||||
"class @name@ extends \\Google\\Protobuf\\Internal\\Message\n" |
||||
"{\n", |
||||
"name", message_name); |
||||
Indent(printer); |
||||
|
||||
// Field and oneof definitions.
|
||||
for (int i = 0; i < message->field_count(); i++) { |
||||
const FieldDescriptor* field = message->field(i); |
||||
GenerateField(field, printer, is_descriptor); |
||||
} |
||||
for (int i = 0; i < message->oneof_decl_count(); i++) { |
||||
const OneofDescriptor* oneof = message->oneof_decl(i); |
||||
GenerateOneofField(oneof, printer); |
||||
} |
||||
printer->Print("\n"); |
||||
|
||||
// Field and oneof accessors.
|
||||
for (int i = 0; i < message->field_count(); i++) { |
||||
const FieldDescriptor* field = message->field(i); |
||||
GenerateFieldAccessor(field, is_descriptor, printer); |
||||
} |
||||
for (int i = 0; i < message->oneof_decl_count(); i++) { |
||||
const google::protobuf::OneofDescriptor* oneof = message->oneof_decl(i); |
||||
printer->Print( |
||||
"public function get@camel_name@()\n" |
||||
"{\n" |
||||
" return $this->@name@;\n" |
||||
"}\n\n", |
||||
"camel_name", UnderscoresToCamelCase(oneof->name(), true), "name", |
||||
oneof->name()); |
||||
} |
||||
|
||||
Outdent(printer); |
||||
printer->Print("}\n\n"); |
||||
|
||||
// Nested messages and enums.
|
||||
for (int i = 0; i < message->nested_type_count(); i++) { |
||||
GenerateMessage(message_name, message->nested_type(i), is_descriptor, |
||||
printer); |
||||
} |
||||
for (int i = 0; i < message->enum_type_count(); i++) { |
||||
GenerateEnum(message->enum_type(i), printer); |
||||
} |
||||
} |
||||
|
||||
void GenerateEnumToPool(const google::protobuf::EnumDescriptor* en, |
||||
bool is_descriptor, |
||||
google::protobuf::io::Printer* printer) { |
||||
printer->Print( |
||||
"$pool->addEnum('@name@', @class_name@::class)\n", |
||||
"name", EnumFullName(en, is_descriptor), |
||||
"class_name", en->name()); |
||||
Indent(printer); |
||||
|
||||
for (int i = 0; i < en->value_count(); i++) { |
||||
const EnumValueDescriptor* value = en->value(i); |
||||
printer->Print( |
||||
"->value(\"@name@\", @number@)\n", |
||||
"name", value->name(), |
||||
"number", IntToString(value->number())); |
||||
} |
||||
printer->Print("->finalizeToPool();\n\n"); |
||||
Outdent(printer); |
||||
} |
||||
|
||||
void GenerateMessageToPool(const string& name_prefix, |
||||
const google::protobuf::Descriptor* message, |
||||
bool is_descriptor, |
||||
google::protobuf::io::Printer* printer) { |
||||
// Don't generate MapEntry messages -- we use the PHP extension's native
|
||||
// support for map fields instead.
|
||||
if (message->options().map_entry()) { |
||||
return; |
||||
} |
||||
string class_name = name_prefix.empty()? |
||||
message->name() : name_prefix + "_" + message->name(); |
||||
|
||||
printer->Print( |
||||
"$pool->addMessage('@message@', @class_name@::class)\n", |
||||
"message", MessageFullName(message, is_descriptor), |
||||
"class_name", class_name); |
||||
|
||||
Indent(printer); |
||||
|
||||
for (int i = 0; i < message->field_count(); i++) { |
||||
const FieldDescriptor* field = message->field(i); |
||||
if (field->is_map()) { |
||||
const FieldDescriptor* key = |
||||
field->message_type()->FindFieldByName("key"); |
||||
const FieldDescriptor* val = |
||||
field->message_type()->FindFieldByName("value"); |
||||
printer->Print( |
||||
"->map('@field@', GPBType::@key@, " |
||||
"GPBType::@value@, @number@@other@)\n", |
||||
"field", field->name(), |
||||
"key", ToUpper(key->type_name()), |
||||
"value", ToUpper(val->type_name()), |
||||
"number", SimpleItoa(field->number()), |
||||
"other", EnumOrMessageSuffix(val, is_descriptor)); |
||||
} else if (!field->containing_oneof()) { |
||||
printer->Print( |
||||
"->@label@('@field@', GPBType::@type@, @number@@other@)\n", |
||||
"field", field->name(), |
||||
"label", LabelForField(field), |
||||
"type", ToUpper(field->type_name()), |
||||
"number", SimpleItoa(field->number()), |
||||
"other", EnumOrMessageSuffix(field, is_descriptor)); |
||||
} |
||||
} |
||||
|
||||
// oneofs.
|
||||
for (int i = 0; i < message->oneof_decl_count(); i++) { |
||||
const OneofDescriptor* oneof = message->oneof_decl(i); |
||||
printer->Print("->oneof(@name@)\n", |
||||
"name", oneof->name()); |
||||
Indent(printer); |
||||
for (int index = 0; index < oneof->field_count(); index++) { |
||||
const FieldDescriptor* field = oneof->field(index); |
||||
printer->Print( |
||||
"->value('@field@', GPBType::@type@, @number@@other@)\n", |
||||
"field", field->name(), |
||||
"type", ToUpper(field->type_name()), |
||||
"number", SimpleItoa(field->number()), |
||||
"other", EnumOrMessageSuffix(field, is_descriptor)); |
||||
} |
||||
printer->Print("->finish()\n"); |
||||
Outdent(printer); |
||||
} |
||||
|
||||
printer->Print( |
||||
"->finalizeToPool();\n"); |
||||
|
||||
Outdent(printer); |
||||
|
||||
printer->Print( |
||||
"\n"); |
||||
|
||||
for (int i = 0; i < message->nested_type_count(); i++) { |
||||
GenerateMessageToPool(class_name, message->nested_type(i), is_descriptor, |
||||
printer); |
||||
} |
||||
for (int i = 0; i < message->enum_type_count(); i++) { |
||||
GenerateEnumToPool(message->enum_type(i), is_descriptor, printer); |
||||
} |
||||
} |
||||
|
||||
void GenerateAddFileToPool(const google::protobuf::FileDescriptor* file, |
||||
bool is_descriptor, |
||||
google::protobuf::io::Printer* printer) { |
||||
if (is_descriptor) { |
||||
printer->Print("$pool = DescriptorPool::getGeneratedPool();\n\n"); |
||||
|
||||
for (int i = 0; i < file->message_type_count(); i++) { |
||||
GenerateMessageToPool("", file->message_type(i), is_descriptor, printer); |
||||
} |
||||
for (int i = 0; i < file->enum_type_count(); i++) { |
||||
GenerateEnumToPool(file->enum_type(i), is_descriptor, printer); |
||||
} |
||||
|
||||
printer->Print( |
||||
"$pool->finish();\n"); |
||||
} else { |
||||
// Add messages and enums to descriptor pool.
|
||||
printer->Print("$pool = DescriptorPool::getGeneratedPool();\n\n"); |
||||
|
||||
FileDescriptorSet files; |
||||
FileDescriptorProto* file_proto = files.add_file(); |
||||
file->CopyTo(file_proto); |
||||
string files_data; |
||||
files.SerializeToString(&files_data); |
||||
|
||||
printer->Print("$pool->internalAddGeneratedFile(hex2bin(\n"); |
||||
Indent(printer); |
||||
|
||||
// Only write 30 bytes per line.
|
||||
static const int kBytesPerLine = 30; |
||||
for (int i = 0; i < files_data.size(); i += kBytesPerLine) { |
||||
printer->Print( |
||||
"\"@data@\"@dot@\n", |
||||
"data", BinaryToHex(files_data.substr(i, kBytesPerLine)), |
||||
"dot", i + kBytesPerLine < files_data.size() ? " ." : ""); |
||||
} |
||||
|
||||
Outdent(printer); |
||||
printer->Print( |
||||
"));\n\n"); |
||||
} |
||||
|
||||
} |
||||
|
||||
void GenerateEnum(const google::protobuf::EnumDescriptor* en, |
||||
google::protobuf::io::Printer* printer) { |
||||
printer->Print( |
||||
"class @name@\n" |
||||
"{\n", |
||||
"name", EnumClassName(en)); |
||||
Indent(printer); |
||||
|
||||
for (int i = 0; i < en->value_count(); i++) { |
||||
const EnumValueDescriptor* value = en->value(i); |
||||
printer->Print("const @name@ = @number@;\n", |
||||
"name", value->name(), |
||||
"number", IntToString(value->number())); |
||||
} |
||||
Outdent(printer); |
||||
printer->Print("}\n\n"); |
||||
} |
||||
|
||||
void GenerateUseDeclaration(bool is_descriptor, |
||||
google::protobuf::io::Printer* printer) { |
||||
if (!is_descriptor) { |
||||
printer->Print( |
||||
"use Google\\Protobuf\\Internal\\DescriptorPool;\n" |
||||
"use Google\\Protobuf\\Internal\\GPBType;\n" |
||||
"use Google\\Protobuf\\Internal\\RepeatedField;\n" |
||||
"use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); |
||||
} else { |
||||
printer->Print( |
||||
"use Google\\Protobuf\\Internal\\DescriptorPool;\n" |
||||
"use Google\\Protobuf\\Internal\\GPBType;\n" |
||||
"use Google\\Protobuf\\Internal\\GPBWire;\n" |
||||
"use Google\\Protobuf\\Internal\\RepeatedField;\n" |
||||
"use Google\\Protobuf\\Internal\\InputStream;\n\n" |
||||
"use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); |
||||
} |
||||
} |
||||
|
||||
void GenerateFile(const google::protobuf::FileDescriptor* file, |
||||
bool is_descriptor, google::protobuf::io::Printer* printer) { |
||||
printer->Print( |
||||
"<?php\n" |
||||
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
||||
"# source: @filename@\n" |
||||
"\n", |
||||
"filename", file->name()); |
||||
if (!file->package().empty()) { |
||||
printer->Print("namespace @name@;\n\n", |
||||
"name", PhpName(file->package(), is_descriptor)); |
||||
} |
||||
|
||||
for (int i = 0; i < file->dependency_count(); i++) { |
||||
const std::string& name = file->dependency(i)->name(); |
||||
printer->Print("require_once('@name@');\n", "name", |
||||
GeneratedFileName(name, is_descriptor)); |
||||
} |
||||
|
||||
GenerateUseDeclaration(is_descriptor, printer); |
||||
|
||||
for (int i = 0; i < file->message_type_count(); i++) { |
||||
GenerateMessage("", file->message_type(i), is_descriptor, printer); |
||||
} |
||||
for (int i = 0; i < file->enum_type_count(); i++) { |
||||
GenerateEnum(file->enum_type(i), printer); |
||||
} |
||||
|
||||
GenerateAddFileToPool(file, is_descriptor, printer); |
||||
} |
||||
|
||||
bool Generator::Generate( |
||||
const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error) const { |
||||
bool is_descriptor = parameter == "internal"; |
||||
|
||||
if (is_descriptor && file->name() != kDescriptorFile) { |
||||
*error = |
||||
"Can only generate PHP code for google/protobuf/descriptor.proto.\n"; |
||||
return false; |
||||
} |
||||
|
||||
if (!is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) { |
||||
*error = |
||||
"Can only generate PHP code for proto3 .proto files.\n" |
||||
"Please add 'syntax = \"proto3\";' to the top of your .proto file.\n"; |
||||
return false; |
||||
} |
||||
|
||||
std::string filename = GeneratedFileName(file->name(), is_descriptor); |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
generator_context->Open(filename)); |
||||
io::Printer printer(output.get(), '@'); |
||||
|
||||
GenerateFile(file, is_descriptor, &printer); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
} // namespace php
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,57 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__ |
||||
|
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
|
||||
#include <string> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace php { |
||||
|
||||
class LIBPROTOC_EXPORT Generator |
||||
: public google::protobuf::compiler::CodeGenerator { |
||||
virtual bool Generate( |
||||
const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error) const; |
||||
}; |
||||
|
||||
} // namespace php
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PHP_GENERATOR_H__
|
Loading…
Reference in new issue