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