1 /* radare - LGPL - Copyright 2007-2020 - pancake */
2 
3 #include <r_util/r_print.h>
4 #include <r_anal.h>
5 
6 #define DFLT_ROWS 16
7 
8 static const char hex[16] = "0123456789ABCDEF";
9 
nullprinter(const char * a,...)10 static int nullprinter(const char *a, ...) {
11 	return 0;
12 }
13 
libc_printf(const char * format,...)14 static int libc_printf(const char *format, ...) {
15 	va_list ap;
16 	va_start (ap, format);
17 	vprintf (format, ap);
18 	va_end (ap);
19 	return 0;
20 }
21 
libc_eprintf(const char * format,...)22 static int libc_eprintf(const char *format, ...) {
23 	va_list ap;
24 	va_start (ap, format);
25 	vfprintf (stderr, format, ap);
26 	va_end (ap);
27 	return 0;
28 }
29 
30 static RPrintIsInterruptedCallback is_interrupted_cb = NULL;
31 
r_print_portionbar(RPrint * p,const ut64 * portions,int n_portions)32 R_API void r_print_portionbar(RPrint *p, const ut64 *portions, int n_portions) {
33 	const int use_color = p->flags & R_PRINT_FLAGS_COLOR;
34 	int i, j;
35 	ut64 total = 0LL;
36 	for (i = 0; i < n_portions; i++) {
37 		ut64 sum = total + portions[i];
38 		if (total > sum) {
39 			eprintf ("portionbar overflow aborted\n");
40 			return;
41 		}
42 		total = sum;
43 	}
44 	p->cb_printf ("[");
45 	if (total == 0) {
46 		total = 1;
47 	}
48 	for (i = 0; i < n_portions; i++) {
49 		int pc = portions[i] * 100 / total;
50 		// adjust pc to screen columns
51 		pc = pc * p->width / 100;
52 		if (use_color) {
53 			p->cb_printf ("\x1b[%dm", 31 + (i % 8));
54 		}
55 		if (pc == 0) {
56 			pc = 1;
57 		}
58 		for (j = 0; j < pc; j++) {
59 			p->cb_printf ("%c", 'A'+ i);
60 		}
61 		if (use_color) {
62 			p->cb_printf (Color_RESET);
63 		}
64 	}
65 	p->cb_printf ("]\n");
66 }
67 
r_print_columns(RPrint * p,const ut8 * buf,int len,int height)68 R_API void r_print_columns(RPrint *p, const ut8 *buf, int len, int height) {
69 #define cb_print(x) p->cb_printf("%s", x)
70 	size_t i, j;
71 	int cols = 78; // TODO: do not hardcode this value, columns should be defined by the user
72 	int rows = height > 0 ? height : 10;
73 	// int realrows = rows * 2;
74 	bool colors = p->flags & R_PRINT_FLAGS_COLOR;
75 	RConsPrintablePalette *pal = &p->cons->context->pal;
76 	const char *vline = p->cons->use_utf8 ? RUNE_LINE_VERT : "|";
77 	const char *block = p->cons->use_utf8 ? UTF_BLOCK : "#";
78 	const char *kol[5];
79 	kol[0] = pal->call;
80 	kol[1] = pal->jmp;
81 	kol[2] = pal->cjmp;
82 	kol[3] = pal->mov;
83 	kol[4] = pal->nop;
84 	if (colors) {
85 		for (i = 0; i < rows; i++) {
86 			size_t threshold = i * (0xff / rows);
87 			size_t koli = i * 5 / rows;
88 			for (j = 0; j < cols; j++) {
89 				int realJ = j * len / cols;
90 	 			if (255 - buf[realJ] < threshold || (i + 1 == rows)) {
91 					if (p->histblock) {
92 						p->cb_printf ("%s%s%s", kol[koli], block, Color_RESET);
93 					} else {
94 						p->cb_printf ("%s%s%s", kol[koli], vline, Color_RESET);
95 					}
96 				} else {
97 					cb_print (" ");
98 				}
99 			}
100 			cb_print ("\n");
101 		}
102 		return;
103 	}
104 
105 	for (i = 0; i < rows; i++) {
106 		size_t threshold = i * (0xff / rows);
107 		for (j = 0; j < cols; j++) {
108 			size_t realJ = j * len / cols;
109 			if (255 - buf[realJ] < threshold) {
110 				if (p->histblock) {
111 					p->cb_printf ("%s%s%s", Color_BGGRAY, block, Color_RESET);
112 				} else {
113 					cb_print (vline);
114 				}
115 			} else if (i + 1 == rows) {
116 				cb_print ("_");
117 			} else {
118 				cb_print (" ");
119 			}
120 		}
121 		cb_print ("\n");
122 	}
123 }
124 
r_util_lines_getline(ut64 * lines_cache,int lines_cache_sz,ut64 off)125 R_API int r_util_lines_getline(ut64 *lines_cache, int lines_cache_sz, ut64 off) {
126 	int imax = lines_cache_sz;
127 	int imin = 0;
128 	int imid = 0;
129 
130 	while (imin <= imax) {
131 		imid = imin + ((imax - imin) / 2);
132 		if (lines_cache[imid] == off) {
133 			return imid + 1;
134 		}
135 		if (lines_cache[imid] < off) {
136 			imin = imid + 1;
137 		} else {
138 			imax = imid - 1;
139 		}
140 	}
141 	return imin;
142 }
143 
r_print_is_interrupted(void)144 R_API bool r_print_is_interrupted(void) {
145 	if (is_interrupted_cb) {
146 		return is_interrupted_cb ();
147 	}
148 	return false;
149 }
150 
r_print_set_is_interrupted_cb(RPrintIsInterruptedCallback cb)151 R_API void r_print_set_is_interrupted_cb(RPrintIsInterruptedCallback cb) {
152 	is_interrupted_cb = cb;
153 }
154 
r_print_mute(RPrint * p,int x)155 R_API bool r_print_mute(RPrint *p, int x) {
156 	if (x) {
157 		if (p->cb_printf == &nullprinter) {
158 			return false;
159 		}
160 		p->oprintf = p->cb_printf;
161 		p->cb_printf = nullprinter;
162 		return true;
163 	}
164 	if (p->cb_printf == nullprinter) {
165 		p->cb_printf = p->oprintf;
166 		return true;
167 	}
168 	return false;
169 }
170 
r_print_stereogram_private(const char * bump,int w,int h,char * out,int size)171 static int r_print_stereogram_private(const char *bump, int w, int h, char *out, int size) {
172 	static char data[32768]; // ???
173 	const char *string = "Az+|.-=/^@_pT";
174 	const int string_len = strlen (string);
175 
176 	int x, y, s, l = 0, l2 = 0, ch;
177 	int skip = 7;
178 	int bumpi = 0, outi = 0;
179 	if (!bump || !out) {
180 		return 0;
181 	}
182 	for (y = 0; bump[bumpi] && outi < size; y++) {
183 		l = l2 = 0;
184 		for (x = 0; bump[bumpi] && outi < size && x < w; x++) {
185 			ch = string[x % string_len];
186 			if (!l && x > skip) {
187 				s = bump[bumpi++];
188 				if (s >= '0' && s <= '9') {
189 					s = '0' - s;
190 				} else {
191 					switch (s) {
192 					case 0:
193 						bumpi--;
194 					/* passthru */
195 					case '\n':
196 						s = 0;
197 						l = 1;
198 						break;
199 					case ' ':
200 						s = 0;
201 						break;
202 					default:
203 						s = -2;
204 						break;
205 					}
206 				}
207 			} else {
208 				s = 0;
209 			}
210 			s += skip;
211 			s = x - s;
212 			if (s >= 0) {
213 				ch = data[s];
214 			}
215 			if (!ch) {
216 				ch = *string;
217 			}
218 			data[x] = ch;
219 			if (outi >= size) {
220 				break;
221 			}
222 			out[outi++] = ch;
223 		}
224 		out[outi++] = '\n';
225 		s = 'a';
226 		while (!l && s != '\n') {
227 			s = bump[bumpi++];
228 			if (!s) {
229 				bumpi--;
230 				break;
231 			}
232 		}
233 	}
234 	out[outi] = 0;
235 	return 1;
236 }
237 
r_print_stereogram(const char * bump,int w,int h)238 R_API char* r_print_stereogram(const char *bump, int w, int h) {
239 	if (w < 1 || h < 1) {
240 		return NULL;
241 	}
242 	ut64 size = w * (ut64) h * 2;
243 	if (size > UT32_MAX) {
244 		return NULL;
245 	}
246 	char *out = calloc (1, size * 2);
247 	if (!out) {
248 		return NULL;
249 	}
250 	//eprintf ("%s\n", bump);
251 	(void) r_print_stereogram_private (bump, w, h, out, size);
252 	return out;
253 }
254 
255 #define STEREOGRAM_IN_COLOR 1
r_print_stereogram_bytes(const ut8 * buf,int len)256 R_API char* r_print_stereogram_bytes(const ut8 *buf, int len) {
257 	int i, bumpi;
258 	char *ret;
259 	int scr_width = 80;
260 	if (!buf || len < 1) {
261 		return NULL;
262 	}
263 	//scr_width = r_cons_get_size (NULL) -10;
264 	int cols = scr_width;
265 	int rows = len / cols;
266 
267 	int size = (2 + cols) * rows;
268 	char *bump = malloc (size + 1); //(cols+2) * rows);
269 	if (!bump) {
270 		return NULL;
271 	}
272 	for (i = bumpi = 0; bumpi < size && i < len; i++) {
273 		int v = buf[i] / 26;
274 		if (i && !(i % scr_width)) {
275 			bump[bumpi++] = '\n';
276 		}
277 		bump[bumpi++] = '0' + v;
278 	}
279 	bump[bumpi] = 0;
280 	ret = r_print_stereogram (bump, cols, rows);
281 	free (bump);
282 	return ret;
283 }
284 
r_print_stereogram_print(RPrint * p,const char * ret)285 R_API void r_print_stereogram_print(RPrint *p, const char *ret) {
286 	int i;
287 	const int use_color = p->flags & R_PRINT_FLAGS_COLOR;
288 	if (!ret) {
289 		return;
290 	}
291 	if (use_color) {
292 		for (i = 0; ret[i]; i++) {
293 			p->cb_printf ("\x1b[%dm%c", 30 + (ret[i] % 8), ret[i]);
294 		}
295 		p->cb_printf ("\x1b[0m\n");
296 	} else {
297 		p->cb_printf ("%s\n", ret);
298 	}
299 }
300 
r_print_new(void)301 R_API RPrint* r_print_new(void) {
302 	RPrint *p = R_NEW0 (RPrint);
303 	if (!p) {
304 		return NULL;
305 	}
306 	strcpy (p->datefmt, "%Y-%m-%d %H:%M:%S %z");
307 	r_io_bind_init (p->iob);
308 	p->pairs = true;
309 	p->resetbg = true;
310 	p->cb_printf = libc_printf;
311 	p->cb_eprintf = libc_eprintf;
312 	p->oprintf = nullprinter;
313 	p->bits = 32;
314 	p->stride = 0;
315 	p->bytespace = 0;
316 	p->big_endian = false;
317 	p->datezone = 0;
318 	p->col = 0;
319 	p->width = 78;
320 	p->cols = 16;
321 	p->cur_enabled = false;
322 	p->cur = p->ocur = -1;
323 	p->formats = sdb_new0 ();
324 	p->addrmod = 4;
325 	p->flags =
326 		R_PRINT_FLAGS_COLOR |
327 		R_PRINT_FLAGS_OFFSET |
328 		R_PRINT_FLAGS_HEADER |
329 		R_PRINT_FLAGS_ADDRMOD;
330 	p->seggrn = 4;
331 	p->zoom = R_NEW0 (RPrintZoom);
332 	p->reg = NULL;
333 	p->get_register = NULL;
334 	p->get_register_value = NULL;
335 	p->lines_cache = NULL;
336 	p->calc_row_offsets = true;
337 	p->row_offsets_sz = 0;
338 	p->row_offsets = NULL;
339 	p->vflush = true;
340 	p->screen_bounds = 0;
341 	p->esc_bslash = false;
342 	p->strconv_mode = NULL;
343 	memset (&p->consbind, 0, sizeof (p->consbind));
344 	p->io_unalloc_ch = '.';
345 	p->enable_progressbar = true;
346 	p->charset = r_charset_new ();
347 	return p;
348 }
349 
r_print_free(RPrint * p)350 R_API RPrint* r_print_free(RPrint *p) {
351 	if (!p) {
352 		return NULL;
353 	}
354 	sdb_free (p->formats);
355 	p->formats = NULL;
356 	R_FREE (p->strconv_mode);
357 	if (p->zoom) {
358 		free (p->zoom->buf);
359 		free (p->zoom);
360 		p->zoom = NULL;
361 	}
362 	R_FREE (p->lines_cache);
363 	R_FREE (p->row_offsets);
364 	r_charset_free (p->charset);
365 	free (p);
366 	return NULL;
367 }
368 
369 // dummy setter can be removed
r_print_set_flags(RPrint * p,int _flags)370 R_API void r_print_set_flags(RPrint *p, int _flags) {
371 	p->flags = _flags;
372 }
373 
r_print_unset_flags(RPrint * p,int flags)374 R_API void r_print_unset_flags(RPrint *p, int flags) {
375 	p->flags = p->flags & (p->flags ^ flags);
376 }
377 
r_print_set_cursor(RPrint * p,int enable,int ocursor,int cursor)378 R_API void r_print_set_cursor(RPrint *p, int enable, int ocursor, int cursor) {
379 	if (!p) {
380 		return;
381 	}
382 	p->cur_enabled = enable;
383 	p->ocur = ocursor;
384 	if (cursor < 0) {
385 		cursor = 0;
386 	}
387 	p->cur = cursor;
388 }
389 
r_print_have_cursor(RPrint * p,int cur,int len)390 R_API bool r_print_have_cursor(RPrint *p, int cur, int len) {
391 	if (!p || !p->cur_enabled) {
392 		return false;
393 	}
394 	if (p->ocur != -1) {
395 		int from = p->ocur;
396 		int to = p->cur;
397 		r_num_minmax_swap_i (&from, &to);
398 		do {
399 			if (cur + len - 1 >= from && cur + len - 1 <= to) {
400 				return true;
401 			}
402 		} while (--len);
403 	} else if (p->cur >= cur && p->cur <= cur + len - 1) {
404 		return true;
405 	}
406 	return false;
407 }
408 
r_print_cursor_pointer(RPrint * p,int cur,int len)409 R_API bool r_print_cursor_pointer(RPrint *p, int cur, int len) {
410 	r_return_val_if_fail (p, false);
411 	if (!p->cur_enabled) {
412 		return false;
413 	}
414 	int to = p->cur;
415 	do {
416 		if (cur + len - 1 == to) {
417 			return true;
418 		}
419 	} while (--len);
420 	return false;
421 }
422 
r_print_cursor(RPrint * p,int cur,int len,int set)423 R_API void r_print_cursor(RPrint *p, int cur, int len, int set) {
424 	if (r_print_have_cursor (p, cur, len)) {
425 		p->cb_printf ("%s", R_CONS_INVERT (set, 1));
426 	}
427 }
428 
r_print_addr(RPrint * p,ut64 addr)429 R_API void r_print_addr(RPrint *p, ut64 addr) {
430 	char space[32] = {
431 		0
432 	};
433 	const char *white = "";
434 #define PREOFF(x) (p && p->cons && p->cons->context && p->cons->context->pal.x)? p->cons->context->pal.x
435 	PrintfCallback printfmt = (PrintfCallback) (p? p->cb_printf: libc_printf);
436 #define print(x) printfmt("%s", x)
437 	bool use_segoff = p? (p->flags & R_PRINT_FLAGS_SEGOFF): false;
438 	bool use_color = p? (p->flags & R_PRINT_FLAGS_COLOR): false;
439 	bool dec = p? (p->flags & R_PRINT_FLAGS_ADDRDEC): false;
440 	bool mod = p? (p->flags & R_PRINT_FLAGS_ADDRMOD): false;
441 	char ch = p? ((p->addrmod && mod)? ((addr % p->addrmod)? ' ': ','): ' '): ' ';
442 	if (p && p->flags & R_PRINT_FLAGS_COMPACT && p->col == 1) {
443 		ch = '|';
444 	}
445 	if (p && p->pava) {
446 		ut64 va = p->iob.p2v (p->iob.io, addr);
447 		if (va != UT64_MAX) {
448 			addr = va;
449 		}
450 	}
451 	if (use_segoff) {
452 		ut32 s, a;
453 		a = addr & 0xffff;
454 		s = (addr - a) >> (p? p->seggrn: 0);
455 		if (dec) {
456 			snprintf (space, sizeof (space), "%d:%d", s & 0xffff, a & 0xffff);
457 			white = r_str_pad (' ', 9 - strlen (space));
458 		}
459 		if (use_color) {
460 			const char *pre = PREOFF (offset): Color_GREEN;
461 			const char *fin = Color_RESET;
462 			if (dec) {
463 				printfmt ("%s%s%s%s%c", pre, white, space, fin, ch);
464 			} else {
465 				printfmt ("%s%04x:%04x%s%c", pre, s & 0xffff, a & 0xffff, fin, ch);
466 			}
467 		} else {
468 			if (dec) {
469 				printfmt ("%s%s%c", white, space, ch);
470 			} else {
471 				printfmt ("%04x:%04x%c", s & 0xffff, a & 0xffff, ch);
472 			}
473 		}
474 	} else {
475 		if (dec) {
476 			snprintf (space, sizeof (space), "%" PFMT64d, addr);
477 			int w = R_MAX (10 - strlen (space), 0);
478 			white = r_str_pad (' ', w);
479 		}
480 		if (use_color) {
481 			const char *pre = PREOFF (offset): Color_GREEN;
482 			const char *fin = Color_RESET;
483 			if (p && p->flags & R_PRINT_FLAGS_RAINBOW) {
484 				// pre = r_cons_rgb_str_off (rgbstr, addr);
485 				if (p->cons && p->cons->rgbstr) {
486 					static char rgbstr[32];
487 					pre = p->cons->rgbstr (rgbstr, sizeof (rgbstr), addr);
488 				}
489 			}
490 			if (dec) {
491 				printfmt ("%s%s%" PFMT64d "%s%c", pre, white, addr, fin, ch);
492 			} else {
493 				if (p && p->wide_offsets) {
494 					// TODO: make %016 depend on asm.bits
495 					printfmt ("%s0x%016" PFMT64x "%s%c", pre, addr, fin, ch);
496 				} else {
497 					printfmt ("%s0x%08" PFMT64x "%s%c", pre, addr, fin, ch);
498 				}
499 			}
500 		} else {
501 			if (dec) {
502 				printfmt ("%s%" PFMT64d "%c", white, addr, ch);
503 			} else {
504 				if (p && p->wide_offsets) {
505 					// TODO: make %016 depend on asm.bits
506 					printfmt ("0x%016" PFMT64x "%c", addr, ch);
507 				} else {
508 					printfmt ("0x%08" PFMT64x "%c", addr, ch);
509 				}
510 			}
511 		}
512 	}
513 }
514 
r_print_hexpair(RPrint * p,const char * str,int n)515 R_API char* r_print_hexpair(RPrint *p, const char *str, int n) {
516 	const char *s, *lastcol = Color_WHITE;
517 	char *d, *dst = (char *) calloc ((strlen (str) + 2), 32);
518 	int colors = p->flags & R_PRINT_FLAGS_COLOR;
519 	const char *color_0x00 = "";
520 	const char *color_0x7f = "";
521 	const char *color_0xff = "";
522 	const char *color_text = "";
523 	const char *color_other = "";
524 	int bs = p->bytespace;
525 	/* XXX That's hacky as shit.. but partially works O:) */
526 	/* TODO: Use r_print_set_cursor for win support */
527 	int cur = R_MIN (p->cur, p->ocur);
528 	int ocur = R_MAX (p->cur, p->ocur);
529 	int ch, i;
530 
531 	if (colors) {
532 #define P(x) (p->cons && p->cons->context->pal.x)? p->cons->context->pal.x
533 		color_0x00 = P (b0x00): Color_GREEN;
534 		color_0x7f = P (b0x7f): Color_YELLOW;
535 		color_0xff = P (b0xff): Color_RED;
536 		color_text = P (btext): Color_MAGENTA;
537 		color_other = P (other): "";
538 	}
539 	if (p->cur_enabled && cur == -1) {
540 		cur = ocur;
541 	}
542 	ocur++;
543 	d = dst;
544 // XXX: overflow here
545 // TODO: Use r_cons primitives here
546 #define memcat(x, y)\
547 	{ \
548 		memcpy (x, y, strlen (y));\
549 		(x) += strlen (y);\
550 	}
551 	for (s = str, i = 0; s[0]; i++) {
552 		int d_inc = 2;
553 		if (p->cur_enabled) {
554 			if (i == ocur - n) {
555 				memcat (d, Color_RESET);
556 			}
557 			if (colors) {
558 				memcat (d, lastcol);
559 			}
560 			if (i >= cur - n && i < ocur - n) {
561 				memcat (d, Color_INVERT);
562 			}
563 		}
564 		if (colors) {
565 			if (s[0] == '0' && s[1] == '0') {
566 				lastcol = color_0x00;
567 			} else if (s[0] == '7' && s[1] == 'f') {
568 				lastcol = color_0x7f;
569 			} else if (s[0] == 'f' && s[1] == 'f') {
570 				lastcol = color_0xff;
571 			} else {
572 				ch = r_hex_pair2bin (s);
573 				if (ch == -1) {
574 					break;
575 				}
576 				if (IS_PRINTABLE (ch)) {
577 					lastcol = color_text;
578 				} else {
579 					lastcol = color_other;
580 				}
581 			}
582 			memcat (d, lastcol);
583 		}
584 		if (s[0] == '.') {
585 			d_inc = 1;
586 		}
587 		memcpy (d, s, d_inc);
588 		d += d_inc;
589 		s += d_inc;
590 		if (bs) {
591 			memcat (d, " ");
592 		}
593 	}
594 	if (colors || p->cur_enabled) {
595 		if (p->resetbg) {
596 			memcat (d, Color_RESET);
597 		} else {
598 			memcat (d, Color_RESET_NOBG);
599 		}
600 	}
601 	*d = '\0';
602 	return dst;
603 }
604 
605 static char colorbuffer[64];
606 #define P(x) (p->cons && p->cons->context->pal.x)? p->cons->context->pal.x
r_print_byte_color(RPrint * p,int ch)607 R_API const char *r_print_byte_color(RPrint *p, int ch) {
608 	if (p->flags & R_PRINT_FLAGS_RAINBOW) {
609 		// EXPERIMENTAL
610 		int bg = (p->flags & R_PRINT_FLAGS_NONHEX)? 48: 38;
611 		snprintf (colorbuffer, sizeof (colorbuffer), "\033[%d;5;%dm", bg, ch);
612 		return colorbuffer;
613 	}
614 	const bool use_color = p->flags & R_PRINT_FLAGS_COLOR;
615 	if (!use_color) {
616 		return NULL;
617 	}
618 	switch (ch) {
619 	case 0x00: return P (b0x00): Color_GREEN;
620 	case 0x7F: return P (b0x7f): Color_YELLOW;
621 	case 0xFF: return P (b0xff): Color_RED;
622 	default: return IS_PRINTABLE (ch)? P (btext): Color_MAGENTA: P (other): Color_WHITE;
623 	}
624 	return NULL;
625 }
626 
r_print_byte(RPrint * p,const char * fmt,int idx,ut8 ch)627 R_API void r_print_byte(RPrint *p, const char *fmt, int idx, ut8 ch) {
628 	PrintfCallback printfmt = (PrintfCallback) (p? p->cb_printf: libc_printf);
629 	#define print(x) printfmt("%s", x)
630 	ut8 rch = ch;
631 	if (!IS_PRINTABLE (ch) && fmt[0] == '%' && fmt[1] == 'c') {
632 		rch = '.';
633 	}
634 	r_print_cursor (p, idx, 1, 1);
635 	if (p && p->flags & R_PRINT_FLAGS_COLOR) {
636 		const char *bytecolor = r_print_byte_color (p, ch);
637 		if (bytecolor) {
638 			print ( bytecolor);
639 		}
640 		printfmt (fmt, rch);
641 		if (bytecolor) {
642 			print (Color_RESET);
643 		}
644 	} else {
645 		printfmt (fmt, rch);
646 	}
647 	r_print_cursor (p, idx, 1, 0);
648 }
649 
r_print_string(RPrint * p,ut64 seek,const ut8 * buf,int len,int options)650 R_API int r_print_string(RPrint *p, ut64 seek, const ut8 *buf, int len, int options) {
651 	int i;
652 	bool wide = (options & R_PRINT_STRING_WIDE);
653 	bool wide32 = (options & R_PRINT_STRING_WIDE32);
654 	bool zeroend = (options & R_PRINT_STRING_ZEROEND);
655 	bool wrap = (options & R_PRINT_STRING_WRAP);
656 	bool urlencode = (options & R_PRINT_STRING_URLENCODE);
657 	bool esc_nl = (options & R_PRINT_STRING_ESC_NL);
658 	int col = 0;
659 	i = 0;
660 	for (; !r_print_is_interrupted () && i < len; i++) {
661 		if (wide32) {
662 			int j = i;
663 			while (buf[j] == '\0' && j < (i + 3)) {
664 				j++;
665 			}
666 			i = j;
667 		}
668 		if (zeroend && buf[i] == '\0') {
669 			break;
670 		}
671 		r_print_cursor (p, i, 1, 1);
672 		ut8 b = buf[i];
673 		if (b == '\n') {
674 			col = 0;
675 		}
676 		col++;
677 		if (urlencode) {
678 			// TODO: some ascii can be bypassed here
679 			p->cb_printf ("%%%02x", b);
680 		} else {
681 			if (b == '\\') {
682 				p->cb_printf ("\\\\");
683 			} else if ((b == '\n' && !esc_nl) || IS_PRINTABLE (b)) {
684 				p->cb_printf ("%c", b);
685 			} else {
686 				p->cb_printf ("\\x%02x", b);
687 			}
688 		}
689 		r_print_cursor (p, i, 1, 0);
690 		if (wrap && col + 1 >= p->width) {
691 			p->cb_printf ("\n");
692 			col = 0;
693 		}
694 		if (wide) {
695 			i++;
696 		}
697 	}
698 	p->cb_printf ("\n");
699 	return i;
700 }
701 
r_print_hexpairs(RPrint * p,ut64 addr,const ut8 * buf,int len)702 R_API void r_print_hexpairs(RPrint *p, ut64 addr, const ut8 *buf, int len) {
703 	int i;
704 	for (i = 0; i < len; i++) {
705 		p->cb_printf ("%02x ", buf[i]);
706 	}
707 }
708 
checkSparse(const ut8 * p,int len,int ch)709 static bool checkSparse(const ut8 *p, int len, int ch) {
710 	int i;
711 	ut8 q = *p;
712 	if (ch && ch != q) {
713 		return false;
714 	}
715 	for (i = 1; i < len; i++) {
716 		if (p[i] != q) {
717 			return false;
718 		}
719 	}
720 	return true;
721 }
722 
isAllZeros(const ut8 * buf,int len)723 static bool isAllZeros(const ut8 *buf, int len) {
724 	int i;
725 	for (i = 0; i < len; i++) {
726 		if (buf[i] != 0) {
727 			return false;
728 		}
729 	}
730 	return true;
731 }
732 
733 #define Pal(x,y) (x->cons && x->cons->context->pal.y)? x->cons->context->pal.y
r_print_hexii(RPrint * rp,ut64 addr,const ut8 * buf,int len,int step)734 R_API void r_print_hexii(RPrint *rp, ut64 addr, const ut8 *buf, int len, int step) {
735 	PrintfCallback p = (PrintfCallback) rp->cb_printf;
736 	bool c = rp->flags & R_PRINT_FLAGS_COLOR;
737 	const char *color_0xff = c? (Pal (rp, b0xff): Color_RED): "";
738 	const char *color_text = c? (Pal (rp, btext): Color_MAGENTA): "";
739 	const char *color_other = c? (Pal (rp, other): Color_WHITE): "";
740 	const char *color_reset = c? Color_RESET: "";
741 	int i, j;
742 	bool show_offset = rp->show_offset;
743 
744 	if (rp->flags & R_PRINT_FLAGS_HEADER) {
745 		p ("         ");
746 		for (i = 0; i < step; i++) {
747 			p ("%3X", i);
748 		}
749 		p ("\n");
750 	}
751 
752 	for (i = 0; i < len; i += step) {
753 		int inc = R_MIN (step, (len - i));
754 		if (isAllZeros (buf + i, inc)) {
755 			continue;
756 		}
757 		if (show_offset) {
758 			p ("%8"PFMT64x":", addr + i);
759 		}
760 		for (j = 0; j < inc; j++) {
761 			ut8 ch = buf[i + j];
762 			if (ch == 0x00) {
763 				p ("   ");
764 			} else if (ch == 0xff) {
765 				p ("%s ##%s", color_0xff, color_reset);
766 			} else if (IS_PRINTABLE (ch)) {
767 				p ("%s .%c%s", color_text, ch, color_reset);
768 			} else {
769 				p ("%s %02x%s", color_other, ch, color_reset);
770 			}
771 		}
772 		p ("\n");
773 	}
774 	p ("%8"PFMT64x" ]\n", addr + i);
775 }
776 
777 /* set screen_bounds to addr if the cursor is not visible on the screen anymore.
778  * Note: screen_bounds is set only the first time this happens. */
r_print_set_screenbounds(RPrint * p,ut64 addr)779 R_API void r_print_set_screenbounds(RPrint *p, ut64 addr) {
780 	int r, rc;
781 
782 	r_return_if_fail (p);
783 
784 	if (!p->screen_bounds) {
785 		return;
786 	}
787 	if (!p->consbind.get_size) {
788 		return;
789 	}
790 	if (!p->consbind.get_cursor) {
791 		return;
792 	}
793 
794 	if (p->screen_bounds == 1) {
795 		(void)p->consbind.get_size (&r);
796 		(void)p->consbind.get_cursor (&rc);
797 
798 		if (rc > r - 1) {
799 			p->screen_bounds = addr;
800 		}
801 	}
802 }
803 
r_print_section(RPrint * p,ut64 at)804 R_API void r_print_section(RPrint *p, ut64 at) {
805 	bool use_section = p && p->flags & R_PRINT_FLAGS_SECTION;
806 	if (use_section) {
807 		const char *s = p->get_section_name (p->user, at);
808 		if (!s) {
809 			s = "";
810 		}
811 		char *tail = r_str_ndup (s, 19);
812 		p->cb_printf ("%20s ", tail);
813 		free (tail);
814 	}
815 }
816 
r_print_hexdump(RPrint * p,ut64 addr,const ut8 * buf,int len,int base,int step,size_t zoomsz)817 R_API void r_print_hexdump(RPrint *p, ut64 addr, const ut8 *buf, int len, int base, int step, size_t zoomsz) {
818 	PrintfCallback printfmt = (PrintfCallback)printf;
819 #define print(x) printfmt("%s", x)
820 	bool c = p? (p->flags & R_PRINT_FLAGS_COLOR): false;
821 	const char *color_title = c? (Pal (p, offset): Color_MAGENTA): "";
822 	int inc = p? p->cols : 16;
823 	size_t i, j, k;
824 	int sparse_char = 0;
825 	int stride = 0;
826 	int col = 0; // selected column (0=none, 1=hex, 2=ascii)
827 	int use_sparse = 0;
828 	bool use_header = true;
829 	bool use_hdroff = true;
830 	bool use_pair = true;
831 	bool use_offset = true;
832 	bool compact = false;
833 	bool use_segoff = false;
834 	bool pairs = false;
835 	const char *bytefmt = "%02x";
836 	const char *pre = "";
837 	int last_sparse = 0;
838 	bool use_hexa = true;
839 	bool use_align = false;
840 	bool use_unalloc = false;
841 	const char *a, *b;
842 	int K = 0;
843 	bool hex_style = false;
844 	if (step < len) {
845 		len = len - (len % step);
846 	}
847 	if (p) {
848 		pairs = p->pairs;
849 		use_sparse = p->flags & R_PRINT_FLAGS_SPARSE;
850 		use_header = p->flags & R_PRINT_FLAGS_HEADER;
851 		use_hdroff = p->flags & R_PRINT_FLAGS_HDROFF;
852 		use_segoff = p->flags & R_PRINT_FLAGS_SEGOFF;
853 		use_align = p->flags & R_PRINT_FLAGS_ALIGN;
854 		use_offset = p->flags & R_PRINT_FLAGS_OFFSET;
855 		hex_style = p->flags & R_PRINT_FLAGS_STYLE;
856 		use_hexa = !(p->flags & R_PRINT_FLAGS_NONHEX);
857 		use_unalloc = p->flags & R_PRINT_FLAGS_UNALLOC;
858 		compact = p->flags & R_PRINT_FLAGS_COMPACT;
859 		inc = p->cols; // row width
860 		col = p->col;
861 		printfmt = (PrintfCallback) p->cb_printf;
862 		stride = p->stride;
863 	}
864 	if (!use_hexa) {
865 		inc *= 4;
866 	}
867 	if (step < 1) {
868 		step = 1;
869 	}
870 	if (inc < 1) {
871 		inc = 1;
872 	}
873 	if (zoomsz < 1) {
874 		zoomsz = 1;
875 	}
876 	switch (base) {
877 	case -10:
878 		bytefmt = "0x%08x ";
879 		pre = " ";
880 		if (inc < 4) {
881 			inc = 4;
882 		}
883 		break;
884 	case -1:
885 		bytefmt = "0x%08x ";
886 		pre = "  ";
887 		if (inc < 4) {
888 			inc = 4;
889 		}
890 		break;
891 	case 8:
892 		bytefmt = "%03o";
893 		pre = " ";
894 		break;
895 	case 10:
896 		bytefmt = "%3d";
897 		pre = " ";
898 		break;
899 	case 16:
900 		if (inc < 2) {
901 			inc = 2;
902 			use_header = false;
903 		}
904 		break;
905 	case 32:
906 		bytefmt = "0x%08x ";
907 		pre = " ";
908 		if (inc < 4) {
909 			inc = 4;
910 		}
911 		break;
912 	case 64:
913 		bytefmt = "0x%016x ";
914 		pre = " ";
915 		if (inc < 8) {
916 			inc = 8;
917 		}
918 		break;
919 	}
920 	const char *space = hex_style? ".": " ";
921 	// TODO: Use base to change %03o and so on
922 	if (step == 1 && base < 0) {
923 		use_header = false;
924 	}
925 	if (use_header) {
926 		if (c) {
927 			print (color_title);
928 		}
929 		if (base < 32) {
930 			{ // XXX: use r_print_addr_header
931 				int i, delta;
932 				char soff[32];
933 				if (hex_style) {
934 					print ("..offset..");
935 				} else {
936 					print ("- offset -");
937 					if (p->wide_offsets) {
938 						print ("       ");
939 					}
940 				}
941 				if (use_segoff) {
942 					ut32 s, a;
943 					a = addr & 0xffff;
944 					s = ((addr - a) >> p->seggrn) & 0xffff;
945 					snprintf (soff, sizeof (soff), "%04x:%04x ", s, a);
946 					delta = strlen (soff) - 10;
947 				} else {
948 					snprintf (soff, sizeof (soff), "0x%08" PFMT64x, addr);
949 					delta = strlen (soff) - 9;
950 				}
951 				if (compact) {
952 					delta--;
953 				}
954 				for (i = 0; i < delta; i++) {
955 					print (space);
956 				}
957 			}
958 			/* column after number, before hex data */
959 			print ((col == 1)? "|": space);
960 			if (use_hdroff)  {
961 				k = addr & 0xf;
962 				K = (addr >> 4) & 0xf;
963 			} else {
964 				k = 0; // TODO: ??? SURE??? config.seek & 0xF;
965 			}
966 			if (use_hexa) {
967 				/* extra padding for offsets > 8 digits */
968 				for (i = 0; i < inc; i++) {
969 					print (pre);
970 					if (base < 0) {
971 						if (i & 1) {
972 							print (space);
973 						}
974 					}
975 					if  (use_hdroff) {
976 						if (use_pair) {
977 							printfmt ("%c%c",
978 									hex[(((i+k) >> 4) + K) % 16],
979 									hex[(i + k) % 16]);
980 						} else {
981 							printfmt (" %c", hex[(i + k) % 16]);
982 						}
983 					} else {
984 						printfmt (" %c", hex[(i + k) % 16]);
985 					}
986 					if (i & 1 || !pairs) {
987 						if (!compact) {
988 							print (col != 1? space: ((i + 1) < inc)? space: "|");
989 						}
990 					}
991 				}
992 			}
993 			/* ascii column */
994 			if (compact) {
995 				print (col > 0? "|": space);
996 			} else {
997 				print (col == 2? "|": space);
998 			}
999 			if (!p || !(p->flags & R_PRINT_FLAGS_NONASCII)) {
1000 				for (i = 0; i < inc; i++) {
1001 					printfmt ("%c", hex[(i + k) % 16]);
1002 				}
1003 			}
1004 			if (col == 2) {
1005 				printfmt ("|");
1006 			}
1007 			/* print comment header*/
1008 			if (p && p->use_comments && !compact) {
1009 				if (col != 2) {
1010 					print (" ");
1011 				}
1012 				if (!hex_style) {
1013 					print (" comment");
1014 				}
1015 			}
1016 			print ("\n");
1017 		}
1018 
1019 		if (c) {
1020 			print (Color_RESET);
1021 		}
1022 	}
1023 
1024 	// is this necessary?
1025 	r_print_set_screenbounds (p, addr);
1026 	int rowbytes;
1027 	int rows = 0;
1028 	int bytes = 0;
1029 	bool printValue = true;
1030 	bool oPrintValue = true;
1031 	bool isPxr = (p && p->flags & R_PRINT_FLAGS_REFS);
1032 
1033 	for (i = j = 0; i < len; i += (stride? stride: inc)) {
1034 		if (p && p->cons && p->cons->context && p->cons->context->breaked) {
1035 			break;
1036 		}
1037 		rowbytes = inc;
1038 		if (use_align) {
1039 			int sz = (p && p->offsize)? p->offsize (p->user, addr + j): -1;
1040 			if (sz > 0) { // flags with size 0 dont work
1041 				rowbytes = sz;
1042 			}
1043 		}
1044 
1045 		if (use_sparse) {
1046 			if (checkSparse (buf + i, inc, sparse_char)) {
1047 				if (i + inc >= len || checkSparse (buf + i + inc, inc, sparse_char)) {
1048 					if (i + inc + inc >= len ||
1049 					checkSparse (buf + i + inc + inc, inc, sparse_char)) {
1050 						sparse_char = buf[j];
1051 						last_sparse++;
1052 						if (last_sparse == 2) {
1053 							print (" ...\n");
1054 							continue;
1055 						}
1056 						if (last_sparse > 2) {
1057 							continue;
1058 						}
1059 					}
1060 				}
1061 			} else {
1062 				last_sparse = 0;
1063 			}
1064 		}
1065 		ut64 at = addr + (j * zoomsz);
1066 		if (use_offset && (!isPxr || inc < 4)) {
1067 			r_print_section (p, at);
1068 			r_print_addr (p, at);
1069 		}
1070 		int row_have_cursor = -1;
1071 		ut64 row_have_addr = UT64_MAX;
1072 		if (use_hexa) {
1073 			if (!compact && !isPxr) {
1074 				print ((col == 1)? "|": " ");
1075 			}
1076 			for (j = i; j < i + inc; j++) {
1077 				if (j!=i && use_align && rowbytes == inc) {
1078 					int sz = (p && p->offsize)? p->offsize (p->user, addr + j): -1;
1079 					if (sz >= 0) {
1080 						rowbytes = bytes;
1081 					}
1082 				}
1083 				if (row_have_cursor == -1) {
1084 					if (r_print_cursor_pointer (p, j, 1)) {
1085 						row_have_cursor = j - i;
1086 						row_have_addr = addr + j;
1087 					}
1088 				}
1089 				if (!compact && ((j >= len) || bytes >= rowbytes)) {
1090 					if (col == 1) {
1091 						if (j + 1 >= inc + i) {
1092 							print (j % 2? "  |": "| ");
1093 						} else {
1094 							print (j % 2? "   ": "  ");
1095 						}
1096 					} else {
1097 						if (base == 32) {
1098 							print ((j % 4)? "   ": "  ");
1099 						} else if (base == 10) {
1100 							print (j % 2? "     ": "  ");
1101 						} else {
1102 							print (j % 2? "   ": "  ");
1103 						}
1104 					}
1105 					continue;
1106 				}
1107 				const char *hl = (hex_style && p && p->offname (p->user, addr + j))? Color_INVERT: NULL;
1108 				if (hl) {
1109 					print (hl);
1110 				}
1111 				if (p && (base == 32 || base == 64)) {
1112 					int left = len - i;
1113 					/* TODO: check step. it should be 2/4 for base(32) and 8 for
1114 					 *       base(64) */
1115 					ut64 n = 0;
1116 					size_t sz_n = (base == 64)
1117 						? sizeof (ut64) : (step == 2)
1118 						? sizeof (ut16) : sizeof (ut32);
1119 					sz_n = R_MIN (left, sz_n);
1120 					if (j + sz_n > len) {
1121 						// oob
1122 						j += sz_n;
1123 						continue;
1124 					}
1125 					r_mem_swaporcopy ((ut8 *) &n, buf + j, sz_n, p && p->big_endian);
1126 					r_print_cursor (p, j, sz_n, 1);
1127 					// stub for colors
1128 					if (p && p->colorfor) {
1129 						if (!p->iob.addr_is_mapped (p->iob.io, addr + j)) {
1130 							a = p->cons->context->pal.ai_unmap;
1131 						} else {
1132 							a = p->colorfor (p->user, n, true);
1133 						}
1134 						if (a && *a) {
1135 							b = Color_RESET;
1136 						} else {
1137 							a = b = "";
1138 						}
1139 					} else {
1140 						a = b = "";
1141 					}
1142 					printValue = true;
1143 					bool hasNull = false;
1144 					if (isPxr) {
1145 						if (n == 0) {
1146 							if (oPrintValue) {
1147 								hasNull = true;
1148 							}
1149 							printValue = false;
1150 						}
1151 					}
1152 					if (printValue) {
1153 						if (use_offset && !hasNull && isPxr) {
1154 							r_print_section (p, at);
1155 							r_print_addr (p, addr + j * zoomsz);
1156 						}
1157 						if (base == 64) {
1158 							printfmt ("%s0x%016" PFMT64x "%s  ", a, (ut64) n, b);
1159 						} else if (step == 2) {
1160 							printfmt ("%s0x%04x%s ", a, (ut16) n, b);
1161 						} else {
1162 							printfmt ("%s0x%08x%s ", a, (ut32) n, b);
1163 						}
1164 					} else {
1165 						if (hasNull) {
1166 							const char *n = p->offname (p->user, addr + j);
1167 							r_print_section (p, at);
1168 							r_print_addr (p, addr + j * zoomsz);
1169 							printfmt ("..[ null bytes ]..   00000000 %s\n", r_str_get (n));
1170 						}
1171 					}
1172 					r_print_cursor (p, j, sz_n, 0);
1173 					oPrintValue = printValue;
1174 					j += step - 1;
1175 				} else if (base == -8) {
1176 					long long w = r_read_ble64 (buf + j, p && p->big_endian);
1177 					r_print_cursor (p, j, 8, 1);
1178 					printfmt ("%23" PFMT64d " ", w);
1179 					r_print_cursor (p, j, 8, 0);
1180 					j += 7;
1181 				} else if (base == -1) {
1182 					st8 w = r_read_ble8 (buf + j);
1183 					r_print_cursor (p, j, 1, 1);
1184 					printfmt ("%4d ", w);
1185 					r_print_cursor (p, j, 1, 0);
1186 				} else if (base == -10) {
1187 					if (j + 1 < len) {
1188 						st16 w = r_read_ble16 (buf + j, p && p->big_endian);
1189 						r_print_cursor (p, j, 2, 1);
1190 						printfmt ("%7d ", w);
1191 						r_print_cursor (p, j, 2, 0);
1192 					}
1193 					j += 1;
1194 				} else if (base == 10) { // "pxd"
1195 					if (j + 3 < len) {
1196 						int w = r_read_ble32 (buf + j, p && p->big_endian);
1197 						r_print_cursor (p, j, 4, 1);
1198 						printfmt ("%13d ", w);
1199 						r_print_cursor (p, j, 4, 0);
1200 					}
1201 					j += 3;
1202 				} else {
1203 					if (j >= len) {
1204 						break;
1205 					}
1206 					if (use_unalloc && !p->iob.is_valid_offset (p->iob.io, addr + j, false)) {
1207 						char ch = p->io_unalloc_ch;
1208 						char dbl_ch_str[] = { ch, ch, 0 };
1209 						p->cb_printf ("%s", dbl_ch_str);
1210 					} else {
1211 						r_print_byte (p, bytefmt, j, buf[j]);
1212 					}
1213 					if (pairs && !compact && (inc & 1)) {
1214 						bool mustspace = (rows % 2) ? !(j&1) : (j&1);
1215 						if (mustspace) {
1216 							print (" ");
1217 						}
1218 					} else if (bytes % 2 || !pairs) {
1219 						if (col == 1) {
1220 							if (j + 1 < inc + i) {
1221 								if (!compact) {
1222 									print (" ");
1223 								}
1224 							} else {
1225 								print ("|");
1226 							}
1227 						} else {
1228 							if (!compact) {
1229 								print (" ");
1230 							}
1231 						}
1232 					}
1233 				}
1234 				if (hl) {
1235 					print (Color_RESET);
1236 				}
1237 				bytes++;
1238 			}
1239 		}
1240 		if (printValue) {
1241 			if (compact) {
1242 				if (col == 0) {
1243 					print (" ");
1244 				} else if (col == 1) {
1245 					//print (" ");
1246 				} else {
1247 					print ((col == 2)? "|": "");
1248 				}
1249 			} else {
1250 				print ((col == 2)? "|": " ");
1251 			}
1252 			if (!p || !(p->flags & R_PRINT_FLAGS_NONASCII)) {
1253 				bytes = 0;
1254 				size_t end = i + inc;
1255 				for (j = i; j < end; j++) {
1256 					if (j != i && use_align  && bytes >= rowbytes) {
1257 						int sz = (p && p->offsize)? p->offsize (p->user, addr + j): -1;
1258 						if (sz >= 0) {
1259 							print (" ");
1260 							break;
1261 						}
1262 					}
1263 					if (j >= len || (use_align && bytes >= rowbytes)) {
1264 						break;
1265 					}
1266 					ut8 ch = (use_unalloc && p && !p->iob.is_valid_offset (p->iob.io, addr + j, false))
1267 						? ' ' : buf[j];
1268 					r_print_byte (p, "%c", j, ch);
1269 					bytes++;
1270 				}
1271 			}
1272 			/* ascii column */
1273 			if (col == 2) {
1274 				print ("|");
1275 			}
1276 			bool eol = false;
1277 			if (!eol && p && p->flags & R_PRINT_FLAGS_REFS) {
1278 				ut64 off = UT64_MAX;
1279 				if (inc == 8) {
1280 					if (i + sizeof (ut64) - 1 < len) {
1281 						off = r_read_le64 (buf + i);
1282 					}
1283 				} else if (inc == 4) {
1284 					if (i + sizeof (ut32) - 1 < len) {
1285 						off = r_read_le32 (buf + i);
1286 					}
1287 				} else if (inc == 2 && base == 16) {
1288 					if (i + sizeof (ut16) - 1 < len) {
1289 						off = r_read_le16 (buf + i);
1290 						if (off == 0) {
1291 							off = UT64_MAX;
1292 						}
1293 					}
1294 				}
1295 				if (p->hasrefs && off != UT64_MAX) {
1296 					char *rstr = p->hasrefs (p->user, addr + i, false);
1297 					if (rstr && *rstr) {
1298 						printfmt (" @ %s", rstr);
1299 					}
1300 					free (rstr);
1301 					rstr = p->hasrefs (p->user, off, true);
1302 					if (rstr && *rstr) {
1303 						printfmt (" %s", rstr);
1304 					}
1305 					free (rstr);
1306 				}
1307 			}
1308 			if (!eol && p && p->use_comments) {
1309 				for (; j < i + inc; j++) {
1310 					print (" ");
1311 				}
1312 				for (j = i; j < i + inc; j++) {
1313 					if (use_align && (j-i) >= rowbytes) {
1314 						break;
1315 					}
1316 					if (p && p->offname) {
1317 						a = p->offname (p->user, addr + j);
1318 						if (p->colorfor && a && *a) {
1319 							const char *color = p->colorfor (p->user, addr + j, true);
1320 							printfmt ("%s  ; %s%s", r_str_get (color), a,
1321 									color ? Color_RESET : "");
1322 						}
1323 					}
1324 					char *comment = p->get_comments (p->user, addr + j);
1325 					if (comment) {
1326 						if (p && p->colorfor) {
1327 							a = p->colorfor (p->user, addr + j, true);
1328 							if (R_STR_ISEMPTY (a)) {
1329 								a = "";
1330 							}
1331 						} else {
1332 							a = "";
1333 						}
1334 						printfmt ("%s  ; %s", a, comment);
1335 						free (comment);
1336 					}
1337 				}
1338 			}
1339 			if (use_align && rowbytes < inc && bytes >= rowbytes) {
1340 				i -= (inc - bytes);
1341 			}
1342 			print ("\n");
1343 		}
1344 		rows++;
1345 		bytes = 0;
1346 		if (p && p->cfmt && *p->cfmt) {
1347 			if (row_have_cursor != -1) {
1348 				int i = 0;
1349 				print (" _________");
1350 				if (!compact) {
1351 					print ("_");
1352 				}
1353 				for (i = 0; i < row_have_cursor; i++) {
1354 					if (!pairs || (!compact && i % 2)) {
1355 						print ("___");
1356 					} else {
1357 						print ("__");
1358 					}
1359 				}
1360 				print ("__|\n");
1361 				printfmt ("| cmd.hexcursor = %s\n", p->cfmt);
1362 				p->coreb.cmdf (p->coreb.core,
1363 						"%s @ 0x%08"PFMT64x, p->cfmt, row_have_addr);
1364 			}
1365 		}
1366 	}
1367 }
1368 
r_print_hexdump_simple(const ut8 * buf,int len)1369 R_API void r_print_hexdump_simple(const ut8 *buf, int len) {
1370 	r_print_hexdump (NULL, 0, buf, len, 16, 16, 0);
1371 }
1372 
getbytediff(RPrint * p,char * fmt,ut8 a,ut8 b)1373 static const char* getbytediff(RPrint *p, char *fmt, ut8 a, ut8 b) {
1374 	if (*fmt) {
1375 		if (a == b) {
1376 			sprintf (fmt, "%s%02x" Color_RESET, p->cons->context->pal.graph_true, a);
1377 		} else {
1378 			sprintf (fmt, "%s%02x" Color_RESET, p->cons->context->pal.graph_false, a);
1379 		}
1380 	} else {
1381 		sprintf (fmt, "%02x", a);
1382 	}
1383 	return fmt;
1384 }
1385 
getchardiff(RPrint * p,char * fmt,ut8 a,ut8 b)1386 static const char* getchardiff(RPrint *p, char *fmt, ut8 a, ut8 b) {
1387 	char ch = IS_PRINTABLE (a)? a: '.';
1388 	if (*fmt) {
1389 		if (a == b) {
1390 			sprintf (fmt, "%s%c" Color_RESET, p->cons->context->pal.graph_true, ch);
1391 		} else {
1392 			sprintf (fmt, "%s%c" Color_RESET, p->cons->context->pal.graph_false, ch);
1393 		}
1394 	} else {
1395 		sprintf (fmt, "%c", ch);
1396 	}
1397 	//else { fmt[0] = ch; fmt[1]=0; }
1398 	return fmt;
1399 }
1400 
1401 #define BD(a, b) getbytediff (p, fmt, (a)[i + j], (b)[i + j])
1402 #define CD(a, b) getchardiff (p, fmt, (a)[i + j], (b)[i + j])
1403 
M(const ut8 * b,int len)1404 static ut8* M(const ut8 *b, int len) {
1405 	ut8 *r = malloc (len + 16);
1406 	if (r) {
1407 		memset (r, 0xff, len + 16);
1408 		memcpy (r, b, len);
1409 	}
1410 	return r;
1411 }
1412 
1413 // TODO: add support for cursor
r_print_hexdiff(RPrint * p,ut64 aa,const ut8 * _a,ut64 ba,const ut8 * _b,int len,int scndcol)1414 R_API void r_print_hexdiff(RPrint *p, ut64 aa, const ut8 *_a, ut64 ba, const ut8 *_b, int len, int scndcol) {
1415 	ut8 *a, *b;
1416 	char linediff, fmt[64];
1417 	int color = p->flags & R_PRINT_FLAGS_COLOR;
1418 	int diffskip = p->flags & R_PRINT_FLAGS_DIFFOUT;
1419 	int i, j, min;
1420 	if (!((a = M (_a, len)))) {
1421 		return;
1422 	}
1423 	if (!((b = M (_b, len)))) {
1424 		free (a);
1425 		return;
1426 	}
1427 	for (i = 0; i < len; i += 16) {
1428 		min = R_MIN (16, len - i);
1429 		linediff = (memcmp (a + i, b + i, min))? '!': '|';
1430 		if (diffskip && linediff == '|') {
1431 			continue;
1432 		}
1433 		p->cb_printf ("0x%08" PFMT64x " ", aa + i);
1434 		for (j = 0; j < min; j++) {
1435 			*fmt = color;
1436 			r_print_cursor (p, i + j, 1, 1);
1437 			p->cb_printf ("%s", BD (a, b));
1438 			r_print_cursor (p, i + j, 1, 0);
1439 		}
1440 		p->cb_printf (" ");
1441 		for (j = 0; j < min; j++) {
1442 			*fmt = color;
1443 			r_print_cursor (p, i + j, 1, 1);
1444 			p->cb_printf ("%s", CD (a, b));
1445 			r_print_cursor (p, i + j, 1, 0);
1446 		}
1447 		if (scndcol) {
1448 			p->cb_printf (" %c 0x%08" PFMT64x " ", linediff, ba + i);
1449 			for (j = 0; j < min; j++) {
1450 				*fmt = color;
1451 				r_print_cursor (p, i + j, 1, 1);
1452 				p->cb_printf ("%s", BD (b, a));
1453 				r_print_cursor (p, i + j, 1, 0);
1454 			}
1455 			p->cb_printf (" ");
1456 			for (j = 0; j < min; j++) {
1457 				*fmt = color;
1458 				r_print_cursor (p, i + j, 1, 1);
1459 				p->cb_printf ("%s", CD (b, a));
1460 				r_print_cursor (p, i + j, 1, 0);
1461 			}
1462 			p->cb_printf ("\n");
1463 		} else {
1464 			p->cb_printf (" %c\n", linediff);
1465 		}
1466 	}
1467 	free (a);
1468 	free (b);
1469 }
1470 
r_print_bytes(RPrint * p,const ut8 * buf,int len,const char * fmt)1471 R_API void r_print_bytes(RPrint *p, const ut8 *buf, int len, const char *fmt) {
1472 	int i;
1473 	if (p) {
1474 		for (i = 0; i < len; i++) {
1475 			p->cb_printf (fmt, buf[i]);
1476 		}
1477 		p->cb_printf ("\n");
1478 	} else {
1479 		for (i = 0; i < len; i++) {
1480 			printf (fmt, buf[i]);
1481 		}
1482 		printf ("\n");
1483 	}
1484 }
1485 
r_print_raw(RPrint * p,ut64 addr,const ut8 * buf,int len,int offlines)1486 R_API void r_print_raw(RPrint *p, ut64 addr, const ut8 *buf, int len, int offlines) {
1487 	if (offlines == 2) {
1488 		int i, j, cols = p->cols * 4;
1489 		char ch;
1490 		for (i = 0; i < len; i += cols) {
1491 			p->cb_printf ("0x%08"PFMT64x"  ", addr + i);
1492 			for (j = 0; j < cols; j++) {
1493 				if ((i + j) >= len) {
1494 					break;
1495 				}
1496 				ch = buf[i + j];
1497 				if (p->cur_enabled) {
1498 					r_print_cursor (p, i + j, 1, 1);
1499 					p->cb_printf ("%c", IS_PRINTABLE (ch)? ch: ' ');
1500 					r_print_cursor (p, i + j, 1, 0);
1501 				} else {
1502 					p->cb_printf ("%c", IS_PRINTABLE (ch)? ch: ' ');
1503 				}
1504 			}
1505 			p->cb_printf ("\n");
1506 		}
1507 	} else if (offlines) {
1508 		const ut8 *o, *q;
1509 		ut64 off;
1510 		int i, linenum_abs, mustbreak = 0, linenum = 1;
1511 		o = q = buf;
1512 		i = 0;
1513 		do {
1514 			off = addr + (int) (size_t) (q - buf);
1515 			linenum_abs = r_util_lines_getline (p->lines_cache, p->lines_cache_sz, off);
1516 			if (p->lines_cache_sz > 0 && p->lines_abs) {
1517 				p->cb_printf ("%d 0x%08" PFMT64x " ", linenum_abs, off);
1518 			} else {
1519 				p->cb_printf ("+%d 0x%08" PFMT64x " ", linenum, off);
1520 			}
1521 			for (; i < len && *q && *q != '\n'; q++, i++) {
1522 				// just loop
1523 			}
1524 			if ((i + 1) >= len || !*q) {
1525 				mustbreak = 1;
1526 			}
1527 			if ((q - o) > 0) {
1528 				p->write (o, (int) (size_t) (q - o));
1529 			}
1530 			p->cb_printf ("\n");
1531 			linenum++;
1532 			o = ++q;
1533 			i++;
1534 		} while (!mustbreak);
1535 	} else {
1536 		p->write (buf, len);
1537 	}
1538 }
1539 
r_print_c(RPrint * p,const ut8 * str,int len)1540 R_API void r_print_c(RPrint *p, const ut8 *str, int len) {
1541 	int i, inc = p->width / 6;
1542 	p->cb_printf ("#define _BUFFER_SIZE %d\n"
1543 	"unsigned char buffer[_BUFFER_SIZE] = {\n",
1544 	len);
1545 	for (i = 0; !r_print_is_interrupted () && i < len;) {
1546 		r_print_byte (p, "0x%02x", i, str[i]);
1547 		if (++i < len) {
1548 			p->cb_printf (", ");
1549 		}
1550 		if (!(i % inc)) {
1551 			p->cb_printf ("\n");
1552 		}
1553 	}
1554 	p->cb_printf (" };\n");
1555 }
1556 
1557 // HACK :D
1558 static RPrint staticp = {
1559 	.cb_printf = libc_printf
1560 };
1561 
1562 /* TODO: handle screen width */
r_print_progressbar(RPrint * p,int pc,int _cols)1563 R_API void r_print_progressbar(RPrint *p, int pc, int _cols) {
1564 	// TODO: add support for colors
1565 	int i, cols = (_cols == -1)? 78: _cols;
1566 	if (!p) {
1567 		p = &staticp;
1568 	}
1569 	const char *h_line = p->cons->use_utf8 ? RUNE_LONG_LINE_HORIZ : "-";
1570 	const char *block = p->cons->use_utf8 ? UTF_BLOCK : "#";
1571 
1572 	pc = R_MAX (0, R_MIN (100, pc));
1573 	if (p->flags & R_PRINT_FLAGS_HEADER) {
1574 		p->cb_printf ("%4d%% ", pc);
1575 	}
1576 	cols -= 15;
1577 	p->cb_printf ("[");
1578 	for (i = cols * pc / 100; i; i--) {
1579 		p->cb_printf ("%s", block);
1580 	}
1581 	for (i = cols - (cols * pc / 100); i; i--) {
1582 		p->cb_printf ("%s", h_line);
1583 	}
1584 	p->cb_printf ("]");
1585 }
1586 
1587 /* TODO: handle screen width */
r_print_progressbar_with_count(RPrint * p,unsigned int pc,unsigned int total,int _cols,bool reset_line)1588 R_API void r_print_progressbar_with_count(RPrint *p, unsigned int pc, unsigned int total, int _cols, bool reset_line) {
1589 	int i, cols = (_cols == -1)? 78: _cols;
1590 	if (!p) {
1591 		p = &staticp;
1592 	}
1593 	const bool enable_colors = p && (p->flags & R_PRINT_FLAGS_COLOR);
1594 	const char *h_line = p->cons->use_utf8? RUNE_LONG_LINE_HORIZ: "-";
1595 	const char *block = p->cons->use_utf8? UTF_BLOCK: "#";
1596 
1597 	total = R_MAX (1, total);
1598 	pc = R_MAX (0, R_MIN (total, pc));
1599 	if (reset_line) {
1600 		p->cb_printf ("\r");
1601 	}
1602 	if (p->flags & R_PRINT_FLAGS_HEADER) {
1603 		if (enable_colors) {
1604 			p->cb_printf ("%s%4d%s%% %s%6d%s/%6d%s ", Color_GREEN, pc * 100 / total, Color_RESET, Color_GREEN, pc, Color_RESET, total, Color_YELLOW);
1605 		} else {
1606 			p->cb_printf ("%4d%% %6d/%6d ", pc * 100 / total, pc, total);
1607 		}
1608 		// TODO: determine string length of the numbers
1609 		cols -= 20;
1610 	}
1611 	if (cols > 0) {
1612 		if (enable_colors) {
1613 			p->cb_printf ("[%s", Color_YELLOW);
1614 		} else {
1615 			p->cb_printf ("[");
1616 		}
1617 		for (i = cols * pc / total; i; i--) {
1618 			p->cb_printf ("%s", block);
1619 		}
1620 		if (enable_colors) {
1621 			p->cb_printf ("%s", Color_RESET);
1622 		}
1623 		for (i = cols - (cols * pc / total); i; i--) {
1624 			p->cb_printf ("%s", h_line);
1625 		}
1626 		if (enable_colors) {
1627 			p->cb_printf ("%s]", Color_RESET);
1628 		}
1629 		else {
1630 			p->cb_printf ("]");
1631 		}
1632 	}
1633 }
1634 
r_print_rangebar(RPrint * p,ut64 startA,ut64 endA,ut64 min,ut64 max,int cols)1635 R_API void r_print_rangebar(RPrint *p, ut64 startA, ut64 endA, ut64 min, ut64 max, int cols) {
1636 	const char *h_line = p->cons->use_utf8? RUNE_LONG_LINE_HORIZ: "-";
1637 	const char *block = p->cons->use_utf8? UTF_BLOCK: "#";
1638 	const bool show_colors = p->flags & R_PRINT_FLAGS_COLOR;
1639 	int j = 0;
1640 	p->cb_printf ("|");
1641 	if (cols < 1) {
1642 		cols = 1;
1643 	}
1644 	int mul = (max - min) / cols;
1645 	bool isFirst = true;
1646 	for (j = 0; j < cols; j++) {
1647 		ut64 startB = min + (j * mul);
1648 		ut64 endB = min + ((j + 1) * mul);
1649 		if (startA <= endB && endA >= startB) {
1650 			if (show_colors & isFirst) {
1651 				p->cb_printf (Color_GREEN);
1652 				isFirst = false;
1653 			}
1654 			p->cb_printf ("%s", block);
1655 		} else {
1656 			if (!isFirst) {
1657 				p->cb_printf (Color_RESET);
1658 			}
1659 			p->cb_printf ("%s", h_line);
1660 		}
1661 	}
1662 	p->cb_printf ("|");
1663 }
1664 
r_print_zoom_buf(RPrint * p,void * user,RPrintZoomCallback cb,ut64 from,ut64 to,int len,int maxlen)1665 R_API void r_print_zoom_buf(RPrint *p, void *user, RPrintZoomCallback cb, ut64 from, ut64 to, int len, int maxlen) {
1666 	static int mode = -1;
1667 	ut8 *bufz = NULL, *bufz2 = NULL;
1668 	int i, j = 0;
1669 	ut64 size = (to - from);
1670 	size = len? size / len: 0;
1671 
1672 	if (maxlen < 2) {
1673 		maxlen = 1024 * 1024;
1674 	}
1675 	if (size > maxlen) {
1676 		size = maxlen;
1677 	}
1678 	if (size < 1) {
1679 		size = 1;
1680 	}
1681 	if (len < 1) {
1682 		len = 1;
1683 	}
1684 
1685 	if (mode == p->zoom->mode && from == p->zoom->from && to == p->zoom->to && size == p->zoom->size) {
1686 		// get from cache
1687 		bufz = p->zoom->buf;
1688 		size = p->zoom->size;
1689 	} else {
1690 		mode = p->zoom->mode;
1691 		bufz = (ut8 *) calloc (1, len);
1692 		if (!bufz) {
1693 			return;
1694 		}
1695 		bufz2 = (ut8 *) calloc (1, size);
1696 		if (!bufz2) {
1697 			free (bufz);
1698 			return;
1699 		}
1700 
1701 		// TODO: memoize blocks or gtfo
1702 		for (i = 0; i < len; i++) {
1703 			if (p->cons->context->breaked) {
1704 				break;
1705 			}
1706 			p->iob.read_at (p->iob.io, from + j, bufz2, size);
1707 			bufz[i] = cb (user, p->zoom->mode, from + j, bufz2, size);
1708 			j += size;
1709 		}
1710 		free (bufz2);
1711 		// memoize
1712 		free (p->zoom->buf);
1713 		p->zoom->buf = bufz;
1714 		p->zoom->from = from;
1715 		p->zoom->to = to;
1716 		p->zoom->size = len; // size;
1717 	}
1718 }
1719 
r_print_zoom(RPrint * p,void * user,RPrintZoomCallback cb,ut64 from,ut64 to,int len,int maxlen)1720 R_API void r_print_zoom(RPrint *p, void *user, RPrintZoomCallback cb, ut64 from, ut64 to, int len, int maxlen) {
1721 	ut64 size = (to - from);
1722 	r_print_zoom_buf (p, user, cb, from, to, len, maxlen);
1723 	size = len? size / len: 0;
1724 	p->flags &= ~R_PRINT_FLAGS_HEADER;
1725 	r_print_hexdump (p, from, p->zoom->buf, p->zoom->size, 16, 1, size);
1726 	p->flags |= R_PRINT_FLAGS_HEADER;
1727 }
1728 
printHistBlock(RPrint * p,int k,int cols)1729 static inline void printHistBlock (RPrint *p, int k, int cols) {
1730 	RConsPrintablePalette *pal = &p->cons->context->pal;
1731 	const char *h_line = p->cons->use_utf8 ? RUNE_LONG_LINE_HORIZ : "-";
1732 	const char *block = p->cons->use_utf8 ? UTF_BLOCK : "#";
1733 	const char *kol[5];
1734 	kol[0] = pal->nop;
1735 	kol[1] = pal->mov;
1736 	kol[2] = pal->cjmp;
1737 	kol[3] = pal->jmp;
1738 	kol[4] = pal->call;
1739 	if (cols < 1) {
1740 		cols = 1;
1741 	}
1742 	const bool show_colors = (p && (p->flags & R_PRINT_FLAGS_COLOR));
1743 	if (show_colors) {
1744 		int idx = (int) ((k * 4) / cols);
1745 		const char *str = kol[idx];
1746 		if (p->histblock) {
1747 			p->cb_printf ("%s%s%s", str, block, Color_RESET);
1748 		} else {
1749 			p->cb_printf ("%s%s%s", str, h_line, Color_RESET);
1750 		}
1751 	} else {
1752 		if (p->histblock) {
1753 			p->cb_printf ("%s", block);
1754 		} else {
1755 			p->cb_printf ("%s", h_line);
1756 		}
1757 	}
1758 }
1759 
r_print_fill(RPrint * p,const ut8 * arr,int size,ut64 addr,int step)1760 R_API void r_print_fill(RPrint *p, const ut8 *arr, int size, ut64 addr, int step) {
1761 	r_return_if_fail (p && arr);
1762 	const bool show_colors = (p && (p->flags & R_PRINT_FLAGS_COLOR));
1763 	const bool show_offset = (p && (p->flags & R_PRINT_FLAGS_OFFSET));
1764 	bool useUtf8 = p->cons->use_utf8;
1765 	const char *v_line = useUtf8 ? RUNE_LINE_VERT : "|";
1766 	int i = 0, j;
1767 
1768 #define INC 5
1769 #if TOPLINE
1770 	if (arr[0] > 1) {
1771 		p->cb_printf ("         ");
1772 		if (addr != UT64_MAX && step > 0) {
1773 			p->cb_printf ("           ");
1774 		}
1775 		if (arr[0] > 1) {
1776 			for (i = 0; i < arr[0]; i += INC) {
1777 				p->cb_printf (h_line);
1778 			}
1779 		}
1780 		p->cb_printf ("\n");
1781 	}
1782 #endif
1783 	// get the max of columns
1784 	int cols = 0;
1785 	for (i = 0; i < size; i++) {
1786 		cols = arr[i] > cols ? arr[i] : cols;
1787 	}
1788 	cols /= 5;
1789 	for (i = 0; i < size; i++) {
1790 		ut8 next = (i + 1 < size)? arr[i + 1]: 0;
1791 		int base = 0, k = 0;
1792 		if (addr != UT64_MAX && step > 0) {
1793 			ut64 at = addr + (i * step);
1794 			if (show_offset) {
1795 				if (p->cur_enabled) {
1796 					if (i == p->cur) {
1797 						p->cb_printf (Color_INVERT"> 0x%08" PFMT64x " "Color_RESET, at);
1798 						if (p->num) {
1799 							p->num->value = at;
1800 						}
1801 					} else {
1802 						p->cb_printf ("  0x%08" PFMT64x " ", at);
1803 					}
1804 				} else {
1805 					p->cb_printf ("0x%08" PFMT64x " ", at);
1806 				}
1807 			}
1808 			p->cb_printf ("%03x %04x %s", i, arr[i], v_line);
1809 		} else {
1810 			p->cb_printf ("%s", v_line);
1811 		}
1812 		if (next < INC) {
1813 			base = 1;
1814 		}
1815 		if (next < arr[i]) {
1816 			if (arr[i] > INC) {
1817 				for (j = 0; j < next + base; j += INC) {
1818 					printHistBlock (p, k, cols);
1819 					k++;
1820 				}
1821 			}
1822 			for (j = next + INC; j + base < arr[i]; j += INC) {
1823 				printHistBlock (p, k, cols);
1824 				k++;
1825 			}
1826 		} else {
1827 			printHistBlock (p, k, cols);
1828 			k++;
1829 		}
1830 		if (i + 1 == size) {
1831 			for (j = arr[i] + INC + base; j + base < next; j += INC) {
1832 				printHistBlock (p, k, cols);
1833 				k++;
1834 			}
1835 		} else if (arr[i + 1] > arr[i]) {
1836 			for (j = arr[i] + INC + base; j + base < next; j += INC) {
1837 				printHistBlock (p, k, cols);
1838 				k++;
1839 			}
1840 		}
1841 		if (show_colors) {
1842 			p->cb_printf ("%s", Color_RESET);
1843 		}
1844 		p->cb_printf ("\n");
1845 	}
1846 }
1847 
r_print_2bpp_row(RPrint * p,ut8 * buf,const char ** colors)1848 R_API void r_print_2bpp_row(RPrint *p, ut8 *buf, const char **colors) {
1849 	const bool useColor = p? (p->flags & R_PRINT_FLAGS_COLOR): false;
1850 	int i, c = 0;
1851 	for (i = 0; i < 8; i++) {
1852 		if (buf[1] & ((1 << 7) >> i)) {
1853 			c = 2;
1854 		}
1855 		if (buf[0] & ((1 << 7) >> i)) {
1856 			c++;
1857 		}
1858 		const char *chstr = ".=*@";
1859 		const char ch = chstr[c % 4];
1860 		if (useColor) {
1861 			const char *color = "";
1862 			color = colors[c]; // c is by definition 0, 1, 2 or 3
1863 			if (p) {
1864 				p->cb_printf ("%s%c%c"Color_RESET, color, ch, ch);
1865 			} else {
1866 				printf ("%s%c%c"Color_RESET, color, ch, ch);
1867 			}
1868 		} else {
1869 			if (p) {
1870 				p->cb_printf ("%c%c", ch, ch);
1871 			} else {
1872 				printf ("%c%c", ch, ch);
1873 			}
1874 		}
1875 		c = 0;
1876 	}
1877 }
1878 
r_print_2bpp_newline(RPrint * p,bool useColor)1879 static void r_print_2bpp_newline(RPrint *p, bool useColor) {
1880 	if (p) {
1881 		if (useColor) {
1882 			p->cb_printf (Color_RESET "\n");
1883 		} else {
1884 			p->cb_printf ("\n");
1885 		}
1886 	} else {
1887 		printf ("\n");
1888 	}
1889 }
1890 
r_print_2bpp_tiles(RPrint * p,ut8 * buf,size_t buflen,ut32 tiles,const char ** colors)1891 R_API void r_print_2bpp_tiles(RPrint *p, ut8 *buf, size_t buflen, ut32 tiles, const char **colors) {
1892 	if (!colors) {
1893 		colors = (const char *[]){
1894 			Color_BGWHITE,
1895 			Color_BGRED,
1896 			Color_BGBLUE,
1897 			Color_BGBLACK,
1898 		};
1899 	}
1900 	int i, r;
1901 	const bool useColor = p? (p->flags & R_PRINT_FLAGS_COLOR): false;
1902 	int rows = buflen / tiles;
1903 	int row, delta = 0;
1904 	// hex.cols = 64 = 256 byte stride
1905 	int stride = tiles * 16;
1906 	bool eof = false;
1907 	for (row = 1; row < rows; row++) {
1908 		for (i = 0; i < 8 && !eof; i++) {
1909 			for (r = 0; r < tiles; r++) {
1910 				//int off = delta + 2 * i + r * 16;
1911 				int off = delta + (2 * i) + (r * 16);
1912 				if (off >= buflen) {
1913 					eof = true;
1914 					break;
1915 				}
1916 				r_print_2bpp_row (p, buf + off, colors);
1917 			}
1918 			r_print_2bpp_newline (p, useColor);
1919 		}
1920 		delta += stride;
1921 	}
1922 }
1923 
1924 // probably move somewhere else. RPrint doesnt needs to know about the R_ANAL_ enums
r_print_color_op_type(RPrint * p,ut32 anal_type)1925 R_API const char* r_print_color_op_type(RPrint *p, ut32 anal_type) {
1926 	RConsPrintablePalette *pal = &p->cons->context->pal;
1927 	switch (anal_type & R_ANAL_OP_TYPE_MASK) {
1928 	case R_ANAL_OP_TYPE_NOP:
1929 		return pal->nop;
1930 	case R_ANAL_OP_TYPE_ADD:
1931 	case R_ANAL_OP_TYPE_SUB:
1932 	case R_ANAL_OP_TYPE_MUL:
1933 	case R_ANAL_OP_TYPE_DIV:
1934 	case R_ANAL_OP_TYPE_MOD:
1935 	case R_ANAL_OP_TYPE_LENGTH:
1936 		return pal->math;
1937 	case R_ANAL_OP_TYPE_AND:
1938 	case R_ANAL_OP_TYPE_OR:
1939 	case R_ANAL_OP_TYPE_XOR:
1940 	case R_ANAL_OP_TYPE_NOT:
1941 	case R_ANAL_OP_TYPE_SHL:
1942 	case R_ANAL_OP_TYPE_SAL:
1943 	case R_ANAL_OP_TYPE_SAR:
1944 	case R_ANAL_OP_TYPE_SHR:
1945 	case R_ANAL_OP_TYPE_ROL:
1946 	case R_ANAL_OP_TYPE_ROR:
1947 	case R_ANAL_OP_TYPE_CPL:
1948 		return pal->bin;
1949 	case R_ANAL_OP_TYPE_IO:
1950 		return pal->swi;
1951 	case R_ANAL_OP_TYPE_JMP:
1952 	case R_ANAL_OP_TYPE_UJMP:
1953 		return pal->ujmp;
1954 	case R_ANAL_OP_TYPE_IJMP:
1955 	case R_ANAL_OP_TYPE_RJMP:
1956 	case R_ANAL_OP_TYPE_IRJMP:
1957 	case R_ANAL_OP_TYPE_MJMP:
1958 		return pal->jmp;
1959 	case R_ANAL_OP_TYPE_CJMP:
1960 	case R_ANAL_OP_TYPE_UCJMP:
1961 	case R_ANAL_OP_TYPE_SWITCH:
1962 		return pal->cjmp;
1963 	case R_ANAL_OP_TYPE_CMP:
1964 	case R_ANAL_OP_TYPE_ACMP:
1965 		return pal->cmp;
1966 	case R_ANAL_OP_TYPE_UCALL:
1967 		return pal->ucall;
1968 	case R_ANAL_OP_TYPE_ICALL:
1969 	case R_ANAL_OP_TYPE_RCALL:
1970 	case R_ANAL_OP_TYPE_IRCALL:
1971 	case R_ANAL_OP_TYPE_UCCALL:
1972 	case R_ANAL_OP_TYPE_CALL:
1973 	case R_ANAL_OP_TYPE_CCALL:
1974 		return pal->call;
1975 	case R_ANAL_OP_TYPE_NEW:
1976 	case R_ANAL_OP_TYPE_SWI:
1977 		return pal->swi;
1978 	case R_ANAL_OP_TYPE_ILL:
1979 	case R_ANAL_OP_TYPE_TRAP:
1980 		return pal->trap;
1981 	case R_ANAL_OP_TYPE_CRET:
1982 	case R_ANAL_OP_TYPE_RET:
1983 		return pal->ret;
1984 	case R_ANAL_OP_TYPE_CAST:
1985 	case R_ANAL_OP_TYPE_MOV:
1986 	case R_ANAL_OP_TYPE_LEA:
1987 	case R_ANAL_OP_TYPE_CMOV: // TODO: add cmov cathegory?
1988 		return pal->mov;
1989 	case R_ANAL_OP_TYPE_PUSH:
1990 	case R_ANAL_OP_TYPE_UPUSH:
1991 	case R_ANAL_OP_TYPE_RPUSH:
1992 	case R_ANAL_OP_TYPE_LOAD:
1993 		return pal->push;
1994 	case R_ANAL_OP_TYPE_POP:
1995 	case R_ANAL_OP_TYPE_STORE:
1996 		return pal->pop;
1997 	case R_ANAL_OP_TYPE_CRYPTO:
1998 		return pal->crypto;
1999 	case R_ANAL_OP_TYPE_NULL:
2000 		return pal->other;
2001 	case R_ANAL_OP_TYPE_UNK:
2002 	default:
2003 		return pal->invalid;
2004 	}
2005 }
2006 
2007 // Global buffer to speed up colorizing performance
2008 #define COLORIZE_BUFSIZE 1024
2009 static char o[COLORIZE_BUFSIZE];
2010 
issymbol(char c)2011 static bool issymbol(char c) {
2012 	switch (c) {
2013 	case '$':
2014 	case ':':
2015 	case '+':
2016 	case '-':
2017 	/* case '/': not good for dalvik */
2018 	case '>':
2019 	case '<':
2020 	case '(':
2021 	case ')':
2022 	case '*':
2023 	case '%':
2024 	case ']':
2025 	case '[':
2026 	case ',':
2027 	case ' ':
2028 	case '{':
2029 	case '}':
2030 		return true;
2031 	default:
2032 		return false;
2033 	}
2034 }
2035 
check_arg_name(RPrint * print,char * p,ut64 func_addr)2036 static bool check_arg_name(RPrint *print, char *p, ut64 func_addr) {
2037 	if (func_addr && print->exists_var) {
2038 		int z;
2039 		for (z = 0; p[z] && (isalpha ((unsigned char)p[z]) || isdigit ((unsigned char)p[z]) || p[z] == '_'); z++) {
2040 			;
2041 		}
2042 		char tmp = p[z];
2043 		p[z] = '\0';
2044 		bool ret = print->exists_var (print, func_addr, p);
2045 		p[z] = tmp;
2046 		return ret;
2047 	}
2048 	return false;
2049 }
2050 
ishexprefix(char * p)2051 static bool ishexprefix(char *p) {
2052 	return (p[0] == '0' && p[1] == 'x');
2053 }
2054 
r_print_colorize_opcode(RPrint * print,char * p,const char * reg,const char * num,bool partial_reset,ut64 func_addr)2055 R_API char* r_print_colorize_opcode(RPrint *print, char *p, const char *reg, const char *num, bool partial_reset, ut64 func_addr) {
2056 	int i, j, k, is_mod, is_float = 0, is_arg = 0;
2057 	char *reset = partial_reset ? Color_RESET_NOBG : Color_RESET;
2058 	ut32 c_reset = strlen (reset);
2059 	int is_jmp = p && (*p == 'j' || ((*p == 'c') && (p[1] == 'a')))? 1: 0;
2060 	ut32 opcode_sz = p && *p? strlen (p) * 10 + 1: 0;
2061 	char previous = '\0';
2062 	const char *color_flag = print->cons->context->pal.flag;
2063 
2064 	if (!p || !*p) {
2065 		return NULL;
2066 	}
2067 	if (is_jmp) {
2068 		return strdup (p);
2069 	}
2070 	r_str_trim (p);
2071 	if (opcode_sz > COLORIZE_BUFSIZE) {
2072 		/* return same string in case of error */
2073 		return strdup (p);
2074 	}
2075 
2076 	memset (o, 0, COLORIZE_BUFSIZE);
2077 	for (i = j = 0; p[i]; i++, j++) {
2078 		/* colorize numbers */
2079 		if ((ishexprefix (&p[i]) && previous != ':') \
2080 		     || (isdigit ((ut8)p[i]) && issymbol (previous))) {
2081 			const char *num2 = num;
2082 			ut64 n = r_num_get (NULL, p + i);
2083 			const char *name = print->offname (print->user, n)? color_flag: NULL;
2084 			if (name) {
2085 				num2 = name;
2086 			}
2087 			int nlen = strlen (num2);
2088 			if (nlen + j >= sizeof (o)) {
2089 				eprintf ("Colorize buffer is too small\n");
2090 				break;
2091 			}
2092 			memcpy (o + j, num2, nlen + 1);
2093 			j += nlen;
2094 		}
2095 		previous = p[i];
2096 		if (j + 100 >= COLORIZE_BUFSIZE) {
2097 			eprintf ("r_print_colorize_opcode(): buffer overflow!\n");
2098 			return strdup (p);
2099 		}
2100 		switch (p[i]) {
2101 		// We dont need to skip ansi codes.
2102 		// original colors must be preserved somehow
2103 		case 0x1b:
2104 #define STRIP_ANSI 1
2105 #if STRIP_ANSI
2106 			/* skip until 'm' */
2107 			for (++i; p[i] && p[i] != 'm'; i++) {
2108 				o[j] = p[i];
2109 			}
2110 			j--;
2111 			continue;
2112 #else
2113 			/* copy until 'm' */
2114 			for (; p[i] && p[i] != 'm'; i++) {
2115 				o[j++] = p[i];
2116 			}
2117 			o[j++] = p[i++];
2118 #endif
2119 		case '+':
2120 		case '-':
2121 		case '/':
2122 		case '>':
2123 		case '<':
2124 		case '(':
2125 		case ')':
2126 		case '*':
2127 		case '%':
2128 		case ']':
2129 		case '[':
2130 		case ',':
2131 			/* ugly trick for dalvik */
2132 			if (is_float) {
2133 				/* do nothing, keep going until next */
2134 				is_float = 0;
2135 			} else if (is_arg) {
2136 				if (c_reset + j + 10 >= COLORIZE_BUFSIZE) {
2137 					eprintf ("r_print_colorize_opcode(): buffer overflow!\n");
2138 					return strdup (p);
2139 				}
2140 
2141 				bool found_var = check_arg_name (print, p + i + 1, func_addr);
2142 				strcpy (o + j, reset);
2143 				j += strlen (reset);
2144 				o[j] = p[i];
2145 				if (!(p[i+1] == '$' || ((p[i+1] > '0') && (p[i+1] < '9')))) {
2146 					const char *color = found_var ? print->cons->context->pal.func_var_type : reg;
2147 					ut32 color_len = strlen (color);
2148 					if (color_len + j + 10 >= COLORIZE_BUFSIZE) {
2149 						eprintf ("r_print_colorize_opcode(): buffer overflow!\n");
2150 						return strdup (p);
2151 					}
2152 					strcpy (o + j + 1, color);
2153 					j += strlen (color);
2154 				}
2155 				continue;
2156 			}
2157 			break;
2158 		case ' ':
2159 			is_arg = 1;
2160 			// find if next ',' before ' ' is found
2161 			is_mod = 0;
2162 			is_float = 0;
2163 			for (k = i + 1; p[k]; k++) {
2164 				if (p[k] == 'e' && p[k + 1] == '+') {
2165 					is_float = 1;
2166 					break;
2167 				}
2168 				if (p[k] == ' ') {
2169 					break;
2170 				}
2171 				if (p[k] == ',') {
2172 					is_mod = 1;
2173 					break;
2174 				}
2175 			}
2176 			if (is_float) {
2177 				strcpy (o + j, num);
2178 				j += strlen (num);
2179 			}
2180 			if (!p[k]) {
2181 				is_mod = 1;
2182 			}
2183 			if (is_mod) {
2184 				// COLOR FOR REGISTER
2185 				ut32 reg_len = strlen (reg);
2186 				/* if (reg_len+j+10 >= opcode_sz) o = realloc_color_buffer (o, &opcode_sz, reg_len+100); */
2187 				if (reg_len + j + 10 >= COLORIZE_BUFSIZE) {
2188 					eprintf ("r_print_colorize_opcode(): buffer overflow!\n");
2189 					return strdup (p);
2190 				}
2191 				strcpy (o + j, reg);
2192 				j += strlen (reg);
2193 			}
2194 			break;
2195 		case '0': /* address */
2196 			if (p[i + 1] == 'x') {
2197 				if (print->flags & R_PRINT_FLAGS_SECSUB) {
2198 					RIOMap *map = print->iob.map_get (print->iob.io, r_num_get (NULL, p + i));
2199 					if (map && map->name) {
2200 						if (strlen (map->name) + j + 1 >= COLORIZE_BUFSIZE) {
2201 							eprintf ("stop before overflow\n");
2202 							break;
2203 						}
2204 						strcpy (o + j, map->name);
2205 						j += strlen (o + j);
2206 						strcpy (o + j, ".");
2207 						j++;
2208 					}
2209 				}
2210 			}
2211 			break;
2212 		}
2213 		o[j] = p[i];
2214 	}
2215 	// decolorize at the end
2216 	if (j + 20 >= opcode_sz) {
2217 		char *t_o = o;
2218 		/* o = malloc (opcode_sz+21); */
2219 		memmove (o, t_o, opcode_sz);
2220 		/* free (t_o); */
2221 	}
2222 	strcpy (o + j, reset);
2223 	//strcpy (p, o); // may overflow .. but shouldnt because asm.buf_asm is big enought
2224 	return strdup (o);
2225 }
2226 
2227 // reset the status of row_offsets
r_print_init_rowoffsets(RPrint * p)2228 R_API void r_print_init_rowoffsets(RPrint *p) {
2229 	if (p->calc_row_offsets) {
2230 		R_FREE (p->row_offsets);
2231 		p->row_offsets_sz = 0;
2232 	}
2233 }
2234 
2235 // set the offset, from the start of the printing, of the i-th row
r_print_set_rowoff(RPrint * p,int i,ut32 offset,bool overwrite)2236 R_API void r_print_set_rowoff(RPrint *p, int i, ut32 offset, bool overwrite) {
2237 	if (!overwrite) {
2238 		return;
2239 	}
2240 	if (i < 0) {
2241 		return;
2242 	}
2243 	if (!p->row_offsets || !p->row_offsets_sz) {
2244 		p->row_offsets_sz = R_MAX (i + 1, DFLT_ROWS);
2245 		p->row_offsets = R_NEWS (ut32, p->row_offsets_sz);
2246 	}
2247 	if (i >= p->row_offsets_sz) {
2248 		size_t new_size;
2249 		p->row_offsets_sz *= 2;
2250 		//XXX dangerous
2251 		while (i >= p->row_offsets_sz) {
2252 			p->row_offsets_sz *= 2;
2253 		}
2254 		new_size = sizeof (ut32) * p->row_offsets_sz;
2255 		p->row_offsets = realloc (p->row_offsets, new_size);
2256 	}
2257 	p->row_offsets[i] = offset;
2258 }
2259 
2260 // return the offset, from the start of the printing, of the i-th row.
2261 // if the line index is not valid, UT32_MAX is returned.
r_print_rowoff(RPrint * p,int i)2262 R_API ut32 r_print_rowoff(RPrint *p, int i) {
2263 	if (i < 0 || i >= p->row_offsets_sz) {
2264 		return UT32_MAX;
2265 	}
2266 	return p->row_offsets[i];
2267 }
2268 
2269 // return the index of the row that contains the given offset or -1 if
2270 // that row doesn't exist.
r_print_row_at_off(RPrint * p,ut32 offset)2271 R_API int r_print_row_at_off(RPrint *p, ut32 offset) {
2272 	int i = 0;
2273 	ut32 tt;
2274 	while ((tt = r_print_rowoff (p, i)) != UT32_MAX && tt <= offset) {
2275 		i++;
2276 	}
2277 	return tt != UT32_MAX? i - 1: -1;
2278 }
2279 
r_print_get_cursor(RPrint * p)2280 R_API int r_print_get_cursor(RPrint *p) {
2281 	return p->cur_enabled? p->cur: 0;
2282 }
2283 
r_print_jsondump(RPrint * p,const ut8 * buf,int len,int wordsize)2284 R_API int r_print_jsondump(RPrint *p, const ut8 *buf, int len, int wordsize) {
2285 	ut16 *buf16 = (ut16*) buf;
2286 	ut32 *buf32 = (ut32*) buf;
2287 	ut64 *buf64 = (ut64*) buf;
2288 	// TODDO: support p==NULL too
2289 	if (!p || !buf || len < 1 || wordsize < 1) {
2290 		return 0;
2291 	}
2292 	int bytesize = wordsize / 8;
2293 	if (bytesize < 1) {
2294 		bytesize = 8;
2295 	}
2296 	int i, words = (len / bytesize);
2297 	p->cb_printf ("[");
2298 	for (i = 0; i < words; i++) {
2299 		switch (wordsize) {
2300 		case 8: {
2301 			p->cb_printf ("%s%d", i ? "," : "", buf[i]);
2302 			break;
2303 		}
2304 		case 16: {
2305 			ut16 w16 = r_read_ble16 (&buf16[i], p->big_endian);
2306 			p->cb_printf ("%s%hd", i ? "," : "", w16);
2307 			break;
2308 		}
2309 		case 32: {
2310 			ut32 w32 = r_read_ble32 (&buf32[i], p->big_endian);
2311 			p->cb_printf ("%s%d", i ? "," : "", w32);
2312 			break;
2313 		}
2314 		case 64: {
2315 			ut64 w64 = r_read_ble64 (&buf64[i], p->big_endian);
2316 			p->cb_printf ("%s%"PFMT64d, i ? "," : "", w64);
2317 			break;
2318 		}
2319 		}
2320 	}
2321 	p->cb_printf ("]\n");
2322 	return words;
2323 }
2324 
r_print_hex_from_bin(RPrint * p,char * bin_str)2325 R_API void r_print_hex_from_bin(RPrint *p, char *bin_str) {
2326 	int i, j, index;
2327 	RPrint myp = {.cb_printf = libc_printf};
2328 	const int len = strlen (bin_str);
2329 	if (!len) {
2330 		return;
2331 	}
2332 	ut64 n, *buf = malloc (sizeof (ut64) * ((len + 63) / 64));
2333 	if (!buf) {
2334 		eprintf ("allocation failed\n");
2335 		return;
2336 	}
2337 	if (!p) {
2338 		p = &myp;
2339 	}
2340 	for (i = len - 1, index = 0; i >= 0; i -= 64, index++) {
2341 		n = 0;
2342 		for (j = 0; j < 64 && i - j >= 0; j++) {
2343 			n += (ut64) (bin_str[i - j] - '0') << j;
2344 		}
2345 		buf[index] = n;
2346 	}
2347 	index--;
2348 	p->cb_printf ("0x");
2349 	while (buf[index] == 0 && index > 0) {
2350 		index--;
2351 	}
2352 	p->cb_printf ("%" PFMT64x, buf[index]);
2353 	index--;
2354 	for (i = index; i >= 0; i--) {
2355 		p->cb_printf ("%016" PFMT64x, buf[i]);
2356 	}
2357 	p->cb_printf ("\n");
2358 	free (buf);
2359 }
2360 
r_print_rowlog(RPrint * print,const char * str)2361 R_API const char* r_print_rowlog(RPrint *print, const char *str) {
2362 	int use_color = print->flags & R_PRINT_FLAGS_COLOR;
2363 	bool verbose = print->scr_prompt;
2364 	r_return_val_if_fail (print->cb_eprintf, NULL);
2365 	if (!verbose) {
2366 		return NULL;
2367 	}
2368 	if (use_color) {
2369 		print->cb_eprintf ("[ ] "Color_YELLOW"%s\r["Color_RESET, str);
2370 	} else {
2371 		print->cb_eprintf ("[ ] %s\r[", str);
2372 	}
2373 	return str;
2374 }
2375 
r_print_rowlog_done(RPrint * print,const char * str)2376 R_API void r_print_rowlog_done(RPrint *print, const char *str) {
2377 	int use_color = print->flags & R_PRINT_FLAGS_COLOR;
2378 	bool verbose =  print->scr_prompt;
2379 	r_return_if_fail (print->cb_eprintf);
2380 	if (verbose) {
2381 		if (use_color) {
2382 			print->cb_eprintf ("\r"Color_GREEN"[x]"Color_RESET" %s\n", str);
2383 		} else {
2384 			print->cb_eprintf ("\r[x] %s\n", str);
2385 		}
2386 	}
2387 }
2388