/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "hexdump.h" #include "xalloc.h" #include "c.h" #include "nls.h" #include "colors.h" static void doskip(const char *, int, struct hexdump *); static u_char *get(struct hexdump *); enum _vflag vflag = FIRST; static off_t address; /* address/offset in stream */ static off_t eaddress; /* end address */ static const char *color_cond(struct hexdump_pr *pr, unsigned char *bp, int bcnt) { register struct list_head *p; register struct hexdump_clr *clr; off_t offt; int match; list_for_each(p, pr->colorlist) { clr = list_entry(p, struct hexdump_clr, colorlist); offt = clr->offt; match = 0; /* no offset or offset outside this print unit */ if (offt < 0) offt = address; if (offt < address || offt + clr->range > address + bcnt) continue; /* match a string */ if (clr->str) { if (pr->flags == F_ADDRESS) { /* TODO */ } else if (!strncmp(clr->str, (char *)bp + offt - address, clr->range)) match = 1; /* match a value */ } else if (clr->val != -1) { int val = 0; /* addresses are not part of the input, so we can't * compare with the contents of bp */ if (pr->flags == F_ADDRESS) { if (clr->val == address) match = 1; } else { memcpy(&val, bp + offt - address, clr->range); if (val == clr->val) match = 1; } /* no conditions, only a color was specified */ } else return clr->fmt; /* return the format string or check for another */ if (match ^ clr->invert) return clr->fmt; } /* no match */ return NULL; } static inline void print(struct hexdump_pr *pr, unsigned char *bp) { const char *color = NULL; if (pr->colorlist && (color = color_cond(pr, bp, pr->bcnt))) color_enable(color); switch(pr->flags) { case F_ADDRESS: printf(pr->fmt, address); break; case F_BPAD: printf(pr->fmt, ""); break; case F_C: conv_c(pr, bp); break; case F_CHAR: printf(pr->fmt, *bp); break; case F_DBL: { double dval; float fval; switch(pr->bcnt) { case 4: memmove(&fval, bp, sizeof(fval)); printf(pr->fmt, fval); break; case 8: memmove(&dval, bp, sizeof(dval)); printf(pr->fmt, dval); break; } break; } case F_INT: { char cval; /* int8_t */ short sval; /* int16_t */ int ival; /* int32_t */ long long Lval; /* int64_t, int64_t */ switch(pr->bcnt) { case 1: memmove(&cval, bp, sizeof(cval)); printf(pr->fmt, (unsigned long long) cval); break; case 2: memmove(&sval, bp, sizeof(sval)); printf(pr->fmt, (unsigned long long) sval); break; case 4: memmove(&ival, bp, sizeof(ival)); printf(pr->fmt, (unsigned long long) ival); break; case 8: memmove(&Lval, bp, sizeof(Lval)); printf(pr->fmt, Lval); break; } break; } case F_P: printf(pr->fmt, isprint(*bp) ? *bp : '.'); break; case F_STR: printf(pr->fmt, (char *)bp); break; case F_TEXT: printf("%s", pr->fmt); break; case F_U: conv_u(pr, bp); break; case F_UINT: { unsigned short sval; /* u_int16_t */ unsigned int ival; /* u_int32_t */ unsigned long long Lval;/* u_int64_t, u_int64_t */ switch(pr->bcnt) { case 1: printf(pr->fmt, (unsigned long long) *bp); break; case 2: memmove(&sval, bp, sizeof(sval)); printf(pr->fmt, (unsigned long long) sval); break; case 4: memmove(&ival, bp, sizeof(ival)); printf(pr->fmt, (unsigned long long) ival); break; case 8: memmove(&Lval, bp, sizeof(Lval)); printf(pr->fmt, Lval); break; } break; } } if (color) /* did we colorize something? */ color_disable(); } static void bpad(struct hexdump_pr *pr) { static const char *spec = " -0+#"; char *p1, *p2; /* * remove all conversion flags; '-' is the only one valid * with %s, and it's not useful here. */ pr->flags = F_BPAD; pr->cchar[0] = 's'; pr->cchar[1] = 0; p1 = pr->fmt; while (*p1 != '%') ++p1; p2 = ++p1; while (*p1 && strchr(spec, *p1)) ++p1; while ((*p2++ = *p1++)) ; } void display(struct hexdump *hex) { register struct list_head *fs; register struct hexdump_fs *fss; register struct hexdump_fu *fu; register struct hexdump_pr *pr; register int cnt; register unsigned char *bp; off_t saveaddress; unsigned char savech = 0, *savebp; struct list_head *p, *q, *r; while ((bp = get(hex)) != NULL) { fs = &hex->fshead; savebp = bp; saveaddress = address; list_for_each(p, fs) { fss = list_entry(p, struct hexdump_fs, fslist); list_for_each(q, &fss->fulist) { fu = list_entry(q, struct hexdump_fu, fulist); if (fu->flags&F_IGNORE) break; cnt = fu->reps; while (cnt) { list_for_each(r, &fu->prlist) { pr = list_entry(r, struct hexdump_pr, prlist); if (eaddress && address >= eaddress && !(pr->flags&(F_TEXT|F_BPAD))) bpad(pr); if (cnt == 1 && pr->nospace) { savech = *pr->nospace; *pr->nospace = '\0'; print(pr, bp); *pr->nospace = savech; } else print(pr, bp); address += pr->bcnt; bp += pr->bcnt; } --cnt; } } bp = savebp; address = saveaddress; } } if (endfu) { /* * if eaddress not set, error or file size was multiple of * blocksize, and no partial block ever found. */ if (!eaddress) { if (!address) return; eaddress = address; } list_for_each (p, &endfu->prlist) { const char *color = NULL; pr = list_entry(p, struct hexdump_pr, prlist); if (colors_wanted() && pr->colorlist && (color = color_cond(pr, bp, pr->bcnt))) { color_enable(color); } switch(pr->flags) { case F_ADDRESS: printf(pr->fmt, eaddress); break; case F_TEXT: printf("%s", pr->fmt); break; } if (color) /* did we highlight something? */ color_disable(); } } } static char **_argv; static u_char * get(struct hexdump *hex) { static int ateof = 1; static u_char *curp, *savp; ssize_t n, need, nread; u_char *tmpp; if (!curp) { curp = xcalloc(1, hex->blocksize); savp = xcalloc(1, hex->blocksize); } else { tmpp = curp; curp = savp; savp = tmpp; address += hex->blocksize; } need = hex->blocksize, nread = 0; while (TRUE) { /* * if read the right number of bytes, or at EOF for one file, * and no other files are available, zero-pad the rest of the * block and set the end flag. */ if (!hex->length || (ateof && !next(NULL, hex))) { if (need == hex->blocksize) goto retnul; if (!need && vflag != ALL && !memcmp(curp, savp, nread)) { if (vflag != DUP) printf("*\n"); goto retnul; } if (need > 0) memset((char *)curp + nread, 0, need); eaddress = address + nread; return(curp); } if (fileno(stdin) == -1) { warnx(_("all input file arguments failed")); goto retnul; } n = fread((char *)curp + nread, sizeof(unsigned char), hex->length == -1 ? need : min(hex->length, need), stdin); if (!n) { if (ferror(stdin)) warn("%s", _argv[-1]); ateof = 1; continue; } ateof = 0; if (hex->length != -1) hex->length -= n; if (!(need -= n)) { if (vflag == ALL || vflag == FIRST || memcmp(curp, savp, hex->blocksize) != 0) { if (vflag == DUP || vflag == FIRST) vflag = WAIT; return(curp); } if (vflag == WAIT) printf("*\n"); vflag = DUP; address += hex->blocksize; need = hex->blocksize; nread = 0; } else nread += n; } retnul: free (curp); free (savp); return NULL; } int next(char **argv, struct hexdump *hex) { static int done; int statok; if (argv) { _argv = argv; return(1); } while (TRUE) { if (*_argv) { if (!(freopen(*_argv, "r", stdin))) { warn("%s", *_argv); hex->exitval = EXIT_FAILURE; ++_argv; continue; } statok = done = 1; } else { if (done++) return(0); statok = 0; } if (hex->skip) doskip(statok ? *_argv : "stdin", statok, hex); if (*_argv) ++_argv; if (!hex->skip) return(1); } /* NOTREACHED */ } static void doskip(const char *fname, int statok, struct hexdump *hex) { struct stat sbuf; if (statok) { if (fstat(fileno(stdin), &sbuf)) err(EXIT_FAILURE, "%s", fname); if (S_ISREG(sbuf.st_mode) && hex->skip > sbuf.st_size) { /* If size valid and skip >= size */ hex->skip -= sbuf.st_size; address += sbuf.st_size; return; } } /* sbuf may be undefined here - do not test it */ if (fseek(stdin, hex->skip, SEEK_SET)) err(EXIT_FAILURE, "%s", fname); address += hex->skip; hex->skip = 0; }