mirror of
https://github.com/Dev-Wiki/git-repo.git
synced 2025-12-16 03:10:28 +08:00
Initial Contribution
This commit is contained in:
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
|
||||
Reference in New Issue
Block a user