• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Protocol Buffers - Google's data interchange format
2# Copyright 2008 Google Inc.  All rights reserved.
3# https://developers.google.com/protocol-buffers/
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15#     * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Provides type checking routines.
32
33This module defines type checking utilities in the forms of dictionaries:
34
35VALUE_CHECKERS: A dictionary of field types and a value validation object.
36TYPE_TO_BYTE_SIZE_FN: A dictionary with field types and a size computing
37  function.
38TYPE_TO_SERIALIZE_METHOD: A dictionary with field types and serialization
39  function.
40FIELD_TYPE_TO_WIRE_TYPE: A dictionary with field typed and their
41  coresponding wire types.
42TYPE_TO_DESERIALIZE_METHOD: A dictionary with field types and deserialization
43  function.
44"""
45
46__author__ = 'robinson@google.com (Will Robinson)'
47
48import six
49
50if six.PY3:
51  long = int
52
53from google.protobuf.internal import api_implementation
54from google.protobuf.internal import decoder
55from google.protobuf.internal import encoder
56from google.protobuf.internal import wire_format
57from google.protobuf import descriptor
58
59_FieldDescriptor = descriptor.FieldDescriptor
60
61def SupportsOpenEnums(field_descriptor):
62  return field_descriptor.containing_type.syntax == "proto3"
63
64def GetTypeChecker(field):
65  """Returns a type checker for a message field of the specified types.
66
67  Args:
68    field: FieldDescriptor object for this field.
69
70  Returns:
71    An instance of TypeChecker which can be used to verify the types
72    of values assigned to a field of the specified type.
73  """
74  if (field.cpp_type == _FieldDescriptor.CPPTYPE_STRING and
75      field.type == _FieldDescriptor.TYPE_STRING):
76    return UnicodeValueChecker()
77  if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
78    if SupportsOpenEnums(field):
79      # When open enums are supported, any int32 can be assigned.
80      return _VALUE_CHECKERS[_FieldDescriptor.CPPTYPE_INT32]
81    else:
82      return EnumValueChecker(field.enum_type)
83  return _VALUE_CHECKERS[field.cpp_type]
84
85
86# None of the typecheckers below make any attempt to guard against people
87# subclassing builtin types and doing weird things.  We're not trying to
88# protect against malicious clients here, just people accidentally shooting
89# themselves in the foot in obvious ways.
90
91class TypeChecker(object):
92
93  """Type checker used to catch type errors as early as possible
94  when the client is setting scalar fields in protocol messages.
95  """
96
97  def __init__(self, *acceptable_types):
98    self._acceptable_types = acceptable_types
99
100  def CheckValue(self, proposed_value):
101    """Type check the provided value and return it.
102
103    The returned value might have been normalized to another type.
104    """
105    if not isinstance(proposed_value, self._acceptable_types):
106      message = ('%.1024r has type %s, but expected one of: %s' %
107                 (proposed_value, type(proposed_value), self._acceptable_types))
108      raise TypeError(message)
109    return proposed_value
110
111
112class TypeCheckerWithDefault(TypeChecker):
113
114  def __init__(self, default_value, *acceptable_types):
115    TypeChecker.__init__(self, acceptable_types)
116    self._default_value = default_value
117
118  def DefaultValue(self):
119    return self._default_value
120
121
122# IntValueChecker and its subclasses perform integer type-checks
123# and bounds-checks.
124class IntValueChecker(object):
125
126  """Checker used for integer fields.  Performs type-check and range check."""
127
128  def CheckValue(self, proposed_value):
129    if not isinstance(proposed_value, six.integer_types):
130      message = ('%.1024r has type %s, but expected one of: %s' %
131                 (proposed_value, type(proposed_value), six.integer_types))
132      raise TypeError(message)
133    if not self._MIN <= proposed_value <= self._MAX:
134      raise ValueError('Value out of range: %d' % proposed_value)
135    # We force 32-bit values to int and 64-bit values to long to make
136    # alternate implementations where the distinction is more significant
137    # (e.g. the C++ implementation) simpler.
138    proposed_value = self._TYPE(proposed_value)
139    return proposed_value
140
141  def DefaultValue(self):
142    return 0
143
144
145class EnumValueChecker(object):
146
147  """Checker used for enum fields.  Performs type-check and range check."""
148
149  def __init__(self, enum_type):
150    self._enum_type = enum_type
151
152  def CheckValue(self, proposed_value):
153    if not isinstance(proposed_value, six.integer_types):
154      message = ('%.1024r has type %s, but expected one of: %s' %
155                 (proposed_value, type(proposed_value), six.integer_types))
156      raise TypeError(message)
157    if proposed_value not in self._enum_type.values_by_number:
158      raise ValueError('Unknown enum value: %d' % proposed_value)
159    return proposed_value
160
161  def DefaultValue(self):
162    return self._enum_type.values[0].number
163
164
165class UnicodeValueChecker(object):
166
167  """Checker used for string fields.
168
169  Always returns a unicode value, even if the input is of type str.
170  """
171
172  def CheckValue(self, proposed_value):
173    if not isinstance(proposed_value, (bytes, six.text_type)):
174      message = ('%.1024r has type %s, but expected one of: %s' %
175                 (proposed_value, type(proposed_value), (bytes, six.text_type)))
176      raise TypeError(message)
177
178    # If the value is of type 'bytes' make sure that it is valid UTF-8 data.
179    if isinstance(proposed_value, bytes):
180      try:
181        proposed_value = proposed_value.decode('utf-8')
182      except UnicodeDecodeError:
183        raise ValueError('%.1024r has type bytes, but isn\'t valid UTF-8 '
184                         'encoding. Non-UTF-8 strings must be converted to '
185                         'unicode objects before being added.' %
186                         (proposed_value))
187    return proposed_value
188
189  def DefaultValue(self):
190    return u""
191
192
193class Int32ValueChecker(IntValueChecker):
194  # We're sure to use ints instead of longs here since comparison may be more
195  # efficient.
196  _MIN = -2147483648
197  _MAX = 2147483647
198  _TYPE = int
199
200
201class Uint32ValueChecker(IntValueChecker):
202  _MIN = 0
203  _MAX = (1 << 32) - 1
204  _TYPE = int
205
206
207class Int64ValueChecker(IntValueChecker):
208  _MIN = -(1 << 63)
209  _MAX = (1 << 63) - 1
210  _TYPE = long
211
212
213class Uint64ValueChecker(IntValueChecker):
214  _MIN = 0
215  _MAX = (1 << 64) - 1
216  _TYPE = long
217
218
219# Type-checkers for all scalar CPPTYPEs.
220_VALUE_CHECKERS = {
221    _FieldDescriptor.CPPTYPE_INT32: Int32ValueChecker(),
222    _FieldDescriptor.CPPTYPE_INT64: Int64ValueChecker(),
223    _FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
224    _FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
225    _FieldDescriptor.CPPTYPE_DOUBLE: TypeCheckerWithDefault(
226        0.0, float, int, long),
227    _FieldDescriptor.CPPTYPE_FLOAT: TypeCheckerWithDefault(
228        0.0, float, int, long),
229    _FieldDescriptor.CPPTYPE_BOOL: TypeCheckerWithDefault(
230        False, bool, int),
231    _FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes),
232    }
233
234
235# Map from field type to a function F, such that F(field_num, value)
236# gives the total byte size for a value of the given type.  This
237# byte size includes tag information and any other additional space
238# associated with serializing "value".
239TYPE_TO_BYTE_SIZE_FN = {
240    _FieldDescriptor.TYPE_DOUBLE: wire_format.DoubleByteSize,
241    _FieldDescriptor.TYPE_FLOAT: wire_format.FloatByteSize,
242    _FieldDescriptor.TYPE_INT64: wire_format.Int64ByteSize,
243    _FieldDescriptor.TYPE_UINT64: wire_format.UInt64ByteSize,
244    _FieldDescriptor.TYPE_INT32: wire_format.Int32ByteSize,
245    _FieldDescriptor.TYPE_FIXED64: wire_format.Fixed64ByteSize,
246    _FieldDescriptor.TYPE_FIXED32: wire_format.Fixed32ByteSize,
247    _FieldDescriptor.TYPE_BOOL: wire_format.BoolByteSize,
248    _FieldDescriptor.TYPE_STRING: wire_format.StringByteSize,
249    _FieldDescriptor.TYPE_GROUP: wire_format.GroupByteSize,
250    _FieldDescriptor.TYPE_MESSAGE: wire_format.MessageByteSize,
251    _FieldDescriptor.TYPE_BYTES: wire_format.BytesByteSize,
252    _FieldDescriptor.TYPE_UINT32: wire_format.UInt32ByteSize,
253    _FieldDescriptor.TYPE_ENUM: wire_format.EnumByteSize,
254    _FieldDescriptor.TYPE_SFIXED32: wire_format.SFixed32ByteSize,
255    _FieldDescriptor.TYPE_SFIXED64: wire_format.SFixed64ByteSize,
256    _FieldDescriptor.TYPE_SINT32: wire_format.SInt32ByteSize,
257    _FieldDescriptor.TYPE_SINT64: wire_format.SInt64ByteSize
258    }
259
260
261# Maps from field types to encoder constructors.
262TYPE_TO_ENCODER = {
263    _FieldDescriptor.TYPE_DOUBLE: encoder.DoubleEncoder,
264    _FieldDescriptor.TYPE_FLOAT: encoder.FloatEncoder,
265    _FieldDescriptor.TYPE_INT64: encoder.Int64Encoder,
266    _FieldDescriptor.TYPE_UINT64: encoder.UInt64Encoder,
267    _FieldDescriptor.TYPE_INT32: encoder.Int32Encoder,
268    _FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Encoder,
269    _FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Encoder,
270    _FieldDescriptor.TYPE_BOOL: encoder.BoolEncoder,
271    _FieldDescriptor.TYPE_STRING: encoder.StringEncoder,
272    _FieldDescriptor.TYPE_GROUP: encoder.GroupEncoder,
273    _FieldDescriptor.TYPE_MESSAGE: encoder.MessageEncoder,
274    _FieldDescriptor.TYPE_BYTES: encoder.BytesEncoder,
275    _FieldDescriptor.TYPE_UINT32: encoder.UInt32Encoder,
276    _FieldDescriptor.TYPE_ENUM: encoder.EnumEncoder,
277    _FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Encoder,
278    _FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Encoder,
279    _FieldDescriptor.TYPE_SINT32: encoder.SInt32Encoder,
280    _FieldDescriptor.TYPE_SINT64: encoder.SInt64Encoder,
281    }
282
283
284# Maps from field types to sizer constructors.
285TYPE_TO_SIZER = {
286    _FieldDescriptor.TYPE_DOUBLE: encoder.DoubleSizer,
287    _FieldDescriptor.TYPE_FLOAT: encoder.FloatSizer,
288    _FieldDescriptor.TYPE_INT64: encoder.Int64Sizer,
289    _FieldDescriptor.TYPE_UINT64: encoder.UInt64Sizer,
290    _FieldDescriptor.TYPE_INT32: encoder.Int32Sizer,
291    _FieldDescriptor.TYPE_FIXED64: encoder.Fixed64Sizer,
292    _FieldDescriptor.TYPE_FIXED32: encoder.Fixed32Sizer,
293    _FieldDescriptor.TYPE_BOOL: encoder.BoolSizer,
294    _FieldDescriptor.TYPE_STRING: encoder.StringSizer,
295    _FieldDescriptor.TYPE_GROUP: encoder.GroupSizer,
296    _FieldDescriptor.TYPE_MESSAGE: encoder.MessageSizer,
297    _FieldDescriptor.TYPE_BYTES: encoder.BytesSizer,
298    _FieldDescriptor.TYPE_UINT32: encoder.UInt32Sizer,
299    _FieldDescriptor.TYPE_ENUM: encoder.EnumSizer,
300    _FieldDescriptor.TYPE_SFIXED32: encoder.SFixed32Sizer,
301    _FieldDescriptor.TYPE_SFIXED64: encoder.SFixed64Sizer,
302    _FieldDescriptor.TYPE_SINT32: encoder.SInt32Sizer,
303    _FieldDescriptor.TYPE_SINT64: encoder.SInt64Sizer,
304    }
305
306
307# Maps from field type to a decoder constructor.
308TYPE_TO_DECODER = {
309    _FieldDescriptor.TYPE_DOUBLE: decoder.DoubleDecoder,
310    _FieldDescriptor.TYPE_FLOAT: decoder.FloatDecoder,
311    _FieldDescriptor.TYPE_INT64: decoder.Int64Decoder,
312    _FieldDescriptor.TYPE_UINT64: decoder.UInt64Decoder,
313    _FieldDescriptor.TYPE_INT32: decoder.Int32Decoder,
314    _FieldDescriptor.TYPE_FIXED64: decoder.Fixed64Decoder,
315    _FieldDescriptor.TYPE_FIXED32: decoder.Fixed32Decoder,
316    _FieldDescriptor.TYPE_BOOL: decoder.BoolDecoder,
317    _FieldDescriptor.TYPE_STRING: decoder.StringDecoder,
318    _FieldDescriptor.TYPE_GROUP: decoder.GroupDecoder,
319    _FieldDescriptor.TYPE_MESSAGE: decoder.MessageDecoder,
320    _FieldDescriptor.TYPE_BYTES: decoder.BytesDecoder,
321    _FieldDescriptor.TYPE_UINT32: decoder.UInt32Decoder,
322    _FieldDescriptor.TYPE_ENUM: decoder.EnumDecoder,
323    _FieldDescriptor.TYPE_SFIXED32: decoder.SFixed32Decoder,
324    _FieldDescriptor.TYPE_SFIXED64: decoder.SFixed64Decoder,
325    _FieldDescriptor.TYPE_SINT32: decoder.SInt32Decoder,
326    _FieldDescriptor.TYPE_SINT64: decoder.SInt64Decoder,
327    }
328
329# Maps from field type to expected wiretype.
330FIELD_TYPE_TO_WIRE_TYPE = {
331    _FieldDescriptor.TYPE_DOUBLE: wire_format.WIRETYPE_FIXED64,
332    _FieldDescriptor.TYPE_FLOAT: wire_format.WIRETYPE_FIXED32,
333    _FieldDescriptor.TYPE_INT64: wire_format.WIRETYPE_VARINT,
334    _FieldDescriptor.TYPE_UINT64: wire_format.WIRETYPE_VARINT,
335    _FieldDescriptor.TYPE_INT32: wire_format.WIRETYPE_VARINT,
336    _FieldDescriptor.TYPE_FIXED64: wire_format.WIRETYPE_FIXED64,
337    _FieldDescriptor.TYPE_FIXED32: wire_format.WIRETYPE_FIXED32,
338    _FieldDescriptor.TYPE_BOOL: wire_format.WIRETYPE_VARINT,
339    _FieldDescriptor.TYPE_STRING:
340      wire_format.WIRETYPE_LENGTH_DELIMITED,
341    _FieldDescriptor.TYPE_GROUP: wire_format.WIRETYPE_START_GROUP,
342    _FieldDescriptor.TYPE_MESSAGE:
343      wire_format.WIRETYPE_LENGTH_DELIMITED,
344    _FieldDescriptor.TYPE_BYTES:
345      wire_format.WIRETYPE_LENGTH_DELIMITED,
346    _FieldDescriptor.TYPE_UINT32: wire_format.WIRETYPE_VARINT,
347    _FieldDescriptor.TYPE_ENUM: wire_format.WIRETYPE_VARINT,
348    _FieldDescriptor.TYPE_SFIXED32: wire_format.WIRETYPE_FIXED32,
349    _FieldDescriptor.TYPE_SFIXED64: wire_format.WIRETYPE_FIXED64,
350    _FieldDescriptor.TYPE_SINT32: wire_format.WIRETYPE_VARINT,
351    _FieldDescriptor.TYPE_SINT64: wire_format.WIRETYPE_VARINT,
352    }
353