writer.h
Go to the documentation of this file.
1 //Copyright (c) 2013-2023, The MercuryDPM Developers Team. All rights reserved.
2 //For the list of developers, see <http://www.MercuryDPM.org/Team>.
3 //
4 //Redistribution and use in source and binary forms, with or without
5 //modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name MercuryDPM nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 //DISCLAIMED. IN NO EVENT SHALL THE MERCURYDPM DEVELOPERS TEAM BE LIABLE FOR ANY
19 //DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #ifndef RAPIDJSON_WRITER_H_
27 #define RAPIDJSON_WRITER_H_
28 
29 #include "rapidjson.h"
30 #include "internal/stack.h"
31 #include "internal/strfunc.h"
32 #include <cstdio> // snprintf() or _sprintf_s()
33 #include <new> // placement new
34 #include <limits>
35 
36 #ifdef _MSC_VER
37 #pragma warning(push)
38 #pragma warning(disable : 4127) // conditional expression is constant
39 #endif
40 
41 namespace rapidjson {
42 
44 
57 template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
58 class Writer {
59 public:
60  typedef typename Encoding::Ch Ch;
61 
62  Writer(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
63  stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level))
64  {
65 #if _MSC_VER
66  (void) sprintf_s(double_format, sizeof(double_format), "%%0.%dg", precision);
67  (void) sprintf_s( long_double_format, sizeof( long_double_format ), "%%0.%dLg", precision );
68 #else
69  (void) snprintf(double_format, sizeof(double_format), "%%0.%dg", precision);
70  (void) snprintf( long_double_format, sizeof( long_double_format ), "%%0.%dLg", precision );
71 #endif
72 
73  }
74 
75 protected:
76  char double_format[32];
78 public:
79 
80  //@name Implementation of Handler
82 
83  Writer& Null_() { Prefix(kNull_Type); WriteNull_(); return *this; }
84  Writer& Bool_(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool_(b); return *this; }
85  Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; }
86  Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; }
87  Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; }
88  Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; }
89  Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; }
90  Writer& LongDouble(long double d) { Prefix(kNumberType); WriteLongDouble(d); return *this; }
91  Writer& LongLong(long long d) { Prefix(kNumberType); WriteLongLong(d); return *this; }
92  Writer& ULongLong(unsigned long long d) { Prefix(kNumberType); WriteULongLong(d); return *this; }
93 
94  Writer& String(const Ch* str, SizeType length, bool copy = false) {
95  (void)copy;
97  WriteString(str, length);
98  return *this;
99  }
100 
103  new (level_stack_.template Push<Level>()) Level(false);
105  return *this;
106  }
107 
108  Writer& EndObject(SizeType memberCount = 0) {
109  (void)memberCount;
110  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
111  RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
112  level_stack_.template Pop<Level>(1);
113  WriteEndObject();
114  return *this;
115  }
116 
119  new (level_stack_.template Push<Level>()) Level(true);
120  WriteStartArray();
121  return *this;
122  }
123 
124  Writer& EndArray(SizeType elementCount = 0) {
125  (void)elementCount;
126  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
127  RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
128  level_stack_.template Pop<Level>(1);
129  WriteEndArray();
130  return *this;
131  }
133 
135  Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
136 
137 protected:
139  struct Level {
140  Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
141  bool inArray;
142  size_t valueCount;
143  };
144 
145  static const size_t kDefaultLevelDepth = 32;
146 
147  void WriteNull_() {
148  stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
149  }
150 
151  void WriteBool_(bool b) {
152  if (b) {
153  stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
154  }
155  else {
156  stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
157  }
158  }
159 
160  void WriteInt(int i) {
161  if (i < 0) {
162  stream_.Put('-');
163  i = -i;
164  }
165  WriteUint((unsigned)i);
166  }
167 
168  void WriteUint(unsigned u) {
169  char buffer[10];
170  char *p = buffer;
171  do {
172  *p++ = (u % 10) + '0';
173  u /= 10;
174  } while (u > 0);
175 
176  do {
177  --p;
178  stream_.Put(*p);
179  } while (p != buffer);
180  }
181 
182  void WriteInt64(int64_t i64) {
183  if (i64 < 0) {
184  stream_.Put('-');
185  i64 = -i64;
186  }
187  WriteUint64((uint64_t)i64);
188  }
189 
190  void WriteUint64(uint64_t u64) {
191  char buffer[20];
192  char *p = buffer;
193  do {
194  *p++ = char(u64 % 10) + '0';
195  u64 /= 10;
196  } while (u64 > 0);
197 
198  do {
199  --p;
200  stream_.Put(*p);
201  } while (p != buffer);
202  }
203 
204  // cereal Temporary until constexpr support is added in RTM
205 #ifdef _MSC_VER
206  template <class Ch>
207  bool characterOk( Ch c )
208  {
209  return c < 256;
210  }
211 
212  template <>
213  bool characterOk<char>( Ch )
214  {
215  return true;
216  }
217 
218 #else
219  // As part of a fix for GCC 4.7
220  template <class T>
221  static constexpr int to_int( T t ){ return t; }
222 
223  template<class Ch>
224  typename std::enable_if < to_int(std::numeric_limits<Ch>::max()) < to_int(256), bool>::type
225  characterOk( Ch )
226  {
227  return true;
228  }
229 
230  template<class Ch>
231  typename std::enable_if< to_int(std::numeric_limits<Ch>::max()) >= to_int(256), bool>::type
233  { return c < 256; }
234 #endif
235 
237  void WriteDouble(double d) {
238  char buffer[100];
239 #if _MSC_VER
240  int ret = sprintf_s(buffer, sizeof(buffer), double_format, d);
241 #else
242  int ret = snprintf(buffer, sizeof(buffer), double_format, d);
243 #endif
244  RAPIDJSON_ASSERT(ret >= 1);
245  for (int i = 0; i < ret; i++)
246  stream_.Put(buffer[i]);
247  }
248 
249  void WriteLongDouble(long double d) {
250  char buffer[256];
251 #if _MSC_VER
252  int ret = sprintf_s(buffer, sizeof(buffer), long_double_format, d);
253 #else
254  int ret = snprintf(buffer, sizeof(buffer), long_double_format, d);
255 #endif
256  RAPIDJSON_ASSERT(ret >= 1);
257  for (int i = 0; i < ret; i++)
258  stream_.Put(buffer[i]);
259  }
260 
261  void WriteLongLong(long long d) {
262  char buffer[256];
263 #if _MSC_VER
264  int ret = sprintf_s(buffer, sizeof(buffer), "%lld", d);
265 #else
266  int ret = snprintf(buffer, sizeof(buffer), "%lld", d);
267 #endif
268  RAPIDJSON_ASSERT(ret >= 1);
269  for (int i = 0; i < ret; i++)
270  stream_.Put(buffer[i]);
271  }
272 
273  void WriteULongLong(unsigned long long d) {
274  char buffer[256];
275 #if _MSC_VER
276  int ret = sprintf_s(buffer, sizeof(buffer), "%llu", d);
277 #else
278  int ret = snprintf(buffer, sizeof(buffer), "%llu", d);
279 #endif
280  RAPIDJSON_ASSERT(ret >= 1);
281  for (int i = 0; i < ret; i++)
282  stream_.Put(buffer[i]);
283  }
284 
285  void WriteString(const Ch* str, SizeType length) {
286  static const char hexDigits[] = "0123456789ABCDEF";
287  static const char escape[256] = {
288 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
289  //0 1 2 3 4 5 6 7 8 9 A B C D E F
290  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
291  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
292  0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
293  Z16, Z16, // 30~4F
294  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
295  Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
296 #undef Z16
297  };
298 
299  stream_.Put('\"');
300  for (const Ch* p = str; p != str + length; ++p) {
301  if ((sizeof(Ch) == 1 || characterOk(*p)) && escape[(unsigned char)*p]) {
302  //if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p]) {
303  stream_.Put('\\');
304  stream_.Put(escape[(unsigned char)*p]);
305  if (escape[(unsigned char)*p] == 'u') {
306  stream_.Put('0');
307  stream_.Put('0');
308  stream_.Put(hexDigits[(*p) >> 4]);
309  stream_.Put(hexDigits[(*p) & 0xF]);
310  }
311  }
312  else
313  stream_.Put(*p);
314  }
315  stream_.Put('\"');
316  }
317 
318  void WriteStartObject() { stream_.Put('{'); }
319  void WriteEndObject() { stream_.Put('}'); }
320  void WriteStartArray() { stream_.Put('['); }
321  void WriteEndArray() { stream_.Put(']'); }
322 
323  void Prefix(Type type) {
324  (void)type;
325  if (level_stack_.GetSize() != 0) { // this value is not at root
326  Level* level = level_stack_.template Top<Level>();
327  if (level->valueCount > 0) {
328  if (level->inArray)
329  stream_.Put(','); // add comma if it is not the first element in array
330  else // in object
331  stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
332  }
333  if (!level->inArray && level->valueCount % 2 == 0)
334  RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
335  level->valueCount++;
336  }
337  else
338  RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
339  }
340 
343 
344 private:
345  // Prohibit assignment for VC C4512 warning
346  Writer& operator=(const Writer& w);
347 };
348 
349 } // namespace rapidjson
350 
351 #ifdef _MSC_VER
352 #pragma warning(pop)
353 #endif
354 
355 #endif // RAPIDJSON_RAPIDJSON_H_
Concept for allocating, resizing and freeing memory block.
Concept for reading and writing characters.
JSON writer.
Definition: writer.h:58
Writer & Uint(unsigned u)
Definition: writer.h:86
void WriteULongLong(unsigned long long d)
Definition: writer.h:273
Writer & Double(double d)
Definition: writer.h:89
void WriteStartArray()
Definition: writer.h:320
Writer & operator=(const Writer &w)
Writer & LongDouble(long double d)
Definition: writer.h:90
Writer & String(const Ch *str, SizeType length, bool copy=false)
Definition: writer.h:94
Writer & ULongLong(unsigned long long d)
Definition: writer.h:92
Writer & Bool_(bool b)
Definition: writer.h:84
char double_format[32]
Definition: writer.h:76
void WriteString(const Ch *str, SizeType length)
Definition: writer.h:285
std::enable_if< to_int(std::numeric_limits< Ch >::max())< to_int(256), bool >::type characterOk(Ch) { return true;} template< class Ch > typename std::enable_if< to_int(std::numeric_limits< Ch >::max()) >=to_int(256), bool >::type characterOk(Ch c)
Definition: writer.h:232
static const size_t kDefaultLevelDepth
Definition: writer.h:145
static constexpr int to_int(T t)
Definition: writer.h:221
Writer & String(const Ch *str)
Simpler but slower overload.
Definition: writer.h:135
Writer(Stream &stream, int precision=20, Allocator *allocator=0, size_t levelDepth=kDefaultLevelDepth)
Definition: writer.h:62
Writer & EndObject(SizeType memberCount=0)
Definition: writer.h:108
void WriteDouble(double d)
Definition: writer.h:237
void WriteUint(unsigned u)
Definition: writer.h:168
Writer & StartArray()
Definition: writer.h:117
void WriteInt64(int64_t i64)
Definition: writer.h:182
void WriteStartObject()
Definition: writer.h:318
Writer & Uint64(uint64_t u64)
Definition: writer.h:88
Writer & Int64(int64_t i64)
Definition: writer.h:87
void WriteLongDouble(long double d)
Definition: writer.h:249
Encoding::Ch Ch
Definition: writer.h:60
void WriteBool_(bool b)
Definition: writer.h:151
Writer & StartObject()
Definition: writer.h:101
void WriteUint64(uint64_t u64)
Definition: writer.h:190
Writer & Int(int i)
Definition: writer.h:85
internal::Stack< Allocator > level_stack_
Definition: writer.h:342
Stream & stream_
Definition: writer.h:341
void WriteLongLong(long long d)
Definition: writer.h:261
void WriteNull_()
Definition: writer.h:147
void WriteEndObject()
Definition: writer.h:319
Writer & EndArray(SizeType elementCount=0)
Definition: writer.h:124
char long_double_format[32]
Definition: writer.h:77
Writer & LongLong(long long d)
Definition: writer.h:91
void Prefix(Type type)
Definition: writer.h:323
void WriteInt(int i)
Definition: writer.h:160
void WriteEndArray()
Definition: writer.h:321
Writer & Null_()
Definition: writer.h:83
A type-unsafe stack for storing different types of data.
Definition: stack.h:39
const std::complex< Mdouble > i
Definition: ExtendedMath.h:51
SizeType StrLen(const Ch *s)
Custom strlen() which works on different character types.
Definition: strfunc.h:39
Definition: document.h:38
unsigned SizeType
Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
Definition: rapidjson.h:92
Type
Type of JSON value.
Definition: rapidjson.h:538
@ kArrayType
array
Definition: rapidjson.h:543
@ kNull_Type
null
Definition: rapidjson.h:539
@ kTrueType
true
Definition: rapidjson.h:541
@ kFalseType
false
Definition: rapidjson.h:540
@ kNumberType
number
Definition: rapidjson.h:545
@ kObjectType
object
Definition: rapidjson.h:542
@ kStringType
string
Definition: rapidjson.h:544
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:105
Information for each nested level.
Definition: writer.h:139
Level(bool inArray_)
Definition: writer.h:140
size_t valueCount
number of values in this level
Definition: writer.h:142
bool inArray
true if in array, otherwise in object
Definition: writer.h:141
#define Z16