aboutsummaryrefslogtreecommitdiffhomepage
path: root/php/ext
diff options
context:
space:
mode:
authorGravatar Paul Yang <TeBoring@users.noreply.github.com>2017-02-08 10:27:54 -0800
committerGravatar GitHub <noreply@github.com>2017-02-08 10:27:54 -0800
commitcba04b19e88dba2c13241b733bf7f595f1463082 (patch)
treeda61ea725e19eadce400ae17df845e04f36bc608 /php/ext
parentc00274313d03a0a7f10e8f6473541faf3739353b (diff)
Implement json encoding decoding for php. (#2682)
Diffstat (limited to 'php/ext')
-rw-r--r--php/ext/google/protobuf/def.c15
-rw-r--r--php/ext/google/protobuf/encode_decode.c111
-rw-r--r--php/ext/google/protobuf/message.c18
-rw-r--r--php/ext/google/protobuf/protobuf.h5
-rw-r--r--php/ext/google/protobuf/storage.c1
5 files changed, 144 insertions, 6 deletions
diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c
index 0ce39ec3..32b158e2 100644
--- a/php/ext/google/protobuf/def.c
+++ b/php/ext/google/protobuf/def.c
@@ -398,10 +398,22 @@ static void descriptor_free_c(Descriptor *self TSRMLS_DC) {
if (self->fill_method) {
upb_pbdecodermethod_unref(self->fill_method, &self->fill_method);
}
+ if (self->json_fill_method) {
+ upb_json_parsermethod_unref(self->json_fill_method,
+ &self->json_fill_method);
+ }
if (self->pb_serialize_handlers) {
upb_handlers_unref(self->pb_serialize_handlers,
&self->pb_serialize_handlers);
}
+ if (self->json_serialize_handlers) {
+ upb_handlers_unref(self->json_serialize_handlers,
+ &self->json_serialize_handlers);
+ }
+ if (self->json_serialize_handlers_preserve) {
+ upb_handlers_unref(self->json_serialize_handlers_preserve,
+ &self->json_serialize_handlers_preserve);
+ }
}
static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) {
@@ -411,7 +423,10 @@ static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) {
desc->klass = NULL;
desc->fill_handlers = NULL;
desc->fill_method = NULL;
+ desc->json_fill_method = NULL;
desc->pb_serialize_handlers = NULL;
+ desc->json_serialize_handlers = NULL;
+ desc->json_serialize_handlers_preserve = NULL;
}
// -----------------------------------------------------------------------------
diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c
index 32a0fbea..57fc81d3 100644
--- a/php/ext/google/protobuf/encode_decode.c
+++ b/php/ext/google/protobuf/encode_decode.c
@@ -103,6 +103,7 @@ static void stackenv_uninit(stackenv* se);
// Callback invoked by upb if any error occurs during parsing or serialization.
static bool env_error_func(void* ud, const upb_status* status) {
+ char err_msg[100] = "";
stackenv* se = ud;
// Free the env -- zend_error will longjmp up the stack past the
// encode/decode function so it would not otherwise have been freed.
@@ -110,7 +111,9 @@ static bool env_error_func(void* ud, const upb_status* status) {
// TODO(teboring): have a way to verify that this is actually a parse error,
// instead of just throwing "parse error" unconditionally.
- zend_error(E_ERROR, se->php_error_template, upb_status_errmsg(status));
+ sprintf(err_msg, se->php_error_template, upb_status_errmsg(status));
+ TSRMLS_FETCH();
+ zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
// Never reached.
return false;
}
@@ -866,6 +869,14 @@ static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
return desc->fill_method;
}
+static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
+ if (desc->json_fill_method == NULL) {
+ desc->json_fill_method =
+ upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method);
+ }
+ return desc->json_fill_method;
+}
+
// -----------------------------------------------------------------------------
// Serializing.
// -----------------------------------------------------------------------------
@@ -883,8 +894,8 @@ static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink,
static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC);
-static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink, int depth
- TSRMLS_DC);
+static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
+ int depth TSRMLS_DC);
static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) {
upb_selector_t ret;
@@ -961,10 +972,13 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
const upb_fielddef* key_field;
const upb_fielddef* value_field;
MapIter it;
- int len;
+ int len, size;
- if (map == NULL) return;
- self = UNBOX(Map, map);
+ assert(map != NULL);
+ Map* intern =
+ (Map*)zend_object_store_get_object(map TSRMLS_CC);
+ size = upb_strtable_count(&intern->table);
+ if (size == 0) return;
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
@@ -1197,6 +1211,25 @@ static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
return desc->pb_serialize_handlers;
}
+static const upb_handlers* msgdef_json_serialize_handlers(
+ Descriptor* desc, bool preserve_proto_fieldnames) {
+ if (preserve_proto_fieldnames) {
+ if (desc->json_serialize_handlers == NULL) {
+ desc->json_serialize_handlers =
+ upb_json_printer_newhandlers(
+ desc->msgdef, true, &desc->json_serialize_handlers);
+ }
+ return desc->json_serialize_handlers;
+ } else {
+ if (desc->json_serialize_handlers_preserve == NULL) {
+ desc->json_serialize_handlers_preserve =
+ upb_json_printer_newhandlers(
+ desc->msgdef, false, &desc->json_serialize_handlers_preserve);
+ }
+ return desc->json_serialize_handlers_preserve;
+ }
+}
+
// -----------------------------------------------------------------------------
// PHP encode/decode methods
// -----------------------------------------------------------------------------
@@ -1255,3 +1288,69 @@ PHP_METHOD(Message, decode) {
stackenv_uninit(&se);
}
}
+
+PHP_METHOD(Message, jsonEncode) {
+ zval* php_descriptor = get_ce_obj(Z_OBJCE_P(getThis()));
+ Descriptor* desc =
+ (Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
+
+ zend_bool preserve_proto_fieldnames = false;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b",
+ &preserve_proto_fieldnames) == FAILURE) {
+ return;
+ }
+
+ stringsink sink;
+ stringsink_init(&sink);
+
+ {
+ const upb_handlers* serialize_handlers =
+ msgdef_json_serialize_handlers(desc, preserve_proto_fieldnames);
+ upb_json_printer* printer;
+ stackenv se;
+
+ stackenv_init(&se, "Error occurred during encoding: %s");
+ printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
+
+ putmsg(getThis(), desc, upb_json_printer_input(printer), 0 TSRMLS_CC);
+
+ RETVAL_STRINGL(sink.ptr, sink.len, 1);
+
+ stackenv_uninit(&se);
+ stringsink_uninit(&sink);
+ }
+}
+
+PHP_METHOD(Message, jsonDecode) {
+ zval* php_descriptor = get_ce_obj(Z_OBJCE_P(getThis()));
+ Descriptor* desc =
+ (Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
+ MessageHeader* msg = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ char *data = NULL;
+ int data_len;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
+ FAILURE) {
+ return;
+ }
+
+ // TODO(teboring): Check and respect string encoding. If not UTF-8, we need to
+ // convert, because string handlers pass data directly to message string
+ // fields.
+
+ // TODO(teboring): Clear message.
+
+ {
+ const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc);
+ stackenv se;
+ upb_sink sink;
+ upb_json_parser* parser;
+ stackenv_init(&se, "Error occurred during parsing: %s");
+
+ upb_sink_reset(&sink, get_fill_handlers(desc), msg);
+ parser = upb_json_parser_create(&se.env, method, &sink);
+ upb_bufsrc_putbuf(data, data_len, upb_json_parser_input(parser));
+
+ stackenv_uninit(&se);
+ }
+}
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c
index f5a9499d..e8b8ae81 100644
--- a/php/ext/google/protobuf/message.c
+++ b/php/ext/google/protobuf/message.c
@@ -30,6 +30,7 @@
#include <php.h>
#include <stdlib.h>
+#include <ext/json/php_json.h>
#include "protobuf.h"
@@ -39,6 +40,8 @@ zend_object_handlers* message_handlers;
static zend_function_entry message_methods[] = {
PHP_ME(Message, encode, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Message, decode, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Message, jsonEncode, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Message, jsonDecode, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED)
PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED)
PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED)
@@ -54,6 +57,8 @@ static zval* message_get_property(zval* object, zval* member, int type,
const zend_literal* key TSRMLS_DC);
static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type,
const zend_literal* key TSRMLS_DC);
+static HashTable* message_get_properties(zval* object TSRMLS_DC);
+static HashTable* message_get_gc(zval* object, zval*** table, int* n TSRMLS_DC);
static zend_object_value message_create(zend_class_entry* ce TSRMLS_DC);
static void message_free(void* object TSRMLS_DC);
@@ -74,6 +79,8 @@ void message_init(TSRMLS_D) {
message_handlers->write_property = message_set_property;
message_handlers->read_property = message_get_property;
message_handlers->get_property_ptr_ptr = message_get_property_ptr_ptr;
+ message_handlers->get_properties = message_get_properties;
+ message_handlers->get_gc = message_get_gc;
}
static void message_set_property(zval* object, zval* member, zval* value,
@@ -144,6 +151,17 @@ static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type,
return NULL;
}
+static HashTable* message_get_properties(zval* object TSRMLS_DC) {
+ return NULL;
+}
+
+static HashTable* message_get_gc(zval* object, zval*** table, int* n TSRMLS_DC) {
+ zend_object* zobj = Z_OBJ_P(object);
+ *table = zobj->properties_table;
+ *n = zobj->ce->default_properties_count;
+ return NULL;
+}
+
// -----------------------------------------------------------------------------
// C Message Utilities
// -----------------------------------------------------------------------------
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index df452d6f..678f2682 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -122,7 +122,10 @@ struct Descriptor {
zend_class_entry* klass; // begins as NULL
const upb_handlers* fill_handlers;
const upb_pbdecodermethod* fill_method;
+ const upb_json_parsermethod* json_fill_method;
const upb_handlers* pb_serialize_handlers;
+ const upb_handlers* json_serialize_handlers;
+ const upb_handlers* json_serialize_handlers_preserve;
};
extern zend_class_entry* descriptor_type;
@@ -261,6 +264,8 @@ const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc,
PHP_METHOD(Message, encode);
PHP_METHOD(Message, decode);
+PHP_METHOD(Message, jsonEncode);
+PHP_METHOD(Message, jsonDecode);
// -----------------------------------------------------------------------------
// Type check / conversion.
diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c
index 42bcce59..ba6ac59e 100644
--- a/php/ext/google/protobuf/storage.c
+++ b/php/ext/google/protobuf/storage.c
@@ -482,6 +482,7 @@ void layout_init(MessageLayout* layout, void* storage,
repeated_field_create_with_type(repeated_field_type, field,
property_ptr TSRMLS_CC);
DEREF(memory, zval**) = property_ptr;
+ property_ptr = NULL;
} else {
native_slot_init(upb_fielddef_type(field), memory, property_ptr);
}