Esempio n. 1
0
 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;
         }
         $name = $field->getName();
         if ($field->getType() === Protobuf::TYPE_MESSAGE) {
             $nested = $field->getReference();
             if ($field->isRepeated()) {
                 foreach ($v as $kk => $vv) {
                     $v[$kk] = $this->decodeMessage(new $nested(), $vv);
                 }
                 $message->initValue($name, $v);
             } else {
                 $obj = $this->decodeMessage(new $nested(), $v);
                 $message->initValue($name, $obj);
             }
         } else {
             $message->initValue($name, $v);
         }
     }
     return $message;
 }
Esempio n. 2
0
 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;
 }
Esempio n. 3
0
 protected function decodeMessage(Protobuf\MessageInterface $message, $data)
 {
     // Get message descriptor
     $descriptor = Protobuf::getRegistry()->getDescriptor($message);
     $isLazy = $this->getOption('lazy');
     $useTagNumber = $this->getOption('tags');
     foreach ($data as $key => $v) {
         // Get the field by tag number or name
         $field = $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) && (empty($v) || is_int(key($v))) ? $v : array($v);
             // If we are packing lazy values use a LazyRepeat as container
             if ($isLazy && $field->getType() === Protobuf::TYPE_MESSAGE) {
                 $v = new Protobuf\LazyRepeat($v);
                 $v->codec = $this;
                 $v->descriptor = $field;
             } else {
                 foreach ($v as $k => $vv) {
                     $v[$k] = $this->filterValue($vv, $field);
                 }
             }
         } else {
             $v = $this->filterValue($v, $field);
         }
         $message->initValue($field->getName(), $v);
     }
     return $message;
 }
Esempio n. 4
0
 /**
  * @param string $data
  */
 public function __construct($data = null)
 {
     // Cache the descriptor instance
     $this->_descriptor = Protobuf::getRegistry()->getDescriptor($this);
     // Assign default values to extensions
     foreach ($this->_descriptor->getFields() as $f) {
         if ($f->isExtension() && $f->hasDefault()) {
             $this->_extensions[$f->getName()] = $f->getDefault();
         }
     }
     if (NULL !== $data) {
         $this->parse($data);
     }
 }
