| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- # Protocol Buffers - Google's data interchange format
- # Copyright 2008 Google Inc. All rights reserved.
- # http://code.google.com/p/protobuf/
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are
- # met:
- #
- # * Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # * Redistributions in binary form must reproduce the above
- # copyright notice, this list of conditions and the following disclaimer
- # in the documentation and/or other materials provided with the
- # distribution.
- # * Neither the name of Google Inc. nor the names of its
- # contributors may be used to endorse or promote products derived from
- # this software without specific prior written permission.
- #
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- """Class for decoding protocol buffer primitives.
- Contains the logic for decoding every logical protocol field type
- from one of the 5 physical wire types.
- """
- __author__ = 'robinson@google.com (Will Robinson)'
- import struct
- from froofle.protobuf import message
- from froofle.protobuf.internal import input_stream
- from froofle.protobuf.internal import wire_format
- # Note that much of this code is ported from //net/proto/ProtocolBuffer, and
- # that the interface is strongly inspired by WireFormat from the C++ proto2
- # implementation.
- class Decoder(object):
- """Decodes logical protocol buffer fields from the wire."""
- def __init__(self, s):
- """Initializes the decoder to read from s.
- Args:
- s: An immutable sequence of bytes, which must be accessible
- via the Python buffer() primitive (i.e., buffer(s)).
- """
- self._stream = input_stream.InputStream(s)
- def EndOfStream(self):
- """Returns true iff we've reached the end of the bytes we're reading."""
- return self._stream.EndOfStream()
- def Position(self):
- """Returns the 0-indexed position in |s|."""
- return self._stream.Position()
- def ReadFieldNumberAndWireType(self):
- """Reads a tag from the wire. Returns a (field_number, wire_type) pair."""
- tag_and_type = self.ReadUInt32()
- return wire_format.UnpackTag(tag_and_type)
- def SkipBytes(self, bytes):
- """Skips the specified number of bytes on the wire."""
- self._stream.SkipBytes(bytes)
- # Note that the Read*() methods below are not exactly symmetrical with the
- # corresponding Encoder.Append*() methods. Those Encoder methods first
- # encode a tag, but the Read*() methods below assume that the tag has already
- # been read, and that the client wishes to read a field of the specified type
- # starting at the current position.
- def ReadInt32(self):
- """Reads and returns a signed, varint-encoded, 32-bit integer."""
- return self._stream.ReadVarint32()
- def ReadInt64(self):
- """Reads and returns a signed, varint-encoded, 64-bit integer."""
- return self._stream.ReadVarint64()
- def ReadUInt32(self):
- """Reads and returns an signed, varint-encoded, 32-bit integer."""
- return self._stream.ReadVarUInt32()
- def ReadUInt64(self):
- """Reads and returns an signed, varint-encoded,64-bit integer."""
- return self._stream.ReadVarUInt64()
- def ReadSInt32(self):
- """Reads and returns a signed, zigzag-encoded, varint-encoded,
- 32-bit integer."""
- return wire_format.ZigZagDecode(self._stream.ReadVarUInt32())
- def ReadSInt64(self):
- """Reads and returns a signed, zigzag-encoded, varint-encoded,
- 64-bit integer."""
- return wire_format.ZigZagDecode(self._stream.ReadVarUInt64())
- def ReadFixed32(self):
- """Reads and returns an unsigned, fixed-width, 32-bit integer."""
- return self._stream.ReadLittleEndian32()
- def ReadFixed64(self):
- """Reads and returns an unsigned, fixed-width, 64-bit integer."""
- return self._stream.ReadLittleEndian64()
- def ReadSFixed32(self):
- """Reads and returns a signed, fixed-width, 32-bit integer."""
- value = self._stream.ReadLittleEndian32()
- if value >= (1 << 31):
- value -= (1 << 32)
- return value
- def ReadSFixed64(self):
- """Reads and returns a signed, fixed-width, 64-bit integer."""
- value = self._stream.ReadLittleEndian64()
- if value >= (1 << 63):
- value -= (1 << 64)
- return value
- def ReadFloat(self):
- """Reads and returns a 4-byte floating-point number."""
- serialized = self._stream.ReadBytes(4)
- return struct.unpack('f', serialized)[0]
- def ReadDouble(self):
- """Reads and returns an 8-byte floating-point number."""
- serialized = self._stream.ReadBytes(8)
- return struct.unpack('d', serialized)[0]
- def ReadBool(self):
- """Reads and returns a bool."""
- i = self._stream.ReadVarUInt32()
- return bool(i)
- def ReadEnum(self):
- """Reads and returns an enum value."""
- return self._stream.ReadVarUInt32()
- def ReadString(self):
- """Reads and returns a length-delimited string."""
- bytes = self.ReadBytes()
- return unicode(bytes, 'utf-8')
- def ReadBytes(self):
- """Reads and returns a length-delimited byte sequence."""
- length = self._stream.ReadVarUInt32()
- return self._stream.ReadBytes(length)
- def ReadMessageInto(self, msg):
- """Calls msg.MergeFromString() to merge
- length-delimited serialized message data into |msg|.
- REQUIRES: The decoder must be positioned at the serialized "length"
- prefix to a length-delmiited serialized message.
- POSTCONDITION: The decoder is positioned just after the
- serialized message, and we have merged those serialized
- contents into |msg|.
- """
- length = self._stream.ReadVarUInt32()
- sub_buffer = self._stream.GetSubBuffer(length)
- num_bytes_used = msg.MergeFromString(sub_buffer)
- if num_bytes_used != length:
- raise message.DecodeError(
- 'Submessage told to deserialize from %d-byte encoding, '
- 'but used only %d bytes' % (length, num_bytes_used))
- self._stream.SkipBytes(num_bytes_used)
- def ReadGroupInto(self, expected_field_number, group):
- """Calls group.MergeFromString() to merge
- END_GROUP-delimited serialized message data into |group|.
- We'll raise an exception if we don't find an END_GROUP
- tag immediately after the serialized message contents.
- REQUIRES: The decoder is positioned just after the START_GROUP
- tag for this group.
- POSTCONDITION: The decoder is positioned just after the
- END_GROUP tag for this group, and we have merged
- the contents of the group into |group|.
- """
- sub_buffer = self._stream.GetSubBuffer() # No a priori length limit.
- num_bytes_used = group.MergeFromString(sub_buffer)
- if num_bytes_used < 0:
- raise message.DecodeError('Group message reported negative bytes read.')
- self._stream.SkipBytes(num_bytes_used)
- field_number, field_type = self.ReadFieldNumberAndWireType()
- if field_type != wire_format.WIRETYPE_END_GROUP:
- raise message.DecodeError('Group message did not end with an END_GROUP.')
- if field_number != expected_field_number:
- raise message.DecodeError('END_GROUP tag had field '
- 'number %d, was expecting field number %d' % (
- field_number, expected_field_number))
- # We're now positioned just after the END_GROUP tag. Perfect.
|