desc = $desc; return; } $pool = DescriptorPool::getGeneratedPool(); $this->desc = $pool->getDescriptorByClassName(get_class($this)); foreach ($this->desc->getField() as $field) { $setter = $field->getSetter(); if ($field->isMap()) { $message_type = $field->getMessageType(); $key_field = $message_type->getFieldByNumber(1); $value_field = $message_type->getFieldByNumber(2); switch ($value_field->getType()) { case GPBType::MESSAGE: case GPBType::GROUP: $map_field = new MapField( $key_field->getType(), $value_field->getType(), $value_field->getMessageType()->getClass()); $this->$setter($map_field); break; case GPBType::ENUM: $map_field = new MapField( $key_field->getType(), $value_field->getType(), $value_field->getEnumType()->getClass()); $this->$setter($map_field); break; default: $map_field = new MapField( $key_field->getType(), $value_field->getType()); $this->$setter($map_field); break; } } else if ($field->getLabel() === GPBLabel::REPEATED) { switch ($field->getType()) { case GPBType::MESSAGE: case GPBType::GROUP: $repeated_field = new RepeatedField( $field->getType(), $field->getMessageType()->getClass()); $this->$setter($repeated_field); break; case GPBType::ENUM: $repeated_field = new RepeatedField( $field->getType(), $field->getEnumType()->getClass()); $this->$setter($repeated_field); break; default: $repeated_field = new RepeatedField($field->getType()); $this->$setter($repeated_field); break; } } else if ($field->getOneofIndex() !== -1) { $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; $oneof_name = $oneof->getName(); $this->$oneof_name = new OneofField($oneof); } } } protected function readOneof($number) { $field = $this->desc->getFieldByNumber($number); $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; $oneof_name = $oneof->getName(); $oneof_field = $this->$oneof_name; if ($number === $oneof_field->getNumber()) { return $oneof_field->getValue(); } else { return $this->defaultValue($field); } } protected function writeOneof($number, $value) { $field = $this->desc->getFieldByNumber($number); $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; $oneof_name = $oneof->getName(); $oneof_field = $this->$oneof_name; $oneof_field->setValue($value); $oneof_field->setFieldName($field->getName()); $oneof_field->setNumber($number); } /** * @ignore */ private function defaultValue($field) { $value = null; switch ($field->getType()) { case GPBType::DOUBLE: case GPBType::FLOAT: return 0.0; case GPBType::UINT32: case GPBType::UINT64: case GPBType::INT32: case GPBType::INT64: case GPBType::FIXED32: case GPBType::FIXED64: case GPBType::SFIXED32: case GPBType::SFIXED64: case GPBType::SINT32: case GPBType::SINT64: case GPBType::ENUM: return 0; case GPBType::BOOL: return false; case GPBType::STRING: case GPBType::BYTES: return ""; case GPBType::GROUP: case GPBType::MESSAGE: return null; default: user_error("Unsupported type."); return false; } } /** * @ignore */ private static function parseFieldFromStreamNoTag($input, $field, &$value) { switch ($field->getType()) { case GPBType::DOUBLE: if (!GPBWire::readDouble($input, $value)) { return false; } break; case GPBType::FLOAT: if (!GPBWire::readFloat($input, $value)) { return false; } break; case GPBType::INT64: if (!GPBWire::readInt64($input, $value)) { return false; } $value = $value->toInteger(); break; case GPBType::UINT64: if (!GPBWire::readUint64($input, $value)) { return false; } $value = $value->toInteger(); break; case GPBType::INT32: if (!GPBWire::readInt32($input, $value)) { return false; } break; case GPBType::FIXED64: if (!GPBWire::readFixed64($input, $value)) { return false; } $value = $value->toInteger(); break; case GPBType::FIXED32: if (!GPBWire::readFixed32($input, $value)) { return false; } break; case GPBType::BOOL: if (!GPBWire::readBool($input, $value)) { return false; } break; case GPBType::STRING: // TODO(teboring): Add utf-8 check. if (!GPBWire::readString($input, $value)) { return false; } break; case GPBType::GROUP: echo "GROUP\xA"; trigger_error("Not implemented.", E_ERROR); break; case GPBType::MESSAGE: if ($field->isMap()) { $value = new MapEntry($field->getMessageType()); } else { $klass = $field->getMessageType()->getClass(); $value = new $klass; } if (!GPBWire::readMessage($input, $value)) { return false; } break; case GPBType::BYTES: if (!GPBWire::readString($input, $value)) { return false; } break; case GPBType::UINT32: if (!GPBWire::readUint32($input, $value)) { return false; } break; case GPBType::ENUM: // TODO(teboring): Check unknown enum value. if (!GPBWire::readInt32($input, $value)) { return false; } break; case GPBType::SFIXED32: if (!GPBWire::readSfixed32($input, $value)) { return false; } break; case GPBType::SFIXED64: if (!GPBWire::readSfixed64($input, $value)) { return false; } $value = $value->toInteger(); break; case GPBType::SINT32: if (!GPBWire::readSint32($input, $value)) { return false; } break; case GPBType::SINT64: if (!GPBWire::readSint64($input, $value)) { return false; } $value = $value->toInteger(); break; default: user_error("Unsupported type."); return false; } return true; } /** * @ignore */ private function parseFieldFromStream($tag, $input, $field) { $value = null; $field_type = $field->getType(); $value_format = GPBWire::UNKNOWN; if (GPBWire::getTagWireType($tag) === GPBWire::getWireType($field_type)) { $value_format = GPBWire::NORMAL_FORMAT; } elseif ($field->isPackable() && GPBWire::getTagWireType($tag) === GPBWire::WIRETYPE_LENGTH_DELIMITED) { $value_format = GPBWire::PACKED_FORMAT; } if ($value_format === GPBWire::NORMAL_FORMAT) { if (!self::parseFieldFromStreamNoTag($input, $field, $value)) { return false; } } elseif ($value_format === GPBWire::PACKED_FORMAT) { $length = 0; if (!GPBWire::readInt32($input, $length)) { return false; } $limit = $input->pushLimit($length); $getter = $field->getGetter(); while ($input->bytesUntilLimit() > 0) { if (!self::parseFieldFromStreamNoTag($input, $field, $value)) { return false; } $this->$getter()[] = $value; } $input->popLimit($limit); return true; } else { return false; } if ($field->isMap()) { $getter = $field->getGetter(); $this->$getter()[$value->getKey()] = $value->getValue(); } else if ($field->isRepeated()) { $getter = $field->getGetter(); $this->$getter()[] = $value; } else { $setter = $field->getSetter(); $this->$setter($value); } return true; } /** * Parses a protocol buffer contained in a string. * * This function takes a string in the (non-human-readable) binary wire * format, matching the encoding output by encode(). * * @param string $data Binary protobuf data. * @return bool Return true on success. */ public function decode($data) { $input = new InputStream($data); $this->parseFromStream($input); } /** * @ignore */ public function parseFromStream($input) { while (true) { $tag = $input->readTag(); // End of input. This is a valid place to end, so return true. if ($tag === 0) { return true; } $number = GPBWire::getTagFieldNumber($tag); $field = $this->desc->getFieldByNumber($number); if (!$this->parseFieldFromStream($tag, $input, $field)) { return false; } } } /** * @ignore */ private function serializeSingularFieldToStream($field, &$output) { if (!$this->existField($field)) { return true; } $getter = $field->getGetter(); $value = $this->$getter(); if (!GPBWire::serializeFieldToStream($value, $field, true, $output)) { return false; } return true; } /** * @ignore */ private function serializeRepeatedFieldToStream($field, &$output) { $getter = $field->getGetter(); $values = $this->$getter(); $count = count($values); if ($count === 0) { return true; } $packed = $field->getPacked(); if ($packed) { if (!GPBWire::writeTag( $output, GPBWire::makeTag($field->getNumber(), GPBType::STRING))) { return false; } $size = 0; foreach ($values as $value) { $size += $this->fieldDataOnlyByteSize($field, $value); } if (!$output->writeVarint32($size)) { return false; } } foreach ($values as $value) { if (!GPBWire::serializeFieldToStream( $value, $field, !$packed, $output)) { return false; } } return true; } /** * @ignore */ private function serializeMapFieldToStream($field, $output) { $getter = $field->getGetter(); $values = $this->$getter(); $count = count($values); if ($count === 0) { return true; } foreach ($values as $key => $value) { $map_entry = new MapEntry($field->getMessageType()); $map_entry->setKey($key); $map_entry->setValue($value); if (!GPBWire::serializeFieldToStream( $map_entry, $field, true, $output)) { return false; } } return true; } /** * @ignore */ private function serializeFieldToStream(&$output, $field) { if ($field->isMap()) { return $this->serializeMapFieldToStream($field, $output); } elseif ($field->isRepeated()) { return $this->serializeRepeatedFieldToStream($field, $output); } else { return $this->serializeSingularFieldToStream($field, $output); } } /** * @ignore */ public function serializeToStream(&$output) { $fields = $this->desc->getField(); foreach ($fields as $field) { if (!$this->serializeFieldToStream($output, $field)) { return false; } } return true; } /** * Serialize the message to string. * @return string Serialized binary protobuf data. */ public function encode() { $output = new OutputStream($this->byteSize()); $this->serializeToStream($output); return $output->getData(); } /** * @ignore */ private function existField($field) { $getter = $field->getGetter(); $value = $this->$getter(); return $value !== $this->defaultValue($field); } /** * @ignore */ private function repeatedFieldDataOnlyByteSize($field) { $size = 0; $getter = $field->getGetter(); $values = $this->$getter(); $count = count($values); if ($count !== 0) { $size += $count * GPBWire::tagSize($field); foreach ($values as $value) { $size += $this->singularFieldDataOnlyByteSize($field); } } } /** * @ignore */ private function fieldDataOnlyByteSize($field, $value) { $size = 0; switch ($field->getType()) { case GPBType::BOOL: $size += 1; break; case GPBType::FLOAT: case GPBType::FIXED32: case GPBType::SFIXED32: $size += 4; break; case GPBType::DOUBLE: case GPBType::FIXED64: case GPBType::SFIXED64: $size += 8; break; case GPBType::UINT32: case GPBType::INT32: case GPBType::ENUM: $size += GPBWire::varint32Size($value); break; case GPBType::UINT64: case GPBType::INT64: $size += GPBWire::varint64Size($value); break; case GPBType::SINT32: $size += GPBWire::sint32Size($value); break; case GPBType::SINT64: $size += GPBWire::sint64Size($value); break; case GPBType::STRING: case GPBType::BYTES: $size += strlen($value); $size += GPBWire::varint32Size($size); break; case GPBType::MESSAGE: $size += $value->byteSize(); $size += GPBWire::varint32Size($size); break; case GPBType::GROUP: // TODO(teboring): Add support. user_error("Unsupported type."); break; default: user_error("Unsupported type."); return 0; } return $size; } /** * @ignore */ private function fieldByteSize($field) { $size = 0; if ($field->isMap()) { $getter = $field->getGetter(); $values = $this->$getter(); $count = count($values); if ($count !== 0) { $size += $count * GPBWire::tagSize($field); $message_type = $field->getMessageType(); $key_field = $message_type->getFieldByNumber(1); $value_field = $message_type->getFieldByNumber(2); foreach ($values as $key => $value) { $data_size = 0; $data_size += $this->fieldDataOnlyByteSize($key_field, $key); $data_size += $this->fieldDataOnlyByteSize( $value_field, $value); $data_size += GPBWire::tagSize($key_field); $data_size += GPBWire::tagSize($value_field); $size += GPBWire::varint32Size($data_size) + $data_size; } } } elseif ($field->isRepeated()) { $getter = $field->getGetter(); $values = $this->$getter(); $count = count($values); if ($count !== 0) { if ($field->getPacked()) { $data_size = 0; foreach ($values as $value) { $data_size += $this->fieldDataOnlyByteSize($field, $value); } $size += GPBWire::tagSize($field); $size += GPBWire::varint32Size($data_size); $size += $data_size; } else { $size += $count * GPBWire::tagSize($field); foreach ($values as $value) { $size += $this->fieldDataOnlyByteSize($field, $value); } } } } elseif ($this->existField($field)) { $size += GPBWire::tagSize($field); $getter = $field->getGetter(); $value = $this->$getter(); $size += $this->fieldDataOnlyByteSize($field, $value); } return $size; } /** * @ignore */ public function byteSize() { $size = 0; $fields = $this->desc->getField(); foreach ($fields as $field) { $size += $this->fieldByteSize($field); } return $size; } }