1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "vm/JSONPrinter.h"
8
9 #include "mozilla/Assertions.h"
10 #include "mozilla/FloatingPoint.h"
11 #include "mozilla/IntegerPrintfMacros.h"
12
13 #include <stdarg.h>
14
15 #include "util/DoubleToString.h"
16
17 using namespace js;
18
~JSONPrinter()19 JSONPrinter::~JSONPrinter() {
20 if (dtoaState_) {
21 DestroyDtoaState(dtoaState_);
22 }
23 }
24
indent()25 void JSONPrinter::indent() {
26 MOZ_ASSERT(indentLevel_ >= 0);
27 if (indent_) {
28 out_.putChar('\n');
29 for (int i = 0; i < indentLevel_; i++) {
30 out_.put(" ");
31 }
32 }
33 }
34
propertyName(const char * name)35 void JSONPrinter::propertyName(const char* name) {
36 if (!first_) {
37 out_.putChar(',');
38 }
39 indent();
40 out_.printf("\"%s\":", name);
41 first_ = false;
42 }
43
beginObject()44 void JSONPrinter::beginObject() {
45 if (!first_) {
46 out_.putChar(',');
47 indent();
48 }
49 out_.putChar('{');
50 indentLevel_++;
51 first_ = true;
52 }
53
beginList()54 void JSONPrinter::beginList() {
55 if (!first_) {
56 out_.putChar(',');
57 }
58 out_.putChar('[');
59 first_ = true;
60 }
61
beginObjectProperty(const char * name)62 void JSONPrinter::beginObjectProperty(const char* name) {
63 propertyName(name);
64 out_.putChar('{');
65 indentLevel_++;
66 first_ = true;
67 }
68
beginListProperty(const char * name)69 void JSONPrinter::beginListProperty(const char* name) {
70 propertyName(name);
71 out_.putChar('[');
72 first_ = true;
73 }
74
beginStringProperty(const char * name)75 void JSONPrinter::beginStringProperty(const char* name) {
76 propertyName(name);
77 out_.putChar('"');
78 }
79
endStringProperty()80 void JSONPrinter::endStringProperty() { out_.putChar('"'); }
81
property(const char * name,const char * value)82 void JSONPrinter::property(const char* name, const char* value) {
83 beginStringProperty(name);
84 out_.put(value);
85 endStringProperty();
86 }
87
formatProperty(const char * name,const char * format,...)88 void JSONPrinter::formatProperty(const char* name, const char* format, ...) {
89 va_list ap;
90 va_start(ap, format);
91
92 beginStringProperty(name);
93 out_.vprintf(format, ap);
94 endStringProperty();
95
96 va_end(ap);
97 }
98
formatProperty(const char * name,const char * format,va_list ap)99 void JSONPrinter::formatProperty(const char* name, const char* format,
100 va_list ap) {
101 beginStringProperty(name);
102 out_.vprintf(format, ap);
103 endStringProperty();
104 }
105
value(const char * format,...)106 void JSONPrinter::value(const char* format, ...) {
107 va_list ap;
108 va_start(ap, format);
109
110 if (!first_) {
111 out_.putChar(',');
112 }
113 out_.putChar('"');
114 out_.vprintf(format, ap);
115 out_.putChar('"');
116
117 va_end(ap);
118 first_ = false;
119 }
120
property(const char * name,int32_t value)121 void JSONPrinter::property(const char* name, int32_t value) {
122 propertyName(name);
123 out_.printf("%" PRId32, value);
124 }
125
value(int val)126 void JSONPrinter::value(int val) {
127 if (!first_) {
128 out_.putChar(',');
129 }
130 out_.printf("%d", val);
131 first_ = false;
132 }
133
property(const char * name,uint32_t value)134 void JSONPrinter::property(const char* name, uint32_t value) {
135 propertyName(name);
136 out_.printf("%" PRIu32, value);
137 }
138
property(const char * name,int64_t value)139 void JSONPrinter::property(const char* name, int64_t value) {
140 propertyName(name);
141 out_.printf("%" PRId64, value);
142 }
143
property(const char * name,uint64_t value)144 void JSONPrinter::property(const char* name, uint64_t value) {
145 propertyName(name);
146 out_.printf("%" PRIu64, value);
147 }
148
149 #if defined(XP_DARWIN) || defined(__OpenBSD__)
property(const char * name,size_t value)150 void JSONPrinter::property(const char* name, size_t value) {
151 propertyName(name);
152 out_.printf("%zu", value);
153 }
154 #endif
155
floatProperty(const char * name,double value,size_t precision)156 void JSONPrinter::floatProperty(const char* name, double value,
157 size_t precision) {
158 if (!mozilla::IsFinite(value)) {
159 propertyName(name);
160 out_.put("null");
161 return;
162 }
163
164 if (!dtoaState_) {
165 dtoaState_ = NewDtoaState();
166 if (!dtoaState_) {
167 out_.reportOutOfMemory();
168 return;
169 }
170 }
171
172 char buffer[DTOSTR_STANDARD_BUFFER_SIZE];
173 char* str = js_dtostr(dtoaState_, buffer, sizeof(buffer), DTOSTR_STANDARD,
174 precision, value);
175 if (!str) {
176 out_.reportOutOfMemory();
177 return;
178 }
179
180 property(name, str);
181 }
182
property(const char * name,const mozilla::TimeDuration & dur,TimePrecision precision)183 void JSONPrinter::property(const char* name, const mozilla::TimeDuration& dur,
184 TimePrecision precision) {
185 if (precision == MICROSECONDS) {
186 property(name, static_cast<int64_t>(dur.ToMicroseconds()));
187 return;
188 }
189
190 propertyName(name);
191 lldiv_t split;
192 switch (precision) {
193 case SECONDS:
194 split = lldiv(static_cast<int64_t>(dur.ToMilliseconds()), 1000);
195 break;
196 case MILLISECONDS:
197 split = lldiv(static_cast<int64_t>(dur.ToMicroseconds()), 1000);
198 break;
199 case MICROSECONDS:
200 MOZ_ASSERT_UNREACHABLE("");
201 };
202 out_.printf("%lld.%03lld", split.quot, split.rem);
203 }
204
endObject()205 void JSONPrinter::endObject() {
206 indentLevel_--;
207 indent();
208 out_.putChar('}');
209 first_ = false;
210 }
211
endList()212 void JSONPrinter::endList() {
213 out_.putChar(']');
214 first_ = false;
215 }
216