diff options
author | Paul Yang <TeBoring@users.noreply.github.com> | 2017-08-25 08:49:34 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-25 08:49:34 -0700 |
commit | c7457ef65a7a8584b1e3bd396c401ccf8e275ffa (patch) | |
tree | a142f1ed092807b1bd38683f57e37bcf852f665a /php/ext/google/protobuf/message.c | |
parent | 98a3734b5aa680f565af10a5fd4430baa4b4aa10 (diff) | |
download | protobuf-c7457ef65a7a8584b1e3bd396c401ccf8e275ffa.tar.gz protobuf-c7457ef65a7a8584b1e3bd396c401ccf8e275ffa.tar.bz2 protobuf-c7457ef65a7a8584b1e3bd396c401ccf8e275ffa.zip |
Add any support in php runtime. (#3486)
* Add any support in php runtime.
* Remove unused file in config.m4
* Fix comments
* Fix error for tsrmls build
* Add newly added file to Makefile.am
Diffstat (limited to 'php/ext/google/protobuf/message.c')
-rw-r--r-- | php/ext/google/protobuf/message.c | 277 |
1 files changed, 276 insertions, 1 deletions
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 519786dd..052865ad 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -32,9 +32,11 @@ #include <stdlib.h> #include "protobuf.h" +#include "utf8.h" -static zend_class_entry* message_type; +zend_class_entry* message_type; zend_object_handlers* message_handlers; +static const char TYPE_URL_PREFIX[] = "type.googleapis.com/"; static zend_function_entry message_methods[] = { PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC) @@ -342,3 +344,276 @@ PHP_METHOD(Message, whichOneof) { msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC); PHP_PROTO_RETURN_STRING(oneof_case_name, 1); } + +// ----------------------------------------------------------------------------- +// Any +// ----------------------------------------------------------------------------- + +static zend_function_entry any_methods[] = { + PHP_ME(Any, __construct, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, getTypeUrl, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, setTypeUrl, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, getValue, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, setValue, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, pack, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, unpack, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Any, is, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +zend_class_entry* any_type; + +// Init class entry. +PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Any", Any, any) + zend_class_implements(any_type TSRMLS_CC, 1, message_type); + zend_declare_property_string(any_type, "type_url", strlen("type_url"), + "" ,ZEND_ACC_PRIVATE TSRMLS_CC); + zend_declare_property_string(any_type, "value", strlen("value"), + "" ,ZEND_ACC_PRIVATE TSRMLS_CC); +PHP_PROTO_INIT_SUBMSGCLASS_END + +void hex_to_binary(const char* hex, char** binary, int* binary_len) { + int i; + int hex_len = strlen(hex); + *binary_len = hex_len / 2; + *binary = ALLOC_N(char, *binary_len); + for (i = 0; i < *binary_len; i++) { + char value = 0; + if (hex[i * 2] >= '0' && hex[i * 2] <= '9') { + value += (hex[i * 2] - '0') * 16; + } else { + value += (hex[i * 2] - 'a' + 10) * 16; + } + if (hex[i * 2 + 1] >= '0' && hex[i * 2 + 1] <= '9') { + value += hex[i * 2 + 1] - '0'; + } else { + value += hex[i * 2 + 1] - 'a' + 10; + } + (*binary)[i] = value; + } +} + +PHP_METHOD(Any, __construct) { + PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(any_type); + if (desc_php == NULL) { + init_generated_pool_once(TSRMLS_C); + const char* generated_file = + "0acd010a19676f6f676c652f70726f746f6275662f616e792e70726f746f" + "120f676f6f676c652e70726f746f62756622260a03416e7912100a087479" + "70655f75726c180120012809120d0a0576616c756518022001280c426f0a" + "13636f6d2e676f6f676c652e70726f746f6275664208416e7950726f746f" + "50015a256769746875622e636f6d2f676f6c616e672f70726f746f627566" + "2f7074797065732f616e79a20203475042aa021e476f6f676c652e50726f" + "746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33"; + char* binary; + int binary_len; + hex_to_binary(generated_file, &binary, &binary_len); + + internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC); + FREE(binary); + } + + MessageHeader* intern = UNBOX(MessageHeader, getThis()); + custom_data_init(any_type, intern PHP_PROTO_TSRMLS_CC); +} + +PHP_METHOD(Any, getTypeUrl) { + zval member; + PHP_PROTO_ZVAL_STRING(&member, "type_url", 1); + + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); +#if PHP_MAJOR_VERSION < 7 + zval* value = message_handlers->read_property(getThis(), &member, BP_VAR_R, + NULL PHP_PROTO_TSRMLS_CC); +#else + zval* value = message_handlers->read_property(getThis(), &member, BP_VAR_R, + NULL, NULL PHP_PROTO_TSRMLS_CC); +#endif + PHP_PROTO_FAKE_SCOPE_END; + + PHP_PROTO_RETVAL_ZVAL(value); +} + +PHP_METHOD(Any, setTypeUrl) { + char *type_url = NULL; + PHP_PROTO_SIZE type_url_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &type_url, + &type_url_len) == FAILURE) { + return; + } + + zval member; + zval value; + PHP_PROTO_ZVAL_STRING(&member, "type_url", 1); + PHP_PROTO_ZVAL_STRINGL(&value, type_url, type_url_len, 1); + + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); + message_handlers->write_property(getThis(), &member, &value, + NULL PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + PHP_PROTO_RETVAL_ZVAL(getThis()); +} + +PHP_METHOD(Any, getValue) { + zval member; + PHP_PROTO_ZVAL_STRING(&member, "value", 1); + + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); + zval* value = + php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + PHP_PROTO_RETVAL_ZVAL(value); +} + +PHP_METHOD(Any, setValue) { + char *value = NULL; + PHP_PROTO_SIZE value_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value, + &value_len) == FAILURE) { + return; + } + + zval member; + zval value_to_set; + PHP_PROTO_ZVAL_STRING(&member, "value", 1); + PHP_PROTO_ZVAL_STRINGL(&value_to_set, value, value_len, 1); + + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); + message_handlers->write_property(getThis(), &member, &value_to_set, + NULL PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + PHP_PROTO_RETVAL_ZVAL(getThis()); +} + +PHP_METHOD(Any, unpack) { + // Get type url. + zval type_url_member; + PHP_PROTO_ZVAL_STRING(&type_url_member, "type_url", 1); + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); + zval* type_url_php = php_proto_message_read_property( + getThis(), &type_url_member PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + // Get fully-qualified name from type url. + size_t url_prefix_len = strlen(TYPE_URL_PREFIX); + const char* type_url = Z_STRVAL_P(type_url_php); + size_t type_url_len = Z_STRLEN_P(type_url_php); + + if (url_prefix_len > type_url_len || + strncmp(TYPE_URL_PREFIX, type_url, url_prefix_len) != 0) { + zend_throw_exception( + NULL, "Type url needs to be type.googleapis.com/fully-qulified", + 0 TSRMLS_CC); + return; + } + + const char* fully_qualified_name = type_url + url_prefix_len; + PHP_PROTO_HASHTABLE_VALUE desc_php = get_proto_obj(fully_qualified_name); + if (desc_php == NULL) { + zend_throw_exception( + NULL, "Specified message in any hasn't been added to descriptor pool", + 0 TSRMLS_CC); + return; + } + Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php); + zend_class_entry* klass = desc->klass; + ZVAL_OBJ(return_value, klass->create_object(klass TSRMLS_CC)); + MessageHeader* msg = UNBOX(MessageHeader, return_value); + custom_data_init(klass, msg PHP_PROTO_TSRMLS_CC); + + // Get value. + zval value_member; + PHP_PROTO_ZVAL_STRING(&value_member, "value", 1); + PHP_PROTO_FAKE_SCOPE_RESTART(any_type); + zval* value = php_proto_message_read_property( + getThis(), &value_member PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + merge_from_string(Z_STRVAL_P(value), Z_STRLEN_P(value), desc, msg); +} + +PHP_METHOD(Any, pack) { + zval* val; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &val) == + FAILURE) { + return; + } + + if (!instanceof_function(Z_OBJCE_P(val), message_type TSRMLS_CC)) { + zend_error(E_USER_ERROR, "Given value is not an instance of Message."); + return; + } + + // Set value by serialized data. + zval data; + serialize_to_string(val, &data TSRMLS_CC); + + zval member; + PHP_PROTO_ZVAL_STRING(&member, "value", 1); + + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); + message_handlers->write_property(getThis(), &member, &data, + NULL PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + // Set type url. + Descriptor* desc = + UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(val))); + const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef); + size_t type_url_len = + strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1; + char* type_url = ALLOC_N(char, type_url_len); + sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name); + zval type_url_php; + PHP_PROTO_ZVAL_STRING(&type_url_php, type_url, 1); + PHP_PROTO_ZVAL_STRING(&member, "type_url", 1); + + PHP_PROTO_FAKE_SCOPE_RESTART(any_type); + message_handlers->write_property(getThis(), &member, &type_url_php, + NULL PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + FREE(type_url); +} + +PHP_METHOD(Any, is) { + zend_class_entry *klass = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &klass) == + FAILURE) { + return; + } + + PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(klass); + if (desc_php == NULL) { + RETURN_BOOL(false); + } + + // Create corresponded type url. + Descriptor* desc = + UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(klass)); + const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef); + size_t type_url_len = + strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1; + char* type_url = ALLOC_N(char, type_url_len); + sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name); + + // Fetch stored type url. + zval member; + PHP_PROTO_ZVAL_STRING(&member, "type_url", 1); + PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); + zval* value = + php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC); + PHP_PROTO_FAKE_SCOPE_END; + + // Compare two type url. + bool is = strcmp(type_url, Z_STRVAL_P(value)) == 0; + FREE(type_url); + + RETURN_BOOL(is); +} |