protected function decodeMessage(Protobuf\Message $message, $data) { // Get message descriptor $descriptor = Protobuf::getRegistry()->getDescriptor($message); foreach ($data as $key => $v) { // Get the field by tag number or name $field = $this->useTagNumber ? $descriptor->getField($key) : $descriptor->getFieldByName($key); // Unknown field found if (!$field) { $unknown = new PhpArray\Unknown($key, gettype($v), $v); $message->addUnknown($unknown); continue; } if ($field->isRepeated()) { // Make sure the value is an array of values $v = is_array($v) && is_int(key($v)) ? $v : array($v); foreach ($v as $k => $vv) { $v[$k] = $this->filterValue($vv, $field); } } else { $v = $this->filterValue($v, $field); } $message->_set($field->getNumber(), $v); } return $message; }
protected function decodeMessage(Protobuf\Message $message, $data) { // Get message descriptor $descriptor = Protobuf::getRegistry()->getDescriptor($message); // Split the index in UTF8 characters preg_match_all('/./u', $data[0], $chars); $chars = $chars[0]; for ($i = 1; $i < count($data); $i++) { $k = $this->c2i($chars[$i - 1]) - 48; $v = $data[$i]; $field = $descriptor->getField($k); if (NULL === $field) { // Unknown $unknown = new PhpArray\Unknown($k, gettype($v), $v); $message->addUnknown($unknown); continue; } if ($field->getType() === Protobuf::TYPE_MESSAGE) { $nested = $field->getReference(); if ($field->isRepeated()) { foreach ($v as $vv) { $obj = $this->decodeMessage(new $nested(), $vv); $message->_add($k, $obj); } } else { $obj = $this->decodeMessage(new $nested(), $v); $message->_set($k, $obj); } } else { $message->_set($k, $v); } } return $message; }
protected function encodeMessage(Protobuf\Message $message, $level = 0) { $descriptor = Protobuf::getRegistry()->getDescriptor($message); $indent = str_repeat(' ', $level); $data = ''; foreach ($descriptor->getFields() as $tag => $field) { $empty = !$message->_has($tag); if ($field->isRequired() && $empty) { throw new \UnexpectedValueException('Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value'); } if ($empty) { continue; } $name = $field->getName(); $value = $message->_get($tag); if ($field->isRepeated()) { foreach ($value as $val) { // Skip nullified repeated values if (NULL === $val) { continue; } else { if ($field->getType() !== Protobuf::TYPE_MESSAGE) { $data .= $indent . $name . ': ' . json_encode($val) . "\n"; } else { $data .= $indent . $name . " {\n"; $data .= $this->encodeMessage($val, $level + 1); $data .= $indent . "}\n"; } } } } else { if ($field->getType() === Protobuf::TYPE_MESSAGE) { $data .= $indent . $name . " {\n"; $data .= $this->encodeMessage($value, $level + 1); $data .= $indent . "}\n"; } else { $data .= $indent . $name . ': ' . json_encode($value) . "\n"; } } } return $data; }
/** * Serialize the current object data * * @param CodecInterface|null $codec * @return string */ public function serialize(Protobuf\CodecInterface $codec = null) { $codec = Protobuf::getCodec($codec); return $codec->encode($this); }
/** * @param \StudyDrSlump\Protobuf\Codec\Binary\Reader $reader * @param \StudyDrSlump\Protobuf\Message $message * @param int $length * @return \StudyDrSlump\Protobuf\Message */ protected function decodeMessage($reader, \StudyDrSlump\Protobuf\Message $message, $length = NULL) { /** @var $message \StudyDrSlump\Protobuf\Message */ /** @var $descriptor \StudyDrSlump\Protobuf\Descriptor */ // Get message descriptor $descriptor = Protobuf::getRegistry()->getDescriptor($message); // Cache locally the message fields $fields = $descriptor->getFields(); // Calculate the maximum offset if we have defined a length $limit = !is_null($length) ? $reader->pos() + $length : NULL; $pos = $reader->pos(); // Keep reading until we reach the end or the limit while ($limit === NULL && !$reader->eof() || $limit !== NULL && $reader->pos() < $limit) { // Get initial varint with tag number and wire type $key = $reader->varint(); if ($reader->eof()) { break; } $wire = $key & 0x7; $tag = $key >> 3; // Find the matching field for the tag number if (!isset($fields[$tag])) { $data = $this->decodeUnknown($reader, $wire); $unknown = new Binary\Unknown($tag, $wire, $data); $message->addUnknown($unknown); continue; } $field = $fields[$tag]; $type = $field->getType(); // Check if we are dealing with a packed stream, we cannot rely on the packed // flag of the message since we cannot be certain if the creator of the message // was using it. if ($wire === self::WIRE_LENGTH && $field->isRepeated() && self::$PACKABLE[$type]) { $len = $reader->varint(); $until = $reader->pos() + $len; $wire = $this->getWireType($type); while ($reader->pos() < $until) { $item = $this->decodeSimpleType($reader, $type, $wire); $message->_add($tag, $item); } } else { // Assert wire and type match $this->assertWireType($wire, $type); // Check if it's a sub-message if ($type === Protobuf::TYPE_MESSAGE) { $submessage = $field->getReference(); $submessage = new $submessage(); $len = $reader->varint(); $value = $this->decodeMessage($reader, $submessage, $len); } else { $value = $this->decodeSimpleType($reader, $type, $wire); } // Support non-packed repeated fields if ($field->isRepeated()) { $message->_add($tag, $value); } else { $message->_set($tag, $value); } } } return $message; }