Message.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <?php
  2. // Protocol Buffers - Google's data interchange format
  3. // Copyright 2008 Google Inc. All rights reserved.
  4. // https://developers.google.com/protocol-buffers/
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. /**
  32. * Defines Message, the parent class extended by all protocol message classes.
  33. */
  34. namespace Google\Protobuf\Internal;
  35. use Google\Protobuf\Internal\InputStream;
  36. use Google\Protobuf\Internal\OutputStream;
  37. use Google\Protobuf\Internal\DescriptorPool;
  38. use Google\Protobuf\Internal\GPBLabel;
  39. use Google\Protobuf\Internal\GPBType;
  40. use Google\Protobuf\Internal\GPBWire;
  41. use Google\Protobuf\Internal\MapEntry;
  42. use Google\Protobuf\Internal\RepeatedField;
  43. /**
  44. * Parent class of all proto messages. Users should not instantiate this class
  45. * or extend this class or its child classes by their own. See the comment of
  46. * specific functions for more details.
  47. */
  48. class Message
  49. {
  50. /**
  51. * @ignore
  52. */
  53. private $desc;
  54. /**
  55. * @ignore
  56. */
  57. public function __construct($desc = NULL)
  58. {
  59. // MapEntry message is shared by all types of map fields, whose
  60. // descriptors are different from each other. Thus, we cannot find a
  61. // specific descriptor from the descriptor pool.
  62. if (get_class($this) === 'Google\Protobuf\Internal\MapEntry') {
  63. $this->desc = $desc;
  64. return;
  65. }
  66. $pool = DescriptorPool::getGeneratedPool();
  67. $this->desc = $pool->getDescriptorByClassName(get_class($this));
  68. foreach ($this->desc->getField() as $field) {
  69. $setter = $field->getSetter();
  70. if ($field->isMap()) {
  71. $message_type = $field->getMessageType();
  72. $key_field = $message_type->getFieldByNumber(1);
  73. $value_field = $message_type->getFieldByNumber(2);
  74. switch ($value_field->getType()) {
  75. case GPBType::MESSAGE:
  76. case GPBType::GROUP:
  77. $map_field = new MapField(
  78. $key_field->getType(),
  79. $value_field->getType(),
  80. $value_field->getMessageType()->getClass());
  81. $this->$setter($map_field);
  82. break;
  83. case GPBType::ENUM:
  84. $map_field = new MapField(
  85. $key_field->getType(),
  86. $value_field->getType(),
  87. $value_field->getEnumType()->getClass());
  88. $this->$setter($map_field);
  89. break;
  90. default:
  91. $map_field = new MapField(
  92. $key_field->getType(),
  93. $value_field->getType());
  94. $this->$setter($map_field);
  95. break;
  96. }
  97. } else if ($field->getLabel() === GPBLabel::REPEATED) {
  98. switch ($field->getType()) {
  99. case GPBType::MESSAGE:
  100. case GPBType::GROUP:
  101. $repeated_field = new RepeatedField(
  102. $field->getType(),
  103. $field->getMessageType()->getClass());
  104. $this->$setter($repeated_field);
  105. break;
  106. case GPBType::ENUM:
  107. $repeated_field = new RepeatedField(
  108. $field->getType(),
  109. $field->getEnumType()->getClass());
  110. $this->$setter($repeated_field);
  111. break;
  112. default:
  113. $repeated_field = new RepeatedField($field->getType());
  114. $this->$setter($repeated_field);
  115. break;
  116. }
  117. } else if ($field->getOneofIndex() !== -1) {
  118. $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
  119. $oneof_name = $oneof->getName();
  120. $this->$oneof_name = new OneofField($oneof);
  121. }
  122. }
  123. }
  124. protected function readOneof($number)
  125. {
  126. $field = $this->desc->getFieldByNumber($number);
  127. $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
  128. $oneof_name = $oneof->getName();
  129. $oneof_field = $this->$oneof_name;
  130. if ($number === $oneof_field->getNumber()) {
  131. return $oneof_field->getValue();
  132. } else {
  133. return $this->defaultValue($field);
  134. }
  135. }
  136. protected function writeOneof($number, $value)
  137. {
  138. $field = $this->desc->getFieldByNumber($number);
  139. $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
  140. $oneof_name = $oneof->getName();
  141. $oneof_field = $this->$oneof_name;
  142. $oneof_field->setValue($value);
  143. $oneof_field->setFieldName($field->getName());
  144. $oneof_field->setNumber($number);
  145. }
  146. /**
  147. * @ignore
  148. */
  149. private function defaultValue($field)
  150. {
  151. $value = null;
  152. switch ($field->getType()) {
  153. case GPBType::DOUBLE:
  154. case GPBType::FLOAT:
  155. return 0.0;
  156. case GPBType::UINT32:
  157. case GPBType::UINT64:
  158. case GPBType::INT32:
  159. case GPBType::INT64:
  160. case GPBType::FIXED32:
  161. case GPBType::FIXED64:
  162. case GPBType::SFIXED32:
  163. case GPBType::SFIXED64:
  164. case GPBType::SINT32:
  165. case GPBType::SINT64:
  166. case GPBType::ENUM:
  167. return 0;
  168. case GPBType::BOOL:
  169. return false;
  170. case GPBType::STRING:
  171. case GPBType::BYTES:
  172. return "";
  173. case GPBType::GROUP:
  174. case GPBType::MESSAGE:
  175. return null;
  176. default:
  177. user_error("Unsupported type.");
  178. return false;
  179. }
  180. }
  181. /**
  182. * @ignore
  183. */
  184. private static function parseFieldFromStreamNoTag($input, $field, &$value)
  185. {
  186. switch ($field->getType()) {
  187. case GPBType::DOUBLE:
  188. if (!GPBWire::readDouble($input, $value)) {
  189. return false;
  190. }
  191. break;
  192. case GPBType::FLOAT:
  193. if (!GPBWire::readFloat($input, $value)) {
  194. return false;
  195. }
  196. break;
  197. case GPBType::INT64:
  198. if (!GPBWire::readInt64($input, $value)) {
  199. return false;
  200. }
  201. $value = $value->toInteger();
  202. break;
  203. case GPBType::UINT64:
  204. if (!GPBWire::readUint64($input, $value)) {
  205. return false;
  206. }
  207. $value = $value->toInteger();
  208. break;
  209. case GPBType::INT32:
  210. if (!GPBWire::readInt32($input, $value)) {
  211. return false;
  212. }
  213. break;
  214. case GPBType::FIXED64:
  215. if (!GPBWire::readFixed64($input, $value)) {
  216. return false;
  217. }
  218. $value = $value->toInteger();
  219. break;
  220. case GPBType::FIXED32:
  221. if (!GPBWire::readFixed32($input, $value)) {
  222. return false;
  223. }
  224. break;
  225. case GPBType::BOOL:
  226. if (!GPBWire::readBool($input, $value)) {
  227. return false;
  228. }
  229. break;
  230. case GPBType::STRING:
  231. // TODO(teboring): Add utf-8 check.
  232. if (!GPBWire::readString($input, $value)) {
  233. return false;
  234. }
  235. break;
  236. case GPBType::GROUP:
  237. echo "GROUP\xA";
  238. trigger_error("Not implemented.", E_ERROR);
  239. break;
  240. case GPBType::MESSAGE:
  241. if ($field->isMap()) {
  242. $value = new MapEntry($field->getMessageType());
  243. } else {
  244. $klass = $field->getMessageType()->getClass();
  245. $value = new $klass;
  246. }
  247. if (!GPBWire::readMessage($input, $value)) {
  248. return false;
  249. }
  250. break;
  251. case GPBType::BYTES:
  252. if (!GPBWire::readString($input, $value)) {
  253. return false;
  254. }
  255. break;
  256. case GPBType::UINT32:
  257. if (!GPBWire::readUint32($input, $value)) {
  258. return false;
  259. }
  260. break;
  261. case GPBType::ENUM:
  262. // TODO(teboring): Check unknown enum value.
  263. if (!GPBWire::readInt32($input, $value)) {
  264. return false;
  265. }
  266. break;
  267. case GPBType::SFIXED32:
  268. if (!GPBWire::readSfixed32($input, $value)) {
  269. return false;
  270. }
  271. break;
  272. case GPBType::SFIXED64:
  273. if (!GPBWire::readSfixed64($input, $value)) {
  274. return false;
  275. }
  276. $value = $value->toInteger();
  277. break;
  278. case GPBType::SINT32:
  279. if (!GPBWire::readSint32($input, $value)) {
  280. return false;
  281. }
  282. break;
  283. case GPBType::SINT64:
  284. if (!GPBWire::readSint64($input, $value)) {
  285. return false;
  286. }
  287. $value = $value->toInteger();
  288. break;
  289. default:
  290. user_error("Unsupported type.");
  291. return false;
  292. }
  293. return true;
  294. }
  295. /**
  296. * @ignore
  297. */
  298. private function parseFieldFromStream($tag, $input, $field)
  299. {
  300. $value = null;
  301. $field_type = $field->getType();
  302. $value_format = GPBWire::UNKNOWN;
  303. if (GPBWire::getTagWireType($tag) ===
  304. GPBWire::getWireType($field_type)) {
  305. $value_format = GPBWire::NORMAL_FORMAT;
  306. } elseif ($field->isPackable() &&
  307. GPBWire::getTagWireType($tag) ===
  308. GPBWire::WIRETYPE_LENGTH_DELIMITED) {
  309. $value_format = GPBWire::PACKED_FORMAT;
  310. }
  311. if ($value_format === GPBWire::NORMAL_FORMAT) {
  312. if (!self::parseFieldFromStreamNoTag($input, $field, $value)) {
  313. return false;
  314. }
  315. } elseif ($value_format === GPBWire::PACKED_FORMAT) {
  316. $length = 0;
  317. if (!GPBWire::readInt32($input, $length)) {
  318. return false;
  319. }
  320. $limit = $input->pushLimit($length);
  321. $getter = $field->getGetter();
  322. while ($input->bytesUntilLimit() > 0) {
  323. if (!self::parseFieldFromStreamNoTag($input, $field, $value)) {
  324. return false;
  325. }
  326. $this->$getter()[] = $value;
  327. }
  328. $input->popLimit($limit);
  329. return true;
  330. } else {
  331. return false;
  332. }
  333. if ($field->isMap()) {
  334. $getter = $field->getGetter();
  335. $this->$getter()[$value->getKey()] = $value->getValue();
  336. } else if ($field->isRepeated()) {
  337. $getter = $field->getGetter();
  338. $this->$getter()[] = $value;
  339. } else {
  340. $setter = $field->getSetter();
  341. $this->$setter($value);
  342. }
  343. return true;
  344. }
  345. /**
  346. * Parses a protocol buffer contained in a string.
  347. *
  348. * This function takes a string in the (non-human-readable) binary wire
  349. * format, matching the encoding output by encode().
  350. *
  351. * @param string $data Binary protobuf data.
  352. * @return bool Return true on success.
  353. */
  354. public function decode($data)
  355. {
  356. $input = new InputStream($data);
  357. $this->parseFromStream($input);
  358. }
  359. /**
  360. * @ignore
  361. */
  362. public function parseFromStream($input)
  363. {
  364. while (true) {
  365. $tag = $input->readTag();
  366. // End of input. This is a valid place to end, so return true.
  367. if ($tag === 0) {
  368. return true;
  369. }
  370. $number = GPBWire::getTagFieldNumber($tag);
  371. $field = $this->desc->getFieldByNumber($number);
  372. if (!$this->parseFieldFromStream($tag, $input, $field)) {
  373. return false;
  374. }
  375. }
  376. }
  377. /**
  378. * @ignore
  379. */
  380. private function serializeSingularFieldToStream($field, &$output)
  381. {
  382. if (!$this->existField($field)) {
  383. return true;
  384. }
  385. $getter = $field->getGetter();
  386. $value = $this->$getter();
  387. if (!GPBWire::serializeFieldToStream($value, $field, true, $output)) {
  388. return false;
  389. }
  390. return true;
  391. }
  392. /**
  393. * @ignore
  394. */
  395. private function serializeRepeatedFieldToStream($field, &$output)
  396. {
  397. $getter = $field->getGetter();
  398. $values = $this->$getter();
  399. $count = count($values);
  400. if ($count === 0) {
  401. return true;
  402. }
  403. $packed = $field->getPacked();
  404. if ($packed) {
  405. if (!GPBWire::writeTag(
  406. $output,
  407. GPBWire::makeTag($field->getNumber(), GPBType::STRING))) {
  408. return false;
  409. }
  410. $size = 0;
  411. foreach ($values as $value) {
  412. $size += $this->fieldDataOnlyByteSize($field, $value);
  413. }
  414. if (!$output->writeVarint32($size)) {
  415. return false;
  416. }
  417. }
  418. foreach ($values as $value) {
  419. if (!GPBWire::serializeFieldToStream(
  420. $value,
  421. $field,
  422. !$packed,
  423. $output)) {
  424. return false;
  425. }
  426. }
  427. return true;
  428. }
  429. /**
  430. * @ignore
  431. */
  432. private function serializeMapFieldToStream($field, $output)
  433. {
  434. $getter = $field->getGetter();
  435. $values = $this->$getter();
  436. $count = count($values);
  437. if ($count === 0) {
  438. return true;
  439. }
  440. foreach ($values as $key => $value) {
  441. $map_entry = new MapEntry($field->getMessageType());
  442. $map_entry->setKey($key);
  443. $map_entry->setValue($value);
  444. if (!GPBWire::serializeFieldToStream(
  445. $map_entry,
  446. $field,
  447. true,
  448. $output)) {
  449. return false;
  450. }
  451. }
  452. return true;
  453. }
  454. /**
  455. * @ignore
  456. */
  457. private function serializeFieldToStream(&$output, $field)
  458. {
  459. if ($field->isMap()) {
  460. return $this->serializeMapFieldToStream($field, $output);
  461. } elseif ($field->isRepeated()) {
  462. return $this->serializeRepeatedFieldToStream($field, $output);
  463. } else {
  464. return $this->serializeSingularFieldToStream($field, $output);
  465. }
  466. }
  467. /**
  468. * @ignore
  469. */
  470. public function serializeToStream(&$output)
  471. {
  472. $fields = $this->desc->getField();
  473. foreach ($fields as $field) {
  474. if (!$this->serializeFieldToStream($output, $field)) {
  475. return false;
  476. }
  477. }
  478. return true;
  479. }
  480. /**
  481. * Serialize the message to string.
  482. * @return string Serialized binary protobuf data.
  483. */
  484. public function encode()
  485. {
  486. $output = new OutputStream($this->byteSize());
  487. $this->serializeToStream($output);
  488. return $output->getData();
  489. }
  490. /**
  491. * @ignore
  492. */
  493. private function existField($field)
  494. {
  495. $getter = $field->getGetter();
  496. $value = $this->$getter();
  497. return $value !== $this->defaultValue($field);
  498. }
  499. /**
  500. * @ignore
  501. */
  502. private function repeatedFieldDataOnlyByteSize($field)
  503. {
  504. $size = 0;
  505. $getter = $field->getGetter();
  506. $values = $this->$getter();
  507. $count = count($values);
  508. if ($count !== 0) {
  509. $size += $count * GPBWire::tagSize($field);
  510. foreach ($values as $value) {
  511. $size += $this->singularFieldDataOnlyByteSize($field);
  512. }
  513. }
  514. }
  515. /**
  516. * @ignore
  517. */
  518. private function fieldDataOnlyByteSize($field, $value)
  519. {
  520. $size = 0;
  521. switch ($field->getType()) {
  522. case GPBType::BOOL:
  523. $size += 1;
  524. break;
  525. case GPBType::FLOAT:
  526. case GPBType::FIXED32:
  527. case GPBType::SFIXED32:
  528. $size += 4;
  529. break;
  530. case GPBType::DOUBLE:
  531. case GPBType::FIXED64:
  532. case GPBType::SFIXED64:
  533. $size += 8;
  534. break;
  535. case GPBType::UINT32:
  536. case GPBType::INT32:
  537. case GPBType::ENUM:
  538. $size += GPBWire::varint32Size($value);
  539. break;
  540. case GPBType::UINT64:
  541. case GPBType::INT64:
  542. $size += GPBWire::varint64Size($value);
  543. break;
  544. case GPBType::SINT32:
  545. $size += GPBWire::sint32Size($value);
  546. break;
  547. case GPBType::SINT64:
  548. $size += GPBWire::sint64Size($value);
  549. break;
  550. case GPBType::STRING:
  551. case GPBType::BYTES:
  552. $size += strlen($value);
  553. $size += GPBWire::varint32Size($size);
  554. break;
  555. case GPBType::MESSAGE:
  556. $size += $value->byteSize();
  557. $size += GPBWire::varint32Size($size);
  558. break;
  559. case GPBType::GROUP:
  560. // TODO(teboring): Add support.
  561. user_error("Unsupported type.");
  562. break;
  563. default:
  564. user_error("Unsupported type.");
  565. return 0;
  566. }
  567. return $size;
  568. }
  569. /**
  570. * @ignore
  571. */
  572. private function fieldByteSize($field)
  573. {
  574. $size = 0;
  575. if ($field->isMap()) {
  576. $getter = $field->getGetter();
  577. $values = $this->$getter();
  578. $count = count($values);
  579. if ($count !== 0) {
  580. $size += $count * GPBWire::tagSize($field);
  581. $message_type = $field->getMessageType();
  582. $key_field = $message_type->getFieldByNumber(1);
  583. $value_field = $message_type->getFieldByNumber(2);
  584. foreach ($values as $key => $value) {
  585. $data_size = 0;
  586. $data_size += $this->fieldDataOnlyByteSize($key_field, $key);
  587. $data_size += $this->fieldDataOnlyByteSize(
  588. $value_field,
  589. $value);
  590. $data_size += GPBWire::tagSize($key_field);
  591. $data_size += GPBWire::tagSize($value_field);
  592. $size += GPBWire::varint32Size($data_size) + $data_size;
  593. }
  594. }
  595. } elseif ($field->isRepeated()) {
  596. $getter = $field->getGetter();
  597. $values = $this->$getter();
  598. $count = count($values);
  599. if ($count !== 0) {
  600. if ($field->getPacked()) {
  601. $data_size = 0;
  602. foreach ($values as $value) {
  603. $data_size += $this->fieldDataOnlyByteSize($field, $value);
  604. }
  605. $size += GPBWire::tagSize($field);
  606. $size += GPBWire::varint32Size($data_size);
  607. $size += $data_size;
  608. } else {
  609. $size += $count * GPBWire::tagSize($field);
  610. foreach ($values as $value) {
  611. $size += $this->fieldDataOnlyByteSize($field, $value);
  612. }
  613. }
  614. }
  615. } elseif ($this->existField($field)) {
  616. $size += GPBWire::tagSize($field);
  617. $getter = $field->getGetter();
  618. $value = $this->$getter();
  619. $size += $this->fieldDataOnlyByteSize($field, $value);
  620. }
  621. return $size;
  622. }
  623. /**
  624. * @ignore
  625. */
  626. public function byteSize()
  627. {
  628. $size = 0;
  629. $fields = $this->desc->getField();
  630. foreach ($fields as $field) {
  631. $size += $this->fieldByteSize($field);
  632. }
  633. return $size;
  634. }
  635. }