Rizin
unix-like reverse engineering framework and cli tools
json_indent.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2012-2017 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: MIT
3 
4 #include <rz_util.h>
5 
6 static void doIndent(int idt, char **o, const char *tab) {
7  int i;
8  char *x;
9  for (i = 0; i < idt; i++) {
10  for (x = (char *)tab; *x; x++) {
11  *(*o)++ = *x;
12  }
13  }
14 }
15 
16 #define EMIT_ESC(s, code) \
17  do { \
18  if (color) { \
19  const char *p = code; \
20  while (*p) { \
21  *(s)++ = *p++; \
22  } \
23  } \
24  } while (0);
25 
26 enum {
27  JC_FALSE, // 31m
28  JC_TRUE, // 32m
29  JC_KEY, // 33m
30  JC_VAL, // 34m
32 };
33 
34 static const char *origColors[] = {
35  "\x1b[31m",
36  "\x1b[32m",
37  "\x1b[33m",
38  "\x1b[34m",
39  "\x1b[0m",
40 };
41 // static const char colors
42 
43 RZ_API char *rz_print_json_path(const char *s, int pos) {
44  int indent = 0;
45 #define DSZ 128
46  const char *words[DSZ] = { NULL };
47  int lengths[DSZ] = { 0 };
48  int indexs[DSZ] = { 0 };
49  int instr = 0;
50  bool isarr = false;
51  if (!s) {
52  return NULL;
53  }
54  int arrpos = 0;
55  const char *os = s;
56  int osz = (1 + strlen(s)) * 20;
57  if (osz < 1) {
58  return NULL;
59  }
60 
61  const char *str_a = NULL;
62  for (; *s; s++) {
63  if (instr) {
64  if (s[0] == '"') {
65  instr = 0;
66  ut64 cur = str_a - os;
67  if (cur > pos) {
68  break;
69  }
70  if (indent < DSZ) {
71  words[indent - 1] = str_a;
72  lengths[indent - 1] = s - str_a;
73  indexs[indent - 1] = 0;
74  }
75  }
76  continue;
77  }
78 
79  if (s[0] == '"') {
80  instr = 1;
81  str_a = s + 1;
82  }
83  if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ') {
84  continue;
85  }
86  switch (*s) {
87  case ':':
88  break;
89  case ',':
90  if (isarr) {
91  arrpos++;
92  if (indent < DSZ) {
93  indexs[indent - 1] = arrpos;
94  lengths[indent - 1] = (s - os);
95  }
96  }
97  break;
98  case '{':
99  case '[':
100  if (*s == '[') {
101  isarr = true;
102  arrpos = 0;
103  }
104  if (indent > 128) {
105  eprintf("JSON indentation is too deep\n");
106  indent = 0;
107  } else {
108  indent++;
109  }
110  break;
111  case '}':
112  case ']':
113  if (*s == ']') {
114  isarr = false;
115  }
116  indent--;
117  break;
118  }
119  }
120  int i;
121  ut64 opos = 0;
122  for (i = 0; i < DSZ && i < indent; i++) {
123  if ((int)(size_t)words[i] < DSZ) {
124  ut64 cur = lengths[i];
125  if (cur < opos) {
126  continue;
127  }
128  opos = cur;
129  if (cur > pos) {
130  break;
131  }
132  eprintf("0x%08" PFMT64x " %d [%d]\n", cur, i, indexs[i]);
133  } else {
134  ut64 cur = words[i] - os - 1;
135  if (cur < opos) {
136  continue;
137  }
138  opos = cur;
139  if (cur > pos) {
140  break;
141  }
142  char *a = rz_str_ndup(words[i], lengths[i]);
143  char *q = strchr(a, '"');
144  if (q) {
145  *q = 0;
146  }
147  eprintf("0x%08" PFMT64x " %d %s\n", cur, i, a);
148  free(a);
149  }
150  }
151  // TODO return something
152  return NULL;
153 }
154 
155 RZ_API char *rz_print_json_human(const char *s) {
156  int indent = 0;
157  const char *tab = " ";
158  const int indentSize = strlen(tab);
159  int instr = 0;
160  char *o, *OE, *tmp;
161  if (!s) {
162  return NULL;
163  }
164  int osz = (1 + strlen(s)) * 20;
165  if (osz < 1) {
166  return NULL;
167  }
168 
169  char *O = malloc(osz);
170  if (!O) {
171  return NULL;
172  }
173  OE = O + osz;
174  for (o = O; *s; s++) {
175  if (o + (indent * indentSize) + 10 > OE) {
176  int delta = o - O;
177  osz += 0x1000 + (indent * indentSize);
178  if (osz < 1) {
179  free(O);
180  return NULL;
181  }
182  tmp = realloc(O, osz);
183  if (!tmp) {
184  free(O);
185  return NULL;
186  }
187  O = tmp;
188  OE = tmp + osz;
189  o = O + delta;
190  }
191  if (instr) {
192  if (s[0] == '"') {
193  instr = 0;
194  } else if (s[0] == '\\' && s[1] == '"') {
195  // XXX maybe buggy
196  *o++ = *s++;
197  }
198  if (*s != '"') {
199  *o++ = *s;
200  }
201  continue;
202  }
203  if (indent <= 0) {
204  // non-JSON part
205  if (s[0] != '{' && s[0] != '[') {
206  *o++ = *s;
207  continue;
208  }
209  }
210 
211  if (s[0] == '"') {
212  instr = 1;
213  }
214  if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ') {
215  continue;
216  }
217  switch (*s) {
218  case ':':
219  *o++ = *s;
220  *o++ = ' ';
221  break;
222  case ',':
223  *o++ = '\n';
224  doIndent(indent - 1, &o, tab);
225  break;
226  case '{':
227  case '[':
228  if (indent > 0) {
229  *o++ = (indent != -1) ? '\n' : ' ';
230  }
231  if (indent > 128) {
232  eprintf("JSON indentation is too deep\n");
233  indent = 0;
234  } else {
235  indent++;
236  }
237  doIndent(indent - 1, &o, tab);
238  break;
239  case '}':
240  case ']':
241  indent--;
242  doIndent(indent - 1, &o, tab);
243  break;
244  default:
245  if (!instr) {
246  *o++ = *s;
247  }
248  }
249  }
250  *o = 0;
251  return O;
252 }
253 
254 RZ_API char *rz_print_json_indent(const char *s, bool color, const char *tab, const char **palette) {
255  int indent = 0;
256  const int indentSize = strlen(tab);
257  int instr = 0;
258  bool isValue = false;
259  char *o, *OE, *tmp;
260  if (!s) {
261  return NULL;
262  }
263  const char **colors = palette ? palette : origColors;
264  int osz = (1 + strlen(s)) * 20;
265  if (osz < 1) {
266  return NULL;
267  }
268 
269  char *O = malloc(osz);
270  if (!O) {
271  return NULL;
272  }
273  OE = O + osz;
274  for (o = O; *s; s++) {
275  if (o + (indent * indentSize) + 10 > OE) {
276  int delta = o - O;
277  osz += 0x1000 + (indent * indentSize);
278  if (osz < 1) {
279  free(O);
280  return NULL;
281  }
282  tmp = realloc(O, osz);
283  if (!tmp) {
284  free(O);
285  return NULL;
286  }
287  O = tmp;
288  OE = tmp + osz;
289  o = O + delta;
290  }
291  if (instr) {
292  if (s[0] == '"') {
293  instr = 0;
294  } else if (s[0] == '\\' && s[1] == '"') {
295  *o++ = *s++;
296  }
297  if (instr) {
298  if (isValue) {
299  // TODO: do not emit color in every char
300  EMIT_ESC(o, colors[JC_VAL]);
301  } else {
302  EMIT_ESC(o, colors[JC_KEY]);
303  }
304  } else {
305  EMIT_ESC(o, colors[JC_RESET]);
306  }
307  *o++ = *s;
308  continue;
309  }
310  if (indent <= 0) {
311  // non-JSON part, skip it
312  if (s[0] != '{' && s[0] != '[') {
313  if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ') {
314  *o++ = *s;
315  }
316  continue;
317  }
318  }
319 
320  if (s[0] == '"') {
321  instr = 1;
322  }
323  if (*s == '\n' || *s == '\r' || *s == '\t' || *s == ' ' || !IS_PRINTABLE(*s)) {
324  continue;
325  }
326  switch (*s) {
327  case ':':
328  *o++ = *s;
329  *o++ = ' ';
330  s = rz_str_trim_head_ro(s + 1);
331  if (!strncmp(s, "true", 4)) {
332  EMIT_ESC(o, colors[JC_TRUE]);
333  } else if (!strncmp(s, "false", 5)) {
334  EMIT_ESC(o, colors[JC_FALSE]);
335  }
336  s--;
337  isValue = true;
338  break;
339  case ',':
340  EMIT_ESC(o, colors[JC_RESET]);
341  *o++ = *s;
342  *o++ = '\n';
343  isValue = false;
344  doIndent(indent, &o, tab);
345  break;
346  case '{':
347  case '[':
348  isValue = false;
349  *o++ = *s;
350  *o++ = (indent != -1) ? '\n' : ' ';
351  if (indent > 128) {
352  eprintf("JSON indentation is too deep\n");
353  indent = 0;
354  } else {
355  indent++;
356  }
357  doIndent(indent, &o, tab);
358  break;
359  case '}':
360  case ']':
361  EMIT_ESC(o, colors[JC_RESET]);
362  isValue = false;
363  *o++ = '\n';
364  indent--;
365  doIndent(indent, &o, tab);
366  *o++ = *s;
367  break;
368  default:
369  *o++ = *s;
370  }
371  }
372  *o = 0;
373  return O;
374 }
375 
376 #undef EMIT_ESC
lzma_index ** i
Definition: index.h:629
#define RZ_API
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
static void doIndent(int idt, char **o, const char *tab)
Definition: json_indent.c:6
RZ_API char * rz_print_json_indent(const char *s, bool color, const char *tab, const char **palette)
Definition: json_indent.c:254
RZ_API char * rz_print_json_path(const char *s, int pos)
Definition: json_indent.c:43
@ JC_FALSE
Definition: json_indent.c:27
@ JC_TRUE
Definition: json_indent.c:28
@ JC_KEY
Definition: json_indent.c:29
@ JC_RESET
Definition: json_indent.c:31
@ JC_VAL
Definition: json_indent.c:30
RZ_API char * rz_print_json_human(const char *s)
Definition: json_indent.c:155
#define DSZ
static const char * origColors[]
Definition: json_indent.c:34
#define EMIT_ESC(s, code)
Definition: json_indent.c:16
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
int x
Definition: mipsasm.c:20
struct @219 colors[]
#define O
Definition: rcond.c:14
#define eprintf(x, y...)
Definition: rlcc.c:7
static RzSocket * s
Definition: rtr.c:28
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
Definition: str.c:1006
RZ_API const char * rz_str_trim_head_ro(const char *str)
Definition: str_trim.c:86
#define IS_PRINTABLE(x)
Definition: rz_str_util.h:10
#define PFMT64x
Definition: rz_types.h:393
#define a(i)
Definition: sha256.c:41
Definition: enough.c:118
int pos
Definition: main.c:11
static int color
Definition: visual.c:20
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()