Example #1
0
 protected function decodeMessage(Protobuf\MessageInterface $message, $data)
 {
     // Get message descriptor
     $descriptor = Protobuf\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\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;
 }
Example #2
0
 protected function decodeMessage(Protobuf\Message $message, $data)
 {
     // Get message descriptor
     $descriptor = Protobuf\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\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;
 }
Example #3
0
 protected function encodeMessage(Protobuf\MessageInterface $message, $level = 0)
 {
     $descriptor = Protobuf\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');
         }
         // skip not set values
         if ($empty) {
             continue;
         }
         $value = $message[$tag];
         // don't send nulls or defaults over the wire
         if (NULL === $value || $field->hasDefault() && $field->getDefault() === $value) {
             continue;
         }
         $name = $field->getName();
         if ($field->isRepeated()) {
             foreach ($value as $val) {
                 // Skip nullified repeated values
                 if (NULL === $val) {
                     continue;
                 } else {
                     if ($field->getType() !== Protobuf\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\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;
 }
Example #4
0
 /**
  * @param \DrSlump\Protobuf\MessageInterface    $message
  * @param string                                $data
  * @return \DrSlump\Protobuf\MessageInterface
  */
 protected function _decodeMessage(\DrSlump\Protobuf\MessageInterface $message, $data)
 {
     $descriptor = Protobuf\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\Protobuf::TYPE_MESSAGE) {
             if ($field->getRule() === Protobuf\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;
 }
Example #5
0
 protected function encodeMessage(Protobuf\Message $message)
 {
     $writer = new NativeWriter();
     // Get message descriptor
     $descriptor = Protobuf\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 not set values
         if ($empty) {
             continue;
         }
         $value = $message[$tag];
         // don't send nulls or defaults over the wire
         if (NULL === $value || $field->hasDefault() && $field->getDefault() === $value) {
             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;
         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(mb_strlen($data, '8bit'));
                 $writer->write($data);
             } else {
                 foreach ($value as $val) {
                     // Skip nullified repeated values
                     if (NULL === $val) {
                         continue;
                     } else {
                         if ($type !== Protobuf\Protobuf::TYPE_MESSAGE) {
                             $writer->varint($key);
                             $this->encodeSimpleType($writer, $type, $val);
                         } else {
                             $writer->varint($key);
                             $data = $this->encodeMessage($val);
                             $writer->varint(mb_strlen($data, '8bit'));
                             $writer->write($data);
                         }
                     }
                 }
             }
         } else {
             if ($type !== Protobuf\Protobuf::TYPE_MESSAGE) {
                 $writer->varint($key);
                 $this->encodeSimpleType($writer, $type, $value);
             } else {
                 $writer->varint($key);
                 $data = $this->encodeMessage($value);
                 $writer->varint(mb_strlen($data, '8bit'));
                 $writer->write($data);
             }
         }
     }
     return $writer->getBytes();
 }