123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- #include "json_prettifier.h"
- #include <util/generic/deque.h>
- #include <util/generic/algorithm.h>
- #include <util/memory/pool.h>
- #include <util/string/util.h>
- #include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
- namespace NJson {
- struct TRewritableOut {
- IOutputStream& Slave;
- char Last = 0;
- bool Dirty = false;
- TRewritableOut(IOutputStream& sl)
- : Slave(sl)
- {
- }
- template <typename T>
- void Write(const T& t) {
- Flush();
- Slave << t;
- }
- void Hold(char c) {
- if (Dirty)
- Flush();
- Last = c;
- Dirty = true;
- }
- void Flush() {
- if (Dirty) {
- Slave << Last;
- Dirty = false;
- }
- }
- void Revert() {
- Dirty = false;
- }
- };
- struct TSpaces {
- char S[256];
- TSpaces() {
- memset(&S, ' ', sizeof(S));
- }
- TStringBuf Get(ui8 sz) const {
- return TStringBuf(S, sz);
- }
- };
- bool TJsonPrettifier::MayUnquoteNew(TStringBuf s) {
- static str_spn alpha("a-zA-Z_@$", true);
- static str_spn alnum("a-zA-Z_@$0-9.-", true);
- static TStringBuf true0("true");
- static TStringBuf false0("false");
- static TStringBuf null0("null");
- return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0);
- }
- // to keep arcadia tests happy
- bool TJsonPrettifier::MayUnquoteOld(TStringBuf s) {
- static str_spn alpha("a-zA-Z_@$", true);
- static str_spn alnum("a-zA-Z_@$0-9", true);
- static TStringBuf true0("true");
- static TStringBuf false0("false");
- static TStringBuf true1("on");
- static TStringBuf false1("off");
- static TStringBuf true2("da");
- static TStringBuf false2("net");
- static TStringBuf null0("null");
- return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0, true1, false1, true2, false2);
- }
- class TPrettifier: public TJsonCallbacks {
- TRewritableOut Out;
- TStringBuf Spaces;
- TStringBuf Quote;
- TStringBuf Unsafe;
- TStringBuf Safe;
- ui32 Level = 0;
- ui32 MaxPaddingLevel;
- bool Unquote = false;
- bool Compactify = false;
- bool NewUnquote = false;
- public:
- TPrettifier(IOutputStream& out, const TJsonPrettifier& p)
- : Out(out)
- , MaxPaddingLevel(p.MaxPaddingLevel)
- , Unquote(p.Unquote)
- , Compactify(p.Compactify)
- , NewUnquote(p.NewUnquote)
- {
- static TSpaces spaces;
- Spaces = spaces.Get(p.Padding);
- if (p.SingleQuotes) {
- Quote = Unsafe = "'";
- Safe = "\"";
- } else {
- Quote = Unsafe = "\"";
- Safe = "'";
- }
- }
- void Pad(bool close = false) {
- if (Compactify) {
- Out.Flush();
- return;
- }
- if (Level > MaxPaddingLevel || (Level == MaxPaddingLevel && close)) {
- Out.Write(" ");
- return;
- }
- if (Level || close) {
- Out.Write(Spaces ? "\n" : " ");
- }
- for (ui32 i = 0; i < Level; ++i) {
- Out.Write(Spaces);
- }
- }
- void WriteSpace(char sp) {
- if (Compactify) {
- Out.Flush();
- return;
- }
- Out.Write(sp);
- }
- void OnVal() {
- if (Out.Dirty && ':' == Out.Last) {
- WriteSpace(' ');
- } else {
- Pad();
- }
- }
- void AfterVal() {
- Out.Hold(',');
- }
- template <typename T>
- bool WriteVal(const T& t) {
- OnVal();
- Out.Write(t);
- AfterVal();
- return true;
- }
- bool OnNull() override {
- return WriteVal(TStringBuf("null"));
- }
- bool OnBoolean(bool v) override {
- return WriteVal(v ? TStringBuf("true") : TStringBuf("false"));
- }
- bool OnInteger(long long i) override {
- return WriteVal(i);
- }
- bool OnUInteger(unsigned long long i) override {
- return WriteVal(i);
- }
- bool OnDouble(double d) override {
- return WriteVal(d);
- }
- void WriteString(TStringBuf s) {
- if (Unquote && (NewUnquote ? TJsonPrettifier::MayUnquoteNew(s) : TJsonPrettifier::MayUnquoteOld(s))) {
- Out.Slave << s;
- } else {
- Out.Slave << Quote;
- NEscJ::EscapeJ<false, true>(s, Out.Slave, Safe, Unsafe);
- Out.Slave << Quote;
- }
- }
- bool OnString(const TStringBuf& s) override {
- OnVal();
- WriteString(s);
- AfterVal();
- return true;
- }
- bool OnOpen(char c) {
- OnVal();
- Level++;
- Out.Hold(c);
- return true;
- }
- bool OnOpenMap() override {
- return OnOpen('{');
- }
- bool OnOpenArray() override {
- return OnOpen('[');
- }
- bool OnMapKey(const TStringBuf& k) override {
- OnVal();
- WriteString(k);
- WriteSpace(' ');
- Out.Hold(':');
- return true;
- }
- bool OnClose(char c) {
- if (!Level)
- return false;
- Level--;
- if (Out.Dirty && c == Out.Last) {
- WriteSpace(' ');
- } else {
- Out.Revert();
- Pad(true);
- }
- return true;
- }
- bool OnCloseMap() override {
- if (!OnClose('{'))
- return false;
- Out.Write("}");
- AfterVal();
- return true;
- }
- bool OnCloseArray() override {
- if (!OnClose('['))
- return false;
- Out.Write("]");
- AfterVal();
- return true;
- }
- bool OnEnd() override {
- return !Level;
- }
- };
- bool TJsonPrettifier::Prettify(TStringBuf in, IOutputStream& out) const {
- TPrettifier p(out, *this);
- if (Strict) {
- TMemoryInput mIn(in.data(), in.size());
- return ReadJson(&mIn, &p);
- } else {
- return ReadJsonFast(in, &p);
- }
- }
- TString TJsonPrettifier::Prettify(TStringBuf in) const {
- TStringStream s;
- if (Prettify(in, s))
- return s.Str();
- return TString();
- }
- }
|