json_objectwriter.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
  31. #define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
  32. #include <memory>
  33. #include <string>
  34. #include <google/protobuf/io/coded_stream.h>
  35. #include <google/protobuf/util/internal/structured_objectwriter.h>
  36. #include <google/protobuf/stubs/bytestream.h>
  37. namespace google {
  38. namespace protobuf {
  39. namespace util {
  40. namespace converter {
  41. // An ObjectWriter implementation that outputs JSON. This ObjectWriter
  42. // supports writing a compact form or a pretty printed form.
  43. //
  44. // Sample usage:
  45. // string output;
  46. // StringOutputStream* str_stream = new StringOutputStream(&output);
  47. // CodedOutputStream* out_stream = new CodedOutputStream(str_stream);
  48. // JsonObjectWriter* ow = new JsonObjectWriter(" ", out_stream);
  49. // ow->StartObject("")
  50. // ->RenderString("name", "value")
  51. // ->RenderString("emptystring", string())
  52. // ->StartObject("nested")
  53. // ->RenderInt64("light", 299792458);
  54. // ->RenderDouble("pi", 3.141592653589793);
  55. // ->EndObject()
  56. // ->StartList("empty")
  57. // ->EndList()
  58. // ->EndObject();
  59. //
  60. // And then the output string would become:
  61. // {
  62. // "name": "value",
  63. // "emptystring": "",
  64. // "nested": {
  65. // "light": "299792458",
  66. // "pi": 3.141592653589793
  67. // },
  68. // "empty": []
  69. // }
  70. //
  71. // JsonObjectWriter does not validate if calls actually result in valid JSON.
  72. // For example, passing an empty name when one would be required won't result
  73. // in an error, just an invalid output.
  74. //
  75. // Note that all int64 and uint64 are rendered as strings instead of numbers.
  76. // This is because JavaScript parses numbers as 64-bit float thus int64 and
  77. // uint64 would lose precision if rendered as numbers.
  78. //
  79. // JsonObjectWriter is thread-unsafe.
  80. class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter {
  81. public:
  82. JsonObjectWriter(StringPiece indent_string,
  83. google::protobuf::io::CodedOutputStream* out)
  84. : element_(new Element(/*parent=*/nullptr, /*is_json_object=*/false)),
  85. stream_(out),
  86. sink_(out),
  87. indent_string_(indent_string.ToString()),
  88. use_websafe_base64_for_bytes_(false) {}
  89. virtual ~JsonObjectWriter();
  90. // ObjectWriter methods.
  91. virtual JsonObjectWriter* StartObject(StringPiece name);
  92. virtual JsonObjectWriter* EndObject();
  93. virtual JsonObjectWriter* StartList(StringPiece name);
  94. virtual JsonObjectWriter* EndList();
  95. virtual JsonObjectWriter* RenderBool(StringPiece name, bool value);
  96. virtual JsonObjectWriter* RenderInt32(StringPiece name, int32 value);
  97. virtual JsonObjectWriter* RenderUint32(StringPiece name, uint32 value);
  98. virtual JsonObjectWriter* RenderInt64(StringPiece name, int64 value);
  99. virtual JsonObjectWriter* RenderUint64(StringPiece name, uint64 value);
  100. virtual JsonObjectWriter* RenderDouble(StringPiece name, double value);
  101. virtual JsonObjectWriter* RenderFloat(StringPiece name, float value);
  102. virtual JsonObjectWriter* RenderString(StringPiece name, StringPiece value);
  103. virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value);
  104. virtual JsonObjectWriter* RenderNull(StringPiece name);
  105. virtual JsonObjectWriter* RenderNullAsEmpty(StringPiece name);
  106. void set_use_websafe_base64_for_bytes(bool value) {
  107. use_websafe_base64_for_bytes_ = value;
  108. }
  109. protected:
  110. class LIBPROTOBUF_EXPORT Element : public BaseElement {
  111. public:
  112. Element(Element* parent, bool is_json_object)
  113. : BaseElement(parent),
  114. is_first_(true),
  115. is_json_object_(is_json_object) {}
  116. // Called before each field of the Element is to be processed.
  117. // Returns true if this is the first call (processing the first field).
  118. bool is_first() {
  119. if (is_first_) {
  120. is_first_ = false;
  121. return true;
  122. }
  123. return false;
  124. }
  125. // Whether we are currently renderring inside a JSON object (i.e., between
  126. // StartObject() and EndObject()).
  127. bool is_json_object() const { return is_json_object_; }
  128. private:
  129. bool is_first_;
  130. bool is_json_object_;
  131. GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element);
  132. };
  133. virtual Element* element() { return element_.get(); }
  134. private:
  135. class LIBPROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink {
  136. public:
  137. explicit ByteSinkWrapper(google::protobuf::io::CodedOutputStream* stream)
  138. : stream_(stream) {}
  139. virtual ~ByteSinkWrapper() {}
  140. // ByteSink methods.
  141. virtual void Append(const char* bytes, size_t n) {
  142. stream_->WriteRaw(bytes, n);
  143. }
  144. private:
  145. google::protobuf::io::CodedOutputStream* stream_;
  146. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSinkWrapper);
  147. };
  148. // Renders a simple value as a string. By default all non-string Render
  149. // methods convert their argument to a string and call this method. This
  150. // method can then be used to render the simple value without escaping it.
  151. JsonObjectWriter* RenderSimple(StringPiece name, const string& value) {
  152. WritePrefix(name);
  153. stream_->WriteString(value);
  154. return this;
  155. }
  156. // Pushes a new JSON array element to the stack.
  157. void PushArray() {
  158. element_.reset(new Element(element_.release(), /*is_json_object=*/false));
  159. }
  160. // Pushes a new JSON object element to the stack.
  161. void PushObject() {
  162. element_.reset(new Element(element_.release(), /*is_json_object=*/true));
  163. }
  164. // Pops an element off of the stack and deletes the popped element.
  165. void Pop() {
  166. bool needs_newline = !element_->is_first();
  167. element_.reset(element_->pop<Element>());
  168. if (needs_newline) NewLine();
  169. }
  170. // If pretty printing is enabled, this will write a newline to the output,
  171. // followed by optional indentation. Otherwise this method is a noop.
  172. void NewLine() {
  173. if (!indent_string_.empty()) {
  174. WriteChar('\n');
  175. for (int i = 0; i < element()->level(); i++) {
  176. stream_->WriteString(indent_string_);
  177. }
  178. }
  179. }
  180. // Writes a prefix. This will write out any pretty printing and
  181. // commas that are required, followed by the name and a ':' if
  182. // the name is not null.
  183. void WritePrefix(StringPiece name);
  184. // Writes an individual character to the output.
  185. void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); }
  186. std::unique_ptr<Element> element_;
  187. google::protobuf::io::CodedOutputStream* stream_;
  188. ByteSinkWrapper sink_;
  189. const string indent_string_;
  190. // Whether to use regular or websafe base64 encoding for byte fields. Defaults
  191. // to regular base64 encoding.
  192. bool use_websafe_base64_for_bytes_;
  193. GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter);
  194. };
  195. } // namespace converter
  196. } // namespace util
  197. } // namespace protobuf
  198. } // namespace google
  199. #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__