Message.php 22 KB

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