Initial Contribution
diff --git a/froofle/protobuf/internal/__init__.py b/froofle/protobuf/internal/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/froofle/protobuf/internal/__init__.py
diff --git a/froofle/protobuf/internal/decoder.py b/froofle/protobuf/internal/decoder.py
new file mode 100644
index 0000000..2dd4c96
--- /dev/null
+++ b/froofle/protobuf/internal/decoder.py
@@ -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.
diff --git a/froofle/protobuf/internal/encoder.py b/froofle/protobuf/internal/encoder.py
new file mode 100644
index 0000000..8b924b3
--- /dev/null
+++ b/froofle/protobuf/internal/encoder.py
@@ -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))
diff --git a/froofle/protobuf/internal/input_stream.py b/froofle/protobuf/internal/input_stream.py
new file mode 100644
index 0000000..26a26dc
--- /dev/null
+++ b/froofle/protobuf/internal/input_stream.py
@@ -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
diff --git a/froofle/protobuf/internal/message_listener.py b/froofle/protobuf/internal/message_listener.py
new file mode 100644
index 0000000..4397895
--- /dev/null
+++ b/froofle/protobuf/internal/message_listener.py
@@ -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
diff --git a/froofle/protobuf/internal/output_stream.py b/froofle/protobuf/internal/output_stream.py
new file mode 100644
index 0000000..f62cd1c
--- /dev/null
+++ b/froofle/protobuf/internal/output_stream.py
@@ -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()
diff --git a/froofle/protobuf/internal/type_checkers.py b/froofle/protobuf/internal/type_checkers.py
new file mode 100644
index 0000000..aaf7a84
--- /dev/null
+++ b/froofle/protobuf/internal/type_checkers.py
@@ -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,
+ }
diff --git a/froofle/protobuf/internal/wire_format.py b/froofle/protobuf/internal/wire_format.py
new file mode 100644
index 0000000..4d823c8
--- /dev/null
+++ b/froofle/protobuf/internal/wire_format.py
@@ -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