Esempio n. 5
0
 protected function encodeMessage(Protobuf\MessageInterface $message, $level = 0)
 {
     $descriptor = Protobuf::getRegistry()->getDescriptor($message);
     $strict = $this->getOption('strict');
     $indent = str_repeat('  ', $level);
     $data = '';
     foreach ($descriptor->getFields() as $tag => $field) {
         $empty = !isset($message[$tag]);
         if ($strict && $empty && $field->isRequired() && !$field->hasDefault()) {
             throw new \UnexpectedValueException('Message ' . $descriptor->getName() . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value');
         }
         if ($empty && !$field->hasDefault()) {
             continue;
         }
         $name = $field->getName();
         $value = $message[$tag];
         if ($value === NULL) {
             continue;
         }
         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;
 }
Esempio n. 6
0
 /**
  * @param mixed $data
  */
 public function __construct($data = null)
 {
     // Cache the descriptor instance for this class
     if (!static::$__descriptor) {
         static::$__descriptor = Protobuf::getRegistry()->getDescriptor($this);
     }
     // Alias the descriptor to this object instance since it's faster to access
     $this->_descriptor = static::$__descriptor;
     // BACKWARDS COMPATIBILITY: Unset public properties
     $publicfields = get_object_vars($this);
     foreach ($this->_descriptor->getFields() as $field) {
         $name = $field->name;
         if (array_key_exists($name, $publicfields)) {
             //trigger_error('DESTROYING PUBLIC FIELD: '  . $name);
             unset($this->{$name});
         }
     }
     if (NULL !== $data) {
         $this->parse($data);
     }
 }
Esempio n. 7
0
 /**
  * @param \DrSlump\Protobuf\MessageInterface    $message
  * @param string                                $data
  * @return \DrSlump\Protobuf\MessageInterface
  */
 protected function _decodeMessage(\DrSlump\Protobuf\MessageInterface $message, $data)
 {
     $descriptor = Protobuf::getRegistry()->getDescriptor($message);
     $name = $descriptor->getName();
     $res = $this->_describe($descriptor);
     $ret = \protobuf_decode($res, $data);
     // In non lazy mode we just pass the returned array thru the PhpArray codec
     if (!$this->getOption('lazy')) {
         if (!$this->_codec) {
             $this->_codec = new PhpArray();
             $this->_codec->setOption('lazy', false);
         }
         return $this->_codec->decode($message, $ret);
     }
     // In lazy mode we need to walk thru the fields to convert message strings
     // to LazyValue / LazyRepeat
     foreach ($descriptor->getFields() as $field) {
         $name = $field->getName();
         if (!isset($ret[$name])) {
             continue;
         }
         $value = $ret[$name];
         if ($field->getType() === Protobuf::TYPE_MESSAGE) {
             if ($field->getRule() === Protobuf::RULE_REPEATED) {
                 $value = new Protobuf\LazyRepeat($value);
                 $value->codec = $this;
                 $value->descriptor = $field;
             } else {
                 $lazy = new Protobuf\LazyValue();
                 $lazy->codec = $this;
                 $lazy->descriptor = $field;
                 $lazy->value = $value;
                 $value = $lazy;
             }
         }
         $message->initValue($name, $value);
     }
     return $message;
 }
Esempio n. 8
0
 protected function encodeMessage(Protobuf\Message $message)
 {
     $writer = new NativeWriter();
     // Get message descriptor
     $descriptor = Protobuf::getRegistry()->getDescriptor($message);
     $strict = $this->getOption('strict');
     foreach ($descriptor->getFields() as $tag => $field) {
         $empty = !isset($message[$tag]);
         if ($strict && $empty && $field->isRequired() && !$field->hasDefault()) {
             throw new \UnexpectedValueException('Message ' . get_class($message) . '\'s field tag ' . $tag . '(' . $field->getName() . ') is required but has no value');
         }
         // Skip unknown fields
         if ($empty && !$field->hasDefault()) {
             continue;
         }
         $type = $field->getType();
         $wire = $field->isPacked() ? self::WIRE_LENGTH : $this->getWireType($type, null);
         // Compute key with tag number and wire type
         $key = $tag << 3 | $wire;
         $value = $message[$tag];
         if (NULL === $value) {
             continue;
         }
         if ($field->isRepeated()) {
             // Packed fields are encoded as a length-delimited stream containing
             // the concatenated encoding of each value.
             if ($field->isPacked() && !empty($value)) {
                 $subwriter = new NativeWriter();
                 foreach ($value as $val) {
                     $this->encodeSimpleType($subwriter, $type, $val);
                 }
                 $data = $subwriter->getBytes();
                 $writer->varint($key);
                 $writer->varint(strlen($data));
                 $writer->write($data);
             } else {
                 foreach ($value as $val) {
                     // Skip nullified repeated values
                     if (NULL === $val) {
                         continue;
                     } else {
                         if ($type !== Protobuf::TYPE_MESSAGE) {
                             $writer->varint($key);
                             $this->encodeSimpleType($writer, $type, $val);
                         } else {
                             $writer->varint($key);
                             $data = $this->encodeMessage($val);
                             $writer->varint(strlen($data));
                             $writer->write($data);
                         }
                     }
                 }
             }
         } else {
             if ($type !== Protobuf::TYPE_MESSAGE) {
                 $writer->varint($key);
                 $this->encodeSimpleType($writer, $type, $value);
             } else {
                 $writer->varint($key);
                 $data = $this->encodeMessage($value);
                 $writer->varint(strlen($data));
                 $writer->write($data);
             }
         }
     }
     return $writer->getBytes();
 }
Esempio n. 9
0
 /**
  * @param \DrSlump\Protobuf\Codec\Binary\Reader $reader
  * @param \DrSlump\Protobuf\Message             $message
  * @param int                                   $length 
  * @return \DrSlump\Protobuf\Message
  */
 protected function decodeMessage($reader, \DrSlump\Protobuf\Message $message, $length = NULL)
 {
     /** @var $message \DrSlump\Protobuf\Message */
     /** @var $descriptor \DrSlump\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;
 }