aboutsummaryrefslogtreecommitdiffhomepage
path: root/php/src/Google/Protobuf/Internal/Message.php
diff options
context:
space:
mode:
Diffstat (limited to 'php/src/Google/Protobuf/Internal/Message.php')
-rw-r--r--php/src/Google/Protobuf/Internal/Message.php286
1 files changed, 260 insertions, 26 deletions
diff --git a/php/src/Google/Protobuf/Internal/Message.php b/php/src/Google/Protobuf/Internal/Message.php
index b3c4e6f1..9785be30 100644
--- a/php/src/Google/Protobuf/Internal/Message.php
+++ b/php/src/Google/Protobuf/Internal/Message.php
@@ -44,6 +44,10 @@ use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\GPBWire;
use Google\Protobuf\Internal\MapEntry;
use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\ListValue;
+use Google\Protobuf\Value;
+use Google\Protobuf\Struct;
+use Google\Protobuf\NullValue;
/**
* Parent class of all proto messages. Users should not instantiate this class
@@ -701,16 +705,22 @@ class Message
$field,
$is_map_key = false)
{
- if (is_null($value)) {
- return $this->defaultValue($field);
- }
switch ($field->getType()) {
case GPBType::MESSAGE:
$klass = $field->getMessageType()->getClass();
$submsg = new $klass;
- if ($field->isTimestamp()) {
- if (!is_string($value)) {
+ if (is_a($submsg, "Google\Protobuf\Duration")) {
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ } else if (!is_string($value)) {
+ throw new GPBDecodeException("Expect string.");
+ }
+ return GPBUtil::parseDuration($value);
+ } else if ($field->isTimestamp()) {
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ } else if (!is_string($value)) {
throw new GPBDecodeException("Expect string.");
}
try {
@@ -721,16 +731,31 @@ class Message
$submsg->setSeconds($timestamp->getSeconds());
$submsg->setNanos($timestamp->getNanos());
- } else if ($klass !== "Google\Protobuf\Any") {
- if (!is_object($value) && !is_array($value)) {
+ } else if (is_a($submsg, "Google\Protobuf\FieldMask")) {
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
+ try {
+ return GPBUtil::parseFieldMask($value);
+ } catch (\Exception $e) {
+ throw new GPBDecodeException("Invalid FieldMask: ".$e->getMessage());
+ }
+ } else {
+ if (is_null($value) &&
+ !is_a($submsg, "Google\Protobuf\Value")) {
+ return $this->defaultValue($field);
+ }
+ if (GPBUtil::hasSpecialJsonMapping($submsg)) {
+ } elseif (!is_object($value) && !is_array($value)) {
throw new GPBDecodeException("Expect message.");
}
-
$submsg->mergeFromJsonArray($value);
}
return $submsg;
case GPBType::ENUM:
- if (is_integer($value)) {
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ } else if (is_integer($value)) {
return $value;
} else {
$enum_value =
@@ -740,11 +765,17 @@ class Message
return $enum_value->getNumber();
}
case GPBType::STRING:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if (!is_string($value)) {
throw new GPBDecodeException("Expect string");
}
return $value;
case GPBType::BYTES:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if (!is_string($value)) {
throw new GPBDecodeException("Expect string");
}
@@ -755,6 +786,9 @@ class Message
}
return $proto_value;
case GPBType::BOOL:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if ($is_map_key) {
if ($value === "true") {
return true;
@@ -771,6 +805,9 @@ class Message
}
return $value;
case GPBType::FLOAT:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if ($value === "Infinity") {
return INF;
}
@@ -782,6 +819,9 @@ class Message
}
return $value;
case GPBType::DOUBLE:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if ($value === "Infinity") {
return INF;
}
@@ -793,6 +833,9 @@ class Message
}
return $value;
case GPBType::INT32:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if (!is_numeric($value)) {
throw new GPBDecodeException(
"Invalid data type for int32 field");
@@ -807,6 +850,9 @@ class Message
}
return $value;
case GPBType::UINT32:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if (!is_numeric($value)) {
throw new GPBDecodeException(
"Invalid data type for uint32 field");
@@ -817,6 +863,9 @@ class Message
}
return $value;
case GPBType::INT64:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if (!is_numeric($value)) {
throw new GPBDecodeException(
"Invalid data type for int64 field");
@@ -831,6 +880,9 @@ class Message
}
return $value;
case GPBType::UINT64:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
if (!is_numeric($value)) {
throw new GPBDecodeException(
"Invalid data type for int64 field");
@@ -844,14 +896,107 @@ class Message
}
return $value;
case GPBType::FIXED64:
+ if (is_null($value)) {
+ return $this->defaultValue($field);
+ }
return $value;
default:
return $value;
}
}
- private function mergeFromJsonArray($array)
+ protected function mergeFromJsonArray($array)
{
+ if (is_a($this, "Google\Protobuf\Any")) {
+ $this->clear();
+ $this->setTypeUrl($array["@type"]);
+ $msg = $this->unpack();
+ if (GPBUtil::hasSpecialJsonMapping($msg)) {
+ $msg->mergeFromJsonArray($array["value"]);
+ } else {
+ unset($array["@type"]);
+ $msg->mergeFromJsonArray($array);
+ }
+ $this->setValue($msg->serializeToString());
+ return;
+ }
+ if (is_a($this, "Google\Protobuf\DoubleValue") ||
+ is_a($this, "Google\Protobuf\FloatValue") ||
+ is_a($this, "Google\Protobuf\Int64Value") ||
+ is_a($this, "Google\Protobuf\UInt64Value") ||
+ is_a($this, "Google\Protobuf\Int32Value") ||
+ is_a($this, "Google\Protobuf\UInt32Value") ||
+ is_a($this, "Google\Protobuf\BoolValue") ||
+ is_a($this, "Google\Protobuf\StringValue")) {
+ $this->setValue($array);
+ return;
+ }
+ if (is_a($this, "Google\Protobuf\BytesValue")) {
+ $this->setValue(base64_decode($array));
+ return;
+ }
+ if (is_a($this, "Google\Protobuf\Duration")) {
+ $this->mergeFrom(GPBUtil::parseDuration($array));
+ return;
+ }
+ if (is_a($this, "Google\Protobuf\FieldMask")) {
+ $this->mergeFrom(GPBUtil::parseFieldMask($array));
+ return;
+ }
+ if (is_a($this, "Google\Protobuf\Timestamp")) {
+ $this->mergeFrom(GPBUtil::parseTimestamp($array));
+ return;
+ }
+ if (is_a($this, "Google\Protobuf\Struct")) {
+ $fields = $this->getFields();
+ foreach($array as $key => $value) {
+ $v = new Value();
+ $v->mergeFromJsonArray($value);
+ $fields[$key] = $v;
+ }
+ }
+ if (is_a($this, "Google\Protobuf\Value")) {
+ if (is_bool($array)) {
+ $this->setBoolValue($array);
+ } elseif (is_string($array)) {
+ $this->setStringValue($array);
+ } elseif (is_null($array)) {
+ $this->setNullValue(0);
+ } elseif (is_double($array) || is_integer($array)) {
+ $this->setNumberValue($array);
+ } elseif (is_array($array)) {
+ if (array_values($array) !== $array) {
+ // Associative array
+ $struct_value = $this->getStructValue();
+ if (is_null($struct_value)) {
+ $struct_value = new Struct();
+ $this->setStructValue($struct_value);
+ }
+ foreach ($array as $key => $v) {
+ $value = new Value();
+ $value->mergeFromJsonArray($v);
+ $values = $struct_value->getFields();
+ $values[$key]= $value;
+ }
+ } else {
+ // Array
+ $list_value = $this->getListValue();
+ if (is_null($list_value)) {
+ $list_value = new ListValue();
+ $this->setListValue($list_value);
+ }
+ foreach ($array as $v) {
+ $value = new Value();
+ $value->mergeFromJsonArray($v);
+ $values = $list_value->getValues();
+ $values[]= $value;
+ }
+ }
+ } else {
+ throw new GPBDecodeException("Invalid type for Value.");
+ }
+ return;
+ }
foreach ($array as $key => $value) {
$field = $this->desc->getFieldByJsonName($key);
if (is_null($field)) {
@@ -1037,7 +1182,8 @@ class Message
{
$getter = $field->getGetter();
$values = $this->$getter();
- return GPBJsonWire::serializeFieldToStream($values, $field, $output);
+ return GPBJsonWire::serializeFieldToStream(
+ $values, $field, $output, !GPBUtil::hasSpecialJsonMapping($this));
}
/**
@@ -1060,16 +1206,57 @@ class Message
*/
public function serializeToJsonStream(&$output)
{
- if (get_class($this) === 'Google\Protobuf\Timestamp') {
+ if (is_a($this, 'Google\Protobuf\Any')) {
+ $output->writeRaw("{", 1);
+ $type_field = $this->desc->getFieldByNumber(1);
+ $value_msg = $this->unpack();
+
+ // Serialize type url.
+ $output->writeRaw("\"@type\":", 8);
+ $output->writeRaw("\"", 1);
+ $output->writeRaw($this->getTypeUrl(), strlen($this->getTypeUrl()));
+ $output->writeRaw("\"", 1);
+
+ // Serialize value
+ if (GPBUtil::hasSpecialJsonMapping($value_msg)) {
+ $output->writeRaw(",\"value\":", 9);
+ $value_msg->serializeToJsonStream($output);
+ } else {
+ $value_fields = $value_msg->desc->getField();
+ foreach ($value_fields as $field) {
+ if ($value_msg->existField($field)) {
+ $output->writeRaw(",", 1);
+ if (!$value_msg->serializeFieldToJsonStream($output, $field)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ $output->writeRaw("}", 1);
+ } elseif (is_a($this, 'Google\Protobuf\FieldMask')) {
+ $field_mask = GPBUtil::formatFieldMask($this);
+ $output->writeRaw("\"", 1);
+ $output->writeRaw($field_mask, strlen($field_mask));
+ $output->writeRaw("\"", 1);
+ } elseif (is_a($this, 'Google\Protobuf\Duration')) {
+ $duration = GPBUtil::formatDuration($this) . "s";
+ $output->writeRaw("\"", 1);
+ $output->writeRaw($duration, strlen($duration));
+ $output->writeRaw("\"", 1);
+ } elseif (get_class($this) === 'Google\Protobuf\Timestamp') {
$timestamp = GPBUtil::formatTimestamp($this);
$timestamp = json_encode($timestamp);
$output->writeRaw($timestamp, strlen($timestamp));
} else {
- $output->writeRaw("{", 1);
+ if (!GPBUtil::hasSpecialJsonMapping($this)) {
+ $output->writeRaw("{", 1);
+ }
$fields = $this->desc->getField();
$first = true;
foreach ($fields as $field) {
- if ($this->existField($field)) {
+ if ($this->existField($field) ||
+ GPBUtil::hasJsonValue($this)) {
if ($first) {
$first = false;
} else {
@@ -1080,7 +1267,9 @@ class Message
}
}
}
- $output->writeRaw("}", 1);
+ if (!GPBUtil::hasSpecialJsonMapping($this)) {
+ $output->writeRaw("}", 1);
+ }
}
return true;
}
@@ -1263,6 +1452,10 @@ class Message
break;
case GPBType::ENUM:
$enum_desc = $field->getEnumType();
+ if ($enum_desc->getClass() === "Google\Protobuf\NullValue") {
+ $size += 4;
+ break;
+ }
$enum_value_desc = $enum_desc->getValueByNumber($value);
if (!is_null($enum_value_desc)) {
$size += 2; // size for ""
@@ -1284,6 +1477,12 @@ class Message
$size += strlen($value);
break;
case GPBType::BYTES:
+ # if (is_a($this, "Google\Protobuf\BytesValue")) {
+ # $size += strlen(json_encode($value));
+ # } else {
+ # $size += strlen(base64_encode($value));
+ # $size += 2; // size for \"\"
+ # }
$size += strlen(base64_encode($value));
$size += 2; // size for \"\"
break;
@@ -1375,8 +1574,11 @@ class Message
$values = $this->$getter();
$count = count($values);
if ($count !== 0) {
- $size += 5; // size for "\"\":{}".
- $size += strlen($field->getJsonName()); // size for field name
+ if (!GPBUtil::hasSpecialJsonMapping($this)) {
+ $size += 3; // size for "\"\":".
+ $size += strlen($field->getJsonName()); // size for field name
+ }
+ $size += 2; // size for "{}".
$size += $count - 1; // size for commas
$getter = $field->getGetter();
$map_entry = $field->getMessageType();
@@ -1408,17 +1610,22 @@ class Message
$values = $this->$getter();
$count = count($values);
if ($count !== 0) {
- $size += 5; // size for "\"\":[]".
- $size += strlen($field->getJsonName()); // size for field name
+ if (!GPBUtil::hasSpecialJsonMapping($this)) {
+ $size += 3; // size for "\"\":".
+ $size += strlen($field->getJsonName()); // size for field name
+ }
+ $size += 2; // size for "[]".
$size += $count - 1; // size for commas
$getter = $field->getGetter();
foreach ($values as $value) {
$size += $this->fieldDataOnlyJsonByteSize($field, $value);
}
}
- } elseif ($this->existField($field)) {
- $size += 3; // size for "\"\":".
- $size += strlen($field->getJsonName()); // size for field name
+ } elseif ($this->existField($field) || GPBUtil::hasJsonValue($this)) {
+ if (!GPBUtil::hasSpecialJsonMapping($this)) {
+ $size += 3; // size for "\"\":".
+ $size += strlen($field->getJsonName()); // size for field name
+ }
$getter = $field->getGetter();
$value = $this->$getter();
$size += $this->fieldDataOnlyJsonByteSize($field, $value);
@@ -1473,14 +1680,41 @@ class Message
public function jsonByteSize()
{
$size = 0;
- if (get_class($this) === 'Google\Protobuf\Timestamp') {
+ if (is_a($this, 'Google\Protobuf\Any')) {
+ // Size for "{}".
+ $size += 2;
+
+ // Size for "\"@type\":".
+ $size += 8;
+
+ // Size for url. +2 for "" /.
+ $size += strlen($this->getTypeUrl()) + 2;
+
+ $value_msg = $this->unpack();
+ if (GPBUtil::hasSpecialJsonMapping($value_msg)) {
+ // Size for "\",value\":".
+ $size += 9;
+ $size += $value_msg->jsonByteSize();
+ } else {
+ // Size for value. +1 for comma, -2 for "{}".
+ $size += $value_msg->jsonByteSize() -1;
+ }
+ } elseif (get_class($this) === 'Google\Protobuf\FieldMask') {
+ $field_mask = GPBUtil::formatFieldMask($this);
+ $size += strlen($field_mask) + 2; // 2 for ""
+ } elseif (get_class($this) === 'Google\Protobuf\Duration') {
+ $duration = GPBUtil::formatDuration($this) . "s";
+ $size += strlen($duration) + 2; // 2 for ""
+ } elseif (get_class($this) === 'Google\Protobuf\Timestamp') {
$timestamp = GPBUtil::formatTimestamp($this);
$timestamp = json_encode($timestamp);
$size += strlen($timestamp);
} else {
- // Size for "{}".
- $size += 2;
-
+ if (!GPBUtil::hasSpecialJsonMapping($this)) {
+ // Size for "{}".
+ $size += 2;
+ }
+
$fields = $this->desc->getField();
$count = 0;
foreach ($fields as $field) {