~ubuntu-branches/ubuntu/oneiric/protobuf/oneiric

« back to all changes in this revision

Viewing changes to python/google/protobuf/internal/decoder.py

  • Committer: Bazaar Package Importer
  • Author(s): Iustin Pop
  • Date: 2008-08-03 11:01:44 UTC
  • Revision ID: james.westby@ubuntu.com-20080803110144-uyiw41bf1m2oe17t
Tags: upstream-2.0.0~b
ImportĀ upstreamĀ versionĀ 2.0.0~b

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Protocol Buffers - Google's data interchange format
 
2
# Copyright 2008 Google Inc.
 
3
# http://code.google.com/p/protobuf/
 
4
#
 
5
# Licensed under the Apache License, Version 2.0 (the "License");
 
6
# you may not use this file except in compliance with the License.
 
7
# You may obtain a copy of the License at
 
8
#
 
9
#      http://www.apache.org/licenses/LICENSE-2.0
 
10
#
 
11
# Unless required by applicable law or agreed to in writing, software
 
12
# distributed under the License is distributed on an "AS IS" BASIS,
 
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
14
# See the License for the specific language governing permissions and
 
15
# limitations under the License.
 
16
 
 
17
"""Class for decoding protocol buffer primitives.
 
18
 
 
19
Contains the logic for decoding every logical protocol field type
 
20
from one of the 5 physical wire types.
 
21
"""
 
22
 
 
23
__author__ = 'robinson@google.com (Will Robinson)'
 
24
 
 
25
import struct
 
26
from google.protobuf import message
 
27
from google.protobuf.internal import input_stream
 
28
from google.protobuf.internal import wire_format
 
29
 
 
30
 
 
31
 
 
32
# Note that much of this code is ported from //net/proto/ProtocolBuffer, and
 
33
# that the interface is strongly inspired by WireFormat from the C++ proto2
 
34
# implementation.
 
35
 
 
36
 
 
37
class Decoder(object):
 
38
 
 
39
  """Decodes logical protocol buffer fields from the wire."""
 
40
 
 
41
  def __init__(self, s):
 
42
    """Initializes the decoder to read from s.
 
43
 
 
44
    Args:
 
45
      s: An immutable sequence of bytes, which must be accessible
 
46
        via the Python buffer() primitive (i.e., buffer(s)).
 
47
    """
 
48
    self._stream = input_stream.InputStream(s)
 
49
 
 
50
  def EndOfStream(self):
 
51
    """Returns true iff we've reached the end of the bytes we're reading."""
 
52
    return self._stream.EndOfStream()
 
53
 
 
54
  def Position(self):
 
55
    """Returns the 0-indexed position in |s|."""
 
56
    return self._stream.Position()
 
57
 
 
58
  def ReadFieldNumberAndWireType(self):
 
59
    """Reads a tag from the wire. Returns a (field_number, wire_type) pair."""
 
60
    tag_and_type = self.ReadUInt32()
 
61
    return wire_format.UnpackTag(tag_and_type)
 
62
 
 
63
  def SkipBytes(self, bytes):
 
64
    """Skips the specified number of bytes on the wire."""
 
65
    self._stream.SkipBytes(bytes)
 
66
 
 
67
  # Note that the Read*() methods below are not exactly symmetrical with the
 
68
  # corresponding Encoder.Append*() methods.  Those Encoder methods first
 
69
  # encode a tag, but the Read*() methods below assume that the tag has already
 
70
  # been read, and that the client wishes to read a field of the specified type
 
71
  # starting at the current position.
 
72
 
 
73
  def ReadInt32(self):
 
74
    """Reads and returns a signed, varint-encoded, 32-bit integer."""
 
75
    return self._stream.ReadVarint32()
 
76
 
 
77
  def ReadInt64(self):
 
78
    """Reads and returns a signed, varint-encoded, 64-bit integer."""
 
79
    return self._stream.ReadVarint64()
 
80
 
 
81
  def ReadUInt32(self):
 
82
    """Reads and returns an signed, varint-encoded, 32-bit integer."""
 
83
    return self._stream.ReadVarUInt32()
 
84
 
 
85
  def ReadUInt64(self):
 
86
    """Reads and returns an signed, varint-encoded,64-bit integer."""
 
87
    return self._stream.ReadVarUInt64()
 
88
 
 
89
  def ReadSInt32(self):
 
90
    """Reads and returns a signed, zigzag-encoded, varint-encoded,
 
91
    32-bit integer."""
 
92
    return wire_format.ZigZagDecode(self._stream.ReadVarUInt32())
 
93
 
 
94
  def ReadSInt64(self):
 
95
    """Reads and returns a signed, zigzag-encoded, varint-encoded,
 
96
    64-bit integer."""
 
