1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "hexdump.h"
44 #include "xalloc.h"
45 #include "c.h"
46 #include "nls.h"
47 #include "colors.h"
48
49 static void doskip(const char *, int, struct hexdump *);
50 static u_char *get(struct hexdump *);
51
52 enum _vflag vflag = FIRST;
53
54 static off_t address; /* address/offset in stream */
55 static off_t eaddress; /* end address */
56
57 static const char *color_cond(struct hexdump_pr *pr, unsigned char *bp, int bcnt)
58 {
59 register struct list_head *p;
60 register struct hexdump_clr *clr;
61 off_t offt;
62 int match;
63
64 list_for_each(p, pr->colorlist) {
65 clr = list_entry(p, struct hexdump_clr, colorlist);
66 offt = clr->offt;
67 match = 0;
68
69 /* no offset or offset outside this print unit */
70 if (offt < 0)
71 offt = address;
72 if (offt < address || offt + clr->range > address + bcnt)
73 continue;
74
75 /* match a string */
76 if (clr->str) {
77 if (pr->flags == F_ADDRESS) {
78 /* TODO */
79 }
80 else if (!strncmp(clr->str, (char *)bp + offt
81 - address, clr->range))
82 match = 1;
83 /* match a value */
84 } else if (clr->val != -1) {
85 int val = 0;
86 /* addresses are not part of the input, so we can't
87 * compare with the contents of bp */
88 if (pr->flags == F_ADDRESS) {
89 if (clr->val == address)
90 match = 1;
91 } else {
92 memcpy(&val, bp + offt - address, clr->range);
93 if (val == clr->val)
94 match = 1;
95 }
96 /* no conditions, only a color was specified */
97 } else
98 return clr->fmt;
99
100 /* return the format string or check for another */
101 if (match ^ clr->invert)
102 return clr->fmt;
103 }
104
105 /* no match */
106 return NULL;
107 }
108
109 static inline void
110 print(struct hexdump_pr *pr, unsigned char *bp) {
111
112 const char *color = NULL;
113
114 if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt)))
115 color_enable(color);
116
117 switch(pr->flags) {
118 case F_ADDRESS:
119 printf(pr->fmt, address);
120 break;
121 case F_BPAD:
122 printf(pr->fmt, "");
123 break;
124 case F_C:
125 conv_c(pr, bp);
126 break;
127 case F_CHAR:
128 printf(pr->fmt, *bp);
129 break;
130 case F_DBL:
131 {
132 double dval;
133 float fval;
134 switch(pr->bcnt) {
135 case 4:
136 memmove(&fval, bp, sizeof(fval));
137 printf(pr->fmt, fval);
138 break;
139 case 8:
140 memmove(&dval, bp, sizeof(dval));
141 printf(pr->fmt, dval);
142 break;
143 }
144 break;
145 }
146 case F_INT:
147 {
148 char cval; /* int8_t */
149 short sval; /* int16_t */
150 int ival; /* int32_t */
151 long long Lval; /* int64_t, int64_t */
152
153 switch(pr->bcnt) {
154 case 1:
155 memmove(&cval, bp, sizeof(cval));
156 printf(pr->fmt, (unsigned long long) cval);
157 break;
158 case 2:
159 memmove(&sval, bp, sizeof(sval));
160 printf(pr->fmt, (unsigned long long) sval);
161 break;
162 case 4:
163 memmove(&ival, bp, sizeof(ival));
164 printf(pr->fmt, (unsigned long long) ival);
165 break;
166 case 8:
167 memmove(&Lval, bp, sizeof(Lval));
168 printf(pr->fmt, Lval);
169 break;
170 }
171 break;
172 }
173 case F_P:
174 printf(pr->fmt, isprint(*bp) ? *bp : '.');
175 break;
176 case F_STR:
177 printf(pr->fmt, (char *)bp);
178 break;
179 case F_TEXT:
180 printf("%s", pr->fmt);
181 break;
182 case F_U:
183 conv_u(pr, bp);
184 break;
185 case F_UINT:
186 {
187 unsigned short sval; /* u_int16_t */
188 unsigned int ival; /* u_int32_t */
189 unsigned long long Lval;/* u_int64_t, u_int64_t */
190
191 switch(pr->bcnt) {
192 case 1:
193 printf(pr->fmt, (unsigned long long) *bp);
194 break;
195 case 2:
196 memmove(&sval, bp, sizeof(sval));
197 printf(pr->fmt, (unsigned long long) sval);
198 break;
199 case 4:
200 memmove(&ival, bp, sizeof(ival));
201 printf(pr->fmt, (unsigned long long) ival);
202 break;
203 case 8:
204 memmove(&Lval, bp, sizeof(Lval));
205 printf(pr->fmt, Lval);
206 break;
207 }
208 break;
209 }
210 }
211 if (color) /* did we colorize something? */
212 color_disable();
213 }
214
215 static void bpad(struct hexdump_pr *pr)
216 {
217 static const char *spec = " -0+#";
218 char *p1, *p2;
219
220 /*
221 * remove all conversion flags; '-' is the only one valid
222 * with %s, and it's not useful here.
223 */
224 pr->flags = F_BPAD;
225 pr->cchar[0] = 's';
226 pr->cchar[1] = 0;
227
228 p1 = pr->fmt;
229 while (*p1 != '%')
230 ++p1;
231
232 p2 = ++p1;
233 while (*p1 && strchr(spec, *p1))
234 ++p1;
235
236 while ((*p2++ = *p1++))
237 ;
238 }
239
240 void display(struct hexdump *hex)
241 {
242 register struct list_head *fs;
243 register struct hexdump_fs *fss;
244 register struct hexdump_fu *fu;
245 register struct hexdump_pr *pr;
246 register int cnt;
247 register unsigned char *bp;
248 off_t saveaddress;
249 unsigned char savech = 0, *savebp;
250 struct list_head *p, *q, *r;
251
252 while ((bp = get(hex)) != NULL) {
253 fs = &hex->fshead; savebp = bp; saveaddress = address;
254
255 list_for_each(p, fs) {
256 fss = list_entry(p, struct hexdump_fs, fslist);
257
258 list_for_each(q, &fss->fulist) {
259 fu = list_entry(q, struct hexdump_fu, fulist);
260
261 if (fu->flags&F_IGNORE)
262 break;
263
264 cnt = fu->reps;
265
266 while (cnt) {
267 list_for_each(r, &fu->prlist) {
268 pr = list_entry(r, struct hexdump_pr, prlist);
269
270 if (eaddress && address >= eaddress
271 && !(pr->flags&(F_TEXT|F_BPAD)))
272 bpad(pr);
273
274 if (cnt == 1 && pr->nospace) {
275 savech = *pr->nospace;
276 *pr->nospace = '\0';
277 print(pr, bp);
278 *pr->nospace = savech;
279 } else
280 print(pr, bp);
281
282 address += pr->bcnt;
283 bp += pr->bcnt;
284 }
285 --cnt;
286 }
287 }
288 bp = savebp;
289 address = saveaddress;
290 }
291 }
292 if (endfu) {
293 /*
294 * if eaddress not set, error or file size was multiple of
295 * blocksize, and no partial block ever found.
296 */
297 if (!eaddress) {
298 if (!address)
299 return;
300 eaddress = address;
301 }
302 list_for_each (p, &endfu->prlist) {
303 const char *color = NULL;
304
305 pr = list_entry(p, struct hexdump_pr, prlist);
306 if (colors_wanted() && pr->colorlist
307 && (color = color_cond(pr, bp, pr->bcnt))) {
308 color_enable(color);
309 }
310
311 switch(pr->flags) {
312 case F_ADDRESS:
313 printf(pr->fmt, eaddress);
314 break;
315 case F_TEXT:
316 printf("%s", pr->fmt);
317 break;
318 }
319 if (color) /* did we highlight something? */
320 color_disable();
321 }
322 }
323 }
324
325 static char **_argv;
326
327 static u_char *
328 get(struct hexdump *hex)
329 {
330 static int ateof = 1;
331 static u_char *curp, *savp;
332 ssize_t n, need, nread;
333 u_char *tmpp;
334
335 if (!curp) {
336 curp = xcalloc(1, hex->blocksize);
337 savp = xcalloc(1, hex->blocksize);
338 } else {
339 tmpp = curp;
340 curp = savp;
341 savp = tmpp;
342 address += hex->blocksize;
343 }
344 need = hex->blocksize, nread = 0;
345 while (TRUE) {
346 /*
347 * if read the right number of bytes, or at EOF for one file,
348 * and no other files are available, zero-pad the rest of the
349 * block and set the end flag.
350 */
351 if (!hex->length || (ateof && !next(NULL, hex))) {
352 if (need == hex->blocksize)
353 goto retnul;
354 if (!need && vflag != ALL &&
355 !memcmp(curp, savp, nread)) {
356 if (vflag != DUP)
357 printf("*\n");
358 goto retnul;
359 }
360 if (need > 0)
361 memset((char *)curp + nread, 0, need);
362 eaddress = address + nread;
363 return(curp);
364 }
365 if (fileno(stdin) == -1) {
366 warnx(_("all input file arguments failed"));
367 goto retnul;
368 }
369 n = fread((char *)curp + nread, sizeof(unsigned char),
370 hex->length == -1 ? need : min(hex->length, need), stdin);
371 if (!n) {
372 if (ferror(stdin))
373 warn("%s", _argv[-1]);
374 ateof = 1;
375 continue;
376 }
377 ateof = 0;
378 if (hex->length != -1)
379 hex->length -= n;
380 if (!(need -= n)) {
381 if (vflag == ALL || vflag == FIRST ||
382 memcmp(curp, savp, hex->blocksize) != 0) {
383 if (vflag == DUP || vflag == FIRST)
384 vflag = WAIT;
385 return(curp);
386 }
387 if (vflag == WAIT)
388 printf("*\n");
389 vflag = DUP;
390 address += hex->blocksize;
391 need = hex->blocksize;
392 nread = 0;
393 }
394 else
395 nread += n;
396 }
397 retnul:
398 free (curp);
399 free (savp);
400 return NULL;
401 }
402
403 int next(char **argv, struct hexdump *hex)
404 {
405 static int done;
406 int statok;
407
408 if (argv) {
409 _argv = argv;
410 return(1);
411 }
412 while (TRUE) {
413 if (*_argv) {
414 if (!(freopen(*_argv, "r", stdin))) {
415 warn("%s", *_argv);
416 hex->exitval = EXIT_FAILURE;
417 ++_argv;
418 continue;
419 }
420 statok = done = 1;
421 } else {
422 if (done++)
423 return(0);
424 statok = 0;
425 }
426 if (hex->skip)
427 doskip(statok ? *_argv : "stdin", statok, hex);
428 if (*_argv)
429 ++_argv;
430 if (!hex->skip)
431 return(1);
432 }
433 /* NOTREACHED */
434 }
435
436 static void
437 doskip(const char *fname, int statok, struct hexdump *hex)
438 {
439 struct stat sbuf;
440
441 if (statok) {
442 if (fstat(fileno(stdin), &sbuf))
443 err(EXIT_FAILURE, "%s", fname);
444 if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) {
445 /* If size valid and skip >= size */
446 hex->skip -= sbuf.st_size;
447 address += sbuf.st_size;
448 return;
449 }
450 }
451 /* sbuf may be undefined here - do not test it */
452 if (fseek(stdin, hex->skip, SEEK_SET))
453 err(EXIT_FAILURE, "%s", fname);
454 address += hex->skip;
455 hex->skip = 0;
456 }