3 * Copyright 2015 The Android Open Source Project
5 * No obvious standard, output looks like:
6 * 0000000: 4c69 6e75 7820 7665 7273 696f 6e20 332e Linux version 3.
8 * TODO: support for reversing a hexdump back into the original data.
11 USE_XXD(NEWTOY(xxd, ">1c#<1>4096=16l#g#<1=2pr", TOYFLAG_USR|TOYFLAG_BIN))
17 usage: xxd [-c n] [-g n] [-l n] [-p] [-r] [file]
19 Hexdump a file to stdout. If no file is listed, copy from stdin.
20 Filename "-" is a synonym for stdin.
22 -c n Show n bytes per line (default 16).
23 -g n Group bytes by adding a ' ' every n bytes (default 2).
24 -l n Limit of n bytes before stopping (default is no limit).
25 -p Plain hexdump (30 bytes/line, no grouping).
26 -r Reverse operation: turn a hexdump into a binary file.
38 static void do_xxd(int fd, char *name)
43 while (0<(len = readall(fd, toybuf, (TT.l && TT.l-pos<TT.c)?TT.l-pos:TT.c))) {
44 if (!(toys.optflags&FLAG_p)) printf("%08llx: ", pos);
46 space = 2*TT.c+TT.c/TT.g+1;
49 space -= printf("%02x", toybuf[i]);
56 if (!(toys.optflags&FLAG_p)) {
57 printf("%*s", space, "");
59 putchar((toybuf[i]>=' ' && toybuf[i]<='~') ? toybuf[i] : '.');
63 if (len<0) perror_exit("read");
66 static int dehex(char ch)
68 if (ch >= '0' && ch <= '9') return ch - '0';
69 if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
70 if (ch >= 'A' && ch <= 'F') return ch - 'a' + 10;
71 return (ch == '\n') ? -2 : -1;
74 static void do_xxd_reverse(int fd, char *name)
76 FILE *fp = xfdopen(fd, "r");
82 // Each line of a non-plain hexdump starts with an offset/address.
83 if (!(toys.optflags&FLAG_p)) {
86 if (fscanf(fp, "%llx: ", &pos) == 1) {
87 if (fseek(stdout, pos, SEEK_SET) != 0) {
88 // TODO: just write out zeros if non-seekable?
89 perror_exit("%s: seek failed", name);
94 // A plain hexdump can have as many bytes per line as you like,
95 // but a non-plain hexdump assumes garbage after it's seen the
96 // specified number of bytes.
97 while (toys.optflags&FLAG_p || col < TT.c) {
100 // If we're at EOF or EOL or we read some non-hex...
101 if ((n1 = n2 = dehex(fgetc(fp))) < 0 || (n2 = dehex(fgetc(fp))) < 0) {
102 // If we're at EOL, start on that line.
103 if (n1 == -2 || n2 == -2) continue;
104 // Otherwise, skip to the next line.
108 fputc((n1 << 4) | (n2 & 0xf), stdout);
111 // Is there any grouping going on? Ignore a single space.
113 if (tmp != ' ') ungetc(tmp, fp);
116 // Skip anything else on this line (such as the ASCII dump).
117 while ((tmp = fgetc(fp)) != EOF && tmp != '\n')
120 if (ferror(fp)) perror_msg_raw(name);
127 // Plain style is 30 bytes/line, no grouping.
128 if (toys.optflags&FLAG_p) TT.c = TT.g = 30;
130 loopfiles(toys.optargs, toys.optflags&FLAG_r ? do_xxd_reverse : do_xxd);