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 31 #ifndef GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__ 32 #define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__ 33 34 #include <memory> 35 #ifndef _SHARED_PTR_H 36 #include <google/protobuf/stubs/shared_ptr.h> 37 #endif 38 #include <string> 39 40 #include <google/protobuf/io/coded_stream.h> 41 #include <google/protobuf/util/internal/structured_objectwriter.h> 42 #include <google/protobuf/stubs/bytestream.h> 43 44 namespace google { 45 namespace protobuf { 46 namespace util { 47 namespace converter { 48 49 // An ObjectWriter implementation that outputs JSON. This ObjectWriter 50 // supports writing a compact form or a pretty printed form. 51 // 52 // Sample usage: 53 // string output; 54 // StringOutputStream* str_stream = new StringOutputStream(&output); 55 // CodedOutputStream* out_stream = new CodedOutputStream(str_stream); 56 // JsonObjectWriter* ow = new JsonObjectWriter(" ", out_stream); 57 // ow->StartObject("") 58 // ->RenderString("name", "value") 59 // ->RenderString("emptystring", string()) 60 // ->StartObject("nested") 61 // ->RenderInt64("light", 299792458); 62 // ->RenderDouble("pi", 3.141592653589793); 63 // ->EndObject() 64 // ->StartList("empty") 65 // ->EndList() 66 // ->EndObject(); 67 // 68 // And then the output string would become: 69 // { 70 // "name": "value", 71 // "emptystring": "", 72 // "nested": { 73 // "light": "299792458", 74 // "pi": 3.141592653589793 75 // }, 76 // "empty": [] 77 // } 78 // 79 // JsonObjectWriter does not validate if calls actually result in valid JSON. 80 // For example, passing an empty name when one would be required won't result 81 // in an error, just an invalid output. 82 // 83 // Note that all int64 and uint64 are rendered as strings instead of numbers. 84 // This is because JavaScript parses numbers as 64-bit float thus int64 and 85 // uint64 would lose precision if rendered as numbers. 86 // 87 // JsonObjectWriter is thread-unsafe. 88 class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { 89 public: JsonObjectWriter(StringPiece indent_string,google::protobuf::io::CodedOutputStream * out)90 JsonObjectWriter(StringPiece indent_string, 91 google::protobuf::io::CodedOutputStream* out) 92 : element_(new Element(NULL)), 93 stream_(out), 94 sink_(out), 95 indent_string_(indent_string.ToString()), 96 use_websafe_base64_for_bytes_(false) {} 97 virtual ~JsonObjectWriter(); 98 99 // ObjectWriter methods. 100 virtual JsonObjectWriter* StartObject(StringPiece name); 101 virtual JsonObjectWriter* EndObject(); 102 virtual JsonObjectWriter* StartList(StringPiece name); 103 virtual JsonObjectWriter* EndList(); 104 virtual JsonObjectWriter* RenderBool(StringPiece name, bool value); 105 virtual JsonObjectWriter* RenderInt32(StringPiece name, int32 value); 106 virtual JsonObjectWriter* RenderUint32(StringPiece name, uint32 value); 107 virtual JsonObjectWriter* RenderInt64(StringPiece name, int64 value); 108 virtual JsonObjectWriter* RenderUint64(StringPiece name, uint64 value); 109 virtual JsonObjectWriter* RenderDouble(StringPiece name, double value); 110 virtual JsonObjectWriter* RenderFloat(StringPiece name, float value); 111 virtual JsonObjectWriter* RenderString(StringPiece name, StringPiece value); 112 virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value); 113 virtual JsonObjectWriter* RenderNull(StringPiece name); 114 set_use_websafe_base64_for_bytes(bool value)115 void set_use_websafe_base64_for_bytes(bool value) { 116 use_websafe_base64_for_bytes_ = value; 117 } 118 119 protected: 120 class LIBPROTOBUF_EXPORT Element : public BaseElement { 121 public: Element(Element * parent)122 explicit Element(Element* parent) : BaseElement(parent), is_first_(true) {} 123 124 // Called before each field of the Element is to be processed. 125 // Returns true if this is the first call (processing the first field). is_first()126 bool is_first() { 127 if (is_first_) { 128 is_first_ = false; 129 return true; 130 } 131 return false; 132 } 133 134 private: 135 bool is_first_; 136 137 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element); 138 }; 139 element()140 virtual Element* element() { return element_.get(); } 141 142 private: 143 class LIBPROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink { 144 public: ByteSinkWrapper(google::protobuf::io::CodedOutputStream * stream)145 explicit ByteSinkWrapper(google::protobuf::io::CodedOutputStream* stream) 146 : stream_(stream) {} ~ByteSinkWrapper()147 virtual ~ByteSinkWrapper() {} 148 149 // ByteSink methods. Append(const char * bytes,size_t n)150 virtual void Append(const char* bytes, size_t n) { 151 stream_->WriteRaw(bytes, n); 152 } 153 154 private: 155 google::protobuf::io::CodedOutputStream* stream_; 156 157 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSinkWrapper); 158 }; 159 160 // Renders a simple value as a string. By default all non-string Render 161 // methods convert their argument to a string and call this method. This 162 // method can then be used to render the simple value without escaping it. RenderSimple(StringPiece name,const string & value)163 JsonObjectWriter* RenderSimple(StringPiece name, const string& value) { 164 WritePrefix(name); 165 stream_->WriteString(value); 166 return this; 167 } 168 169 // Pushes a new element to the stack. Push()170 void Push() { element_.reset(new Element(element_.release())); } 171 172 // Pops an element off of the stack and deletes the popped element. Pop()173 void Pop() { 174 bool needs_newline = !element_->is_first(); 175 element_.reset(element_->pop<Element>()); 176 if (needs_newline) NewLine(); 177 } 178 179 // If pretty printing is enabled, this will write a newline to the output, 180 // followed by optional indentation. Otherwise this method is a noop. NewLine()181 void NewLine() { 182 if (!indent_string_.empty()) { 183 WriteChar('\n'); 184 for (int i = 0; i < element()->level(); i++) { 185 stream_->WriteString(indent_string_); 186 } 187 } 188 } 189 190 // Writes a prefix. This will write out any pretty printing and 191 // commas that are required, followed by the name and a ':' if 192 // the name is not null. 193 void WritePrefix(StringPiece name); 194 195 // Writes an individual character to the output. WriteChar(const char c)196 void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); } 197 198 google::protobuf::scoped_ptr<Element> element_; 199 google::protobuf::io::CodedOutputStream* stream_; 200 ByteSinkWrapper sink_; 201 const string indent_string_; 202 203 // Whether to use regular or websafe base64 encoding for byte fields. Defaults 204 // to regular base64 encoding. 205 bool use_websafe_base64_for_bytes_; 206 207 GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter); 208 }; 209 210 } // namespace converter 211 } // namespace util 212 } // namespace protobuf 213 214 } // namespace google 215 #endif // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__ 216