static void dumpString(std::ostringstream& os, const char *s) { os.put('"'); while (*s) { char c = *s++; switch (c) { case '\b': os << "\\b"; break; case '\f': os << "\\f"; break; case '\n': os << "\\n"; break; case '\r': os << "\\r"; break; case '\t': os << "\\t"; break; case '\\': os << "\\\\"; break; case '"': os << "\\\""; break; default: os.put(c); } } os << s << "\""; }
static void dumpValue(std::ostringstream& os, const JsonValue& o, int shiftWidth, const std::string& linefeed = "", int indent = 0) { switch (o.getTag()) { case JSON_NUMBER: char buffer[32]; sprintf(buffer, "%f", o.toNumber()); os << buffer; break; case JSON_TRUE: os << "true"; break; case JSON_FALSE: os << "false"; break; case JSON_STRING: dumpString(os, o.toString()); break; case JSON_ARRAY: // It is not necessary to use o.toNode() to check if an array or object // is empty before iterating over its members, we do it here to allow // nicer pretty printing. if (!o.toNode()) { os << "[]"; break; } os << "[" << linefeed; for (auto i : o) { if (shiftWidth > 0) os << std::setw(indent + shiftWidth) << " " << std::setw(0); dumpValue(os, i->value, shiftWidth, linefeed, indent + shiftWidth); if (i->next) os << ","; os << linefeed; } if (indent > 0) os << std::setw(indent) << " " << std::setw(0); os.put(']'); break; case JSON_OBJECT: if (!o.toNode()) { os << "{}"; break; } os << "{" << linefeed; for (auto i : o) { if (shiftWidth > 0) os << std::setw(indent + shiftWidth) << " " << std::setw(0); dumpString(os, i->key); os << ":"; dumpValue(os, i->value, shiftWidth, linefeed, indent + shiftWidth); if (i->next) os << ","; os << linefeed; } if (indent > 0) os << std::setw(indent) << " " << std::setw(0); os.put('}'); break; case JSON_NULL: os << "null"; break; } }