Example #1
0
R_API int r_print_format(RPrint *p, ut64 seek, const ut8* b, const int len,
		const char *fmt, int mode, const char *setval, char *ofield) {
	int nargs, i, j, invalid, nexti, idx, times, otimes, endian, isptr = 0;
	const char *argend;
	ut64 addr = 0, addr64 = 0, seeki = 0;;
	char *args = NULL, *bracket, tmp, last = 0;
	const char *arg = fmt;
	int viewflags = 0;
	char namefmt[8], *field = NULL;
	static int slide=0, oldslide=0;
	ut8 *buf;
	if (!fmt)
		return 0;
	argend = fmt+strlen (fmt);

	nexti = nargs = i = j = 0;

	if (len < 1)
		return 0;
	buf = malloc (len);
	if (!buf)
		return 0;
	memcpy (buf, b, len);
	endian = p->big_endian;

	if (ofield && ofield != MINUSONE) field = strdup (ofield);

	while (*arg && iswhitechar (*arg)) arg++;

	/* get times */
	otimes = times = atoi (arg);
	if (times > 0)
		while ((*arg>='0'&&*arg<='9')) arg++;

	bracket = strchr (arg,'{');
	if (bracket) {
		char *end = strchr (arg, '}');
		if (end == NULL) {
			eprintf ("No end bracket. Try pm {ecx}b @ esi\n");
			goto beach;
		}
		*end='\0';
		times = r_num_math (NULL, bracket+1);
		arg = end + 1;
	}

	if (*arg=='\0') {
		goto beach;
	}

	/* get args */
	args = strchr (arg, ' ');
	if (args) {
		int l=0, maxl = 0;
		argend = args;
		args = strdup (args+1);
		nargs = r_str_word_set0 (args);
		if (nargs == 0)
			R_FREE (args);
		for (i=0; i<nargs; i++) {
			const int len = strlen (r_str_word_get0 (args, i));
			if (len > maxl)
				maxl = len;
		}
		l++;
		snprintf (namefmt, sizeof (namefmt), "%%%ds : ", maxl+6*slide%STRUCTPTR);
	}
#define ISPOINTED ((slide%STRUCTFLAG)/STRUCTPTR<=(oldslide%STRUCTFLAG)/STRUCTPTR)
#define ISNESTED ((slide%STRUCTPTR)<=(oldslide%STRUCTPTR))
	if (mode == R_PRINT_JSON && slide==0) p->printf("[");
	if (arg[0] == '0') {
		mode |= R_PRINT_UNIONMODE;
		arg++;
	} else {
		mode &= ~R_PRINT_UNIONMODE;
	}

	/* go format */
	i = 0;
	if (!times)
		otimes = times = 1;
	for (; times; times--) { // repeat N times
		const char * orig = arg;
		int first = 1;
		if (otimes>1) {
			if (mode & R_PRINT_JSON) {
				if (otimes > times) p->printf (",");
				p->printf ("[{\"index\":%d,\"offset\":%d},", otimes-times, seek+i);
			} else
				p->printf ("0x%08"PFMT64x" [%d] {\n", seek+i, otimes-times);
		}
		arg = orig;
		for (idx=0; i<len && arg<argend && *arg; arg++) {
			int size, elem; /* size of the array, element of the array */
			char *fieldname = NULL, *fmtname = NULL, *oarg = NULL;
			if (mode & R_PRINT_UNIONMODE) {
				i = 0;
			}
			seeki = seek+i;
			addr = 0LL;
			invalid = 0;
			if (arg[0] == '[') {
				char *end = strchr (arg,']');
				if (end == NULL) {
					eprintf ("No end bracket.\n");
					goto beach;
				}
				*end = '\0';
				size = r_num_math (NULL, arg+1);
				arg = end + 1;
				*end = ']';
			} else {
				size = -1;
			}
			updateAddr (buf, i, endian, &addr, &addr64);

			tmp = *arg;

			if (args == NULL)
				mode |= R_PRINT_ISFIELD;
			if (mode & R_PRINT_MUSTSEE && otimes>1)
				p->printf ("   ");
			if (idx<nargs && tmp != 'e' && isptr == 0) {
				char *dot = NULL, *bracket = NULL;
				if (field)
					dot = strchr (field, '.');
				if (dot)
					*dot = '\0';
				oarg = fieldname = strdup(r_str_word_get0 (args, idx));
				if (ISSTRUCT || tmp=='E' || tmp=='B') {
					if (*fieldname == '(') {
						fmtname = fieldname+1;
						fieldname = strchr (fieldname, ')');
						if (fieldname) *fieldname++ = '\0';
						else {
							eprintf ("Missing closing parenthesis in format ')'\n");
							free (oarg);
							goto beach;
						}
					} else {
						eprintf ("Missing name (%s)\n", fieldname);
						free(oarg);
						goto beach;
					}
				}
				if (args == NULL || (field==NULL && ofield != MINUSONE)
						|| (field && !strncmp(field, fieldname, strlen(fieldname)))) {
					mode |= R_PRINT_ISFIELD;
				} else {
					mode &= ~R_PRINT_ISFIELD;
				}
				/* There we handle specific element in array */
				if (field != NULL && (bracket = strchr (field, '[')) != NULL && mode & R_PRINT_ISFIELD) {
					char *end = strchr (field, ']');
					if (end == NULL) {
						eprintf ("Missing closing bracket\n");
						goto beach;
					}
					*end = '\0';
					elem = r_num_math (NULL, bracket+1)+1; // +1 to handle 0 index easily
					for ( ; bracket < end; bracket++)
						*bracket = '\0';
					size += elem*ARRAYINDEX_COEF;
				} else {
					elem = -1;
				}
				idx++;
				if (MUSTSEE) {
					p->printf (namefmt, fieldname);
				}
			}

		feed_me_again:
			switch (isptr) {
			case 1:
				{
				nexti = i + (p->bits/8);
				i = 0;
				if(tmp == '?' )seeki = addr;
				memset (buf, '\0', len);
				if (MUSTSEE)
					p->printf ("(*0x%"PFMT64x") ", addr);
				if (addr == 0) isptr = NULLPTR;
				else isptr = PTRBACK;
				if (/*addr<(b+len) && addr>=b && */p->iob.read_at) { /* The test was here to avoid segfault in the next line,
						but len make it doesnt work... */
					p->iob.read_at (p->iob.io, (ut64)addr, buf, len-4);
					updateAddr (buf, i, endian, &addr, &addr64);
				} else {
					eprintf ("(SEGFAULT: cannot read memory at 0x%08"PFMT64x", Block: %s, blocksize: 0x%x)\n",
							addr, b, len);
					p->printf("\n");
					free (oarg);
					goto beach;
				}
				}
				break;
			case 2:
				// restore state after pointer seek
				i = nexti;
				seeki = seek+i;
				memcpy (buf, b, len);
				isptr = NOPTR;
				arg--;
				continue;
			}
			if (tmp == 0 && last != '*')
				break;

			/* skip chars */
			switch (tmp) {
			case '*': // next char is a pointer
				isptr = PTRSEEK;
				arg++;
				tmp = *arg; //last;
				goto feed_me_again;
			case '+': // toggle view flags
				viewflags = !viewflags;
				continue;
			case 'e': // tmp swap endian
				endian ^= 1;
				continue;
			case ':': // skip 4 bytes
				if (size == -1) i+=4;
				else
					while (size--) i+=4;
				continue;
			case '.': // skip 1 byte
				if (size == -1) i++;
				else
					i+=size;
				continue;
			case 'p': // pointer reference
				tmp = (p->bits == 64)? 'q': 'x';
				break;
			}
			/* flags */
			if (mode & R_PRINT_SEEFLAGS && isptr != NULLPTR) {
				if (tmp == '?') {
					p->printf ("f %s.%s_", fmtname, fieldname);
				} else if (tmp == 'E') {
					p->printf ("f %s=0x%08"PFMT64x"\n", fieldname, seeki);
				} else if (slide/STRUCTFLAG>0 && idx==1) {
					p->printf ("%s=0x%08"PFMT64x"\n", fieldname, seeki);
				} else p->printf ("f %s=0x%08"PFMT64x"\n", fieldname , seeki);
			}
			/* json */
			if (mode & R_PRINT_JSON) {
				if (oldslide<=slide) {
					if (!first)
						p->printf (",");
					else
						first = 0;
				} else if(oldslide!=0) {
					p->printf ("]},");
				}
				p->printf ("{\"name\":\"%s\",\"type\":\"", fieldname);
				if (ISSTRUCT) {
					p->printf ("%s", fmtname);
				} else {
					p->printf ("%c", tmp);
				}
				if (isptr) p->printf ("*");
				p->printf ("\",\"offset\":%d,\"value\":",(isptr)?(seek+nexti-(p->bits/8)):seek+i);
			}

			if (isptr == NULLPTR) {
				if (MUSTSEEJSON)
					p->printf ("\"NULL\"}", tmp, seek+i);
				else if (MUSTSEE)
					p->printf ("NULL\n");
				isptr = PTRBACK;
			} else
			/* format chars */
			switch (tmp) {
			case 't':
				r_print_format_time(p, endian, mode, setval, seeki, buf, i, size);
				i+= (size==-1) ? 4 : 4*size;
				break;
			case 'q':
				r_print_format_quadword(p, endian, mode, setval, seeki, buf, i, size);
				i += (size==-1) ? 8 : 8*size;
				break;
			case 'b':
				r_print_format_byte(p, endian, mode, setval, seeki, buf, i, size);
				i+= (size==-1) ? 1 : size;
				break;
			case 'c':
				r_print_format_char (p, endian, mode,
					setval, seeki, buf, i, size);
				i+= (size==-1) ? 1 : size;
				break;
			case 'X':
				size = r_print_format_hexpairs (p, endian, mode,
					setval, seeki, buf, size);
				i += size;
				break;
			case 'T':
				if(r_print_format_10bytes(p, mode,
					setval, seeki, addr, buf) == 0)
					i += (size==-1) ? 4 : 4*size;
				break;
			case 'f':
				r_print_format_float(p, endian, mode, setval, seeki, buf, i, size);
				i += (size==-1) ? 4 : 4*size;
				break;
			case 'i':
			case 'd':
				r_print_format_hex(p, endian, mode, setval, seeki, buf, i, size);
				i+= (size==-1) ? 4 : 4*size;
				break;
			case 'D':
				if (size>0) p->printf ("Size not yet implemented\n");
				if (p->disasm && p->user)
					i += p->disasm (p->user, seeki);
				break;
			case 'o':
				r_print_format_octal (p, endian, mode, setval, seeki, buf, i, size);
				i+= (size==-1) ? 4 : 4*size;
				break;
			case 'x':
				r_print_format_hexflag(p, endian, mode, setval, seeki, buf, i, size);
				i+= (size==-1) ? 4 : 4*size;
				break;
			case 'w':
				r_print_format_word(p, endian, mode, setval, seeki, buf, i, size);
				i+= (size==-1) ? 2 : 2*size;
				break;
			case 'z': // zero terminated string
				r_print_format_nulltermstring (p, len, endian, mode, setval, seeki, buf, i, size);
				if (size == -1)
					i+=strlen((char*)buf+i)+1;
				else
					while (size--) i++;
				break;
			case 'Z': // zero terminated wide string
				r_print_format_nulltermwidestring (p, len, endian, mode, setval, seeki, buf, i, size);
				if (size == -1)
					i+=r_wstr_clen((char*)(buf+seeki))*2+2;
				else
					while (size--) i+=2;
				break;
			case 's':
				if (r_print_format_string (p, seeki, addr64, addr, 0, mode) == 0)
					i += (size==-1) ? 4 : 4*size;
				break;
			case 'S':
				if (r_print_format_string (p, seeki, addr64, addr, 1, mode) == 0)
					i += (size==-1) ? 8 : 8*size;
				break;
			case 'B': // resolve bitfield
				if (size >= ARRAYINDEX_COEF) size %= ARRAYINDEX_COEF;
				r_print_format_bitfield (p, seeki, fmtname, fieldname, addr, mode, size);
				i+=(size==-1)?1:size;
				break;
			case 'E': // resolve enum
				if (size >= ARRAYINDEX_COEF) size %= ARRAYINDEX_COEF;
				r_print_format_enum (p, seeki, fmtname, fieldname, addr, mode, size);
				i+=(size==-1)?1:size;
				break;
			case '?':
				{
				int s = 0;
				char *nxtfield = NULL;
				if (size >= ARRAYINDEX_COEF) {
					elem = size/ARRAYINDEX_COEF-1;
					size %= ARRAYINDEX_COEF;
				}
				if (!(mode & R_PRINT_ISFIELD)) nxtfield = MINUSONE;
				else if (field) nxtfield = strchr (ofield, '.');
				if (nxtfield != MINUSONE && nxtfield != NULL) nxtfield++;

				if (MUSTSEE)
					p->printf ("\n");
				if (MUSTSEEJSON) {
					if (isptr)
						p->printf ("%d},", seeki);
					else
						p->printf ("[");
				}
				if (mode & R_PRINT_SEEFLAGS) slide+=STRUCTFLAG;
				oldslide = slide;
				slide += (isptr) ? STRUCTPTR : NESTEDSTRUCT;
				if (size == -1) {
					s = r_print_format_struct (p, seeki,
						buf+i, len-i, fmtname, slide,
						mode, setval, nxtfield);
					i+= (isptr) ? 4 : s;
				} else {
					p->printf ("[\n");
					while (size--) {
						if (elem == -1 || elem == 0) {
							mode |= R_PRINT_MUSTSEE;
							if (elem == 0) elem = -2;
						} else {
							mode &= ~R_PRINT_MUSTSEE;
						}
						s = r_print_format_struct (p, seek+i,
							buf+i, len-i, fmtname, slide, mode, setval, nxtfield);
						if (size != 0 && elem == -1)
							p->printf (",\n");
						if (elem > -1) elem--;
						i+= (isptr) ? 4 : s;
					}
					if (MUSTSEEJSON) p->printf ("]]}");
					else p->printf ("]");
				}
				oldslide = slide;
				slide -= (isptr) ? STRUCTPTR : NESTEDSTRUCT;
				if (mode & R_PRINT_SEEFLAGS) {
					oldslide = slide;
					slide-=STRUCTFLAG;
				}
				break;
				}
			default:
				/* ignore unknown chars */
				invalid = 1;
				break;
			}
			if (viewflags && p->offname) {
				const char *s = p->offname (p->user, seeki);
				if (s)
					p->printf ("@(%s)", s);
				s = p->offname (p->user, addr);
				if (s)
					p->printf ("*(%s)", s);
			}
			if (tmp != 'D' && !invalid && fmtname==NULL && MUSTSEE)
				p->printf ("\n");
			last = tmp;
			if (oarg)
				free (oarg);
		}
		if (otimes>1) {
			if (MUSTSEEJSON) p->printf ("]");
			else p->printf ("}\n");
		}
		arg = orig;
		oldslide = 0;
	}
	if (mode & R_PRINT_JSON && slide==0) p->printf("]");
beach:
	free (buf);
	free (field);
	if (args)
		free (args);
	return i;
}
Example #2
0
R_API int r_print_format(RPrint *p, ut64 seek, const ut8* b, const int len,
		const char *formatname, int mode, const char *setval, char *ofield) {
	int nargs, i, j, invalid, nexti, idx, times, otimes, endian, isptr = 0;
	const int old_bits = p->bits;
	char *args = NULL, *bracket, tmp, last = 0;
	ut64 addr = 0, addr64 = 0, seeki = 0;
	static int slide = 0, oldslide = 0;
	char namefmt[8], *field = NULL;
	const char *arg = NULL;
	const char *fmt = NULL;
	const char *argend;
	int viewflags = 0;
	char *oarg = NULL;
	ut8 *buf;

	/* Load format from name into fmt */
	if (!formatname) return 0;
	fmt = r_strht_get (p->formats, formatname);
	if (!fmt) fmt = formatname;
	while (*fmt && iswhitechar (*fmt)) fmt++;
	argend = fmt+strlen (fmt);
	arg = fmt;

	nexti = nargs = i = j = 0;

	if (len < 1) return 0;
	// len+2 to save space for the null termination in wide strings
	buf = calloc (1,len + 2);
	if (!buf) return 0;
	memcpy (buf, b, len);
	endian = p->big_endian;

	if (ofield && ofield != MINUSONE) field = strdup (ofield);

	/* get times */
	otimes = times = atoi (arg);
	if (times > 0) {
		while (*arg >= '0' && *arg <= '9') arg++;
	}

	bracket = strchr (arg,'{');
	if (bracket) {
		char *end = strchr (arg, '}');
		if (end == NULL) {
			eprintf ("No end bracket. Try pm {ecx}b @ esi\n");
			goto beach;
		}
		*end = '\0';
		times = r_num_math (NULL, bracket+1);
		arg = end + 1;
	}

	if (*arg=='\0') {
		goto beach;
	}

	/* get args */
	args = get_args_offset (arg);
	if (args) {
		int l=0, maxl = 0;
		argend = args;
		args = strdup (args+1);
		nargs = r_str_word_set0 (args);
		if (nargs == 0)
			R_FREE (args);
		for (i=0; i<nargs; i++) {
			const int len = strlen (r_str_word_get0 (args, i));
			if (len > maxl)
				maxl = len;
		}
		l++;
		snprintf (namefmt, sizeof (namefmt), "%%%ds : ", maxl+6*slide%STRUCTPTR);
	}
#define ISPOINTED ((slide%STRUCTFLAG)/STRUCTPTR<=(oldslide%STRUCTFLAG)/STRUCTPTR)
#define ISNESTED ((slide%STRUCTPTR)<=(oldslide%STRUCTPTR))
	if (mode == R_PRINT_JSON && slide==0) p->cb_printf("[");
	if (arg[0] == '0') {
		mode |= R_PRINT_UNIONMODE;
		arg++;
	} else {
		mode &= ~R_PRINT_UNIONMODE;
	}
	if (mode & R_PRINT_DOT) {
		char *fmtname;
		if (formatname && *formatname) {
			if (strchr (formatname, ' ')) {
				fmtname = r_str_newf ("0x%"PFMT64x, seek);
			} else {
				fmtname = strdup (formatname);
			}
		} else {
			fmtname = r_str_newf ("0x%"PFMT64x, seek);
		}
		p->cb_printf ("digraph g { graph [ rank=same; rankdir=LR; ];\n");
		p->cb_printf ("root [ rank=1; shape=record\nlabel=\"%s", fmtname);
	}

	/* go format */
	i = 0;
	if (!times)
		otimes = times = 1;
	for (; times; times--) { // repeat N times
		const char * orig = arg;
		int first = 1;
		if (otimes>1) {
			if (mode & R_PRINT_JSON) {
				if (otimes > times) p->cb_printf (",");
				p->cb_printf ("[{\"index\":%d,\"offset\":%d},", otimes-times, seek+i);
			} else {
				p->cb_printf ("0x%08"PFMT64x" [%d] {\n", seek+i, otimes-times);
			}
		}
		arg = orig;
		for (idx=0; i<len && arg<argend && *arg; arg++) {
			int size = 0, elem = 0; /* size of the array, element of the array */
			char *fieldname = NULL, *fmtname = NULL;
			if (mode & R_PRINT_UNIONMODE) {
				i = 0;
			}
			seeki = seek+i;
			addr = 0LL;
			invalid = 0;
			p->bits = old_bits;
			if (arg[0] == '[') {
				char *end = strchr (arg,']');
				if (end == NULL) {
					eprintf ("No end bracket.\n");
					goto beach;
				}
				*end = '\0';
				size = r_get_size (p->num, buf, endian, arg+1);
				arg = end + 1;
				*end = ']';
			} else {
				size = -1;
			}
			if (i+7<len) { // Max byte number where updateAddr will look into
				updateAddr (buf, i, endian, &addr, &addr64);
			} else {
				eprintf ("Likely a heap buffer overflow in %s at %d\n", __FILE__, __LINE__);
				goto beach;
			}

			tmp = *arg;

			if (args == NULL)
				mode |= R_PRINT_ISFIELD;
			if (mode & R_PRINT_MUSTSEE && otimes>1)
				p->cb_printf ("   ");
			if (idx<nargs && tmp != 'e' && isptr == 0) {
				char *dot = NULL, *bracket = NULL;
				if (field)
					dot = strchr (field, '.');
				if (dot)
					*dot = '\0';
				if (oarg != NULL)
					free (oarg);
				oarg = fieldname = strdup(r_str_word_get0 (args, idx));
				if (ISSTRUCT || tmp=='E' || tmp=='B' || tmp=='r') {
					if (*fieldname == '(') {
						fmtname = fieldname+1;
						fieldname = strchr (fieldname, ')');
						if (fieldname) *fieldname++ = '\0';
						else {
							eprintf ("Missing closing parenthesis in format ')'\n");
							goto beach;
						}
					} else {
						eprintf ("Missing name (%s)\n", fieldname);
						goto beach;
					}
				}
				if (args == NULL || (field==NULL && ofield != MINUSONE)
						|| (field && !strncmp(field, fieldname,
								strchr(field, '[')!=NULL?strchr(field, '[')-field:strlen(field)+1))) {
					mode |= R_PRINT_ISFIELD;
				} else {
					mode &= ~R_PRINT_ISFIELD;
				}

				/* There we handle specific element in array */
				if (field != NULL && (bracket = strchr (field, '[')) != NULL && mode & R_PRINT_ISFIELD) {
					char *end = strchr (field, ']');
					if (end == NULL) {
						eprintf ("Missing closing bracket\n");
						goto beach;
					}
					*end = '\0';
					elem = r_num_math (NULL, bracket+1)+1; // +1 to handle 0 index easily
					for ( ; bracket < end; bracket++)
						*bracket = '\0';
					size += elem*ARRAYINDEX_COEF;
				} else {
					elem = -1;
				}
				idx++;
				if (MUSTSEE && !SEEVALUE) {
					p->cb_printf (namefmt, fieldname);
				}
			}

		feed_me_again:
			switch (isptr) {
			case PTRSEEK:
				{
				nexti = i + (p->bits/8);
				i = 0;
				if (tmp == '?' ) seeki = addr;
				memset (buf, '\0', len);
				if (MUSTSEE)
					p->cb_printf ("(*0x%"PFMT64x") ", addr);
				if (addr == 0) isptr = NULLPTR;
				else isptr = PTRBACK;
				if (/*addr<(b+len) && addr>=b && */p->iob.read_at) { /* The test was here to avoid segfault in the next line,
						but len make it doesnt work... */
					p->iob.read_at (p->iob.io, (ut64)addr, buf, len-4);
					if (i+3<len || i+7<len)
						updateAddr (buf, i, endian, &addr, &addr64);
					else {
						eprintf ("Likely a heap buffer overflow at %s at %d\n", __FILE__, __LINE__);
						goto beach;
					}
				} else {
					eprintf ("(SEGFAULT: cannot read memory at 0x%08"PFMT64x", Block: %s, blocksize: 0x%x)\n",
							addr, b, len);
					p->cb_printf("\n");
					goto beach;
				}
				}
				break;
			case PTRBACK:
				// restore state after pointer seek
				i = nexti;
				memcpy (buf, b, len);
				isptr = NOPTR;
				arg--;
				continue;
			}
			if (tmp == 0 && last != '*')
				break;

			/* skip chars */
			switch (tmp) {
			case '*': // next char is a pointer
				isptr = PTRSEEK;
				arg++;
				tmp = *arg; //last;
				goto feed_me_again;
			case '+': // toggle view flags
				viewflags = !viewflags;
				continue;
			case 'e': // tmp swap endian
				endian ^= 1;
				continue;
			case ':': // skip 4 bytes
				if (size == -1) i+=4;
				else while (size--) i+=4;
				continue;
			case '.': // skip 1 byte
				if (size == -1) i++;
				else i+=size;
				continue;
			case 'p': // pointer reference
				if (*(arg+1) == '2') {
					p->bits = 16;
					arg++;
				} else if (*(arg+1) == '4') {
					p->bits = 32;
					arg++;
				} else if (*(arg+1) == '8') {
					p->bits = 64;
					arg++;
				}
				switch (p->bits) {
					case 16: tmp = 'w'; break;
					case 32: tmp = 'x'; break;
					default: tmp = 'q'; break;
				}
				break;
			}

			/* flags */
			if (mode & R_PRINT_SEEFLAGS && isptr != NULLPTR) {
				char *newname = NULL;
				if (!fieldname) {
					newname = fieldname = r_str_newf ("pf.%d", seeki);
				}
				if (mode & R_PRINT_UNIONMODE) {
					p->cb_printf ("f %s=0x%08"PFMT64x"\n", formatname, seeki);
					goto beach;
				} else if (tmp == '?') {
					p->cb_printf ("f %s.%s_", fmtname, fieldname);
				} else if (tmp == 'E') {
					p->cb_printf ("f %s=0x%08"PFMT64x"\n", fieldname, seeki);
				} else if (slide/STRUCTFLAG>0 && idx==1) {
					p->cb_printf ("%s=0x%08"PFMT64x"\n", fieldname, seeki);
				} else p->cb_printf ("f %s=0x%08"PFMT64x"\n", fieldname , seeki);
				if (newname) {
					free (newname);
					newname = fieldname = NULL;
				}
			}

			/* dot */
			if (mode & R_PRINT_DOT) {
				if (fieldname) {
					p->cb_printf ("|{0x%"PFMT64x"|%c|%s|<%s>",
						seeki, tmp, fieldname, fieldname);
				} else {
					p->cb_printf ("|{0x%"PFMT64x"|%c|",
						seeki, tmp);
				}
			}

			/* json */
			if (MUSTSEEJSON && mode & R_PRINT_JSON) {
				if (oldslide <= slide) {
					if (first) first = 0;
					else p->cb_printf (",");
				} else if (oldslide) {
					p->cb_printf ("]},");
				}
				p->cb_printf ("{\"name\":\"%s\",\"type\":\"", fieldname);
				if (ISSTRUCT) {
					p->cb_printf ("%s", fmtname);
				} else {
					p->cb_printf ("%c", tmp);
				}
				if (isptr) p->cb_printf ("*");
				p->cb_printf ("\",\"offset\":%d,\"value\":",(isptr)?(seek+nexti-(p->bits/8)):seek+i);
			}

			if (isptr == NULLPTR) {
				if (MUSTSEEJSON) p->cb_printf ("\"NULL\"}", tmp, seek+i);
				else if (MUSTSEE) p->cb_printf ("NULL\n");
				isptr = PTRBACK;
			} else
			/* format chars */
			// before to enter in the switch statement check buf boundaries due to  updateAddr
			// might go beyond its len and it's usually called in each of the following functions
			if (((i+3)<len) || (i+7)<len) {
				switch (tmp) {
				case 'u':
					i+= r_print_format_uleb (p, endian, mode, setval, seeki, buf, i, size);
					break;
				case 't':
					r_print_format_time (p, endian, mode, setval, seeki, buf, i, size);
					i+= (size==-1) ? 4 : 4*size;
					break;
				case 'q':
					r_print_format_quadword (p, endian, mode, setval, seeki, buf, i, size);
					i += (size==-1) ? 8 : 8*size;
					break;
				case 'b':
					r_print_format_byte (p, endian, mode, setval, seeki, buf, i, size);
					i+= (size==-1) ? 1 : size;
					break;
				case 'C':
					r_print_format_decchar (p, endian, mode,
						setval, seeki, buf, i, size);
					i+= (size==-1) ? 1 : size;
					break;
				case 'c':
					r_print_format_char (p, endian, mode,
						setval, seeki, buf, i, size);
					i+= (size==-1) ? 1 : size;
					break;
				case 'X':
					size = r_print_format_hexpairs (p, endian, mode,
						setval, seeki, buf, i, size);
					i += size;
					break;
				case 'T':
					if (r_print_format_10bytes (p, mode,
						setval, seeki, addr, buf) == 0)
						i += (size==-1) ? 4 : 4*size;
					break;
				case 'f':
					r_print_format_float (p, endian, mode, setval, seeki, buf, i, size);
					i += (size==-1) ? 4 : 4*size;
					break;
				case 'i':
				case 'd':
					r_print_format_hex (p, endian, mode, setval, seeki, buf, i, size);
					i+= (size==-1) ? 4 : 4*size;
					break;
				case 'D':
					if (size>0) p->cb_printf ("Size not yet implemented\n");
					if (p->disasm && p->user)
						i += p->disasm (p->user, seeki);
					break;
				case 'o':
					r_print_format_octal (p, endian, mode, setval, seeki, buf, i, size);
					i+= (size==-1) ? 4 : 4*size;
					break;
				case 'x':
					r_print_format_hexflag (p, endian, mode, setval, seeki, buf, i, size);
					i+= (size==-1) ? 4 : 4*size;
					break;
				case 'w':
					r_print_format_word(p, endian, mode, setval, seeki, buf, i, size);
					i+= (size==-1) ? 2 : 2*size;
					break;
				case 'z': // zero terminated string
					r_print_format_nulltermstring (p, len, endian, mode, setval, seeki, buf, i, size);
					if (size == -1)
						i+=strlen((char*)buf+i)+1;
					else
						while (size--) i++;
					break;
				case 'Z': // zero terminated wide string
					r_print_format_nulltermwidestring (p, len, endian, mode, setval, seeki, buf, i, size);
					if (size == -1)
						i += r_wstr_clen((char*)(buf+i))*2+2;
					else
						while (size--) i+=2;
					break;
				case 's':
					if (r_print_format_string (p, seeki, addr64, addr, 0, mode) == 0)
						i += (size==-1) ? 4 : 4*size;
					break;
				case 'S':
					if (r_print_format_string (p, seeki, addr64, addr, 1, mode) == 0)
						i += (size==-1) ? 8 : 8*size;
					break;
				case 'B': // resolve bitfield
					if (size >= ARRAYINDEX_COEF) size %= ARRAYINDEX_COEF;
					r_print_format_bitfield (p, seeki, fmtname, fieldname, addr, mode, size);
					i+=(size==-1)?1:size;
					break;
				case 'E': // resolve enum
					if (size >= ARRAYINDEX_COEF) size %= ARRAYINDEX_COEF;
					r_print_format_enum (p, seeki, fmtname, fieldname, addr, mode, size);
					i+=(size==-1)?1:size;
					break;
				case 'r':
					r_print_format_register (p, mode, fmtname, setval);
					break;
				case '?':
					{
					int s = 0;
					char *nxtfield = NULL;
					if (size >= ARRAYINDEX_COEF) {
						elem = size/ARRAYINDEX_COEF-1;
						size %= ARRAYINDEX_COEF;
					}
					if (!(mode & R_PRINT_ISFIELD)) nxtfield = MINUSONE;
					else if (field) nxtfield = strchr (ofield, '.');
					if (nxtfield != MINUSONE && nxtfield != NULL) nxtfield++;

					if (MUSTSEE)
						if (!SEEVALUE) p->cb_printf ("\n");
					if (MUSTSEEJSON) {
						if (isptr)
							p->cb_printf ("%d},", seeki);
						else
							p->cb_printf ("[");
					}
					if (mode & R_PRINT_SEEFLAGS) slide+=STRUCTFLAG;
					oldslide = slide;
					slide += (isptr) ? STRUCTPTR : NESTEDSTRUCT;
					if (size == -1) {
						s = r_print_format_struct (p, seeki,
							buf+i, len-i, fmtname, slide,
							mode, setval, nxtfield);
						i+= (isptr) ? 4 : s;
					} else {
						if (mode & R_PRINT_ISFIELD)
							if (!SEEVALUE) p->cb_printf ("[\n");
						while (size--) {
							if (elem == -1 || elem == 0) {
								mode |= R_PRINT_MUSTSEE;
								if (elem == 0) elem = -2;
							} else {
								mode &= ~R_PRINT_MUSTSEE;
							}
							s = r_print_format_struct (p, seek+i,
								buf+i, len-i, fmtname, slide, mode, setval, nxtfield);
							if ((MUSTSEE || MUSTSEEJSON) && size != 0 && elem == -1) {
								p->cb_printf (",");
								if (MUSTSEE) p->cb_printf ("\n");
							}
							if (elem > -1) elem--;
							i+= (isptr) ? 4 : s;
						}
						if (mode & R_PRINT_ISFIELD)
							if (!SEEVALUE) p->cb_printf ("]");
						if (MUSTSEEJSON) p->cb_printf ("]}]}");
					}
					oldslide = slide;
					slide -= (isptr) ? STRUCTPTR : NESTEDSTRUCT;
					if (mode & R_PRINT_SEEFLAGS) {
						oldslide = slide;
						slide-=STRUCTFLAG;
					}
					break;
					}
				default:
					/* ignore unknown chars */
					invalid = 1;
					break;
				} //switch
			} else {
				eprintf ("Likely a heap buffer overflow in %s at %d\n", __FILE__, __LINE__);
				goto beach;
			}
			if (mode & R_PRINT_DOT) {
				p->cb_printf ("}");
			}
			if (viewflags && p->offname) {
				const char *s = p->offname (p->user, seeki);
				if (s)
					p->cb_printf ("@(%s)", s);
				s = p->offname (p->user, addr);
				if (s)
					p->cb_printf ("*(%s)", s);
			}
			if (tmp != 'D' && !invalid && fmtname==NULL && MUSTSEE)
				p->cb_printf ("\n");
			last = tmp;
		}
		if (otimes>1) {
			if (MUSTSEEJSON) p->cb_printf ("]");
			else p->cb_printf ("}\n");
		}
		arg = orig;
		oldslide = 0;
	}
	if (mode & R_PRINT_JSON && slide==0) p->cb_printf("]\n");
	if (mode & R_PRINT_DOT) {
		p->cb_printf ("\"];\n}\n");
		// TODO: show nested structs and field reference lines
	}
beach:
	free (oarg);
	free (buf);
	free (field);
	free (args);
	return i;
}