~ubuntu-branches/ubuntu/trusty/protobuf/trusty-proposed

« back to all changes in this revision

Viewing changes to python/google/protobuf/text_format.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2011-05-31 14:41:47 UTC
  • mfrom: (2.2.8 sid)
  • Revision ID: james.westby@ubuntu.com-20110531144147-s41g5fozgvyo462l
Tags: 2.4.0a-2ubuntu1
* Merge with Debian; remaining changes:
  - Fix linking with -lpthread.

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
  """Thrown in case of ASCII parsing error."""
54
54
 
55
55
 
56
 
def MessageToString(message):
 
56
def MessageToString(message, as_utf8=False, as_one_line=False):
57
57
  out = cStringIO.StringIO()
58
 
  PrintMessage(message, out)
 
58
  PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line)
59
59
  result = out.getvalue()
60
60
  out.close()
 
61
  if as_one_line:
 
62
    return result.rstrip()
61
63
  return result
62
64
 
63
65
 
64
 
def PrintMessage(message, out, indent = 0):
 
66
def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False):
65
67
  for field, value in message.ListFields():
66
68
    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
67
69
      for element in value:
68
 
        PrintField(field, element, out, indent)
 
70
        PrintField(field, element, out, indent, as_utf8, as_one_line)
69
71
    else:
70
 
      PrintField(field, value, out, indent)
71
 
 
72
 
 
73
 
def PrintField(field, value, out, indent = 0):
 
72
      PrintField(field, value, out, indent, as_utf8, as_one_line)
 
73
 
 
74
 
 
75
def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False):
74
76
  """Print a single field name/value pair.  For repeated fields, the value
75
77
  should be a single element."""
76
78
 
96
98
    # don't include it.
97
99
    out.write(': ')
98
100
 
99
 
  PrintFieldValue(field, value, out, indent)
100
 
  out.write('\n')
101
 
 
102
 
 
103
 
def PrintFieldValue(field, value, out, indent = 0):
 
101
  PrintFieldValue(field, value, out, indent, as_utf8, as_one_line)
 
102
  if as_one_line:
 
103
    out.write(' ')
 
104
  else:
 
105
    out.write('\n')
 
106
 
 
107
 
 
108
def PrintFieldValue(field, value, out, indent=0,
 
109
                    as_utf8=False, as_one_line=False):
104
110
  """Print a single field value (not including name).  For repeated fields,
105
111
  the value should be a single element."""
106
112
 
107
113
  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
108
 
    out.write(' {\n')
109
 
    PrintMessage(value, out, indent + 2)
110
 
    out.write(' ' * indent + '}')
 
114
    if as_one_line:
 
115
      out.write(' { ')
 
116
      PrintMessage(value, out, indent, as_utf8, as_one_line)
 
117
      out.write('}')
 
118
    else:
 
119
      out.write(' {\n')
 
120
      PrintMessage(value, out, indent + 2, as_utf8, as_one_line)
 
121
      out.write(' ' * indent + '}')
111
122
  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
112
123
    out.write(field.enum_type.values_by_number[value].name)
113
124
  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
114
125
    out.write('\"')
115
 
    out.write(_CEscape(value))
 
126
    if type(value) is unicode:
 
127
      out.write(_CEscape(value.encode('utf-8'), as_utf8))
 
128
    else:
 
129
      out.write(_CEscape(value, as_utf8))
116
130
    out.write('\"')
117
131
  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
118
132
    if value:
208
222
        sub_message = message.Extensions[field]
209
223
      else:
210
224
        sub_message = getattr(message, field.name)
211
 
        sub_message.SetInParent()
 
225
      sub_message.SetInParent()
212
226
 
213
227
    while not tokenizer.TryConsume(end_token):
214
228
      if tokenizer.AtEnd():
334
348
    Returns:
335
349
      True iff the end was reached.
336
350
    """
337
 
    return not self._lines and not self._current_line
 
351
    return self.token == ''
338
352
 
339
353
  def _PopLine(self):
340
 
    while not self._current_line:
 
354
    while len(self._current_line) <= self._column:
341
355
      if not self._lines:
342
356
        self._current_line = ''
343
357
        return
348
362
  def _SkipWhitespace(self):
349
363
    while True:
350
364
      self._PopLine()
351
 
      match = re.match(self._WHITESPACE, self._current_line)
 
365
      match = self._WHITESPACE.match(self._current_line, self._column)
352
366
      if not match:
353
367
        break
354
368
      length = len(match.group(0))
355
 
      self._current_line = self._current_line[length:]
356
369
      self._column += length
357
370
 
358
371
  def TryConsume(self, token):
402
415
      ParseError: If an identifier couldn't be consumed.
403
416
    """
404
417
    result = self.token
405
 
    if not re.match(self._IDENTIFIER, result):
 
