decoder.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. # Protocol Buffers - Google's data interchange format
  2. # Copyright 2008 Google Inc. All rights reserved.
  3. # http://code.google.com/p/protobuf/
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are
  7. # met:
  8. #
  9. # * Redistributions of source code must retain the above copyright
  10. # notice, this list of conditions and the following disclaimer.
  11. # * Redistributions in binary form must reproduce the above
  12. # copyright notice, this list of conditions and the following disclaimer
  13. # in the documentation and/or other materials provided with the
  14. # distribution.
  15. # * Neither the name of Google Inc. nor the names of its
  16. # contributors may be used to endorse or promote products derived from
  17. # this software without specific prior written permission.
  18. #
  19. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. """Class for decoding protocol buffer primitives.
  31. Contains the logic for decoding every logical protocol field type
  32. from one of the 5 physical wire types.
  33. """
  34. __author__ = 'robinson@google.com (Will Robinson)'
  35. import struct
  36. from froofle.protobuf import message
  37. from froofle.protobuf.internal import input_stream
  38. from froofle.protobuf.internal import wire_format
  39. # Note that much of this code is ported from //net/proto/ProtocolBuffer, and
  40. # that the interface is strongly inspired by WireFormat from the C++ proto2
  41. # implementation.
  42. class Decoder(object):
  43. """Decodes logical protocol buffer fields from the wire."""
  44. def __init__(self, s):
  45. """Initializes the decoder to read from s.
  46. Args:
  47. s: An immutable sequence of bytes, which must be accessible
  48. via the Python buffer() primitive (i.e., buffer(s)).
  49. """
  50. self._stream = input_stream.InputStream(s)
  51. def EndOfStream(self):
  52. """Returns true iff we've reached the end of the bytes we're reading."""
  53. return self._stream.EndOfStream()
  54. def Position(self):
  55. """Returns the 0-indexed position in |s|."""
  56. return self._stream.Position()
  57. def ReadFieldNumberAndWireType(self):
  58. """Reads a tag from the wire. Returns a (field_number, wire_type) pair."""
  59. tag_and_type = self.ReadUInt32()
  60. return wire_format.UnpackTag(tag_and_type)
  61. def SkipBytes(self, bytes):
  62. """Skips the specified number of bytes on the wire."""
  63. self._stream.SkipBytes(bytes)
  64. # Note that the Read*() methods below are not exactly symmetrical with the
  65. # corresponding Encoder.Append*() methods. Those Encoder methods first
  66. # encode a tag, but the Read*() methods below assume that the tag has already
  67. # been read, and that the client wishes to read a field of the specified type
  68. # starting at the current position.
  69. def ReadInt32(self):
  70. """Reads and returns a signed, varint-encoded, 32-bit integer."""
  71. return self._stream.ReadVarint32()
  72. def ReadInt64(self):
  73. """Reads and returns a signed, varint-encoded, 64-bit integer."""
  74. return self._stream.ReadVarint64()
  75. def ReadUInt32(self):
  76. """Reads and returns an signed, varint-encoded, 32-bit integer."""
  77. return self._stream.ReadVarUInt32()
  78. def ReadUInt64(self):
  79. """Reads and returns an signed, varint-encoded,64-bit integer."""
  80. return self._stream.ReadVarUInt64()
  81. def ReadSInt32(self):
  82. """Reads and returns a signed, zigzag-encoded, varint-encoded,
  83. 32-bit integer."""
  84. return wire_format.ZigZagDecode(self._stream.ReadVarUInt32())
  85. def ReadSInt64(self):
  86. """Reads and returns a signed, zigzag-encoded, varint-encoded,
  87. 64-bit integer."""
  88. return wire_format.ZigZagDecode(self._stream.ReadVarUInt64())
  89. def ReadFixed32(self):
  90. """Reads and returns an unsigned, fixed-width, 32-bit integer."""
  91. return self._stream.ReadLittleEndian32()
  92. def ReadFixed64(self):
  93. """Reads and returns an unsigned, fixed-width, 64-bit integer."""
  94. return self._stream.ReadLittleEndian64()
  95. def ReadSFixed32(self):
  96. """Reads and returns a signed, fixed-width, 32-bit integer."""
  97. value = self._stream.ReadLittleEndian32()
  98. if value >= (1 << 31):
  99. value -= (1 << 32)
  100. return value
  101. def ReadSFixed64(self):
  102. """Reads and returns a signed, fixed-width, 64-bit integer."""
  103. value = self._stream.ReadLittleEndian64()
  104. if value >= (1 << 63):
  105. value -= (1 << 64)
  106. return value
  107. def ReadFloat(self):
  108. """Reads and returns a 4-byte floating-point number."""
  109. serialized = self._stream.ReadBytes(4)
  110. return struct.unpack('f', serialized)[0]
  111. def ReadDouble(self):
  112. """Reads and returns an 8-byte floating-point number."""
  113. serialized = self._stream.ReadBytes(8)
  114. return struct.unpack('d', serialized)[0]
  115. def ReadBool(self):
  116. """Reads and returns a bool."""
  117. i = self._stream.ReadVarUInt32()
  118. return bool(i)
  119. def ReadEnum(self):
  120. """Reads and returns an enum value."""
  121. return self._stream.ReadVarUInt32()
  122. def ReadString(self):
  123. """Reads and returns a length-delimited string."""
  124. bytes = self.ReadBytes()
  125. return unicode(bytes, 'utf-8')
  126. def ReadBytes(self):
  127. """Reads and returns a length-delimited byte sequence."""
  128. length = self._stream.ReadVarUInt32()
  129. return self._stream.ReadBytes(length)
  130. def ReadMessageInto(self, msg):
  131. """Calls msg.MergeFromString() to merge
  132. length-delimited serialized message data into |msg|.
  133. REQUIRES: The decoder must be positioned at the serialized "length"
  134. prefix to a length-delmiited serialized message.
  135. POSTCONDITION: The decoder is positioned just after the
  136. serialized message, and we have merged those serialized
  137. contents into |msg|.
  138. """
  139. length = self._stream.ReadVarUInt32()
  140. sub_buffer = self._stream.GetSubBuffer(length)
  141. num_bytes_used = msg.MergeFromString(sub_buffer)
  142. if num_bytes_used != length:
  143. raise message.DecodeError(
  144. 'Submessage told to deserialize from %d-byte encoding, '
  145. 'but used only %d bytes' % (length, num_bytes_used))
  146. self._stream.SkipBytes(num_bytes_used)
  147. def ReadGroupInto(self, expected_field_number, group):
  148. """Calls group.MergeFromString() to merge
  149. END_GROUP-delimited serialized message data into |group|.
  150. We'll raise an exception if we don't find an END_GROUP
  151. tag immediately after the serialized message contents.
  152. REQUIRES: The decoder is positioned just after the START_GROUP
  153. tag for this group.
  154. POSTCONDITION: The decoder is positioned just after the
  155. END_GROUP tag for this group, and we have merged
  156. the contents of the group into |group|.
  157. """
  158. sub_buffer = self._stream.GetSubBuffer() # No a priori length limit.
  159. num_bytes_used = group.MergeFromString(sub_buffer)
  160. if num_bytes_used < 0:
  161. raise message.DecodeError('Group message reported negative bytes read.')
  162. self._stream.SkipBytes(num_bytes_used)
  163. field_number, field_type = self.ReadFieldNumberAndWireType()
  164. if field_type != wire_format.WIRETYPE_END_GROUP:
  165. raise message.DecodeError('Group message did not end with an END_GROUP.')
  166. if field_number != expected_field_number:
  167. raise message.DecodeError('END_GROUP tag had field '
  168. 'number %d, was expecting field number %d' % (
  169. field_number, expected_field_number))
  170. # We're now positioned just after the END_GROUP tag. Perfect.