aboutsummaryrefslogtreecommitdiff
path: root/php/ext/google/protobuf/message.c
diff options
context:
space:
mode:
authorPaul Yang <TeBoring@users.noreply.github.com>2017-08-25 08:49:34 -0700
committerGitHub <noreply@github.com>2017-08-25 08:49:34 -0700
commitc7457ef65a7a8584b1e3bd396c401ccf8e275ffa (patch)
treea142f1ed092807b1bd38683f57e37bcf852f665a /php/ext/google/protobuf/message.c
parent98a3734b5aa680f565af10a5fd4430baa4b4aa10 (diff)
downloadprotobuf-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.c277
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);
+}