1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# Protocol Buffers - Google's data interchange format
2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# Copyright 2008 Google Inc.  All rights reserved.
3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson# https://developers.google.com/protocol-buffers/
4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#
5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# Redistribution and use in source and binary forms, with or without
6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# modification, are permitted provided that the following conditions are
7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# met:
8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#
9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#     * Redistributions of source code must retain the above copyright
10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# notice, this list of conditions and the following disclaimer.
11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#     * Redistributions in binary form must reproduce the above
12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# copyright notice, this list of conditions and the following disclaimer
13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# in the documentation and/or other materials provided with the
14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# distribution.
15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#     * Neither the name of Google Inc. nor the names of its
16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# contributors may be used to endorse or promote products derived from
17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# this software without specific prior written permission.
18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#
19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
31a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#PY25 compatible for GAE.
32a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#
33a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Copyright 2007 Google Inc. All Rights Reserved.
34a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville"""Contains routines for printing protocol messages in text format."""
36fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville__author__ = 'kenton@google.com (Kenton Varda)'
38fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport cStringIO
40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleimport re
41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillefrom google.protobuf.internal import type_checkers
43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillefrom google.protobuf import descriptor
44a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonfrom google.protobuf import text_encoding
45a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
46a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson__all__ = ['MessageToString', 'PrintMessage', 'PrintField',
47a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson           'PrintFieldValue', 'Merge']
48fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
49fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
50a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson_INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),
51a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                     type_checkers.Int32ValueChecker(),
52a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                     type_checkers.Uint64ValueChecker(),
53a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                     type_checkers.Int64ValueChecker())
54a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson_FLOAT_INFINITY = re.compile('-?inf(?:inity)?f?', re.IGNORECASE)
55a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson_FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)
56a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
57a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                          descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
58fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
59d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
60a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass Error(Exception):
61a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Top-level module error for text_format."""
62d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
63a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
64a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass ParseError(Error):
65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """Thrown in case of ASCII parsing error."""
66fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
68a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef MessageToString(message, as_utf8=False, as_one_line=False,
69a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                    pointy_brackets=False, use_index_order=False,
70a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                    float_format=None):
71a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Convert protobuf message to text format.
72a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
73a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Floating point values can be formatted compactly with 15 digits of
74a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  precision (which is the most that IEEE 754 "double" can guarantee)
75a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  using float_format='.15g'.
76a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
77a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
78a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    message: The protocol buffers message.
79a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    as_utf8: Produce text output in UTF8 format.
80a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    as_one_line: Don't introduce newlines between fields.
81a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    pointy_brackets: If True, use angle brackets instead of curly braces for
82a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      nesting.
83a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    use_index_order: If True, print fields of a proto message using the order
84a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      defined in source code instead of the field number. By default, use the
85a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      field number order.
86a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    float_format: If set, use this to specify floating point number formatting
87a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      (per the "Format Specification Mini-Language"); otherwise, str() is used.
88a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
89a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
90a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    A string of the text formatted protocol buffer message.
91a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
92fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  out = cStringIO.StringIO()
93a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line,
94a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson               pointy_brackets=pointy_brackets,
95a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson               use_index_order=use_index_order,
96a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson               float_format=float_format)
97fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  result = out.getvalue()
98fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  out.close()
99a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if as_one_line:
100a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return result.rstrip()
101fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  return result
102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
104a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
105a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                 pointy_brackets=False, use_index_order=False,
106a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                 float_format=None):
107a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  fields = message.ListFields()
108a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if use_index_order:
109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    fields.sort(key=lambda x: x[0].index)
110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  for field, value in fields:
111fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      for element in value:
113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        PrintField(field, element, out, indent, as_utf8, as_one_line,
114a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                   pointy_brackets=pointy_brackets,
115a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                   float_format=float_format)
116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
117a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      PrintField(field, value, out, indent, as_utf8, as_one_line,
118a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                 pointy_brackets=pointy_brackets,
119a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                 float_format=float_format)
120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False,
123a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson               pointy_brackets=False, float_format=None):
124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """Print a single field name/value pair.  For repeated fields, the value
125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  should be a single element."""
126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
127a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  out.write(' ' * indent)
128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if field.is_extension:
129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write('[')
130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (field.containing_type.GetOptions().message_set_wire_format and
131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        field.message_type == field.extension_scope and
133fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      out.write(field.message_type.full_name)
135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      out.write(field.full_name)
137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write(']')
138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    # For groups, use the capitalized name.
140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write(field.message_type.name)
141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  else:
142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write(field.name)
143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    # The colon is optional in this case, but our cross-language golden files
146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    # don't include it.
147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write(': ')
148fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
149a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  PrintFieldValue(field, value, out, indent, as_utf8, as_one_line,
150a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                  pointy_brackets=pointy_brackets,
151a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                  float_format=float_format)
152a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if as_one_line:
153a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    out.write(' ')
154a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  else:
155a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    out.write('\n')
156fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
157fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
158a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef PrintFieldValue(field, value, out, indent=0, as_utf8=False,
159a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                    as_one_line=False, pointy_brackets=False,
160a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                    float_format=None):
161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """Print a single field value (not including name).  For repeated fields,
162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  the value should be a single element."""
163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
164a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if pointy_brackets:
165a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    openb = '<'
166a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    closeb = '>'
167a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  else:
168a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    openb = '{'
169a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    closeb = '}'
170a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
171fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
172a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if as_one_line:
173a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write(' %s ' % openb)
174a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      PrintMessage(value, out, indent, as_utf8, as_one_line,
175a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                   pointy_brackets=pointy_brackets,
176a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                   float_format=float_format)
177a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write(closeb)
178a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    else:
179a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write(' %s\n' % openb)
180a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      PrintMessage(value, out, indent + 2, as_utf8, as_one_line,
181a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                   pointy_brackets=pointy_brackets,
182a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson                   float_format=float_format)
183a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write(' ' * indent + closeb)
184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
185a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    enum_value = field.enum_type.values_by_number.get(value, None)
186a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if enum_value is not None:
187a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write(enum_value.name)
188a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    else:
189a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write(str(value))
190fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
191fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write('\"')
192a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if isinstance(value, unicode):
193a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out_value = value.encode('utf-8')
194a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    else:
195a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out_value = value
196a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
197a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      # We need to escape non-UTF8 chars in TYPE_BYTES field.
198a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out_as_utf8 = False
199a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    else:
200a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out_as_utf8 = as_utf8
201a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    out.write(text_encoding.CEscape(out_value, out_as_utf8))
202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write('\"')
203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if value:
205a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write('true')
206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
207a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      out.write('false')
208a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  elif field.cpp_type in _FLOAT_TYPES and float_format is not None:
209a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    out.write('{1:{0}}'.format(float_format, value))
210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  else:
211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    out.write(str(value))
212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
214a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef _ParseOrMerge(lines, message, allow_multiple_scalars):
215a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Converts an ASCII representation of a protocol message into a message.
216a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
217a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
218a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    lines: Lines of a message's ASCII representation.
219a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    message: A protocol buffer message to merge into.
220a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    allow_multiple_scalars: Determines if repeated values for a non-repeated
221a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      field are permitted, e.g., the string "foo: 1 foo: 2" for a
222a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      required/optional field named "foo".
223a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
224a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
225a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ParseError: On ASCII parsing problems.
226a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
227a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  tokenizer = _Tokenizer(lines)
228a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  while not tokenizer.AtEnd():
229a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    _MergeField(tokenizer, message, allow_multiple_scalars)
230a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
231a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
232a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef Parse(text, message):
233a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parses an ASCII representation of a protocol message into a message.
234a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
235a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
236a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    text: Message ASCII representation.
237a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    message: A protocol buffer message to merge into.
238a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
239a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
240a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The same message passed as argument.
241a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
242a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
243a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ParseError: On ASCII parsing problems.
244a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
245a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if not isinstance(text, str): text = text.decode('utf-8')
246a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  return ParseLines(text.split('\n'), message)
247a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
248a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
249fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilledef Merge(text, message):
250a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parses an ASCII representation of a protocol message into a message.
251a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
252a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Like Parse(), but allows repeated values for a non-repeated field, and uses
253a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  the last one.
254fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
255fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Args:
256fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    text: Message ASCII representation.
257fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    message: A protocol buffer message to merge into.
258fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
259a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
260a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The same message passed as argument.
261a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
262fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Raises:
263fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    ParseError: On ASCII parsing problems.
264fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """
265a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  return MergeLines(text.split('\n'), message)
266a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
267a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
268a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef ParseLines(lines, message):
269a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parses an ASCII representation of a protocol message into a message.
270a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
271a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
272a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    lines: An iterable of lines of a message's ASCII representation.
273a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    message: A protocol buffer message to merge into.
274a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
275a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
276a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The same message passed as argument.
277a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
278a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
279a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ParseError: On ASCII parsing problems.
280a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
281a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  _ParseOrMerge(lines, message, False)
282a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  return message
283a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
284a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
285a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef MergeLines(lines, message):
286a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parses an ASCII representation of a protocol message into a message.
287a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
288a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
289a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    lines: An iterable of lines of a message's ASCII representation.
290a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    message: A protocol buffer message to merge into.
291a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
292a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
293a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The same message passed as argument.
294fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
295a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
296a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ParseError: On ASCII parsing problems.
297a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
298a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  _ParseOrMerge(lines, message, True)
299a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  return message
300fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
301a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
302a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef _MergeField(tokenizer, message, allow_multiple_scalars):
303fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """Merges a single protocol message field into a message.
304fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
305fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Args:
306fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    tokenizer: A tokenizer to parse the field name and values.
307fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    message: A protocol message to record the data.
308a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    allow_multiple_scalars: Determines if repeated values for a non-repeated
309a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      field are permitted, e.g., the string "foo: 1 foo: 2" for a
310a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      required/optional field named "foo".
311fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
312fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Raises:
313fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    ParseError: In case of ASCII parsing problems.
314fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """
315fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  message_descriptor = message.DESCRIPTOR
316fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if tokenizer.TryConsume('['):
317fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    name = [tokenizer.ConsumeIdentifier()]
318fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    while tokenizer.TryConsume('.'):
319fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      name.append(tokenizer.ConsumeIdentifier())
320fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    name = '.'.join(name)
321fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
322d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    if not message_descriptor.is_extendable:
323d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      raise tokenizer.ParseErrorPreviousToken(
324d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          'Message type "%s" does not have extensions.' %
325d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville          message_descriptor.full_name)
326a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # pylint: disable=protected-access
327fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    field = message.Extensions._FindExtensionByName(name)
328a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # pylint: enable=protected-access
329fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if not field:
330fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise tokenizer.ParseErrorPreviousToken(
331fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          'Extension "%s" not registered.' % name)
332fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    elif message_descriptor != field.containing_type:
333fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise tokenizer.ParseErrorPreviousToken(
334fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          'Extension "%s" does not extend message type "%s".' % (
335fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              name, message_descriptor.full_name))
336fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    tokenizer.Consume(']')
337fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  else:
338fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    name = tokenizer.ConsumeIdentifier()
339fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    field = message_descriptor.fields_by_name.get(name, None)
340fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
341fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    # Group names are expected to be capitalized as they appear in the
342fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    # .proto file, which actually matches their type names, not their field
343fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    # names.
344fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if not field:
345fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      field = message_descriptor.fields_by_name.get(name.lower(), None)
346fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
347fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        field = None
348fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
349fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
350fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        field.message_type.name != name):
351fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      field = None
352fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
353fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if not field:
354fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise tokenizer.ParseErrorPreviousToken(
355fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          'Message type "%s" has no field named "%s".' % (
356fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville              message_descriptor.full_name, name))
357fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
358fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
359fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    tokenizer.TryConsume(':')
360fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
361fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if tokenizer.TryConsume('<'):
362fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      end_token = '>'
363fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
364fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      tokenizer.Consume('{')
365fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      end_token = '}'
366fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
367fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
368fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if field.is_extension:
369fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        sub_message = message.Extensions[field].add()
370fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      else:
371fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        sub_message = getattr(message, field.name).add()
372fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
373fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if field.is_extension:
374fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        sub_message = message.Extensions[field]
375fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      else:
376fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        sub_message = getattr(message, field.name)
377a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      sub_message.SetInParent()
378fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
379fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    while not tokenizer.TryConsume(end_token):
380fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if tokenizer.AtEnd():
381fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
382a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      _MergeField(tokenizer, sub_message, allow_multiple_scalars)
383fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  else:
384a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
385a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
386a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  # For historical reasons, fields may optionally be separated by commas or
387a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  # semicolons.
388a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if not tokenizer.TryConsume(','):
389a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    tokenizer.TryConsume(';')
390fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
391fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
392a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef _MergeScalarField(tokenizer, message, field, allow_multiple_scalars):
393fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """Merges a single protocol message scalar field into a message.
394fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
395fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Args:
396fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    tokenizer: A tokenizer to parse the field value.
397fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    message: A protocol message to record the data.
398fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    field: The descriptor of the field to be merged.
399a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    allow_multiple_scalars: Determines if repeated values for a non-repeated
400a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      field are permitted, e.g., the string "foo: 1 foo: 2" for a
401a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      required/optional field named "foo".
402fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
403fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  Raises:
404fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    ParseError: In case of ASCII parsing problems.
405fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    RuntimeError: On runtime errors.
406fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """
407fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  tokenizer.Consume(':')
408fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  value = None
409fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
410fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
411fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    descriptor.FieldDescriptor.TYPE_SINT32,
412fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                    descriptor.FieldDescriptor.TYPE_SFIXED32):
413fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeInt32()
414fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
415fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                      descriptor.FieldDescriptor.TYPE_SINT64,
416fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                      descriptor.FieldDescriptor.TYPE_SFIXED64):
417fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeInt64()
418fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
419fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                      descriptor.FieldDescriptor.TYPE_FIXED32):
420fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeUint32()
421fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
422fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                      descriptor.FieldDescriptor.TYPE_FIXED64):
423fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeUint64()
424fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
425fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                      descriptor.FieldDescriptor.TYPE_DOUBLE):
426fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeFloat()
427fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
428fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeBool()
429fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
430fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeString()
431fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
432fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    value = tokenizer.ConsumeByteString()
433fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
434a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    value = tokenizer.ConsumeEnum(field)
435fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  else:
436fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    raise RuntimeError('Unknown field type %d' % field.type)
437fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
438fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
439fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if field.is_extension:
440fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      message.Extensions[field].append(value)
441fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
442fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      getattr(message, field.name).append(value)
443fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  else:
444fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if field.is_extension:
445a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      if not allow_multiple_scalars and message.HasExtension(field):
446a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        raise tokenizer.ParseErrorPreviousToken(
447a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson            'Message type "%s" should not have multiple "%s" extensions.' %
448a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson            (message.DESCRIPTOR.full_name, field.full_name))
449a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      else:
450a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        message.Extensions[field] = value
451fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
452a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      if not allow_multiple_scalars and message.HasField(field.name):
453a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        raise tokenizer.ParseErrorPreviousToken(
454a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson            'Message type "%s" should not have multiple "%s" fields.' %
455a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson            (message.DESCRIPTOR.full_name, field.name))
456a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      else:
457a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        setattr(message, field.name, value)
458fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
459fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
460fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass _Tokenizer(object):
461fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """Protocol buffer ASCII representation tokenizer.
462fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
463fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  This class handles the lower level string parsing by splitting it into
464fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  meaningful tokens.
465fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
466fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  It was directly ported from the Java protocol buffer API.
467fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  """
468fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
469fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
470fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  _TOKEN = re.compile(
471fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      '[a-zA-Z_][0-9a-zA-Z_+-]*|'           # an identifier
472fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      '[0-9+-][0-9a-zA-Z_.+-]*|'            # a number
473fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      '\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|'  # a double-quoted string
474d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      '\'([^\'\n\\\\]|\\\\.)*(\'|\\\\?$)')  # a single-quoted string
475a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  _IDENTIFIER = re.compile(r'\w+')
476fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
477a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def __init__(self, lines):
478fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._position = 0
479fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._line = -1
480fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._column = 0
481fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._token_start = None
482fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.token = ''
483a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self._lines = iter(lines)
484fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._current_line = ''
485fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._previous_line = 0
486fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._previous_column = 0
487a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self._more_lines = True
488fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._SkipWhitespace()
489fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
490fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
491fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def AtEnd(self):
492fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Checks the end of the text was reached.
493fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
494fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
495fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      True iff the end was reached.
496fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
497a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return not self.token
498fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
499fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def _PopLine(self):
500a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    while len(self._current_line) <= self._column:
501a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      try:
502a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        self._current_line = self._lines.next()
503a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      except StopIteration:
504fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        self._current_line = ''
505a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        self._more_lines = False
506fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        return
507a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      else:
508a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        self._line += 1
509a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        self._column = 0
510fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
511fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def _SkipWhitespace(self):
512fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    while True:
513fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      self._PopLine()
514a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      match = self._WHITESPACE.match(self._current_line, self._column)
515fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      if not match:
516fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        break
517fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      length = len(match.group(0))
518fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      self._column += length
519fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
520fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def TryConsume(self, token):
521fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Tries to consume a given piece of text.
522fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
523fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Args:
524fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      token: Text to consume.
525fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
526fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
527fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      True iff the text was consumed.
528fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
529fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if self.token == token:
530fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      self.NextToken()
531fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      return True
532fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return False
533fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
534fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def Consume(self, token):
535fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes a piece of text.
536fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
537fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Args:
538fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      token: Text to consume.
539fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
540fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
541fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If the text couldn't be consumed.
542fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
543fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if not self.TryConsume(token):
544fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise self._ParseError('Expected "%s".' % token)
545fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
546fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeIdentifier(self):
547fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes protocol message field identifier.
548fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
549fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
550fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      Identifier string.
551fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
552fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
553fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If an identifier couldn't be consumed.
554fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
555fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    result = self.token
556a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if not self._IDENTIFIER.match(result):
557fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise self._ParseError('Expected identifier.')
558fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
559fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
560fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
561fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeInt32(self):
562fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes a signed 32bit integer number.
563fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
564fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
565fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The integer parsed.
566fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
567fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
568fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If a signed 32bit integer couldn't be consumed.
569fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
570fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    try:
571a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseInteger(self.token, is_signed=True, is_long=False)
572fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    except ValueError, e:
573a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
574fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
575fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
576fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
577fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeUint32(self):
578fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes an unsigned 32bit integer number.
579fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
580fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
581fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The integer parsed.
582fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
583fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
584fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If an unsigned 32bit integer couldn't be consumed.
585fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
586fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    try:
587a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseInteger(self.token, is_signed=False, is_long=False)
588fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    except ValueError, e:
589a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
590fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
591fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
592fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
593fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeInt64(self):
594fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes a signed 64bit integer number.
595fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
596fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
597fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The integer parsed.
598fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
599fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
600fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If a signed 64bit integer couldn't be consumed.
601fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
602fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    try:
603a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseInteger(self.token, is_signed=True, is_long=True)
604fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    except ValueError, e:
605a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
606fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
607fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
608fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
609fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeUint64(self):
610fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes an unsigned 64bit integer number.
611fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
612fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
613fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The integer parsed.
614fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
615fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
616fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If an unsigned 64bit integer couldn't be consumed.
617fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
618fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    try:
619a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseInteger(self.token, is_signed=False, is_long=True)
620fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    except ValueError, e:
621a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
622fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
623fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
624fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
625fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeFloat(self):
626fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes an floating point number.
627fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
628fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
629fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The number parsed.
630fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
631fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
632fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If a floating point number couldn't be consumed.
633fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
634fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    try:
635a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseFloat(self.token)
636fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    except ValueError, e:
637a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
638fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
639fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
640fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
641fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeBool(self):
642fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes a boolean value.
643fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
644fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
645fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The bool parsed.
646fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
647fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
648fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If a boolean value couldn't be consumed.
649fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
650a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    try:
651a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseBool(self.token)
652a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    except ValueError, e:
653a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
654a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self.NextToken()
655a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return result
656fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
657fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeString(self):
658fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes a string value.
659fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
660fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
661fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The string parsed.
662fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
663fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
664fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If a string value couldn't be consumed.
665fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
666a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    the_bytes = self.ConsumeByteString()
667a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    try:
668a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      return unicode(the_bytes, 'utf-8')
669a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    except UnicodeDecodeError, e:
670a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._StringParseError(e)
671fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
672fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ConsumeByteString(self):
673fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Consumes a byte array value.
674fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
675fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
676fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      The array parsed (as a string).
677fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
678fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Raises:
679fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      ParseError: If a byte array value couldn't be consumed.
680fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
681a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    the_list = [self._ConsumeSingleByteString()]
682a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    while self.token and self.token[0] in ('\'', '"'):
683a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      the_list.append(self._ConsumeSingleByteString())
684a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return ''.encode('latin1').join(the_list)  ##PY25
685a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson##!PY25    return b''.join(the_list)
686d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
687d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  def _ConsumeSingleByteString(self):
688d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    """Consume one token of a string literal.
689d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville
690d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    String literals (whether bytes or text) can come in multiple adjacent
691d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    tokens which are automatically concatenated, like in C or Python.  This
692d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    method only consumes one token.
693d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    """
694fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    text = self.token
695fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if len(text) < 1 or text[0] not in ('\'', '"'):
696a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError('Expected string.')
697fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
698fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if len(text) < 2 or text[-1] != text[0]:
699fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise self._ParseError('String missing ending quote.')
700fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
701fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    try:
702a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = text_encoding.CUnescape(text[1:-1])
703fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    except ValueError, e:
704fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      raise self._ParseError(str(e))
705fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self.NextToken()
706fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
707fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
708a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def ConsumeEnum(self, field):
709a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    try:
710a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = ParseEnum(field, self.token)
711a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    except ValueError, e:
712a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise self._ParseError(str(e))
713a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self.NextToken()
714fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return result
715fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
716fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def ParseErrorPreviousToken(self, message):
717fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Creates and *returns* a ParseError for the previously read token.
718fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
719fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Args:
720fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      message: A message to set for the exception.
721fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
722fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Returns:
723fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      A ParseError instance.
724fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """
725fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return ParseError('%d:%d : %s' % (
726fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        self._previous_line + 1, self._previous_column + 1, message))
727fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
728fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def _ParseError(self, message):
729fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Creates and *returns* a ParseError for the current token."""
730fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return ParseError('%d:%d : %s' % (
731fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville        self._line + 1, self._column + 1, message))
732fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
733a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def _StringParseError(self, e):
734a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return self._ParseError('Couldn\'t parse string: ' + str(e))
735fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
736fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  def NextToken(self):
737fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    """Reads the next meaningful token."""
738fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._previous_line = self._line
739fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._previous_column = self._column
740a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
741fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    self._column += len(self.token)
742a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self._SkipWhitespace()
743fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
744a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if not self._more_lines:
745a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      self.token = ''
746a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      return
747fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
748a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    match = self._TOKEN.match(self._current_line, self._column)
749fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    if match:
750fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      token = match.group(0)
751fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville      self.token = token
752fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    else:
753a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      self.token = self._current_line[self._column]
754a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
755a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
756a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef ParseInteger(text, is_signed=False, is_long=False):
757a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parses an integer.
758a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
759a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
760a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    text: The text to parse.
761a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    is_signed: True if a signed integer must be parsed.
762a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    is_long: True if a long integer must be parsed.
763a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
764a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
765a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The integer value.
766a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
767a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
768a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ValueError: Thrown Iff the text is not a valid integer.
769a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
770a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  # Do the actual parsing. Exception handling is propagated to caller.
771a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  try:
772a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # We force 32-bit values to int and 64-bit values to long to make
773a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # alternate implementations where the distinction is more significant
774a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # (e.g. the C++ implementation) simpler.
775a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if is_long:
776a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = long(text, 0)
777a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    else:
778a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      result = int(text, 0)
779a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  except ValueError:
780a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    raise ValueError('Couldn\'t parse integer: %s' % text)
781a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
782a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  # Check if the integer is sane. Exceptions handled by callers.
783a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
784a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  checker.CheckValue(result)
785a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  return result
786a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
787a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
788a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef ParseFloat(text):
789a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parse a floating point number.
790a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
791a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
792a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    text: Text to parse.
793fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
794a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
795a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The number parsed.
796fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
797a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
798a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ValueError: If a floating point number couldn't be parsed.
799a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
800a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  try:
801a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # Assume Python compatible syntax.
802a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return float(text)
803a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  except ValueError:
804a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # Check alternative spellings.
805a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if _FLOAT_INFINITY.match(text):
806a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      if text[0] == '-':
807a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        return float('-inf')
808a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      else:
809a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        return float('inf')
810a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    elif _FLOAT_NAN.match(text):
811a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      return float('nan')
812a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    else:
813a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      # assume '1.0f' format
814a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      try:
815a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        return float(text.rstrip('f'))
816a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      except ValueError:
817a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        raise ValueError('Couldn\'t parse float: %s' % text)
818a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
819a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
820a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef ParseBool(text):
821a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parse a boolean value.
822a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
823a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
824a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    text: Text to parse.
825a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
826a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
827a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Boolean values parsed
828fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
829a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
830a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ValueError: If text is not a valid boolean.
831a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
832a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  if text in ('true', 't', '1'):
833a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return True
834a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  elif text in ('false', 'f', '0'):
835a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return False
836a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  else:
837a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    raise ValueError('Expected "true" or "false".')
838fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
839fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
840a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef ParseEnum(field, value):
841a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Parse an enum value.
842fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
843a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  The value can be specified by a number (the enum value), or by
844a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  a string literal (the enum name).
845fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
846a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
847a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    field: Enum field descriptor.
848a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    value: String value.
849fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
850a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Returns:
851a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Enum value number.
852a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
853a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Raises:
854a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    ValueError: If the enum value could not be parsed.
855a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
856a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  enum_descriptor = field.enum_type
857a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  try:
858a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    number = int(value, 0)
859a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  except ValueError:
860a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # Identifier.
861a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    enum_value = enum_descriptor.values_by_name.get(value, None)
862a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if enum_value is None:
863a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise ValueError(
864a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson          'Enum type "%s" has no value named %s.' % (
865a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson              enum_descriptor.full_name, value))
866a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  else:
867a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    # Numeric value.
868a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    enum_value = enum_descriptor.values_by_number.get(number, None)
869a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if enum_value is None:
870a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise ValueError(
871a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson          'Enum type "%s" has no value with number %d.' % (
872a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson              enum_descriptor.full_name, number))
873a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  return enum_value.number
874