JSONPrinter.cpp (6117B)
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/IntegerPrintfMacros.h" 11 12 #include <stdarg.h> 13 14 #include "jsnum.h" 15 16 using namespace js; 17 18 void JSONPrinter::indent() { 19 MOZ_ASSERT(indentLevel_ >= 0); 20 21 if (inlineLevel_ > 0) { 22 out_.putChar(' '); 23 return; 24 } 25 26 if (indent_) { 27 out_.putChar('\n'); 28 for (int i = 0; i < indentLevel_; i++) { 29 out_.put(" "); 30 } 31 } 32 } 33 34 void JSONPrinter::beforeValue() { 35 if (!first_) { 36 out_.putChar(','); 37 } 38 indent(); 39 } 40 41 void JSONPrinter::propertyName(const char* name) { 42 beforeValue(); 43 out_.printf("\"%s\":", name); 44 if (indent_) { 45 out_.put(" "); 46 } 47 first_ = false; 48 } 49 50 void JSONPrinter::beginObject() { 51 beforeValue(); 52 out_.putChar('{'); 53 indentLevel_++; 54 first_ = true; 55 } 56 57 void JSONPrinter::beginList() { 58 beforeValue(); 59 out_.putChar('['); 60 indentLevel_++; 61 first_ = true; 62 } 63 64 void JSONPrinter::beginObjectProperty(const char* name) { 65 propertyName(name); 66 out_.putChar('{'); 67 indentLevel_++; 68 first_ = true; 69 } 70 71 void JSONPrinter::beginListProperty(const char* name) { 72 propertyName(name); 73 out_.putChar('['); 74 indentLevel_++; 75 first_ = true; 76 } 77 78 void JSONPrinter::beginInlineListProperty(const char* name) { 79 beginListProperty(name); 80 beginInline(); 81 } 82 83 GenericPrinter& JSONPrinter::beginStringProperty(const char* name) { 84 propertyName(name); 85 out_.putChar('"'); 86 return out_; 87 } 88 89 void JSONPrinter::endStringProperty() { 90 endString(); 91 first_ = false; 92 } 93 94 GenericPrinter& JSONPrinter::beginString() { 95 beforeValue(); 96 out_.putChar('"'); 97 return out_; 98 } 99 100 void JSONPrinter::endString() { out_.putChar('"'); } 101 102 void JSONPrinter::boolProperty(const char* name, bool value) { 103 propertyName(name); 104 out_.put(value ? "true" : "false"); 105 } 106 107 template <typename CharT> 108 static void JSONString(GenericPrinter& out, const CharT* s, size_t length) { 109 const CharT* end = s + length; 110 for (const CharT* t = s; t < end; s = ++t) { 111 // This quote implementation is probably correct, 112 // but uses \u even when not strictly necessary. 113 char16_t c = *t; 114 if (c == '"' || c == '\\') { 115 out.printf("\\"); 116 out.printf("%c", char(c)); 117 } else if (!IsAsciiPrintable(c)) { 118 out.printf("\\u%04x", c); 119 } else { 120 out.printf("%c", char(c)); 121 } 122 } 123 } 124 125 void JSONPrinter::property(const char* name, const JSLinearString* str) { 126 JS::AutoCheckCannotGC nogc; 127 beginStringProperty(name); 128 129 // Limit the string length to reduce the JSON file size. 130 size_t length = std::min(str->length(), size_t(128)); 131 if (str->hasLatin1Chars()) { 132 JSONString(out_, str->latin1Chars(nogc), length); 133 } else { 134 JSONString(out_, str->twoByteChars(nogc), length); 135 } 136 endStringProperty(); 137 } 138 139 void JSONPrinter::property(const char* name, const char* value) { 140 beginStringProperty(name); 141 out_.put(value); 142 endStringProperty(); 143 } 144 145 void JSONPrinter::formatProperty(const char* name, const char* format, ...) { 146 va_list ap; 147 va_start(ap, format); 148 149 beginStringProperty(name); 150 out_.vprintf(format, ap); 151 endStringProperty(); 152 153 va_end(ap); 154 } 155 156 void JSONPrinter::formatPropertyVA(const char* name, const char* format, 157 va_list ap) { 158 beginStringProperty(name); 159 out_.vprintf(format, ap); 160 endStringProperty(); 161 } 162 163 void JSONPrinter::value(const char* format, ...) { 164 va_list ap; 165 va_start(ap, format); 166 167 beforeValue(); 168 out_.putChar('"'); 169 out_.vprintf(format, ap); 170 out_.putChar('"'); 171 172 va_end(ap); 173 first_ = false; 174 } 175 176 void JSONPrinter::property(const char* name, int32_t value) { 177 propertyName(name); 178 out_.printf("%" PRId32, value); 179 } 180 181 void JSONPrinter::value(int val) { 182 beforeValue(); 183 out_.printf("%d", val); 184 first_ = false; 185 } 186 187 void JSONPrinter::property(const char* name, uint32_t value) { 188 propertyName(name); 189 out_.printf("%" PRIu32, value); 190 } 191 192 void JSONPrinter::property(const char* name, int64_t value) { 193 propertyName(name); 194 out_.printf("%" PRId64, value); 195 } 196 197 void JSONPrinter::property(const char* name, uint64_t value) { 198 propertyName(name); 199 out_.printf("%" PRIu64, value); 200 } 201 202 #if defined(XP_DARWIN) || defined(__OpenBSD__) || defined(__wasi__) 203 void JSONPrinter::property(const char* name, size_t value) { 204 propertyName(name); 205 out_.printf("%zu", value); 206 } 207 #endif 208 209 void JSONPrinter::floatProperty(const char* name, double value, 210 size_t precision) { 211 if (!std::isfinite(value)) { 212 propertyName(name); 213 out_.put("null"); 214 return; 215 } 216 217 ToCStringBuf cbuf; 218 const char* str = NumberToCString(&cbuf, value); 219 MOZ_ASSERT(str); 220 221 property(name, str); 222 } 223 224 void JSONPrinter::property(const char* name, const mozilla::TimeDuration& dur, 225 TimePrecision precision) { 226 if (precision == MICROSECONDS) { 227 property(name, static_cast<int64_t>(dur.ToMicroseconds())); 228 return; 229 } 230 231 propertyName(name); 232 lldiv_t split; 233 switch (precision) { 234 case SECONDS: 235 split = lldiv(static_cast<int64_t>(dur.ToMilliseconds()), 1000); 236 break; 237 case MILLISECONDS: 238 split = lldiv(static_cast<int64_t>(dur.ToMicroseconds()), 1000); 239 break; 240 case MICROSECONDS: 241 MOZ_ASSERT_UNREACHABLE(""); 242 }; 243 out_.printf("%lld.%03lld", split.quot, split.rem); 244 } 245 246 void JSONPrinter::nullProperty(const char* name) { 247 propertyName(name); 248 out_.put("null"); 249 } 250 251 void JSONPrinter::nullValue() { 252 beforeValue(); 253 out_.put("null"); 254 first_ = false; 255 } 256 257 void JSONPrinter::endObject() { 258 indentLevel_--; 259 indent(); 260 out_.putChar('}'); 261 first_ = false; 262 } 263 264 void JSONPrinter::endList() { 265 indentLevel_--; 266 indent(); 267 out_.putChar(']'); 268 first_ = false; 269 } 270 271 void JSONPrinter::endInlineList() { 272 endList(); 273 endInline(); 274 } 275 276 void JSONPrinter::beginInline() { inlineLevel_++; } 277 278 void JSONPrinter::endInline() { inlineLevel_--; }