- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / python / google / protobuf / text_format.py
1 # Protocol Buffers - Google's data interchange format
2 # Copyright 2008 Google Inc.  All rights reserved.
3 # http://code.google.com/p/protobuf/
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 """Contains routines for printing protocol messages in text format."""
32
33 __author__ = 'kenton@google.com (Kenton Varda)'
34
35 import cStringIO
36 import re
37
38 from collections import deque
39 from google.protobuf.internal import type_checkers
40 from google.protobuf import descriptor
41
42 __all__ = [ 'MessageToString', 'PrintMessage', 'PrintField',
43             'PrintFieldValue', 'Merge' ]
44
45
46 _INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),
47                      type_checkers.Int32ValueChecker(),
48                      type_checkers.Uint64ValueChecker(),
49                      type_checkers.Int64ValueChecker())
50 _FLOAT_INFINITY = re.compile('-?inf(?:inity)?f?', re.IGNORECASE)
51 _FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)
52
53
54 class ParseError(Exception):
55   """Thrown in case of ASCII parsing error."""
56
57
58 def MessageToString(message, as_utf8=False, as_one_line=False):
59   out = cStringIO.StringIO()
60   PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line)
61   result = out.getvalue()
62   out.close()
63   if as_one_line:
64     return result.rstrip()
65   return result
66
67
68 def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False):
69   for field, value in message.ListFields():
70     if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
71       for element in value:
72         PrintField(field, element, out, indent, as_utf8, as_one_line)
73     else:
74       PrintField(field, value, out, indent, as_utf8, as_one_line)
75
76
77 def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False):
78   """Print a single field name/value pair.  For repeated fields, the value
79   should be a single element."""
80
81   out.write(' ' * indent);
82   if field.is_extension:
83     out.write('[')
84     if (field.containing_type.GetOptions().message_set_wire_format and
85         field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
86         field.message_type == field.extension_scope and
87         field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
88       out.write(field.message_type.full_name)
89     else:
90       out.write(field.full_name)
91     out.write(']')
92   elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
93     # For groups, use the capitalized name.
94     out.write(field.message_type.name)
95   else:
96     out.write(field.name)
97
98   if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
99     # The colon is optional in this case, but our cross-language golden files
100     # don't include it.
101     out.write(': ')
102
103   PrintFieldValue(field, value, out, indent, as_utf8, as_one_line)
104   if as_one_line:
105     out.write(' ')
106   else:
107     out.write('\n')
108
109
110 def PrintFieldValue(field, value, out, indent=0,
111                     as_utf8=False, as_one_line=False):
112   """Print a single field value (not including name).  For repeated fields,
113   the value should be a single element."""
114
115   if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
116     if as_one_line:
117       out.write(' { ')
118       PrintMessage(value, out, indent, as_utf8, as_one_line)
119       out.write('}')
120     else:
121       out.write(' {\n')
122       PrintMessage(value, out, indent + 2, as_utf8, as_one_line)
123       out.write(' ' * indent + '}')
124   elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
125     enum_value = field.enum_type.values_by_number.get(value, None)
126     if enum_value is not None:
127       out.write(enum_value.name)
128     else:
129       out.write(str(value))
130   elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
131     out.write('\"')
132     if type(value) is unicode:
133       out.write(_CEscape(value.encode('utf-8'), as_utf8))
134     else:
135       out.write(_CEscape(value, as_utf8))
136     out.write('\"')
137   elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
138     if value:
139       out.write("true")
140     else:
141       out.write("false")
142   else:
143     out.write(str(value))
144
145
146 def Merge(text, message):
147   """Merges an ASCII representation of a protocol message into a message.
148
149   Args:
150     text: Message ASCII representation.
151     message: A protocol buffer message to merge into.
152
153   Raises:
154     ParseError: On ASCII parsing problems.
155   """
156   tokenizer = _Tokenizer(text)
157   while not tokenizer.AtEnd():
158     _MergeField(tokenizer, message)
159
160
161 def _MergeField(tokenizer, message):
162   """Merges a single protocol message field into a message.
163
164   Args:
165     tokenizer: A tokenizer to parse the field name and values.
166     message: A protocol message to record the data.
167
168   Raises:
169     ParseError: In case of ASCII parsing problems.
170   """
171   message_descriptor = message.DESCRIPTOR
172   if tokenizer.TryConsume('['):
173     name = [tokenizer.ConsumeIdentifier()]
174     while tokenizer.TryConsume('.'):
175       name.append(tokenizer.ConsumeIdentifier())
176     name = '.'.join(name)
177
178     if not message_descriptor.is_extendable:
179       raise tokenizer.ParseErrorPreviousToken(
180           'Message type "%s" does not have extensions.' %
181           message_descriptor.full_name)
182     field = message.Extensions._FindExtensionByName(name)
183     if not field:
184       raise tokenizer.ParseErrorPreviousToken(
185           'Extension "%s" not registered.' % name)
186     elif message_descriptor != field.containing_type:
187       raise tokenizer.ParseErrorPreviousToken(
188           'Extension "%s" does not extend message type "%s".' % (
189               name, message_descriptor.full_name))
190     tokenizer.Consume(']')
191   else:
192     name = tokenizer.ConsumeIdentifier()
193     field = message_descriptor.fields_by_name.get(name, None)
194
195     # Group names are expected to be capitalized as they appear in the
196     # .proto file, which actually matches their type names, not their field
197     # names.
198     if not field:
199       field = message_descriptor.fields_by_name.get(name.lower(), None)
200       if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:
201         field = None
202
203     if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and
204         field.message_type.name != name):
205       field = None
206
207     if not field:
208       raise tokenizer.ParseErrorPreviousToken(
209           'Message type "%s" has no field named "%s".' % (
210               message_descriptor.full_name, name))
211
212   if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
213     tokenizer.TryConsume(':')
214
215     if tokenizer.TryConsume('<'):
216       end_token = '>'
217     else:
218       tokenizer.Consume('{')
219       end_token = '}'
220
221     if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
222       if field.is_extension:
223         sub_message = message.Extensions[field].add()
224       else:
225         sub_message = getattr(message, field.name).add()
226     else:
227       if field.is_extension:
228         sub_message = message.Extensions[field]
229       else:
230         sub_message = getattr(message, field.name)
231       sub_message.SetInParent()
232
233     while not tokenizer.TryConsume(end_token):
234       if tokenizer.AtEnd():
235         raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
236       _MergeField(tokenizer, sub_message)
237   else:
238     _MergeScalarField(tokenizer, message, field)
239
240
241 def _MergeScalarField(tokenizer, message, field):
242   """Merges a single protocol message scalar field into a message.
243
244   Args:
245     tokenizer: A tokenizer to parse the field value.
246     message: A protocol message to record the data.
247     field: The descriptor of the field to be merged.
248
249   Raises:
250     ParseError: In case of ASCII parsing problems.
251     RuntimeError: On runtime errors.
252   """
253   tokenizer.Consume(':')
254   value = None
255
256   if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
257                     descriptor.FieldDescriptor.TYPE_SINT32,
258                     descriptor.FieldDescriptor.TYPE_SFIXED32):
259     value = tokenizer.ConsumeInt32()
260   elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
261                       descriptor.FieldDescriptor.TYPE_SINT64,
262                       descriptor.FieldDescriptor.TYPE_SFIXED64):
263     value = tokenizer.ConsumeInt64()
264   elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
265                       descriptor.FieldDescriptor.TYPE_FIXED32):
266     value = tokenizer.ConsumeUint32()
267   elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
268                       descriptor.FieldDescriptor.TYPE_FIXED64):
269     value = tokenizer.ConsumeUint64()
270   elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
271                       descriptor.FieldDescriptor.TYPE_DOUBLE):
272     value = tokenizer.ConsumeFloat()
273   elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:
274     value = tokenizer.ConsumeBool()
275   elif field.type == descriptor.FieldDescriptor.TYPE_STRING:
276     value = tokenizer.ConsumeString()
277   elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:
278     value = tokenizer.ConsumeByteString()
279   elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:
280     value = tokenizer.ConsumeEnum(field)
281   else:
282     raise RuntimeError('Unknown field type %d' % field.type)
283
284   if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
285     if field.is_extension:
286       message.Extensions[field].append(value)
287     else:
288       getattr(message, field.name).append(value)
289   else:
290     if field.is_extension:
291       message.Extensions[field] = value
292     else:
293       setattr(message, field.name, value)
294
295
296 class _Tokenizer(object):
297   """Protocol buffer ASCII representation tokenizer.
298
299   This class handles the lower level string parsing by splitting it into
300   meaningful tokens.
301
302   It was directly ported from the Java protocol buffer API.
303   """
304
305   _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
306   _TOKEN = re.compile(
307       '[a-zA-Z_][0-9a-zA-Z_+-]*|'           # an identifier
308       '[0-9+-][0-9a-zA-Z_.+-]*|'            # a number
309       '\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|'  # a double-quoted string
310       '\'([^\'\n\\\\]|\\\\.)*(\'|\\\\?$)')  # a single-quoted string
311   _IDENTIFIER = re.compile('\w+')
312
313   def __init__(self, text_message):
314     self._text_message = text_message
315
316     self._position = 0
317     self._line = -1
318     self._column = 0
319     self._token_start = None
320     self.token = ''
321     self._lines = deque(text_message.split('\n'))
322     self._current_line = ''
323     self._previous_line = 0
324     self._previous_column = 0
325     self._SkipWhitespace()
326     self.NextToken()
327
328   def AtEnd(self):
329     """Checks the end of the text was reached.
330
331     Returns:
332       True iff the end was reached.
333     """
334     return self.token == ''
335
336   def _PopLine(self):
337     while len(self._current_line) <= self._column:
338       if not self._lines:
339         self._current_line = ''
340         return
341       self._line += 1
342       self._column = 0
343       self._current_line = self._lines.popleft()
344
345   def _SkipWhitespace(self):
346     while True:
347       self._PopLine()
348       match = self._WHITESPACE.match(self._current_line, self._column)
349       if not match:
350         break
351       length = len(match.group(0))
352       self._column += length
353
354   def TryConsume(self, token):
355     """Tries to consume a given piece of text.
356
357     Args:
358       token: Text to consume.
359
360     Returns:
361       True iff the text was consumed.
362     """
363     if self.token == token:
364       self.NextToken()
365       return True
366     return False
367
368   def Consume(self, token):
369     """Consumes a piece of text.
370
371     Args:
372       token: Text to consume.
373
374     Raises:
375       ParseError: If the text couldn't be consumed.
376     """
377     if not self.TryConsume(token):
378       raise self._ParseError('Expected "%s".' % token)
379
380   def ConsumeIdentifier(self):
381     """Consumes protocol message field identifier.
382
383     Returns:
384       Identifier string.
385
386     Raises:
387       ParseError: If an identifier couldn't be consumed.
388     """
389     result = self.token
390     if not self._IDENTIFIER.match(result):
391       raise self._ParseError('Expected identifier.')
392     self.NextToken()
393     return result
394
395   def ConsumeInt32(self):
396     """Consumes a signed 32bit integer number.
397
398     Returns:
399       The integer parsed.
400
401     Raises:
402       ParseError: If a signed 32bit integer couldn't be consumed.
403     """
404     try:
405       result = ParseInteger(self.token, is_signed=True, is_long=False)
406     except ValueError, e:
407       raise self._ParseError(str(e))
408     self.NextToken()
409     return result
410
411   def ConsumeUint32(self):
412     """Consumes an unsigned 32bit integer number.
413
414     Returns:
415       The integer parsed.
416
417     Raises:
418       ParseError: If an unsigned 32bit integer couldn't be consumed.
419     """
420     try:
421       result = ParseInteger(self.token, is_signed=False, is_long=False)
422     except ValueError, e:
423       raise self._ParseError(str(e))
424     self.NextToken()
425     return result
426
427   def ConsumeInt64(self):
428     """Consumes a signed 64bit integer number.
429
430     Returns:
431       The integer parsed.
432
433     Raises:
434       ParseError: If a signed 64bit integer couldn't be consumed.
435     """
436     try:
437       result = ParseInteger(self.token, is_signed=True, is_long=True)
438     except ValueError, e:
439       raise self._ParseError(str(e))
440     self.NextToken()
441     return result
442
443   def ConsumeUint64(self):
444     """Consumes an unsigned 64bit integer number.
445
446     Returns:
447       The integer parsed.
448
449     Raises:
450       ParseError: If an unsigned 64bit integer couldn't be consumed.
451     """
452     try:
453       result = ParseInteger(self.token, is_signed=False, is_long=True)
454     except ValueError, e:
455       raise self._ParseError(str(e))
456     self.NextToken()
457     return result
458
459   def ConsumeFloat(self):
460     """Consumes an floating point number.
461
462     Returns:
463       The number parsed.
464
465     Raises:
466       ParseError: If a floating point number couldn't be consumed.
467     """
468     try:
469       result = ParseFloat(self.token)
470     except ValueError, e:
471       raise self._ParseError(str(e))
472     self.NextToken()
473     return result
474
475   def ConsumeBool(self):
476     """Consumes a boolean value.
477
478     Returns:
479       The bool parsed.
480
481     Raises:
482       ParseError: If a boolean value couldn't be consumed.
483     """
484     try:
485       result = ParseBool(self.token)
486     except ValueError, e:
487       raise self._ParseError(str(e))
488     self.NextToken()
489     return result
490
491   def ConsumeString(self):
492     """Consumes a string value.
493
494     Returns:
495       The string parsed.
496
497     Raises:
498       ParseError: If a string value couldn't be consumed.
499     """
500     bytes = self.ConsumeByteString()
501     try:
502       return unicode(bytes, 'utf-8')
503     except UnicodeDecodeError, e:
504       raise self._StringParseError(e)
505
506   def ConsumeByteString(self):
507     """Consumes a byte array value.
508
509     Returns:
510       The array parsed (as a string).
511
512     Raises:
513       ParseError: If a byte array value couldn't be consumed.
514     """
515     list = [self._ConsumeSingleByteString()]
516     while len(self.token) > 0 and self.token[0] in ('\'', '"'):
517       list.append(self._ConsumeSingleByteString())
518     return "".join(list)
519
520   def _ConsumeSingleByteString(self):
521     """Consume one token of a string literal.
522
523     String literals (whether bytes or text) can come in multiple adjacent
524     tokens which are automatically concatenated, like in C or Python.  This
525     method only consumes one token.
526     """
527     text = self.token
528     if len(text) < 1 or text[0] not in ('\'', '"'):
529       raise self._ParseError('Expected string.')
530
531     if len(text) < 2 or text[-1] != text[0]:
532       raise self._ParseError('String missing ending quote.')
533
534     try:
535       result = _CUnescape(text[1:-1])
536     except ValueError, e:
537       raise self._ParseError(str(e))
538     self.NextToken()
539     return result
540
541   def ConsumeEnum(self, field):
542     try:
543       result = ParseEnum(field, self.token)
544     except ValueError, e:
545       raise self._ParseError(str(e))
546     self.NextToken()
547     return result
548
549   def ParseErrorPreviousToken(self, message):
550     """Creates and *returns* a ParseError for the previously read token.
551
552     Args:
553       message: A message to set for the exception.
554
555     Returns:
556       A ParseError instance.
557     """
558     return ParseError('%d:%d : %s' % (
559         self._previous_line + 1, self._previous_column + 1, message))
560
561   def _ParseError(self, message):
562     """Creates and *returns* a ParseError for the current token."""
563     return ParseError('%d:%d : %s' % (
564         self._line + 1, self._column + 1, message))
565
566   def _StringParseError(self, e):
567     return self._ParseError('Couldn\'t parse string: ' + str(e))
568
569   def NextToken(self):
570     """Reads the next meaningful token."""
571     self._previous_line = self._line
572     self._previous_column = self._column
573
574     self._column += len(self.token)
575     self._SkipWhitespace()
576
577     if not self._lines and len(self._current_line) <= self._column:
578       self.token = ''
579       return
580
581     match = self._TOKEN.match(self._current_line, self._column)
582     if match:
583       token = match.group(0)
584       self.token = token
585     else:
586       self.token = self._current_line[self._column]
587
588
589 # text.encode('string_escape') does not seem to satisfy our needs as it
590 # encodes unprintable characters using two-digit hex escapes whereas our
591 # C++ unescaping function allows hex escapes to be any length.  So,
592 # "\0011".encode('string_escape') ends up being "\\x011", which will be
593 # decoded in C++ as a single-character string with char code 0x11.
594 def _CEscape(text, as_utf8):
595   def escape(c):
596     o = ord(c)
597     if o == 10: return r"\n"   # optional escape
598     if o == 13: return r"\r"   # optional escape
599     if o ==  9: return r"\t"   # optional escape
600     if o == 39: return r"\'"   # optional escape
601
602     if o == 34: return r'\"'   # necessary escape
603     if o == 92: return r"\\"   # necessary escape
604
605     # necessary escapes
606     if not as_utf8 and (o >= 127 or o < 32): return "\\%03o" % o
607     return c
608   return "".join([escape(c) for c in text])
609
610
611 _CUNESCAPE_HEX = re.compile('\\\\x([0-9a-fA-F]{2}|[0-9a-fA-F])')
612
613
614 def _CUnescape(text):
615   def ReplaceHex(m):
616     return chr(int(m.group(0)[2:], 16))
617   # This is required because the 'string_escape' encoding doesn't
618   # allow single-digit hex escapes (like '\xf').
619   result = _CUNESCAPE_HEX.sub(ReplaceHex, text)
620   return result.decode('string_escape')
621
622
623 def ParseInteger(text, is_signed=False, is_long=False):
624   """Parses an integer.
625
626   Args:
627     text: The text to parse.
628     is_signed: True if a signed integer must be parsed.
629     is_long: True if a long integer must be parsed.
630
631   Returns:
632     The integer value.
633
634   Raises:
635     ValueError: Thrown Iff the text is not a valid integer.
636   """
637   # Do the actual parsing. Exception handling is propagated to caller.
638   try:
639     result = int(text, 0)
640   except ValueError:
641     raise ValueError('Couldn\'t parse integer: %s' % text)
642
643   # Check if the integer is sane. Exceptions handled by callers.
644   checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
645   checker.CheckValue(result)
646   return result
647
648
649 def ParseFloat(text):
650   """Parse a floating point number.
651
652   Args:
653     text: Text to parse.
654
655   Returns:
656     The number parsed.
657
658   Raises:
659     ValueError: If a floating point number couldn't be parsed.
660   """
661   try:
662     # Assume Python compatible syntax.
663     return float(text)
664   except ValueError:
665     # Check alternative spellings.
666     if _FLOAT_INFINITY.match(text):
667       if text[0] == '-':
668         return float('-inf')
669       else:
670         return float('inf')
671     elif _FLOAT_NAN.match(text):
672       return float('nan')
673     else:
674       # assume '1.0f' format
675       try:
676         return float(text.rstrip('f'))
677       except ValueError:
678         raise ValueError('Couldn\'t parse float: %s' % text)
679
680
681 def ParseBool(text):
682   """Parse a boolean value.
683
684   Args:
685     text: Text to parse.
686
687   Returns:
688     Boolean values parsed
689
690   Raises:
691     ValueError: If text is not a valid boolean.
692   """
693   if text in ('true', 't', '1'):
694     return True
695   elif text in ('false', 'f', '0'):
696     return False
697   else:
698     raise ValueError('Expected "true" or "false".')
699
700
701 def ParseEnum(field, value):
702   """Parse an enum value.
703
704   The value can be specified by a number (the enum value), or by
705   a string literal (the enum name).
706
707   Args:
708     field: Enum field descriptor.
709     value: String value.
710
711   Returns:
712     Enum value number.
713
714   Raises:
715     ValueError: If the enum value could not be parsed.
716   """
717   enum_descriptor = field.enum_type
718   try:
719     number = int(value, 0)
720   except ValueError:
721     # Identifier.
722     enum_value = enum_descriptor.values_by_name.get(value, None)
723     if enum_value is None:
724       raise ValueError(
725           'Enum type "%s" has no value named %s.' % (
726               enum_descriptor.full_name, value))
727   else:
728     # Numeric value.
729     enum_value = enum_descriptor.values_by_number.get(number, None)
730     if enum_value is None:
731       raise ValueError(
732           'Enum type "%s" has no value with number %d.' % (
733               enum_descriptor.full_name, number))
734   return enum_value.number