418
    if not self._IDENTIFIER.match(result):
406
419
      raise self._ParseError('Expected identifier.')
407
420
    self.NextToken()
408
421
    return result
481
494
      ParseError: If a floating point number couldn't be consumed.
482
495
    """
483
496
    text = self.token
484
 
    if re.match(self._FLOAT_INFINITY, text):
 
497
    if self._FLOAT_INFINITY.match(text):
485
498
      self.NextToken()
486
499
      if text.startswith('-'):
487
500
        return -_INFINITY
488
501
      return _INFINITY
489
502
 
490
 
    if re.match(self._FLOAT_NAN, text):
 
503
    if self._FLOAT_NAN.match(text):
491
504
      self.NextToken()
492
505
      return _NAN
493
506
 
507
520
    Raises:
508
521
      ParseError: If a boolean value couldn't be consumed.
509
522
    """
510
 
    if self.token == 'true':
 
523
    if self.token in ('true', 't', '1'):
511
524
      self.NextToken()
512
525
      return True
513
 
    elif self.token == 'false':
 
526
    elif self.token in ('false', 'f', '0'):
514
527
      self.NextToken()
515
528
      return False
516
529
    else:
525
538
    Raises:
526
539
      ParseError: If a string value couldn't be consumed.
527
540
    """
528
 
    return unicode(self.ConsumeByteString(), 'utf-8')
 
541
    bytes = self.ConsumeByteString()
 
542
    try:
 
543
      return unicode(bytes, 'utf-8')
 
544
    except UnicodeDecodeError, e:
 
545
      raise self._StringParseError(e)
529
546
 
530
547
  def ConsumeByteString(self):
531
548
    """Consumes a byte array value.
609
626
  def _ParseError(self, message):
610
627
    """Creates and *returns* a ParseError for the current token."""
611
628
    return ParseError('%d:%d : %s' % (
612
 
        self._line + 1, self._column + 1, message))
 
629
        self._line + 1, self._column - len(self.token) + 1, message))
613
630
 
614
631
  def _IntegerParseError(self, e):
615
632
    return self._ParseError('Couldn\'t parse integer: ' + str(e))
617
634
  def _FloatParseError(self, e):
618
635
    return self._ParseError('Couldn\'t parse number: ' + str(e))
619
636
 
 
637
  def _StringParseError(self, e):
 
638
    return self._ParseError('Couldn\'t parse string: ' + str(e))
 
639
 
620
640
  def NextToken(self):
621
641
    """Reads the next meaningful token."""
622
642
    self._previous_line = self._line
623
643
    self._previous_column = self._column
624
 
    if self.AtEnd():
 
644
 
 
645
    self._column += len(self.token)
 
646
    self._SkipWhitespace()
 
647
 
 
648
    if not self._lines and len(self._current_line) <= self._column:
625
649
      self.token = ''
626
650
      return
627
 
    self._column += len(self.token)
628
 
 
629
 
    # Make sure there is data to work on.
630
 
    self._PopLine()
631
 
 
632
 
    match = re.match(self._TOKEN, self._current_line)
 
651
 
 
652
    match = self._TOKEN.match(self._current_line, self._column)
633
653
    if match:
634
654
      token = match.group(0)
635
 
      self._current_line = self._current_line[len(token):]
636
655
      self.token = token
637
656
    else:
638
 
      self.token = self._current_line[0]
639
 
      self._current_line = self._current_line[1:]
640
 
    self._SkipWhitespace()
 
657
      self.token = self._current_line[self._column]
641
658
 
642
659
 
643
660
# text.encode('string_escape') does not seem to satisfy our needs as it
645
662
# C++ unescaping function allows hex escapes to be any length.  So,
646
663
# "\0011".encode('string_escape') ends up being "\\x011", which will be
647
664
# decoded in C++ as a single-character string with char code 0x11.
648
 
def _CEscape(text):
 
665
def _CEscape(text, as_utf8):
649
666
  def escape(c):
650
667
    o = ord(c)
651
668
    if o == 10: return r"\n"   # optional escape
656
673
    if o == 34: return r'\"'   # necessary escape
657
674
    if o == 92: return r"\\"   # necessary escape
658
675
 
659
 
    if o >= 127 or o < 32: return "\\%03o" % o # necessary escapes
 
676
    # necessary escapes
 
677
    if not as_utf8 and (o >= 127 or o < 32): return "\\%03o" % o
660
678
    return c
661
679
  return "".join([escape(c) for c in text])
662
680
 
663
681
 
664
 
_CUNESCAPE_HEX = re.compile('\\\\x([0-9a-fA-F]{2}|[0-9a-f-A-F])')
 
682
_CUNESCAPE_HEX = re.compile('\\\\x([0-9a-fA-F]{2}|[0-9a-fA-F])')
665
683
 
666
684
 
667
685
def _CUnescape(text):