97
    return wire_format.ZigZagDecode(self._stream.ReadVarUInt64())
 
98
 
 
99
  def ReadFixed32(self):
 
100
    """Reads and returns an unsigned, fixed-width, 32-bit integer."""
 
101
    return self._stream.ReadLittleEndian32()
 
102
 
 
103
  def ReadFixed64(self):
 
104
    """Reads and returns an unsigned, fixed-width, 64-bit integer."""
 
105
    return self._stream.ReadLittleEndian64()
 
106
 
 
107
  def ReadSFixed32(self):
 
108
    """Reads and returns a signed, fixed-width, 32-bit integer."""
 
109
    value = self._stream.ReadLittleEndian32()
 
110
    if value >= (1 << 31):
 
111
      value -= (1 << 32)
 
112
    return value
 
113
 
 
114
  def ReadSFixed64(self):
 
115
    """Reads and returns a signed, fixed-width, 64-bit integer."""
 
116
    value = self._stream.ReadLittleEndian64()
 
117
    if value >= (1 << 63):
 
118
      value -= (1 << 64)
 
119
    return value
 
120
 
 
121
  def ReadFloat(self):
 
122
    """Reads and returns a 4-byte floating-point number."""
 
123
    serialized = self._stream.ReadString(4)
 
124
    return struct.unpack('f', serialized)[0]
 
125
 
 
126
  def ReadDouble(self):
 
127
    """Reads and returns an 8-byte floating-point number."""
 
128
    serialized = self._stream.ReadString(8)
 
129
    return struct.unpack('d', serialized)[0]
 
130
 
 
131
  def ReadBool(self):
 
132
    """Reads and returns a bool."""
 
133
    i = self._stream.ReadVarUInt32()
 
134
    return bool(i)
 
135
 
 
136
  def ReadEnum(self):
 
137
    """Reads and returns an enum value."""
 
138
    return self._stream.ReadVarUInt32()
 
139
 
 
140
  def ReadString(self):
 
141
    """Reads and returns a length-delimited string."""
 
142
    length = self._stream.ReadVarUInt32()
 
143
    return self._stream.ReadString(length)
 
144
 
 
145
  def ReadBytes(self):
 
146
    """Reads and returns a length-delimited byte sequence."""
 
147
    return self.ReadString()
 
148
 
 
149
  def ReadMessageInto(self, msg):
 
150
    """Calls msg.MergeFromString() to merge
 
151
    length-delimited serialized message data into |msg|.
 
152
 
 
153
    REQUIRES: The decoder must be positioned at the serialized "length"
 
154
      prefix to a length-delmiited serialized message.
 
155
 
 
156
    POSTCONDITION: The decoder is positioned just after the
 
157
      serialized message, and we have merged those serialized
 
158
      contents into |msg|.
 
159
    """
 
160
    length = self._stream.ReadVarUInt32()
 
161
    sub_buffer = self._stream.GetSubBuffer(length)
 
162
    num_bytes_used = msg.MergeFromString(sub_buffer)
 
163
    if num_bytes_used != length:
 
164
      raise message.DecodeError(
 
165
          'Submessage told to deserialize from %d-byte encoding, '
 
166
          'but used only %d bytes' % (length, num_bytes_used))
 
167
    self._stream.SkipBytes(num_bytes_used)
 
168
 
 
169
  def ReadGroupInto(self, expected_field_number, group):
 
170
    """Calls group.MergeFromString() to merge
 
171
    END_GROUP-delimited serialized message data into |group|.
 
172
    We'll raise an exception if we don't find an END_GROUP
 
173
    tag immediately after the serialized message contents.
 
174
 
 
175
    REQUIRES: The decoder is positioned just after the START_GROUP
 
176
      tag for this group.
 
177
 
 
178
    POSTCONDITION: The decoder is positioned just after the
 
179
      END_GROUP tag for this group, and we have merged
 
180
      the contents of the group into |group|.
 
181
    """
 
182
    sub_buffer = self._stream.GetSubBuffer()  # No a priori length limit.
 
183
    num_bytes_used = group.MergeFromString(sub_buffer)
 
184
    if num_bytes_used < 0:
 
185
      raise message.DecodeError('Group message reported negative bytes read.')
 
186
    self._stream.SkipBytes(num_bytes_used)
 
187
    field_number, field_type = self.ReadFieldNumberAndWireType()
 
188
    if field_type != wire_format.WIRETYPE_END_GROUP:
 
189
      raise message.DecodeError('Group message did not end with an END_GROUP.')
 
190
    if field_number != expected_field_number:
 
191
      raise message.DecodeError('END_GROUP tag had field '
 
192
                                'number %d, was expecting field number %d' % (
 
193
          field_number, expected_field_number))
 
194
    # We're now positioned just after the END_GROUP tag.  Perfect.