aboutsummaryrefslogtreecommitdiff
path: root/php/ext
diff options
context:
space:
mode:
Diffstat (limited to 'php/ext')
-rw-r--r--php/ext/google/protobuf/encode_decode.c7
-rw-r--r--php/ext/google/protobuf/message.c102
-rw-r--r--php/ext/google/protobuf/protobuf.h4
-rw-r--r--php/ext/google/protobuf/upb.c128
-rw-r--r--php/ext/google/protobuf/upb.h9
5 files changed, 169 insertions, 81 deletions
diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c
index de13dfa8..899b99f0 100644
--- a/php/ext/google/protobuf/encode_decode.c
+++ b/php/ext/google/protobuf/encode_decode.c
@@ -1587,8 +1587,11 @@ PHP_METHOD(Message, mergeFromJsonString) {
char *data = NULL;
PHP_PROTO_SIZE data_len;
+ zend_bool ignore_json_unknown = false;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
+ if (zend_parse_parameters(
+ ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &data, &data_len,
+ &ignore_json_unknown) ==
FAILURE) {
return;
}
@@ -1607,7 +1610,7 @@ PHP_METHOD(Message, mergeFromJsonString) {
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);
+ parser = upb_json_parser_create(&se.env, method, &sink, ignore_json_unknown);
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 76b97eef..0efe090d 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 <inttypes.h>
#include "protobuf.h"
#include "utf8.h"
@@ -1251,28 +1252,62 @@ PHP_METHOD(Timestamp, fromDateTime) {
return;
}
- // Get timestamp from Datetime object.
- zval retval;
- zval function_name;
- int64_t timestamp;
+ int64_t timestamp_seconds;
+ {
+ zval retval;
+ zval function_name;
#if PHP_MAJOR_VERSION < 7
- INIT_ZVAL(retval);
- INIT_ZVAL(function_name);
+ INIT_ZVAL(retval);
+ INIT_ZVAL(function_name);
#endif
- PHP_PROTO_ZVAL_STRING(&function_name, "date_timestamp_get", 1);
+ PHP_PROTO_ZVAL_STRING(&function_name, "date_timestamp_get", 1);
- if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1,
- ZVAL_PTR_TO_CACHED_PTR(datetime) TSRMLS_CC) == FAILURE) {
- zend_error(E_ERROR, "Cannot get timestamp from DateTime.");
- return;
+ if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1,
+ ZVAL_PTR_TO_CACHED_PTR(datetime) TSRMLS_CC) == FAILURE) {
+ zend_error(E_ERROR, "Cannot get timestamp from DateTime.");
+ return;
+ }
+
+ protobuf_convert_to_int64(&retval, &timestamp_seconds);
+
+ zval_dtor(&retval);
+ zval_dtor(&function_name);
}
- protobuf_convert_to_int64(&retval, &timestamp);
+ int64_t timestamp_micros;
+ {
+ zval retval;
+ zval function_name;
+ zval format_string;
- zval_dtor(&retval);
- zval_dtor(&function_name);
+#if PHP_MAJOR_VERSION < 7
+ INIT_ZVAL(retval);
+ INIT_ZVAL(function_name);
+ INIT_ZVAL(format_string);
+#endif
+
+ PHP_PROTO_ZVAL_STRING(&function_name, "date_format", 1);
+ PHP_PROTO_ZVAL_STRING(&format_string, "u", 1);
+
+ CACHED_VALUE params[2] = {
+ ZVAL_PTR_TO_CACHED_VALUE(datetime),
+ ZVAL_TO_CACHED_VALUE(format_string),
+ };
+
+ if (call_user_function(EG(function_table), NULL, &function_name, &retval,
+ ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) {
+ zend_error(E_ERROR, "Cannot format DateTime.");
+ return;
+ }
+
+ protobuf_convert_to_int64(&retval, &timestamp_micros);
+
+ zval_dtor(&retval);
+ zval_dtor(&function_name);
+ zval_dtor(&format_string);
+ }
// Set seconds
MessageHeader* self = UNBOX(MessageHeader, getThis());
@@ -1280,13 +1315,13 @@ PHP_METHOD(Timestamp, fromDateTime) {
upb_msgdef_ntofz(self->descriptor->msgdef, "seconds");
void* storage = message_data(self);
void* memory = slot_memory(self->descriptor->layout, storage, field);
- *(int64_t*)memory = timestamp;
+ *(int64_t*)memory = timestamp_seconds;
// Set nanos
field = upb_msgdef_ntofz(self->descriptor->msgdef, "nanos");
storage = message_data(self);
memory = slot_memory(self->descriptor->layout, storage, field);
- *(int32_t*)memory = 0;
+ *(int32_t*)memory = timestamp_micros * 1000;
RETURN_NULL();
}
@@ -1305,38 +1340,41 @@ PHP_METHOD(Timestamp, toDateTime) {
memory = slot_memory(self->descriptor->layout, storage, field);
int32_t nanos = *(int32_t*)memory;
- // Get formated time string.
- char formated_time[50];
- time_t raw_time = seconds;
- struct tm *utc_time = gmtime(&raw_time);
- strftime(formated_time, sizeof(formated_time), "%Y-%m-%dT%H:%M:%SUTC",
- utc_time);
+ // Get formatted time string.
+ char formatted_time[32];
+ snprintf(formatted_time, sizeof(formatted_time), "%" PRId64 ".%06" PRId32,
+ seconds, nanos / 1000);
// Create Datetime object.
zval datetime;
- zval formated_time_php;
zval function_name;
- int64_t timestamp = 0;
+ zval format_string;
+ zval formatted_time_php;
#if PHP_MAJOR_VERSION < 7
INIT_ZVAL(function_name);
- INIT_ZVAL(formated_time_php);
+ INIT_ZVAL(format_string);
+ INIT_ZVAL(formatted_time_php);
#endif
- PHP_PROTO_ZVAL_STRING(&function_name, "date_create", 1);
- PHP_PROTO_ZVAL_STRING(&formated_time_php, formated_time, 1);
+ PHP_PROTO_ZVAL_STRING(&function_name, "date_create_from_format", 1);
+ PHP_PROTO_ZVAL_STRING(&format_string, "U.u", 1);
+ PHP_PROTO_ZVAL_STRING(&formatted_time_php, formatted_time, 1);
- CACHED_VALUE params[1] = {ZVAL_TO_CACHED_VALUE(formated_time_php)};
+ CACHED_VALUE params[2] = {
+ ZVAL_TO_CACHED_VALUE(format_string),
+ ZVAL_TO_CACHED_VALUE(formatted_time_php),
+ };
- if (call_user_function(EG(function_table), NULL,
- &function_name, &datetime, 1,
- params TSRMLS_CC) == FAILURE) {
+ if (call_user_function(EG(function_table), NULL, &function_name, &datetime,
+ ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) {
zend_error(E_ERROR, "Cannot create DateTime.");
return;
}
- zval_dtor(&formated_time_php);
zval_dtor(&function_name);
+ zval_dtor(&format_string);
+ zval_dtor(&formatted_time_php);
#if PHP_MAJOR_VERSION < 7
zval* datetime_ptr = &datetime;
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index 48072a4f..9cb36dc2 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -42,6 +42,10 @@
#define MAX_LENGTH_OF_INT64 20
#define SIZEOF_INT64 8
+/* From Chromium. */
+#define ARRAY_SIZE(x) \
+ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
// -----------------------------------------------------------------------------
// PHP7 Wrappers
// ----------------------------------------------------------------------------
diff --git a/php/ext/google/protobuf/upb.c b/php/ext/google/protobuf/upb.c
index e01f3bfd..4644430e 100644
--- a/php/ext/google/protobuf/upb.c
+++ b/php/ext/google/protobuf/upb.c
@@ -14344,6 +14344,9 @@ struct upb_json_parser {
/* Intermediate result of parsing a unicode escape sequence. */
uint32_t digit;
+
+ /* Whether to proceed if unknown field is met. */
+ bool ignore_json_unknown;
};
struct upb_json_parsermethod {
@@ -14864,6 +14867,11 @@ static bool end_number(upb_json_parser *p, const char *ptr) {
return false;
}
+ if (p->top->f == NULL) {
+ multipart_end(p);
+ return true;
+ }
+
return parse_number(p, false);
}
@@ -15016,6 +15024,10 @@ static bool parse_number(upb_json_parser *p, bool is_quoted) {
static bool parser_putbool(upb_json_parser *p, bool val) {
bool ok;
+ if (p->top->f == NULL) {
+ return true;
+ }
+
if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
upb_status_seterrf(&p->status,
"Boolean value specified for non-bool field: %s",
@@ -15031,7 +15043,10 @@ static bool parser_putbool(upb_json_parser *p, bool val) {
}
static bool start_stringval(upb_json_parser *p) {
- UPB_ASSERT(p->top->f);
+ if (p->top->f == NULL) {
+ multipart_startaccum(p);
+ return true;
+ }
if (upb_fielddef_isstring(p->top->f)) {
upb_jsonparser_frame *inner;
@@ -15082,6 +15097,11 @@ static bool start_stringval(upb_json_parser *p) {
static bool end_stringval(upb_json_parser *p) {
bool ok = true;
+ if (p->top->f == NULL) {
+ multipart_end(p);
+ return true;
+ }
+
switch (upb_fielddef_type(p->top->f)) {
case UPB_TYPE_BYTES:
if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
@@ -15273,6 +15293,10 @@ static bool handle_mapentry(upb_json_parser *p) {
static bool end_membername(upb_json_parser *p) {
UPB_ASSERT(!p->top->f);
+ if (!p->top->m) {
+ return true;
+ }
+
if (p->top->is_map) {
return handle_mapentry(p);
} else {
@@ -15285,9 +15309,10 @@ static bool end_membername(upb_json_parser *p) {
multipart_end(p);
return true;
+ } else if (p->ignore_json_unknown) {
+ multipart_end(p);
+ return true;
} else {
- /* TODO(haberman): Ignore unknown fields if requested/configured to do
- * so. */
upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf);
upb_env_reporterror(p->env, &p->status);
return false;
@@ -15319,7 +15344,18 @@ static void end_member(upb_json_parser *p) {
}
static bool start_subobject(upb_json_parser *p) {
- UPB_ASSERT(p->top->f);
+ if (p->top->f == NULL) {
+ upb_jsonparser_frame *inner;
+ if (!check_stack(p)) return false;
+
+ inner = p->top + 1;
+ inner->m = NULL;
+ inner->f = NULL;
+ inner->is_map = false;
+ inner->is_mapentry = false;
+ p->top = inner;
+ return true;
+ }
if (upb_fielddef_ismap(p->top->f)) {
upb_jsonparser_frame *inner;
@@ -15378,9 +15414,12 @@ static void end_subobject(upb_json_parser *p) {
upb_sink_endseq(&p->top->sink, sel);
} else {
upb_selector_t sel;
+ bool is_unknown = p->top->m == NULL;
p->top--;
- sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
- upb_sink_endsubmsg(&p->top->sink, sel);
+ if (!is_unknown) {
+ sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+ upb_sink_endsubmsg(&p->top->sink, sel);
+ }
}
}
@@ -15462,11 +15501,11 @@ static void end_object(upb_json_parser *p) {
* final state once, when the closing '"' is seen. */
-#line 1310 "upb/json/parser.rl"
+#line 1349 "upb/json/parser.rl"
-#line 1222 "upb/json/parser.c"
+#line 1261 "upb/json/parser.c"
static const char _json_actions[] = {
0, 1, 0, 1, 2, 1, 3, 1,
5, 1, 6, 1, 7, 1, 8, 1,
@@ -15615,7 +15654,7 @@ static const int json_en_value_machine = 27;
static const int json_en_main = 1;
-#line 1313 "upb/json/parser.rl"
+#line 1352 "upb/json/parser.rl"
size_t parse(void *closure, const void *hd, const char *buf, size_t size,
const upb_bufhandle *handle) {
@@ -15637,7 +15676,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size,
capture_resume(parser, buf);
-#line 1393 "upb/json/parser.c"
+#line 1432 "upb/json/parser.c"
{
int _klen;
unsigned int _trans;
@@ -15712,118 +15751,118 @@ _match:
switch ( *_acts++ )
{
case 0:
-#line 1225 "upb/json/parser.rl"
+#line 1264 "upb/json/parser.rl"
{ p--; {cs = stack[--top]; goto _again;} }
break;
case 1:
-#line 1226 "upb/json/parser.rl"
+#line 1265 "upb/json/parser.rl"
{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
break;
case 2:
-#line 1230 "upb/json/parser.rl"
+#line 1269 "upb/json/parser.rl"
{ start_text(parser, p); }
break;
case 3:
-#line 1231 "upb/json/parser.rl"
+#line 1270 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_text(parser, p)); }
break;
case 4:
-#line 1237 "upb/json/parser.rl"
+#line 1276 "upb/json/parser.rl"
{ start_hex(parser); }
break;
case 5:
-#line 1238 "upb/json/parser.rl"
+#line 1277 "upb/json/parser.rl"
{ hexdigit(parser, p); }
break;
case 6:
-#line 1239 "upb/json/parser.rl"
+#line 1278 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_hex(parser)); }
break;
case 7:
-#line 1245 "upb/json/parser.rl"
+#line 1284 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(escape(parser, p)); }
break;
case 8:
-#line 1251 "upb/json/parser.rl"
+#line 1290 "upb/json/parser.rl"
{ p--; {cs = stack[--top]; goto _again;} }
break;
case 9:
-#line 1254 "upb/json/parser.rl"
+#line 1293 "upb/json/parser.rl"
{ {stack[top++] = cs; cs = 19; goto _again;} }
break;
case 10:
-#line 1256 "upb/json/parser.rl"
+#line 1295 "upb/json/parser.rl"
{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
break;
case 11:
-#line 1261 "upb/json/parser.rl"
+#line 1300 "upb/json/parser.rl"
{ start_member(parser); }
break;
case 12:
-#line 1262 "upb/json/parser.rl"
+#line 1301 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_membername(parser)); }
break;
case 13:
-#line 1265 "upb/json/parser.rl"
+#line 1304 "upb/json/parser.rl"
{ end_member(parser); }
break;
case 14:
-#line 1271 "upb/json/parser.rl"
+#line 1310 "upb/json/parser.rl"
{ start_object(parser); }
break;
case 15:
-#line 1274 "upb/json/parser.rl"
+#line 1313 "upb/json/parser.rl"
{ end_object(parser); }
break;
case 16:
-#line 1280 "upb/json/parser.rl"
+#line 1319 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(start_array(parser)); }
break;
case 17:
-#line 1284 "upb/json/parser.rl"
+#line 1323 "upb/json/parser.rl"
{ end_array(parser); }
break;
case 18:
-#line 1289 "upb/json/parser.rl"
+#line 1328 "upb/json/parser.rl"
{ start_number(parser, p); }
break;
case 19:
-#line 1290 "upb/json/parser.rl"
+#line 1329 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_number(parser, p)); }
break;
case 20:
-#line 1292 "upb/json/parser.rl"
+#line 1331 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(start_stringval(parser)); }
break;
case 21:
-#line 1293 "upb/json/parser.rl"
+#line 1332 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(end_stringval(parser)); }
break;
case 22:
-#line 1295 "upb/json/parser.rl"
+#line 1334 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
break;
case 23:
-#line 1297 "upb/json/parser.rl"
+#line 1336 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
break;
case 24:
-#line 1299 "upb/json/parser.rl"
+#line 1338 "upb/json/parser.rl"
{ /* null value */ }
break;
case 25:
-#line 1301 "upb/json/parser.rl"
+#line 1340 "upb/json/parser.rl"
{ CHECK_RETURN_TOP(start_subobject(parser)); }
break;
case 26:
-#line 1302 "upb/json/parser.rl"
+#line 1341 "upb/json/parser.rl"
{ end_subobject(parser); }
break;
case 27:
-#line 1307 "upb/json/parser.rl"
+#line 1346 "upb/json/parser.rl"
{ p--; {cs = stack[--top]; goto _again;} }
break;
-#line 1579 "upb/json/parser.c"
+#line 1618 "upb/json/parser.c"
}
}
@@ -15836,7 +15875,7 @@ _again:
_out: {}
}
-#line 1334 "upb/json/parser.rl"
+#line 1373 "upb/json/parser.rl"
if (p != pe) {
upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p);
@@ -15877,13 +15916,13 @@ static void json_parser_reset(upb_json_parser *p) {
/* Emit Ragel initialization of the parser. */
-#line 1633 "upb/json/parser.c"
+#line 1672 "upb/json/parser.c"
{
cs = json_start;
top = 0;
}
-#line 1374 "upb/json/parser.rl"
+#line 1413 "upb/json/parser.rl"
p->current_state = cs;
p->parser_top = top;
accumulate_clear(p);
@@ -15970,7 +16009,8 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
upb_json_parser *upb_json_parser_create(upb_env *env,
const upb_json_parsermethod *method,
- upb_sink *output) {
+ upb_sink *output,
+ bool ignore_json_unknown) {
#ifndef NDEBUG
const size_t size_before = upb_env_bytesallocated(env);
#endif
@@ -15989,6 +16029,8 @@ upb_json_parser *upb_json_parser_create(upb_env *env,
p->top->m = upb_handlers_msgdef(output->handlers);
set_name_table(p, p->top);
+ p->ignore_json_unknown = ignore_json_unknown;
+
/* If this fails, uncomment and increase the value in parser.h. */
/* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */
UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <=
diff --git a/php/ext/google/protobuf/upb.h b/php/ext/google/protobuf/upb.h
index a263db30..180f4715 100644
--- a/php/ext/google/protobuf/upb.h
+++ b/php/ext/google/protobuf/upb.h
@@ -9457,7 +9457,7 @@ UPB_DECLARE_DERIVED_TYPE(upb::json::ParserMethod, upb::RefCounted,
class upb::json::Parser {
public:
static Parser* Create(Environment* env, const ParserMethod* method,
- Sink* output);
+ Sink* output, bool ignore_json_unknown);
BytesSink* input();
@@ -9491,7 +9491,8 @@ UPB_BEGIN_EXTERN_C
upb_json_parser* upb_json_parser_create(upb_env* e,
const upb_json_parsermethod* m,
- upb_sink* output);
+ upb_sink* output,
+ bool ignore_json_unknown);
upb_bytessink *upb_json_parser_input(upb_json_parser *p);
upb_json_parsermethod* upb_json_parsermethod_new(const upb_msgdef* md,
@@ -9511,8 +9512,8 @@ UPB_END_EXTERN_C
namespace upb {
namespace json {
inline Parser* Parser::Create(Environment* env, const ParserMethod* method,
- Sink* output) {
- return upb_json_parser_create(env, method, output);
+ Sink* output, bool ignore_json_unknown) {
+ return upb_json_parser_create(env, method, output, ignore_json_unknown);
}
inline BytesSink* Parser::input() {
return upb_json_parser_input(this);