summaryrefslogtreecommitdiffstats
path: root/js/src/vm/JSONPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/JSONPrinter.cpp')
-rw-r--r--js/src/vm/JSONPrinter.cpp279
1 files changed, 279 insertions, 0 deletions
diff --git a/js/src/vm/JSONPrinter.cpp b/js/src/vm/JSONPrinter.cpp
new file mode 100644
index 0000000000..5b5183d9fb
--- /dev/null
+++ b/js/src/vm/JSONPrinter.cpp
@@ -0,0 +1,279 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/JSONPrinter.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/IntegerPrintfMacros.h"
+
+#include <stdarg.h>
+
+#include "jsnum.h"
+
+using namespace js;
+
+void JSONPrinter::indent() {
+ MOZ_ASSERT(indentLevel_ >= 0);
+
+ if (inlineLevel_ > 0) {
+ out_.putChar(' ');
+ return;
+ }
+
+ if (indent_) {
+ out_.putChar('\n');
+ for (int i = 0; i < indentLevel_; i++) {
+ out_.put(" ");
+ }
+ }
+}
+
+void JSONPrinter::beforeValue() {
+ if (!first_) {
+ out_.putChar(',');
+ }
+ indent();
+}
+
+void JSONPrinter::propertyName(const char* name) {
+ beforeValue();
+ out_.printf("\"%s\":", name);
+ if (indent_) {
+ out_.put(" ");
+ }
+ first_ = false;
+}
+
+void JSONPrinter::beginObject() {
+ beforeValue();
+ out_.putChar('{');
+ indentLevel_++;
+ first_ = true;
+}
+
+void JSONPrinter::beginList() {
+ beforeValue();
+ out_.putChar('[');
+ indentLevel_++;
+ first_ = true;
+}
+
+void JSONPrinter::beginObjectProperty(const char* name) {
+ propertyName(name);
+ out_.putChar('{');
+ indentLevel_++;
+ first_ = true;
+}
+
+void JSONPrinter::beginListProperty(const char* name) {
+ propertyName(name);
+ out_.putChar('[');
+ indentLevel_++;
+ first_ = true;
+}
+
+void JSONPrinter::beginInlineListProperty(const char* name) {
+ beginListProperty(name);
+ beginInline();
+}
+
+GenericPrinter& JSONPrinter::beginStringProperty(const char* name) {
+ propertyName(name);
+ out_.putChar('"');
+ return out_;
+}
+
+void JSONPrinter::endStringProperty() {
+ endString();
+ first_ = false;
+}
+
+GenericPrinter& JSONPrinter::beginString() {
+ beforeValue();
+ out_.putChar('"');
+ return out_;
+}
+
+void JSONPrinter::endString() { out_.putChar('"'); }
+
+void JSONPrinter::boolProperty(const char* name, bool value) {
+ propertyName(name);
+ out_.put(value ? "true" : "false");
+}
+
+template <typename CharT>
+static void JSONString(GenericPrinter& out, const CharT* s, size_t length) {
+ const CharT* end = s + length;
+ for (const CharT* t = s; t < end; s = ++t) {
+ // This quote implementation is probably correct,
+ // but uses \u even when not strictly necessary.
+ char16_t c = *t;
+ if (c == '"' || c == '\\') {
+ out.printf("\\");
+ out.printf("%c", char(c));
+ } else if (!IsAsciiPrintable(c)) {
+ out.printf("\\u%04x", c);
+ } else {
+ out.printf("%c", char(c));
+ }
+ }
+}
+
+void JSONPrinter::property(const char* name, JSLinearString* str) {
+ JS::AutoCheckCannotGC nogc;
+ beginStringProperty(name);
+
+ // Limit the string length to reduce the JSON file size.
+ size_t length = std::min(str->length(), size_t(128));
+ if (str->hasLatin1Chars()) {
+ JSONString(out_, str->latin1Chars(nogc), length);
+ } else {
+ JSONString(out_, str->twoByteChars(nogc), length);
+ }
+ endStringProperty();
+}
+
+void JSONPrinter::property(const char* name, const char* value) {
+ beginStringProperty(name);
+ out_.put(value);
+ endStringProperty();
+}
+
+void JSONPrinter::formatProperty(const char* name, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+
+ beginStringProperty(name);
+ out_.vprintf(format, ap);
+ endStringProperty();
+
+ va_end(ap);
+}
+
+void JSONPrinter::formatProperty(const char* name, const char* format,
+ va_list ap) {
+ beginStringProperty(name);
+ out_.vprintf(format, ap);
+ endStringProperty();
+}
+
+void JSONPrinter::value(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+
+ beforeValue();
+ out_.putChar('"');
+ out_.vprintf(format, ap);
+ out_.putChar('"');
+
+ va_end(ap);
+ first_ = false;
+}
+
+void JSONPrinter::property(const char* name, int32_t value) {
+ propertyName(name);
+ out_.printf("%" PRId32, value);
+}
+
+void JSONPrinter::value(int val) {
+ beforeValue();
+ out_.printf("%d", val);
+ first_ = false;
+}
+
+void JSONPrinter::property(const char* name, uint32_t value) {
+ propertyName(name);
+ out_.printf("%" PRIu32, value);
+}
+
+void JSONPrinter::property(const char* name, int64_t value) {
+ propertyName(name);
+ out_.printf("%" PRId64, value);
+}
+
+void JSONPrinter::property(const char* name, uint64_t value) {
+ propertyName(name);
+ out_.printf("%" PRIu64, value);
+}
+
+#if defined(XP_DARWIN) || defined(__OpenBSD__) || defined(__wasi__)
+void JSONPrinter::property(const char* name, size_t value) {
+ propertyName(name);
+ out_.printf("%zu", value);
+}
+#endif
+
+void JSONPrinter::floatProperty(const char* name, double value,
+ size_t precision) {
+ if (!std::isfinite(value)) {
+ propertyName(name);
+ out_.put("null");
+ return;
+ }
+
+ ToCStringBuf cbuf;
+ const char* str = NumberToCString(&cbuf, value);
+ MOZ_ASSERT(str);
+
+ property(name, str);
+}
+
+void JSONPrinter::property(const char* name, const mozilla::TimeDuration& dur,
+ TimePrecision precision) {
+ if (precision == MICROSECONDS) {
+ property(name, static_cast<int64_t>(dur.ToMicroseconds()));
+ return;
+ }
+
+ propertyName(name);
+ lldiv_t split;
+ switch (precision) {
+ case SECONDS:
+ split = lldiv(static_cast<int64_t>(dur.ToMilliseconds()), 1000);
+ break;
+ case MILLISECONDS:
+ split = lldiv(static_cast<int64_t>(dur.ToMicroseconds()), 1000);
+ break;
+ case MICROSECONDS:
+ MOZ_ASSERT_UNREACHABLE("");
+ };
+ out_.printf("%lld.%03lld", split.quot, split.rem);
+}
+
+void JSONPrinter::nullProperty(const char* name) {
+ propertyName(name);
+ out_.put("null");
+}
+
+void JSONPrinter::nullValue() {
+ beforeValue();
+ out_.put("null");
+ first_ = false;
+}
+
+void JSONPrinter::endObject() {
+ indentLevel_--;
+ indent();
+ out_.putChar('}');
+ first_ = false;
+}
+
+void JSONPrinter::endList() {
+ indentLevel_--;
+ indent();
+ out_.putChar(']');
+ first_ = false;
+}
+
+void JSONPrinter::endInlineList() {
+ endList();
+ endInline();
+}
+
+void JSONPrinter::beginInline() { inlineLevel_++; }
+
+void JSONPrinter::endInline() { inlineLevel_--; }