text_format.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. """Contains routines for printing protocol messages in text format."""
  31. __author__ = 'kenton@google.com (Kenton Varda)'
  32. import cStringIO
  33. from froofle.protobuf import descriptor
  34. __all__ = [ 'MessageToString', 'PrintMessage', 'PrintField', 'PrintFieldValue' ]
  35. def MessageToString(message):
  36. out = cStringIO.StringIO()
  37. PrintMessage(message, out)
  38. result = out.getvalue()
  39. out.close()
  40. return result
  41. def PrintMessage(message, out, indent = 0):
  42. for field, value in message.ListFields():
  43. if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
  44. for element in value:
  45. PrintField(field, element, out, indent)
  46. else:
  47. PrintField(field, value, out, indent)
  48. def PrintField(field, value, out, indent = 0):
  49. """Print a single field name/value pair. For repeated fields, the value
  50. should be a single element."""
  51. out.write(' ' * indent);
  52. if field.is_extension:
  53. out.write('[')
  54. if (field.containing_type.GetOptions().message_set_wire_format and
  55. field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
  56. field.message_type == field.extension_scope and
  57. field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):
  58. out.write(field.message_type.full_name)
  59. else:
  60. out.write(field.full_name)
  61. out.write(']')
  62. elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:
  63. # For groups, use the capitalized name.
  64. out.write(field.message_type.name)
  65. else:
  66. out.write(field.name)
  67. if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
  68. # The colon is optional in this case, but our cross-language golden files
  69. # don't include it.
  70. out.write(': ')
  71. PrintFieldValue(field, value, out, indent)
  72. out.write('\n')
  73. def PrintFieldValue(field, value, out, indent = 0):
  74. """Print a single field value (not including name). For repeated fields,
  75. the value should be a single element."""
  76. if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
  77. out.write(' {\n')
  78. PrintMessage(value, out, indent + 2)
  79. out.write(' ' * indent + '}')
  80. elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
  81. out.write(field.enum_type.values_by_number[value].name)
  82. elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
  83. out.write('\"')
  84. out.write(_CEscape(value))
  85. out.write('\"')
  86. elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
  87. if value:
  88. out.write("true")
  89. else:
  90. out.write("false")
  91. else:
  92. out.write(str(value))
  93. # text.encode('string_escape') does not seem to satisfy our needs as it
  94. # encodes unprintable characters using two-digit hex escapes whereas our
  95. # C++ unescaping function allows hex escapes to be any length. So,
  96. # "\0011".encode('string_escape') ends up being "\\x011", which will be
  97. # decoded in C++ as a single-character string with char code 0x11.
  98. def _CEscape(text):
  99. def escape(c):
  100. o = ord(c)
  101. if o == 10: return r"\n" # optional escape
  102. if o == 13: return r"\r" # optional escape
  103. if o == 9: return r"\t" # optional escape
  104. if o == 39: return r"\'" # optional escape
  105. if o == 34: return r'\"' # necessary escape
  106. if o == 92: return r"\\" # necessary escape
  107. if o >= 127 or o < 32: return "\\%03o" % o # necessary escapes
  108. return c
  109. return "".join([escape(c) for c in text])