1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57#include "libbb.h"
58#include "common_bufsiz.h"
59#include "dump.h"
60
61
62
63#define OPT_l (1 << 0)
64#define OPT_s (1 << 1)
65#define OPT_a (1 << 2)
66#define OPT_p (1 << 3)
67#define OPT_i (1 << 4)
68#define OPT_r (1 << 5)
69#define OPT_g (1 << 6)
70#define OPT_c (1 << 7)
71#define OPT_o (1 << 8)
72
73#define fillbuf bb_common_bufsiz1
74
75static void write_zeros(off_t count)
76{
77 errno = 0;
78 do {
79 unsigned sz = count < COMMON_BUFSIZE ? (unsigned)count : COMMON_BUFSIZE;
80 if (fwrite(fillbuf, 1, sz, stdout) != sz)
81 bb_simple_perror_msg_and_die("write error");
82 count -= sz;
83 } while (count != 0);
84}
85
86static void reverse(unsigned opt, const char *filename, char *opt_s)
87{
88 FILE *fp;
89 char *buf;
90 off_t cur, opt_s_ofs;
91
92 memset(fillbuf, 0, COMMON_BUFSIZE);
93 opt_s_ofs = cur = 0;
94 if (opt_s) {
95 opt_s_ofs = BB_STRTOOFF(opt_s, NULL, 0);
96 if (errno || opt_s_ofs < 0)
97 bb_error_msg_and_die("invalid number '%s'", opt_s);
98 }
99
100 fp = filename ? xfopen_for_read(filename) : stdin;
101
102 get_new_line:
103 while ((buf = xmalloc_fgetline(fp)) != NULL) {
104 char *p;
105
106 p = buf;
107 if (!(opt & OPT_p)) {
108 char *end;
109 off_t ofs;
110 skip_address:
111 p = skip_whitespace(p);
112 ofs = BB_STRTOOFF(p, &end, 16);
113 if ((errno && errno != EINVAL)
114 || ofs < 0
115
116 || (ofs += opt_s_ofs) < 0
117 ) {
118 bb_error_msg_and_die("invalid number '%s'", p);
119 }
120 if (ofs != cur) {
121 if (fseeko(stdout, ofs, SEEK_SET) != 0) {
122 if (ofs < cur)
123 bb_simple_perror_msg_and_die("cannot seek");
124 write_zeros(ofs - cur);
125 }
126 cur = ofs;
127 }
128 p = end;
129
130
131 if (*p == ':')
132 p++;
133 }
134
135
136 for (;;) {
137 uint8_t val, c;
138 int badchar = 0;
139 nibble1:
140 if (opt & OPT_p)
141 p = skip_whitespace(p);
142 c = *p++;
143 if (isdigit(c))
144 val = c - '0';
145 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
146 val = (c|0x20) - ('a' - 10);
147 else {
148
149
150
151
152
153
154
155
156
157
158
159
160 if (c == '\0' || badchar)
161 break;
162 badchar++;
163 goto nibble1;
164 }
165 val <<= 4;
166
167 nibble2:
168 if (opt & OPT_p) {
169
170
171
172
173
174
175 p = skip_whitespace(p);
176 }
177
178 c = *p++;
179 if (isdigit(c))
180 val |= c - '0';
181 else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
182 val |= (c|0x20) - ('a' - 10);
183 else {
184 if (c != '\0') {
185
186
187
188 while (!isxdigit(*p)) {
189 if (*p == '\0') {
190 free(buf);
191 goto get_new_line;
192 }
193 p++;
194 }
195 goto nibble1;
196 }
197
198
199
200
201 free(buf);
202 p = buf = xmalloc_fgetline(fp);
203 if (!buf)
204 break;
205 if (!(opt & OPT_p))
206 goto skip_address;
207 goto nibble2;
208 }
209 putchar(val);
210 cur++;
211 }
212 free(buf);
213 }
214
215 fflush_stdout_and_exit_SUCCESS();
216}
217
218static void print_C_style(const char *p, const char *hdr)
219{
220 printf(hdr, isdigit(p[0]) ? "__" : "");
221 while (*p) {
222 bb_putchar(isalnum(*p) ? *p : '_');
223 p++;
224 }
225}
226
227int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
228int xxd_main(int argc UNUSED_PARAM, char **argv)
229{
230 char buf[80];
231 dumper_t *dumper;
232 char *opt_l, *opt_o;
233 char *opt_s = NULL;
234 unsigned bytes = 2;
235 unsigned cols = 0;
236 unsigned opt;
237 int r;
238
239 setup_common_bufsiz();
240
241 dumper = alloc_dumper();
242
243 opt = getopt32(argv, "^" "l:s:apirg:+c:+o:" "\0" "?1" ,
244 &opt_l, &opt_s, &bytes, &cols, &opt_o
245 );
246 argv += optind;
247
248 dumper->dump_vflag = ALL;
249
250
251 if (opt & OPT_l) {
252 dumper->dump_length = xstrtou_range(
253 opt_l,
254 0,
255 0, INT_MAX
256 );
257 }
258 if (opt & OPT_s) {
259 dumper->dump_skip = xstrtoull_range(
260 opt_s,
261 0,
262 0, OFF_T_MAX
263 );
264
265 }
266
267 if (opt & OPT_r) {
268 reverse(opt, argv[0], opt_s);
269 }
270
271 if (opt & OPT_o) {
272
273 dumper->xxd_displayoff = xstrtoll(opt_o, 0);
274 }
275
276 if (opt & OPT_p) {
277 if (cols == 0)
278 cols = 30;
279 bytes = cols;
280 } else {
281 if (cols == 0)
282 cols = (opt & OPT_i) ? 12 : 16;
283 if (opt & OPT_i) {
284 bytes = 1;
285
286 bb_dump_add(dumper, "\" \"");
287 } else
288 bb_dump_add(dumper, "\"%08_ax: \"");
289 }
290
291 if (bytes < 1 || bytes >= cols) {
292 sprintf(buf, "%u/1 \"%%02x\"", cols);
293 bb_dump_add(dumper, buf);
294 }
295 else if (bytes == 1) {
296 if (opt & OPT_i)
297 sprintf(buf, "%u/1 \" 0x%%02x,\"", cols);
298
299 else
300 sprintf(buf, "%u/1 \"%%02x \"", cols);
301 bb_dump_add(dumper, buf);
302 }
303 else {
304
305#define BS "/1 \"%02x \""
306#define B "/1 \"%02x\""
307 unsigned i;
308 char *bigbuf = xmalloc(cols * (sizeof(BS)-1));
309 char *p = bigbuf;
310 for (i = 1; i <= cols; i++) {
311 if (i == cols || i % bytes)
312 p = stpcpy(p, B);
313 else
314 p = stpcpy(p, BS);
315 }
316
317
318
319
320 bb_dump_add(dumper, bigbuf);
321 free(bigbuf);
322 }
323
324 if (!(opt & (OPT_p|OPT_i))) {
325 sprintf(buf, "\" \"%u/1 \"%%_p\"\"\n\"", cols);
326 bb_dump_add(dumper, buf);
327 } else {
328 bb_dump_add(dumper, "\"\n\"");
329 dumper->xxd_eofstring = "\n";
330 }
331
332 if ((opt & OPT_i) && argv[0]) {
333 print_C_style(argv[0], "unsigned char %s");
334 printf("[] = {\n");
335 }
336 r = bb_dump_dump(dumper, argv);
337 if (r == 0 && (opt & OPT_i) && argv[0]) {
338 print_C_style(argv[0], "};\nunsigned int %s");
339 printf("_len = %"OFF_FMT"u;\n", dumper->address);
340 }
341 return r;
342}
343