json_prettifier.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "json_prettifier.h"
  2. #include <util/generic/deque.h>
  3. #include <util/generic/algorithm.h>
  4. #include <util/memory/pool.h>
  5. #include <util/string/util.h>
  6. #include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
  7. namespace NJson {
  8. struct TRewritableOut {
  9. IOutputStream& Slave;
  10. char Last = 0;
  11. bool Dirty = false;
  12. TRewritableOut(IOutputStream& sl)
  13. : Slave(sl)
  14. {
  15. }
  16. template <typename T>
  17. void Write(const T& t) {
  18. Flush();
  19. Slave << t;
  20. }
  21. void Hold(char c) {
  22. if (Dirty)
  23. Flush();
  24. Last = c;
  25. Dirty = true;
  26. }
  27. void Flush() {
  28. if (Dirty) {
  29. Slave << Last;
  30. Dirty = false;
  31. }
  32. }
  33. void Revert() {
  34. Dirty = false;
  35. }
  36. };
  37. struct TSpaces {
  38. char S[256];
  39. TSpaces() {
  40. memset(&S, ' ', sizeof(S));
  41. }
  42. TStringBuf Get(ui8 sz) const {
  43. return TStringBuf(S, sz);
  44. }
  45. };
  46. bool TJsonPrettifier::MayUnquoteNew(TStringBuf s) {
  47. static str_spn alpha("a-zA-Z_@$", true);
  48. static str_spn alnum("a-zA-Z_@$0-9.-", true);
  49. static TStringBuf true0("true");
  50. static TStringBuf false0("false");
  51. static TStringBuf null0("null");
  52. return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0);
  53. }
  54. // to keep arcadia tests happy
  55. bool TJsonPrettifier::MayUnquoteOld(TStringBuf s) {
  56. static str_spn alpha("a-zA-Z_@$", true);
  57. static str_spn alnum("a-zA-Z_@$0-9", true);
  58. static TStringBuf true0("true");
  59. static TStringBuf false0("false");
  60. static TStringBuf true1("on");
  61. static TStringBuf false1("off");
  62. static TStringBuf true2("da");
  63. static TStringBuf false2("net");
  64. static TStringBuf null0("null");
  65. 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);
  66. }
  67. class TPrettifier: public TJsonCallbacks {
  68. TRewritableOut Out;
  69. TStringBuf Spaces;
  70. TStringBuf Quote;
  71. TStringBuf Unsafe;
  72. TStringBuf Safe;
  73. ui32 Level = 0;
  74. ui32 MaxPaddingLevel;
  75. bool Unquote = false;
  76. bool Compactify = false;
  77. bool NewUnquote = false;
  78. public:
  79. TPrettifier(IOutputStream& out, const TJsonPrettifier& p)
  80. : Out(out)
  81. , MaxPaddingLevel(p.MaxPaddingLevel)
  82. , Unquote(p.Unquote)
  83. , Compactify(p.Compactify)
  84. , NewUnquote(p.NewUnquote)
  85. {
  86. static TSpaces spaces;
  87. Spaces = spaces.Get(p.Padding);
  88. if (p.SingleQuotes) {
  89. Quote = Unsafe = "'";
  90. Safe = "\"";
  91. } else {
  92. Quote = Unsafe = "\"";
  93. Safe = "'";
  94. }
  95. }
  96. void Pad(bool close = false) {
  97. if (Compactify) {
  98. Out.Flush();
  99. return;
  100. }
  101. if (Level > MaxPaddingLevel || (Level == MaxPaddingLevel && close)) {
  102. Out.Write(" ");
  103. return;
  104. }
  105. if (Level || close) {
  106. Out.Write(Spaces ? "\n" : " ");
  107. }
  108. for (ui32 i = 0; i < Level; ++i) {
  109. Out.Write(Spaces);
  110. }
  111. }
  112. void WriteSpace(char sp) {
  113. if (Compactify) {
  114. Out.Flush();
  115. return;
  116. }
  117. Out.Write(sp);
  118. }
  119. void OnVal() {
  120. if (Out.Dirty && ':' == Out.Last) {
  121. WriteSpace(' ');
  122. } else {
  123. Pad();
  124. }
  125. }
  126. void AfterVal() {
  127. Out.Hold(',');
  128. }
  129. template <typename T>
  130. bool WriteVal(const T& t) {
  131. OnVal();
  132. Out.Write(t);
  133. AfterVal();
  134. return true;
  135. }
  136. bool OnNull() override {
  137. return WriteVal(TStringBuf("null"));
  138. }
  139. bool OnBoolean(bool v) override {
  140. return WriteVal(v ? TStringBuf("true") : TStringBuf("false"));
  141. }
  142. bool OnInteger(long long i) override {
  143. return WriteVal(i);
  144. }
  145. bool OnUInteger(unsigned long long i) override {
  146. return WriteVal(i);
  147. }
  148. bool OnDouble(double d) override {
  149. return WriteVal(d);
  150. }
  151. void WriteString(TStringBuf s) {
  152. if (Unquote && (NewUnquote ? TJsonPrettifier::MayUnquoteNew(s) : TJsonPrettifier::MayUnquoteOld(s))) {
  153. Out.Slave << s;
  154. } else {
  155. Out.Slave << Quote;
  156. NEscJ::EscapeJ<false, true>(s, Out.Slave, Safe, Unsafe);
  157. Out.Slave << Quote;
  158. }
  159. }
  160. bool OnString(const TStringBuf& s) override {
  161. OnVal();
  162. WriteString(s);
  163. AfterVal();
  164. return true;
  165. }
  166. bool OnOpen(char c) {
  167. OnVal();
  168. Level++;
  169. Out.Hold(c);
  170. return true;
  171. }
  172. bool OnOpenMap() override {
  173. return OnOpen('{');
  174. }
  175. bool OnOpenArray() override {
  176. return OnOpen('[');
  177. }
  178. bool OnMapKey(const TStringBuf& k) override {
  179. OnVal();
  180. WriteString(k);
  181. WriteSpace(' ');
  182. Out.Hold(':');
  183. return true;
  184. }
  185. bool OnClose(char c) {
  186. if (!Level)
  187. return false;
  188. Level--;
  189. if (Out.Dirty && c == Out.Last) {
  190. WriteSpace(' ');
  191. } else {
  192. Out.Revert();
  193. Pad(true);
  194. }
  195. return true;
  196. }
  197. bool OnCloseMap() override {
  198. if (!OnClose('{'))
  199. return false;
  200. Out.Write("}");
  201. AfterVal();
  202. return true;
  203. }
  204. bool OnCloseArray() override {
  205. if (!OnClose('['))
  206. return false;
  207. Out.Write("]");
  208. AfterVal();
  209. return true;
  210. }
  211. bool OnEnd() override {
  212. return !Level;
  213. }
  214. };
  215. bool TJsonPrettifier::Prettify(TStringBuf in, IOutputStream& out) const {
  216. TPrettifier p(out, *this);
  217. if (Strict) {
  218. TMemoryInput mIn(in.data(), in.size());
  219. return ReadJson(&mIn, &p);
  220. } else {
  221. return ReadJsonFast(in, &p);
  222. }
  223. }
  224. TString TJsonPrettifier::Prettify(TStringBuf in) const {
  225. TStringStream s;
  226. if (Prettify(in, s))
  227. return s.Str();
  228. return TString();
  229. }
  230. }