Message.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  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. break;
  202. case GPBType::UINT64:
  203. if (!GPBWire::readUint64($input, $value)) {
  204. return false;
  205. }
  206. break;
  207. case GPBType::INT32:
  208. if (!GPBWire::readInt32($input, $value)) {
  209. return false;
  210. }
  211. break;
  212. case GPBType::FIXED64:
  213. if (!GPBWire::readFixed64($input, $value)) {
  214. return false;
  215. }
  216. break;
  217. case GPBType::FIXED32:
  218. if (!GPBWire::readFixed32($input, $value)) {
  219. return false;
  220. }
  221. break;
  222. case GPBType::BOOL:
  223. if (!GPBWire::readBool($input, $value)) {
  224. return false;
  225. }
  226. break;
  227. case GPBType::STRING:
  228. // TODO(teboring): Add utf-8 check.
  229. if (!GPBWire::readString($input, $value)) {
  230. return false;
  231. }
  232. break;
  233. case GPBType::GROUP:
  234. echo "GROUP\xA";
  235. trigger_error("Not implemented.", E_ERROR);
  236. break;
  237. case GPBType::MESSAGE:
  238. if ($field->isMap()) {
  239. $value = new MapEntry($field->getMessageType());
  240. } else {
  241. $klass = $field->getMessageType()->getClass();
  242. $value = new $klass;
  243. }
  244. if (!GPBWire::readMessage($input, $value)) {
  245. return false;
  246. }
  247. break;
  248. case GPBType::BYTES:
  249. if (!GPBWire::readString($input, $value)) {
  250. return false;
  251. }
  252. break;
  253. case GPBType::UINT32:
  254. if (!GPBWire::readUint32($input, $value)) {
  255. return false;
  256. }
  257. break;
  258. case GPBType::ENUM:
  259. // TODO(teboring): Check unknown enum value.
  260. if (!GPBWire::readInt32($input, $value)) {
  261. return false;
  262. }
  263. break;
  264. case GPBType::SFIXED32:
  265. if (!GPBWire::readSfixed32($input, $value)) {
  266. return false;
  267. }
  268. break;
  269. case GPBType::SFIXED64:
  270. if (!GPBWire::readSfixed64($input, $value)) {
  271. return false;
  272. }
  273. break;
  274. case GPBType::SINT32:
  275. if (!GPBWire::readSint32($input, $value)) {
  276. return false;
  277. }
  278. break;
  279. case GPBType::SINT64:
  280. if (!GPBWire::readSint64($input, $value)) {
  281. return false;
  282. }
  283. break;
  284. default:
  285. user_error("Unsupported type.");
  286. return false;
  287. }
  288. return true;
  289. }
  290. /**
  291. * @ignore
  292. */
  293. private function parseFieldFromStream($tag, $input, $field)
  294. {
  295. $value = null;
  296. $field_type = $field->getType();
  297. $value_format = GPBWire::UNKNOWN;
  298. if (GPBWire::getTagWireType($tag) ===
  299. GPBWire::getWireType($field_type)) {
  300. $value_format = GPBWire::NORMAL_FORMAT;
  301. } elseif ($field->isPackable() &&
  302. GPBWire::getTagWireType($tag) ===
  303. GPBWire::WIRETYPE_LENGTH_DELIMITED) {
  304. $value_format = GPBWire::PACKED_FORMAT;
  305. }
  306. if ($value_format === GPBWire::NORMAL_FORMAT) {
  307. if (!self::parseFieldFromStreamNoTag($input, $field, $value)) {
  308. return false;
  309. }
  310. } elseif ($value_format === GPBWire::PACKED_FORMAT) {
  311. $length = 0;
  312. if (!GPBWire::readInt32($input, $length)) {
  313. return false;
  314. }
  315. $limit = $input->pushLimit($length);
  316. $getter = $field->getGetter();
  317. while ($input->bytesUntilLimit() > 0) {
  318. if (!self::parseFieldFromStreamNoTag($input, $field, $value)) {
  319. return false;
  320. }
  321. $this->$getter()[] = $value;
  322. }
  323. $input->popLimit($limit);
  324. return true;
  325. } else {
  326. return false;
  327. }
  328. if ($field->isMap()) {
  329. $getter = $field->getGetter();
  330. $this->$getter()[$value->getKey()] = $value->getValue();
  331. } else if ($field->isRepeated()) {
  332. $getter = $field->getGetter();
  333. $this->$getter()[] = $value;
  334. } else {
  335. $setter = $field->getSetter();
  336. $this->$setter($value);
  337. }
  338. return true;
  339. }
  340. /**
  341. * Parses a protocol buffer contained in a string.
  342. *
  343. * This function takes a string in the (non-human-readable) binary wire
  344. * format, matching the encoding output by encode().
  345. *
  346. * @param string $data Binary protobuf data.
  347. * @return bool Return true on success.
  348. */
  349. public function decode($data)
  350. {
  351. $input = new InputStream($data);
  352. $this->parseFromStream($input);
  353. }
  354. /**
  355. * @ignore
  356. */
  357. public function parseFromStream($input)
  358. {
  359. while (true) {
  360. $tag = $input->readTag();
  361. // End of input. This is a valid place to end, so return true.
  362. if ($tag === 0) {
  363. return true;
  364. }
  365. $number = GPBWire::getTagFieldNumber($tag);
  366. $field = $this->desc->getFieldByNumber($number);
  367. if (!$this->parseFieldFromStream($tag, $input, $field)) {
  368. return false;
  369. }
  370. }
  371. }
  372. /**
  373. * @ignore
  374. */
  375. private function serializeSingularFieldToStream($field, &$output)
  376. {
  377. if (!$this->existField($field)) {
  378. return true;
  379. }
  380. $getter = $field->getGetter();
  381. $value = $this->$getter();
  382. if (!GPBWire::serializeFieldToStream($value, $field, true, $output)) {
  383. return false;
  384. }
  385. return true;
  386. }
  387. /**
  388. * @ignore
  389. */
  390. private function serializeRepeatedFieldToStream($field, &$output)
  391. {
  392. $getter = $field->getGetter();
  393. $values = $this->$getter();
  394. $count = count($values);
  395. if ($count === 0) {
  396. return true;
  397. }
  398. $packed = $field->getPacked();
  399. if ($packed) {
  400. if (!GPBWire::writeTag(
  401. $output,
  402. GPBWire::makeTag($field->getNumber(), GPBType::STRING))) {
  403. return false;
  404. }
  405. $size = 0;
  406. foreach ($values as $value) {
  407. $size += $this->fieldDataOnlyByteSize($field, $value);
  408. }
  409. if (!$output->writeVarint32($size)) {
  410. return false;
  411. }
  412. }
  413. foreach ($values as $value) {
  414. if (!GPBWire::serializeFieldToStream(
  415. $value,
  416. $field,
  417. !$packed,
  418. $output)) {
  419. return false;
  420. }
  421. }
  422. return true;
  423. }
  424. /**
  425. * @ignore
  426. */
  427. private function serializeMapFieldToStream($field, $output)
  428. {
  429. $getter = $field->getGetter();
  430. $values = $this->$getter();
  431. $count = count($values);
  432. if ($count === 0) {
  433. return true;
  434. }
  435. foreach ($values as $key => $value) {
  436. $map_entry = new MapEntry($field->getMessageType());
  437. $map_entry->setKey($key);
  438. $map_entry->setValue($value);
  439. if (!GPBWire::serializeFieldToStream(
  440. $map_entry,
  441. $field,
  442. true,
  443. $output)) {
  444. return false;
  445. }
  446. }
  447. return true;
  448. }
  449. /**
  450. * @ignore
  451. */
  452. private function serializeFieldToStream(&$output, $field)
  453. {
  454. if ($field->isMap()) {
  455. return $this->serializeMapFieldToStream($field, $output);
  456. } elseif ($field->isRepeated()) {
  457. return $this->serializeRepeatedFieldToStream($field, $output);
  458. } else {
  459. return $this->serializeSingularFieldToStream($field, $output);
  460. }
  461. }
  462. /**
  463. * @ignore
  464. */
  465. public function serializeToStream(&$output)
  466. {
  467. $fields = $this->desc->getField();
  468. foreach ($fields as $field) {
  469. if (!$this->serializeFieldToStream($output, $field)) {
  470. return false;
  471. }
  472. }
  473. return true;
  474. }
  475. /**
  476. * Serialize the message to string.
  477. * @return string Serialized binary protobuf data.
  478. */
  479. public function encode()
  480. {
  481. $output = new OutputStream($this->byteSize());
  482. $this->serializeToStream($output);
  483. return $output->getData();
  484. }
  485. /**
  486. * @ignore
  487. */
  488. private function existField($field)
  489. {
  490. $getter = $field->getGetter();
  491. $value = $this->$getter();
  492. return $value !== $this->defaultValue($field);
  493. }
  494. /**
  495. * @ignore
  496. */
  497. private function repeatedFieldDataOnlyByteSize($field)
  498. {
  499. $size = 0;
  500. $getter = $field->getGetter();
  501. $values = $this->$getter();
  502. $count = count($values);
  503. if ($count !== 0) {
  504. $size += $count * GPBWire::tagSize($field);
  505. foreach ($values as $value) {
  506. $size += $this->singularFieldDataOnlyByteSize($field);
  507. }
  508. }
  509. }
  510. /**
  511. * @ignore
  512. */
  513. private function fieldDataOnlyByteSize($field, $value)
  514. {
  515. $size = 0;
  516. switch ($field->getType()) {
  517. case GPBType::BOOL:
  518. $size += 1;
  519. break;
  520. case GPBType::FLOAT:
  521. case GPBType::FIXED32:
  522. case GPBType::SFIXED32:
  523. $size += 4;
  524. break;
  525. case GPBType::DOUBLE:
  526. case GPBType::FIXED64:
  527. case GPBType::SFIXED64:
  528. $size += 8;
  529. break;
  530. case GPBType::UINT32:
  531. case GPBType::INT32:
  532. case GPBType::ENUM:
  533. $size += GPBWire::varint32Size($value);
  534. break;
  535. case GPBType::UINT64:
  536. case GPBType::INT64:
  537. $size += GPBWire::varint64Size($value);
  538. break;
  539. case GPBType::SINT32:
  540. $size += GPBWire::sint32Size($value);
  541. break;
  542. case GPBType::SINT64:
  543. $size += GPBWire::sint64Size($value);
  544. break;
  545. case GPBType::STRING:
  546. case GPBType::BYTES:
  547. $size += strlen($value);
  548. $size += GPBWire::varint32Size($size);
  549. break;
  550. case GPBType::MESSAGE:
  551. $size += $value->byteSize();
  552. $size += GPBWire::varint32Size($size);
  553. break;
  554. case GPBType::GROUP:
  555. // TODO(teboring): Add support.
  556. user_error("Unsupported type.");
  557. break;
  558. default:
  559. user_error("Unsupported type.");
  560. return 0;
  561. }
  562. return $size;
  563. }
  564. /**
  565. * @ignore
  566. */
  567. private function fieldByteSize($field)
  568. {
  569. $size = 0;
  570. if ($field->isMap()) {
  571. $getter = $field->getGetter();
  572. $values = $this->$getter();
  573. $count = count($values);
  574. if ($count !== 0) {
  575. $size += $count * GPBWire::tagSize($field);
  576. $message_type = $field->getMessageType();
  577. $key_field = $message_type->getFieldByNumber(1);
  578. $value_field = $message_type->getFieldByNumber(2);
  579. foreach ($values as $key => $value) {
  580. $data_size = 0;
  581. $data_size += $this->fieldDataOnlyByteSize($key_field, $key);
  582. $data_size += $this->fieldDataOnlyByteSize(
  583. $value_field,
  584. $value);
  585. $data_size += GPBWire::tagSize($key_field);
  586. $data_size += GPBWire::tagSize($value_field);
  587. $size += GPBWire::varint32Size($data_size) + $data_size;
  588. }
  589. }
  590. } elseif ($field->isRepeated()) {
  591. $getter = $field->getGetter();
  592. $values = $this->$getter();
  593. $count = count($values);
  594. if ($count !== 0) {
  595. if ($field->getPacked()) {
  596. $data_size = 0;
  597. foreach ($values as $value) {
  598. $data_size += $this->fieldDataOnlyByteSize($field, $value);
  599. }
  600. $size += GPBWire::tagSize($field);
  601. $size += GPBWire::varint32Size($data_size);
  602. $size += $data_size;
  603. } else {
  604. $size += $count * GPBWire::tagSize($field);
  605. foreach ($values as $value) {
  606. $size += $this->fieldDataOnlyByteSize($field, $value);
  607. }
  608. }
  609. }
  610. } elseif ($this->existField($field)) {
  611. $size += GPBWire::tagSize($field);
  612. $getter = $field->getGetter();
  613. $value = $this->$getter();
  614. $size += $this->fieldDataOnlyByteSize($field, $value);
  615. }
  616. return $size;
  617. }
  618. /**
  619. * @ignore
  620. */
  621. public function byteSize()
  622. {
  623. $size = 0;
  624. $fields = $this->desc->getField();
  625. foreach ($fields as $field) {
  626. $size += $this->fieldByteSize($field);
  627. }
  628. return $size;
  629. }
  630. }