mirror of
https://github.com/Dev-Wiki/git-repo.git
synced 2025-09-26 10:02:46 +08:00
Initial Contribution
This commit is contained in:
0
froofle/protobuf/internal/__init__.py
Normal file
0
froofle/protobuf/internal/__init__.py
Normal file
209
froofle/protobuf/internal/decoder.py
Normal file
209
froofle/protobuf/internal/decoder.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# 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.
|
206
froofle/protobuf/internal/encoder.py
Normal file
206
froofle/protobuf/internal/encoder.py
Normal file
@@ -0,0 +1,206 @@
|
||||
# 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 encoding protocol message primitives.
|
||||
|
||||
Contains the logic for encoding every logical protocol field type
|
||||
into 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 wire_format
|
||||
from froofle.protobuf.internal import output_stream
|
||||
|
||||
|
||||
# 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 Encoder(object):
|
||||
|
||||
"""Encodes logical protocol buffer fields to the wire format."""
|
||||
|
||||
def __init__(self):
|
||||
self._stream = output_stream.OutputStream()
|
||||
|
||||
def ToString(self):
|
||||
"""Returns all values encoded in this object as a string."""
|
||||
return self._stream.ToString()
|
||||
|
||||
# All the Append*() methods below first append a tag+type pair to the buffer
|
||||
# before appending the specified value.
|
||||
|
||||
def AppendInt32(self, field_number, value):
|
||||
"""Appends a 32-bit integer to our buffer, varint-encoded."""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
|
||||
self._stream.AppendVarint32(value)
|
||||
|
||||
def AppendInt64(self, field_number, value):
|
||||
"""Appends a 64-bit integer to our buffer, varint-encoded."""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
|
||||
self._stream.AppendVarint64(value)
|
||||
|
||||
def AppendUInt32(self, field_number, unsigned_value):
|
||||
"""Appends an unsigned 32-bit integer to our buffer, varint-encoded."""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
|
||||
self._stream.AppendVarUInt32(unsigned_value)
|
||||
|
||||
def AppendUInt64(self, field_number, unsigned_value):
|
||||
"""Appends an unsigned 64-bit integer to our buffer, varint-encoded."""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
|
||||
self._stream.AppendVarUInt64(unsigned_value)
|
||||
|
||||
def AppendSInt32(self, field_number, value):
|
||||
"""Appends a 32-bit integer to our buffer, zigzag-encoded and then
|
||||
varint-encoded.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
|
||||
zigzag_value = wire_format.ZigZagEncode(value)
|
||||
self._stream.AppendVarUInt32(zigzag_value)
|
||||
|
||||
def AppendSInt64(self, field_number, value):
|
||||
"""Appends a 64-bit integer to our buffer, zigzag-encoded and then
|
||||
varint-encoded.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_VARINT)
|
||||
zigzag_value = wire_format.ZigZagEncode(value)
|
||||
self._stream.AppendVarUInt64(zigzag_value)
|
||||
|
||||
def AppendFixed32(self, field_number, unsigned_value):
|
||||
"""Appends an unsigned 32-bit integer to our buffer, in little-endian
|
||||
byte-order.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
|
||||
self._stream.AppendLittleEndian32(unsigned_value)
|
||||
|
||||
def AppendFixed64(self, field_number, unsigned_value):
|
||||
"""Appends an unsigned 64-bit integer to our buffer, in little-endian
|
||||
byte-order.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
|
||||
self._stream.AppendLittleEndian64(unsigned_value)
|
||||
|
||||
def AppendSFixed32(self, field_number, value):
|
||||
"""Appends a signed 32-bit integer to our buffer, in little-endian
|
||||
byte-order.
|
||||
"""
|
||||
sign = (value & 0x80000000) and -1 or 0
|
||||
if value >> 32 != sign:
|
||||
raise message.EncodeError('SFixed32 out of range: %d' % value)
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
|
||||
self._stream.AppendLittleEndian32(value & 0xffffffff)
|
||||
|
||||
def AppendSFixed64(self, field_number, value):
|
||||
"""Appends a signed 64-bit integer to our buffer, in little-endian
|
||||
byte-order.
|
||||
"""
|
||||
sign = (value & 0x8000000000000000) and -1 or 0
|
||||
if value >> 64 != sign:
|
||||
raise message.EncodeError('SFixed64 out of range: %d' % value)
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
|
||||
self._stream.AppendLittleEndian64(value & 0xffffffffffffffff)
|
||||
|
||||
def AppendFloat(self, field_number, value):
|
||||
"""Appends a floating-point number to our buffer."""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_FIXED32)
|
||||
self._stream.AppendRawBytes(struct.pack('f', value))
|
||||
|
||||
def AppendDouble(self, field_number, value):
|
||||
"""Appends a double-precision floating-point number to our buffer."""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_FIXED64)
|
||||
self._stream.AppendRawBytes(struct.pack('d', value))
|
||||
|
||||
def AppendBool(self, field_number, value):
|
||||
"""Appends a boolean to our buffer."""
|
||||
self.AppendInt32(field_number, value)
|
||||
|
||||
def AppendEnum(self, field_number, value):
|
||||
"""Appends an enum value to our buffer."""
|
||||
self.AppendInt32(field_number, value)
|
||||
|
||||
def AppendString(self, field_number, value):
|
||||
"""Appends a length-prefixed unicode string, encoded as UTF-8 to our buffer,
|
||||
with the length varint-encoded.
|
||||
"""
|
||||
self.AppendBytes(field_number, value.encode('utf-8'))
|
||||
|
||||
def AppendBytes(self, field_number, value):
|
||||
"""Appends a length-prefixed sequence of bytes to our buffer, with the
|
||||
length varint-encoded.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
self._stream.AppendVarUInt32(len(value))
|
||||
self._stream.AppendRawBytes(value)
|
||||
|
||||
# TODO(robinson): For AppendGroup() and AppendMessage(), we'd really like to
|
||||
# avoid the extra string copy here. We can do so if we widen the Message
|
||||
# interface to be able to serialize to a stream in addition to a string. The
|
||||
# challenge when thinking ahead to the Python/C API implementation of Message
|
||||
# is finding a stream-like Python thing to which we can write raw bytes
|
||||
# from C. I'm not sure such a thing exists(?). (array.array is pretty much
|
||||
# what we want, but it's not directly exposed in the Python/C API).
|
||||
|
||||
def AppendGroup(self, field_number, group):
|
||||
"""Appends a group to our buffer.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_START_GROUP)
|
||||
self._stream.AppendRawBytes(group.SerializeToString())
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_END_GROUP)
|
||||
|
||||
def AppendMessage(self, field_number, msg):
|
||||
"""Appends a nested message to our buffer.
|
||||
"""
|
||||
self._AppendTag(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
|
||||
self._stream.AppendVarUInt32(msg.ByteSize())
|
||||
self._stream.AppendRawBytes(msg.SerializeToString())
|
||||
|
||||
def AppendMessageSetItem(self, field_number, msg):
|
||||
"""Appends an item using the message set wire format.
|
||||
|
||||
The message set message looks like this:
|
||||
message MessageSet {
|
||||
repeated group Item = 1 {
|
||||
required int32 type_id = 2;
|
||||
required string message = 3;
|
||||
}
|
||||
}
|
||||
"""
|
||||
self._AppendTag(1, wire_format.WIRETYPE_START_GROUP)
|
||||
self.AppendInt32(2, field_number)
|
||||
self.AppendMessage(3, msg)
|
||||
self._AppendTag(1, wire_format.WIRETYPE_END_GROUP)
|
||||
|
||||
def _AppendTag(self, field_number, wire_type):
|
||||
"""Appends a tag containing field number and wire type information."""
|
||||
self._stream.AppendVarUInt32(wire_format.PackTag(field_number, wire_type))
|
326
froofle/protobuf/internal/input_stream.py
Normal file
326
froofle/protobuf/internal/input_stream.py
Normal file
@@ -0,0 +1,326 @@
|
||||
# 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.
|
||||
|
||||
"""InputStream is the primitive interface for reading bits from the wire.
|
||||
|
||||
All protocol buffer deserialization can be expressed in terms of
|
||||
the InputStream primitives provided here.
|
||||
"""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
import struct
|
||||
from array import array
|
||||
from froofle.protobuf import message
|
||||
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 CodedInputStream from the C++
|
||||
# proto2 implementation.
|
||||
|
||||
|
||||
class InputStreamBuffer(object):
|
||||
|
||||
"""Contains all logic for reading bits, and dealing with stream position.
|
||||
|
||||
If an InputStream method ever raises an exception, the stream is left
|
||||
in an indeterminate state and is not safe for further use.
|
||||
"""
|
||||
|
||||
def __init__(self, s):
|
||||
# What we really want is something like array('B', s), where elements we
|
||||
# read from the array are already given to us as one-byte integers. BUT
|
||||
# using array() instead of buffer() would force full string copies to result
|
||||
# from each GetSubBuffer() call.
|
||||
#
|
||||
# So, if the N serialized bytes of a single protocol buffer object are
|
||||
# split evenly between 2 child messages, and so on recursively, using
|
||||
# array('B', s) instead of buffer() would incur an additional N*logN bytes
|
||||
# copied during deserialization.
|
||||
#
|
||||
# The higher constant overhead of having to ord() for every byte we read
|
||||
# from the buffer in _ReadVarintHelper() could definitely lead to worse
|
||||
# performance in many real-world scenarios, even if the asymptotic
|
||||
# complexity is better. However, our real answer is that the mythical
|
||||
# Python/C extension module output mode for the protocol compiler will
|
||||
# be blazing-fast and will eliminate most use of this class anyway.
|
||||
self._buffer = buffer(s)
|
||||
self._pos = 0
|
||||
|
||||
def EndOfStream(self):
|
||||
"""Returns true iff we're at the end of the stream.
|
||||
If this returns true, then a call to any other InputStream method
|
||||
will raise an exception.
|
||||
"""
|
||||
return self._pos >= len(self._buffer)
|
||||
|
||||
def Position(self):
|
||||
"""Returns the current position in the stream, or equivalently, the
|
||||
number of bytes read so far.
|
||||
"""
|
||||
return self._pos
|
||||
|
||||
def GetSubBuffer(self, size=None):
|
||||
"""Returns a sequence-like object that represents a portion of our
|
||||
underlying sequence.
|
||||
|
||||
Position 0 in the returned object corresponds to self.Position()
|
||||
in this stream.
|
||||
|
||||
If size is specified, then the returned object ends after the
|
||||
next "size" bytes in this stream. If size is not specified,
|
||||
then the returned object ends at the end of this stream.
|
||||
|
||||
We guarantee that the returned object R supports the Python buffer
|
||||
interface (and thus that the call buffer(R) will work).
|
||||
|
||||
Note that the returned buffer is read-only.
|
||||
|
||||
The intended use for this method is for nested-message and nested-group
|
||||
deserialization, where we want to make a recursive MergeFromString()
|
||||
call on the portion of the original sequence that contains the serialized
|
||||
nested message. (And we'd like to do so without making unnecessary string
|
||||
copies).
|
||||
|
||||
REQUIRES: size is nonnegative.
|
||||
"""
|
||||
# Note that buffer() doesn't perform any actual string copy.
|
||||
if size is None:
|
||||
return buffer(self._buffer, self._pos)
|
||||
else:
|
||||
if size < 0:
|
||||
raise message.DecodeError('Negative size %d' % size)
|
||||
return buffer(self._buffer, self._pos, size)
|
||||
|
||||
def SkipBytes(self, num_bytes):
|
||||
"""Skip num_bytes bytes ahead, or go to the end of the stream, whichever
|
||||
comes first.
|
||||
|
||||
REQUIRES: num_bytes is nonnegative.
|
||||
"""
|
||||
if num_bytes < 0:
|
||||
raise message.DecodeError('Negative num_bytes %d' % num_bytes)
|
||||
self._pos += num_bytes
|
||||
self._pos = min(self._pos, len(self._buffer))
|
||||
|
||||
def ReadBytes(self, size):
|
||||
"""Reads up to 'size' bytes from the stream, stopping early
|
||||
only if we reach the end of the stream. Returns the bytes read
|
||||
as a string.
|
||||
"""
|
||||
if size < 0:
|
||||
raise message.DecodeError('Negative size %d' % size)
|
||||
s = (self._buffer[self._pos : self._pos + size])
|
||||
self._pos += len(s) # Only advance by the number of bytes actually read.
|
||||
return s
|
||||
|
||||
def ReadLittleEndian32(self):
|
||||
"""Interprets the next 4 bytes of the stream as a little-endian
|
||||
encoded, unsiged 32-bit integer, and returns that integer.
|
||||
"""
|
||||
try:
|
||||
i = struct.unpack(wire_format.FORMAT_UINT32_LITTLE_ENDIAN,
|
||||
self._buffer[self._pos : self._pos + 4])
|
||||
self._pos += 4
|
||||
return i[0] # unpack() result is a 1-element tuple.
|
||||
except struct.error, e:
|
||||
raise message.DecodeError(e)
|
||||
|
||||
def ReadLittleEndian64(self):
|
||||
"""Interprets the next 8 bytes of the stream as a little-endian
|
||||
encoded, unsiged 64-bit integer, and returns that integer.
|
||||
"""
|
||||
try:
|
||||
i = struct.unpack(wire_format.FORMAT_UINT64_LITTLE_ENDIAN,
|
||||
self._buffer[self._pos : self._pos + 8])
|
||||
self._pos += 8
|
||||
return i[0] # unpack() result is a 1-element tuple.
|
||||
except struct.error, e:
|
||||
raise message.DecodeError(e)
|
||||
|
||||
def ReadVarint32(self):
|
||||
"""Reads a varint from the stream, interprets this varint
|
||||
as a signed, 32-bit integer, and returns the integer.
|
||||
"""
|
||||
i = self.ReadVarint64()
|
||||
if not wire_format.INT32_MIN <= i <= wire_format.INT32_MAX:
|
||||
raise message.DecodeError('Value out of range for int32: %d' % i)
|
||||
return int(i)
|
||||
|
||||
def ReadVarUInt32(self):
|
||||
"""Reads a varint from the stream, interprets this varint
|
||||
as an unsigned, 32-bit integer, and returns the integer.
|
||||
"""
|
||||
i = self.ReadVarUInt64()
|
||||
if i > wire_format.UINT32_MAX:
|
||||
raise message.DecodeError('Value out of range for uint32: %d' % i)
|
||||
return i
|
||||
|
||||
def ReadVarint64(self):
|
||||
"""Reads a varint from the stream, interprets this varint
|
||||
as a signed, 64-bit integer, and returns the integer.
|
||||
"""
|
||||
i = self.ReadVarUInt64()
|
||||
if i > wire_format.INT64_MAX:
|
||||
i -= (1 << 64)
|
||||
return i
|
||||
|
||||
def ReadVarUInt64(self):
|
||||
"""Reads a varint from the stream, interprets this varint
|
||||
as an unsigned, 64-bit integer, and returns the integer.
|
||||
"""
|
||||
i = self._ReadVarintHelper()
|
||||
if not 0 <= i <= wire_format.UINT64_MAX:
|
||||
raise message.DecodeError('Value out of range for uint64: %d' % i)
|
||||
return i
|
||||
|
||||
def _ReadVarintHelper(self):
|
||||
"""Helper for the various varint-reading methods above.
|
||||
Reads an unsigned, varint-encoded integer from the stream and
|
||||
returns this integer.
|
||||
|
||||
Does no bounds checking except to ensure that we read at most as many bytes
|
||||
as could possibly be present in a varint-encoded 64-bit number.
|
||||
"""
|
||||
result = 0
|
||||
shift = 0
|
||||
while 1:
|
||||
if shift >= 64:
|
||||
raise message.DecodeError('Too many bytes when decoding varint.')
|
||||
try:
|
||||
b = ord(self._buffer[self._pos])
|
||||
except IndexError:
|
||||
raise message.DecodeError('Truncated varint.')
|
||||
self._pos += 1
|
||||
result |= ((b & 0x7f) << shift)
|
||||
shift += 7
|
||||
if not (b & 0x80):
|
||||
return result
|
||||
|
||||
class InputStreamArray(object):
|
||||
def __init__(self, s):
|
||||
self._buffer = array('B', s)
|
||||
self._pos = 0
|
||||
|
||||
def EndOfStream(self):
|
||||
return self._pos >= len(self._buffer)
|
||||
|
||||
def Position(self):
|
||||
return self._pos
|
||||
|
||||
def GetSubBuffer(self, size=None):
|
||||
if size is None:
|
||||
return self._buffer[self._pos : ].tostring()
|
||||
else:
|
||||
if size < 0:
|
||||
raise message.DecodeError('Negative size %d' % size)
|
||||
return self._buffer[self._pos : self._pos + size].tostring()
|
||||
|
||||
def SkipBytes(self, num_bytes):
|
||||
if num_bytes < 0:
|
||||
raise message.DecodeError('Negative num_bytes %d' % num_bytes)
|
||||
self._pos += num_bytes
|
||||
self._pos = min(self._pos, len(self._buffer))
|
||||
|
||||
def ReadBytes(self, size):
|
||||
if size < 0:
|
||||
raise message.DecodeError('Negative size %d' % size)
|
||||
s = self._buffer[self._pos : self._pos + size].tostring()
|
||||
self._pos += len(s) # Only advance by the number of bytes actually read.
|
||||
return s
|
||||
|
||||
def ReadLittleEndian32(self):
|
||||
try:
|
||||
i = struct.unpack(wire_format.FORMAT_UINT32_LITTLE_ENDIAN,
|
||||
self._buffer[self._pos : self._pos + 4])
|
||||
self._pos += 4
|
||||
return i[0] # unpack() result is a 1-element tuple.
|
||||
except struct.error, e:
|
||||
raise message.DecodeError(e)
|
||||
|
||||
def ReadLittleEndian64(self):
|
||||
try:
|
||||
i = struct.unpack(wire_format.FORMAT_UINT64_LITTLE_ENDIAN,
|
||||
self._buffer[self._pos : self._pos + 8])
|
||||
self._pos += 8
|
||||
return i[0] # unpack() result is a 1-element tuple.
|
||||
except struct.error, e:
|
||||
raise message.DecodeError(e)
|
||||
|
||||
def ReadVarint32(self):
|
||||
i = self.ReadVarint64()
|
||||
if not wire_format.INT32_MIN <= i <= wire_format.INT32_MAX:
|
||||
raise message.DecodeError('Value out of range for int32: %d' % i)
|
||||
return int(i)
|
||||
|
||||
def ReadVarUInt32(self):
|
||||
i = self.ReadVarUInt64()
|
||||
if i > wire_format.UINT32_MAX:
|
||||
raise message.DecodeError('Value out of range for uint32: %d' % i)
|
||||
return i
|
||||
|
||||
def ReadVarint64(self):
|
||||
i = self.ReadVarUInt64()
|
||||
if i > wire_format.INT64_MAX:
|
||||
i -= (1 << 64)
|
||||
return i
|
||||
|
||||
def ReadVarUInt64(self):
|
||||
i = self._ReadVarintHelper()
|
||||
if not 0 <= i <= wire_format.UINT64_MAX:
|
||||
raise message.DecodeError('Value out of range for uint64: %d' % i)
|
||||
return i
|
||||
|
||||
def _ReadVarintHelper(self):
|
||||
result = 0
|
||||
shift = 0
|
||||
while 1:
|
||||
if shift >= 64:
|
||||
raise message.DecodeError('Too many bytes when decoding varint.')
|
||||
try:
|
||||
b = self._buffer[self._pos]
|
||||
except IndexError:
|
||||
raise message.DecodeError('Truncated varint.')
|
||||
self._pos += 1
|
||||
result |= ((b & 0x7f) << shift)
|
||||
shift += 7
|
||||
if not (b & 0x80):
|
||||
return result
|
||||
|
||||
try:
|
||||
buffer("")
|
||||
InputStream = InputStreamBuffer
|
||||
except NotImplementedError:
|
||||
# Google App Engine: dev_appserver.py
|
||||
InputStream = InputStreamArray
|
||||
except RuntimeError:
|
||||
# Google App Engine: production
|
||||
InputStream = InputStreamArray
|
69
froofle/protobuf/internal/message_listener.py
Normal file
69
froofle/protobuf/internal/message_listener.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# 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.
|
||||
|
||||
"""Defines a listener interface for observing certain
|
||||
state transitions on Message objects.
|
||||
|
||||
Also defines a null implementation of this interface.
|
||||
"""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
|
||||
class MessageListener(object):
|
||||
|
||||
"""Listens for transitions to nonempty and for invalidations of cached
|
||||
byte sizes. Meant to be registered via Message._SetListener().
|
||||
"""
|
||||
|
||||
def TransitionToNonempty(self):
|
||||
"""Called the *first* time that this message becomes nonempty.
|
||||
Implementations are free (but not required) to call this method multiple
|
||||
times after the message has become nonempty.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def ByteSizeDirty(self):
|
||||
"""Called *every* time the cached byte size value
|
||||
for this object is invalidated (transitions from being
|
||||
"clean" to "dirty").
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class NullMessageListener(object):
|
||||
|
||||
"""No-op MessageListener implementation."""
|
||||
|
||||
def TransitionToNonempty(self):
|
||||
pass
|
||||
|
||||
def ByteSizeDirty(self):
|
||||
pass
|
125
froofle/protobuf/internal/output_stream.py
Normal file
125
froofle/protobuf/internal/output_stream.py
Normal file
@@ -0,0 +1,125 @@
|
||||
# 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.
|
||||
|
||||
"""OutputStream is the primitive interface for sticking bits on the wire.
|
||||
|
||||
All protocol buffer serialization can be expressed in terms of
|
||||
the OutputStream primitives provided here.
|
||||
"""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
import array
|
||||
import struct
|
||||
from froofle.protobuf import message
|
||||
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 CodedOutputStream from the C++
|
||||
# proto2 implementation.
|
||||
|
||||
|
||||
class OutputStream(object):
|
||||
|
||||
"""Contains all logic for writing bits, and ToString() to get the result."""
|
||||
|
||||
def __init__(self):
|
||||
self._buffer = array.array('B')
|
||||
|
||||
def AppendRawBytes(self, raw_bytes):
|
||||
"""Appends raw_bytes to our internal buffer."""
|
||||
self._buffer.fromstring(raw_bytes)
|
||||
|
||||
def AppendLittleEndian32(self, unsigned_value):
|
||||
"""Appends an unsigned 32-bit integer to the internal buffer,
|
||||
in little-endian byte order.
|
||||
"""
|
||||
if not 0 <= unsigned_value <= wire_format.UINT32_MAX:
|
||||
raise message.EncodeError(
|
||||
'Unsigned 32-bit out of range: %d' % unsigned_value)
|
||||
self._buffer.fromstring(struct.pack(
|
||||
wire_format.FORMAT_UINT32_LITTLE_ENDIAN, unsigned_value))
|
||||
|
||||
def AppendLittleEndian64(self, unsigned_value):
|
||||
"""Appends an unsigned 64-bit integer to the internal buffer,
|
||||
in little-endian byte order.
|
||||
"""
|
||||
if not 0 <= unsigned_value <= wire_format.UINT64_MAX:
|
||||
raise message.EncodeError(
|
||||
'Unsigned 64-bit out of range: %d' % unsigned_value)
|
||||
self._buffer.fromstring(struct.pack(
|
||||
wire_format.FORMAT_UINT64_LITTLE_ENDIAN, unsigned_value))
|
||||
|
||||
def AppendVarint32(self, value):
|
||||
"""Appends a signed 32-bit integer to the internal buffer,
|
||||
encoded as a varint. (Note that a negative varint32 will
|
||||
always require 10 bytes of space.)
|
||||
"""
|
||||
if not wire_format.INT32_MIN <= value <= wire_format.INT32_MAX:
|
||||
raise message.EncodeError('Value out of range: %d' % value)
|
||||
self.AppendVarint64(value)
|
||||
|
||||
def AppendVarUInt32(self, value):
|
||||
"""Appends an unsigned 32-bit integer to the internal buffer,
|
||||
encoded as a varint.
|
||||
"""
|
||||
if not 0 <= value <= wire_format.UINT32_MAX:
|
||||
raise message.EncodeError('Value out of range: %d' % value)
|
||||
self.AppendVarUInt64(value)
|
||||
|
||||
def AppendVarint64(self, value):
|
||||
"""Appends a signed 64-bit integer to the internal buffer,
|
||||
encoded as a varint.
|
||||
"""
|
||||
if not wire_format.INT64_MIN <= value <= wire_format.INT64_MAX:
|
||||
raise message.EncodeError('Value out of range: %d' % value)
|
||||
if value < 0:
|
||||
value += (1 << 64)
|
||||
self.AppendVarUInt64(value)
|
||||
|
||||
def AppendVarUInt64(self, unsigned_value):
|
||||
"""Appends an unsigned 64-bit integer to the internal buffer,
|
||||
encoded as a varint.
|
||||
"""
|
||||
if not 0 <= unsigned_value <= wire_format.UINT64_MAX:
|
||||
raise message.EncodeError('Value out of range: %d' % unsigned_value)
|
||||
while True:
|
||||
bits = unsigned_value & 0x7f
|
||||
unsigned_value >>= 7
|
||||
if not unsigned_value:
|
||||
self._buffer.append(bits)
|
||||
break
|
||||
self._buffer.append(0x80|bits)
|
||||
|
||||
def ToString(self):
|
||||
"""Returns a string containing the bytes in our internal buffer."""
|
||||
return self._buffer.tostring()
|
268
froofle/protobuf/internal/type_checkers.py
Normal file
268
froofle/protobuf/internal/type_checkers.py
Normal file
@@ -0,0 +1,268 @@
|
||||
# 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.
|
||||
|
||||
"""Provides type checking routines.
|
||||
|
||||
This module defines type checking utilities in the forms of dictionaries:
|
||||
|
||||
VALUE_CHECKERS: A dictionary of field types and a value validation object.
|
||||
TYPE_TO_BYTE_SIZE_FN: A dictionary with field types and a size computing
|
||||
function.
|
||||
TYPE_TO_SERIALIZE_METHOD: A dictionary with field types and serialization
|
||||
function.
|
||||
FIELD_TYPE_TO_WIRE_TYPE: A dictionary with field typed and their
|
||||
coresponding wire types.
|
||||
TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization
|
||||
function.
|
||||
"""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
from froofle.protobuf.internal import decoder
|
||||
from froofle.protobuf.internal import encoder
|
||||
from froofle.protobuf.internal import wire_format
|
||||
from froofle.protobuf import descriptor
|
||||
|
||||
_FieldDescriptor = descriptor.FieldDescriptor
|
||||
|
||||
|
||||
def GetTypeChecker(cpp_type, field_type):
|
||||
"""Returns a type checker for a message field of the specified types.
|
||||
|
||||
Args:
|
||||
cpp_type: C++ type of the field (see descriptor.py).
|
||||
field_type: Protocol message field type (see descriptor.py).
|
||||
|
||||
Returns:
|
||||
An instance of TypeChecker which can be used to verify the types
|
||||
of values assigned to a field of the specified type.
|
||||
"""
|
||||
if (cpp_type == _FieldDescriptor.CPPTYPE_STRING and
|
||||
field_type == _FieldDescriptor.TYPE_STRING):
|
||||
return UnicodeValueChecker()
|
||||
return _VALUE_CHECKERS[cpp_type]
|
||||
|
||||
|
||||
# None of the typecheckers below make any attempt to guard against people
|
||||
# subclassing builtin types and doing weird things. We're not trying to
|
||||
# protect against malicious clients here, just people accidentally shooting
|
||||
# themselves in the foot in obvious ways.
|
||||
|
||||
class TypeChecker(object):
|
||||
|
||||
"""Type checker used to catch type errors as early as possible
|
||||
when the client is setting scalar fields in protocol messages.
|
||||
"""
|
||||
|
||||
def __init__(self, *acceptable_types):
|
||||
self._acceptable_types = acceptable_types
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
if not isinstance(proposed_value, self._acceptable_types):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), self._acceptable_types))
|
||||
raise TypeError(message)
|
||||
|
||||
|
||||
# IntValueChecker and its subclasses perform integer type-checks
|
||||
# and bounds-checks.
|
||||
class IntValueChecker(object):
|
||||
|
||||
"""Checker used for integer fields. Performs type-check and range check."""
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
if not isinstance(proposed_value, (int, long)):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), (int, long)))
|
||||
raise TypeError(message)
|
||||
if not self._MIN <= proposed_value <= self._MAX:
|
||||
raise ValueError('Value out of range: %d' % proposed_value)
|
||||
|
||||
|
||||
class UnicodeValueChecker(object):
|
||||
|
||||
"""Checker used for string fields."""
|
||||
|
||||
def CheckValue(self, proposed_value):
|
||||
if not isinstance(proposed_value, (str, unicode)):
|
||||
message = ('%.1024r has type %s, but expected one of: %s' %
|
||||
(proposed_value, type(proposed_value), (str, unicode)))
|
||||
raise TypeError(message)
|
||||
|
||||
# If the value is of type 'str' make sure that it is in 7-bit ASCII
|
||||
# encoding.
|
||||
if isinstance(proposed_value, str):
|
||||
try:
|
||||
unicode(proposed_value, 'ascii')
|
||||
except UnicodeDecodeError:
|
||||
raise ValueError('%.1024r isn\'t in 7-bit ASCII encoding.'
|
||||
% (proposed_value))
|
||||
|
||||
|
||||
class Int32ValueChecker(IntValueChecker):
|
||||
# We're sure to use ints instead of longs here since comparison may be more
|
||||
# efficient.
|
||||
_MIN = -2147483648
|
||||
_MAX = 2147483647
|
||||
|
||||
|
||||
class Uint32ValueChecker(IntValueChecker):
|
||||
_MIN = 0
|
||||
_MAX = (1 << 32) - 1
|
||||
|
||||
|
||||
class Int64ValueChecker(IntValueChecker):
|
||||
_MIN = -(1 << 63)
|
||||
_MAX = (1 << 63) - 1
|
||||
|
||||
|
||||
class Uint64ValueChecker(IntValueChecker):
|
||||
_MIN = 0
|
||||
_MAX = (1 << 64) - 1
|
||||
|
||||
|
||||
# Type-checkers for all scalar CPPTYPEs.
|
||||
_VALUE_CHECKERS = {
|
||||
_FieldDescriptor.CPPTYPE_INT32: Int32ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_INT64: Int64ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_DOUBLE: TypeChecker(
|
||||
float, int, long),
|
||||
_FieldDescriptor.CPPTYPE_FLOAT: TypeChecker(
|
||||
float, int, long),
|
||||
_FieldDescriptor.CPPTYPE_BOOL: TypeChecker(bool, int),
|
||||
_FieldDescriptor.CPPTYPE_ENUM: Int32ValueChecker(),
|
||||
_FieldDescriptor.CPPTYPE_STRING: TypeChecker(str),
|
||||
}
|
||||
|
||||
|
||||
# Map from field type to a function F, such that F(field_num, value)
|
||||
# gives the total byte size for a value of the given type. This
|
||||
# byte size includes tag information and any other additional space
|
||||
# associated with serializing "value".
|
||||
TYPE_TO_BYTE_SIZE_FN = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: wire_format.DoubleByteSize,
|
||||
_FieldDescriptor.TYPE_FLOAT: wire_format.FloatByteSize,
|
||||
_FieldDescriptor.TYPE_INT64: wire_format.Int64ByteSize,
|
||||
_FieldDescriptor.TYPE_UINT64: wire_format.UInt64ByteSize,
|
||||
_FieldDescriptor.TYPE_INT32: wire_format.Int32ByteSize,
|
||||
_FieldDescriptor.TYPE_FIXED64: wire_format.Fixed64ByteSize,
|
||||
_FieldDescriptor.TYPE_FIXED32: wire_format.Fixed32ByteSize,
|
||||
_FieldDescriptor.TYPE_BOOL: wire_format.BoolByteSize,
|
||||
_FieldDescriptor.TYPE_STRING: wire_format.StringByteSize,
|
||||
_FieldDescriptor.TYPE_GROUP: wire_format.GroupByteSize,
|
||||
_FieldDescriptor.TYPE_MESSAGE: wire_format.MessageByteSize,
|
||||
_FieldDescriptor.TYPE_BYTES: wire_format.BytesByteSize,
|
||||
_FieldDescriptor.TYPE_UINT32: wire_format.UInt32ByteSize,
|
||||
_FieldDescriptor.TYPE_ENUM: wire_format.EnumByteSize,
|
||||
_FieldDescriptor.TYPE_SFIXED32: wire_format.SFixed32ByteSize,
|
||||
_FieldDescriptor.TYPE_SFIXED64: wire_format.SFixed64ByteSize,
|
||||
_FieldDescriptor.TYPE_SINT32: wire_format.SInt32ByteSize,
|
||||
_FieldDescriptor.TYPE_SINT64: wire_format.SInt64ByteSize
|
||||
}
|
||||
|
||||
|
||||
# Maps from field type to an unbound Encoder method F, such that
|
||||
# F(encoder, field_number, value) will append the serialization
|
||||
# of a value of this type to the encoder.
|
||||
_Encoder = encoder.Encoder
|
||||
TYPE_TO_SERIALIZE_METHOD = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: _Encoder.AppendDouble,
|
||||
_FieldDescriptor.TYPE_FLOAT: _Encoder.AppendFloat,
|
||||
_FieldDescriptor.TYPE_INT64: _Encoder.AppendInt64,
|
||||
_FieldDescriptor.TYPE_UINT64: _Encoder.AppendUInt64,
|
||||
_FieldDescriptor.TYPE_INT32: _Encoder.AppendInt32,
|
||||
_FieldDescriptor.TYPE_FIXED64: _Encoder.AppendFixed64,
|
||||
_FieldDescriptor.TYPE_FIXED32: _Encoder.AppendFixed32,
|
||||
_FieldDescriptor.TYPE_BOOL: _Encoder.AppendBool,
|
||||
_FieldDescriptor.TYPE_STRING: _Encoder.AppendString,
|
||||
_FieldDescriptor.TYPE_GROUP: _Encoder.AppendGroup,
|
||||
_FieldDescriptor.TYPE_MESSAGE: _Encoder.AppendMessage,
|
||||
_FieldDescriptor.TYPE_BYTES: _Encoder.AppendBytes,
|
||||
_FieldDescriptor.TYPE_UINT32: _Encoder.AppendUInt32,
|
||||
_FieldDescriptor.TYPE_ENUM: _Encoder.AppendEnum,
|
||||
_FieldDescriptor.TYPE_SFIXED32: _Encoder.AppendSFixed32,
|
||||
_FieldDescriptor.TYPE_SFIXED64: _Encoder.AppendSFixed64,
|
||||
_FieldDescriptor.TYPE_SINT32: _Encoder.AppendSInt32,
|
||||
_FieldDescriptor.TYPE_SINT64: _Encoder.AppendSInt64,
|
||||
}
|
||||
|
||||
|
||||
# Maps from field type to expected wiretype.
|
||||
FIELD_TYPE_TO_WIRE_TYPE = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: wire_format.WIRETYPE_FIXED64,
|
||||
_FieldDescriptor.TYPE_FLOAT: wire_format.WIRETYPE_FIXED32,
|
||||
_FieldDescriptor.TYPE_INT64: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_UINT64: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_INT32: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_FIXED64: wire_format.WIRETYPE_FIXED64,
|
||||
_FieldDescriptor.TYPE_FIXED32: wire_format.WIRETYPE_FIXED32,
|
||||
_FieldDescriptor.TYPE_BOOL: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_STRING:
|
||||
wire_format.WIRETYPE_LENGTH_DELIMITED,
|
||||
_FieldDescriptor.TYPE_GROUP: wire_format.WIRETYPE_START_GROUP,
|
||||
_FieldDescriptor.TYPE_MESSAGE:
|
||||
wire_format.WIRETYPE_LENGTH_DELIMITED,
|
||||
_FieldDescriptor.TYPE_BYTES:
|
||||
wire_format.WIRETYPE_LENGTH_DELIMITED,
|
||||
_FieldDescriptor.TYPE_UINT32: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_ENUM: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_SFIXED32: wire_format.WIRETYPE_FIXED32,
|
||||
_FieldDescriptor.TYPE_SFIXED64: wire_format.WIRETYPE_FIXED64,
|
||||
_FieldDescriptor.TYPE_SINT32: wire_format.WIRETYPE_VARINT,
|
||||
_FieldDescriptor.TYPE_SINT64: wire_format.WIRETYPE_VARINT,
|
||||
}
|
||||
|
||||
|
||||
# Maps from field type to an unbound Decoder method F,
|
||||
# such that F(decoder) will read a field of the requested type.
|
||||
#
|
||||
# Note that Message and Group are intentionally missing here.
|
||||
# They're handled by _RecursivelyMerge().
|
||||
_Decoder = decoder.Decoder
|
||||
TYPE_TO_DESERIALIZE_METHOD = {
|
||||
_FieldDescriptor.TYPE_DOUBLE: _Decoder.ReadDouble,
|
||||
_FieldDescriptor.TYPE_FLOAT: _Decoder.ReadFloat,
|
||||
_FieldDescriptor.TYPE_INT64: _Decoder.ReadInt64,
|
||||
_FieldDescriptor.TYPE_UINT64: _Decoder.ReadUInt64,
|
||||
_FieldDescriptor.TYPE_INT32: _Decoder.ReadInt32,
|
||||
_FieldDescriptor.TYPE_FIXED64: _Decoder.ReadFixed64,
|
||||
_FieldDescriptor.TYPE_FIXED32: _Decoder.ReadFixed32,
|
||||
_FieldDescriptor.TYPE_BOOL: _Decoder.ReadBool,
|
||||
_FieldDescriptor.TYPE_STRING: _Decoder.ReadString,
|
||||
_FieldDescriptor.TYPE_BYTES: _Decoder.ReadBytes,
|
||||
_FieldDescriptor.TYPE_UINT32: _Decoder.ReadUInt32,
|
||||
_FieldDescriptor.TYPE_ENUM: _Decoder.ReadEnum,
|
||||
_FieldDescriptor.TYPE_SFIXED32: _Decoder.ReadSFixed32,
|
||||
_FieldDescriptor.TYPE_SFIXED64: _Decoder.ReadSFixed64,
|
||||
_FieldDescriptor.TYPE_SINT32: _Decoder.ReadSInt32,
|
||||
_FieldDescriptor.TYPE_SINT64: _Decoder.ReadSInt64,
|
||||
}
|
236
froofle/protobuf/internal/wire_format.py
Normal file
236
froofle/protobuf/internal/wire_format.py
Normal file
@@ -0,0 +1,236 @@
|
||||
# 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.
|
||||
|
||||
"""Constants and static functions to support protocol buffer wire format."""
|
||||
|
||||
__author__ = 'robinson@google.com (Will Robinson)'
|
||||
|
||||
import struct
|
||||
from froofle.protobuf import message
|
||||
|
||||
|
||||
TAG_TYPE_BITS = 3 # Number of bits used to hold type info in a proto tag.
|
||||
_TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1 # 0x7
|
||||
|
||||
# These numbers identify the wire type of a protocol buffer value.
|
||||
# We use the least-significant TAG_TYPE_BITS bits of the varint-encoded
|
||||
# tag-and-type to store one of these WIRETYPE_* constants.
|
||||
# These values must match WireType enum in //net/proto2/public/wire_format.h.
|
||||
WIRETYPE_VARINT = 0
|
||||
WIRETYPE_FIXED64 = 1
|
||||
WIRETYPE_LENGTH_DELIMITED = 2
|
||||
WIRETYPE_START_GROUP = 3
|
||||
WIRETYPE_END_GROUP = 4
|
||||
WIRETYPE_FIXED32 = 5
|
||||
_WIRETYPE_MAX = 5
|
||||
|
||||
|
||||
# Bounds for various integer types.
|
||||
INT32_MAX = int((1 << 31) - 1)
|
||||
INT32_MIN = int(-(1 << 31))
|
||||
UINT32_MAX = (1 << 32) - 1
|
||||
|
||||
INT64_MAX = (1 << 63) - 1
|
||||
INT64_MIN = -(1 << 63)
|
||||
UINT64_MAX = (1 << 64) - 1
|
||||
|
||||
# "struct" format strings that will encode/decode the specified formats.
|
||||
FORMAT_UINT32_LITTLE_ENDIAN = '<I'
|
||||
FORMAT_UINT64_LITTLE_ENDIAN = '<Q'
|
||||
|
||||
|
||||
# We'll have to provide alternate implementations of AppendLittleEndian*() on
|
||||
# any architectures where these checks fail.
|
||||
if struct.calcsize(FORMAT_UINT32_LITTLE_ENDIAN) != 4:
|
||||
raise AssertionError('Format "I" is not a 32-bit number.')
|
||||
if struct.calcsize(FORMAT_UINT64_LITTLE_ENDIAN) != 8:
|
||||
raise AssertionError('Format "Q" is not a 64-bit number.')
|
||||
|
||||
|
||||
def PackTag(field_number, wire_type):
|
||||
"""Returns an unsigned 32-bit integer that encodes the field number and
|
||||
wire type information in standard protocol message wire format.
|
||||
|
||||
Args:
|
||||
field_number: Expected to be an integer in the range [1, 1 << 29)
|
||||
wire_type: One of the WIRETYPE_* constants.
|
||||
"""
|
||||
if not 0 <= wire_type <= _WIRETYPE_MAX:
|
||||
raise message.EncodeError('Unknown wire type: %d' % wire_type)
|
||||
return (field_number << TAG_TYPE_BITS) | wire_type
|
||||
|
||||
|
||||
def UnpackTag(tag):
|
||||
"""The inverse of PackTag(). Given an unsigned 32-bit number,
|
||||
returns a (field_number, wire_type) tuple.
|
||||
"""
|
||||
return (tag >> TAG_TYPE_BITS), (tag & _TAG_TYPE_MASK)
|
||||
|
||||
|
||||
def ZigZagEncode(value):
|
||||
"""ZigZag Transform: Encodes signed integers so that they can be
|
||||
effectively used with varint encoding. See wire_format.h for
|
||||
more details.
|
||||
"""
|
||||
if value >= 0:
|
||||
return value << 1
|
||||
return (value << 1) ^ (~0)
|
||||
|
||||
|
||||
def ZigZagDecode(value):
|
||||
"""Inverse of ZigZagEncode()."""
|
||||
if not value & 0x1:
|
||||
return value >> 1
|
||||
return (value >> 1) ^ (~0)
|
||||
|
||||
|
||||
|
||||
# The *ByteSize() functions below return the number of bytes required to
|
||||
# serialize "field number + type" information and then serialize the value.
|
||||
|
||||
|
||||
def Int32ByteSize(field_number, int32):
|
||||
return Int64ByteSize(field_number, int32)
|
||||
|
||||
|
||||
def Int64ByteSize(field_number, int64):
|
||||
# Have to convert to uint before calling UInt64ByteSize().
|
||||
return UInt64ByteSize(field_number, 0xffffffffffffffff & int64)
|
||||
|
||||
|
||||
def UInt32ByteSize(field_number, uint32):
|
||||
return UInt64ByteSize(field_number, uint32)
|
||||
|
||||
|
||||
def UInt64ByteSize(field_number, uint64):
|
||||
return _TagByteSize(field_number) + _VarUInt64ByteSizeNoTag(uint64)
|
||||
|
||||
|
||||
def SInt32ByteSize(field_number, int32):
|
||||
return UInt32ByteSize(field_number, ZigZagEncode(int32))
|
||||
|
||||
|
||||
def SInt64ByteSize(field_number, int64):
|
||||
return UInt64ByteSize(field_number, ZigZagEncode(int64))
|
||||
|
||||
|
||||
def Fixed32ByteSize(field_number, fixed32):
|
||||
return _TagByteSize(field_number) + 4
|
||||
|
||||
|
||||
def Fixed64ByteSize(field_number, fixed64):
|
||||
return _TagByteSize(field_number) + 8
|
||||
|
||||
|
||||
def SFixed32ByteSize(field_number, sfixed32):
|
||||
return _TagByteSize(field_number) + 4
|
||||
|
||||
|
||||
def SFixed64ByteSize(field_number, sfixed64):
|
||||
return _TagByteSize(field_number) + 8
|
||||
|
||||
|
||||
def FloatByteSize(field_number, flt):
|
||||
return _TagByteSize(field_number) + 4
|
||||
|
||||
|
||||
def DoubleByteSize(field_number, double):
|
||||
return _TagByteSize(field_number) + 8
|
||||
|
||||
|
||||
def BoolByteSize(field_number, b):
|
||||
return _TagByteSize(field_number) + 1
|
||||
|
||||
|
||||
def EnumByteSize(field_number, enum):
|
||||
return UInt32ByteSize(field_number, enum)
|
||||
|
||||
|
||||
def StringByteSize(field_number, string):
|
||||
return BytesByteSize(field_number, string.encode('utf-8'))
|
||||
|
||||
|
||||
def BytesByteSize(field_number, b):
|
||||
return (_TagByteSize(field_number)
|
||||
+ _VarUInt64ByteSizeNoTag(len(b))
|
||||
+ len(b))
|
||||
|
||||
|
||||
def GroupByteSize(field_number, message):
|
||||
return (2 * _TagByteSize(field_number) # START and END group.
|
||||
+ message.ByteSize())
|
||||
|
||||
|
||||
def MessageByteSize(field_number, message):
|
||||
return (_TagByteSize(field_number)
|
||||
+ _VarUInt64ByteSizeNoTag(message.ByteSize())
|
||||
+ message.ByteSize())
|
||||
|
||||
|
||||
def MessageSetItemByteSize(field_number, msg):
|
||||
# First compute the sizes of the tags.
|
||||
# There are 2 tags for the beginning and ending of the repeated group, that
|
||||
# is field number 1, one with field number 2 (type_id) and one with field
|
||||
# number 3 (message).
|
||||
total_size = (2 * _TagByteSize(1) + _TagByteSize(2) + _TagByteSize(3))
|
||||
|
||||
# Add the number of bytes for type_id.
|
||||
total_size += _VarUInt64ByteSizeNoTag(field_number)
|
||||
|
||||
message_size = msg.ByteSize()
|
||||
|
||||
# The number of bytes for encoding the length of the message.
|
||||
total_size += _VarUInt64ByteSizeNoTag(message_size)
|
||||
|
||||
# The size of the message.
|
||||
total_size += message_size
|
||||
return total_size
|
||||
|
||||
|
||||
# Private helper functions for the *ByteSize() functions above.
|
||||
|
||||
|
||||
def _TagByteSize(field_number):
|
||||
"""Returns the bytes required to serialize a tag with this field number."""
|
||||
# Just pass in type 0, since the type won't affect the tag+type size.
|
||||
return _VarUInt64ByteSizeNoTag(PackTag(field_number, 0))
|
||||
|
||||
|
||||
def _VarUInt64ByteSizeNoTag(uint64):
|
||||
"""Returns the bytes required to serialize a single varint.
|
||||
uint64 must be unsigned.
|
||||
"""
|
||||
if uint64 > UINT64_MAX:
|
||||
raise message.EncodeError('Value out of range: %d' % uint64)
|
||||
bytes = 1
|
||||
while uint64 > 0x7f:
|
||||
bytes += 1
|
||||
uint64 >>= 7
|
||||
return bytes
|
Reference in New Issue
Block a user