1 : /*
2 : * Copyright (C) 2003, 2004, 2005 James Antill
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, write to the Free Software
16 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 : *
18 : * email: james@and.org
19 : */
20 : /* hexdump in "readable" format ... note this is a bit more fleshed out than
21 : * some of the other examples mainly because I actually use it */
22 :
23 : /* this is roughly equiv. to the Linux hexdump command...
24 : % rpm -qf /usr/bin/hexdump
25 : util-linux-2.11r-10
26 : % hexdump -e '"%08_ax:"
27 : " " 2/1 "%02X"
28 : " " 2/1 "%02X"
29 : " " 2/1 "%02X"
30 : " " 2/1 "%02X"
31 : " " 2/1 "%02X"
32 : " " 2/1 "%02X"
33 : " " 2/1 "%02X"
34 : " " 2/1 "%02X"'
35 : -e '" " 16 "%_p" "\n"'
36 :
37 :
38 : * ...except that it prints the address in big hex digits, and it doesn't take
39 : * you 30 minutes to remember how to type it out.
40 : * It also acts differently in that seperate files aren't merged
41 : * into one output line (Ie. in this version each file starts on a new line,
42 : * however the addresses are continuious).
43 :
44 : * It's also similar to "xxd" in vim, and "od -tx1z -Ax".
45 : */
46 : #define EX_UTILS_NO_FUNCS 1
47 : #include "ex_utils.h"
48 :
49 : #include "hexdump.h"
50 :
51 : /* number of characters we output per line (assumes 80 char width screen)... */
52 : #define CHRS_PER_LINE 16
53 :
54 : #ifndef CONF_USE_FAST_NUM_PRINT
55 : #define CONF_USE_FAST_NUM_PRINT 1
56 : #endif
57 :
58 : #define APOS() (apos + ((s1)->len - orig_len))
59 :
60 : #if !CONF_USE_FAST_NUM_PRINT
61 : /* simple print of a number */
62 :
63 : /* print the address */
64 : # define EX_HEXDUMP_X8(s1, num) \
65 : vstr_add_fmt(s1, APOS(), "0x%08X:", (num))
66 : /* print a set of two bytes */
67 : # define EX_HEXDUMP_X2X2(s1, num1, num2) \
68 : vstr_add_fmt(s1, APOS(), " %02X%02X", (num1), (num2))
69 : /* print a byte and spaces for the missing byte */
70 : # define EX_HEXDUMP_X2__(s1, num1) \
71 : vstr_add_fmt(s1, APOS(), " %02X ", (num1))
72 : #else
73 : /* fast print of a number */
74 : static const char *hexnums = "0123456789ABCDEF";
75 :
76 : # define EX_HEXDUMP_BYTE(buf, b) do { \
77 : (buf)[1] = hexnums[((b) >> 0) & 0xf]; \
78 : (buf)[0] = hexnums[((b) >> 4) & 0xf]; \
79 : } while (FALSE)
80 :
81 : # define EX_HEXDUMP_UINT(buf, i) do { \
82 : EX_HEXDUMP_BYTE((buf) + 6, (i) >> 0); \
83 : EX_HEXDUMP_BYTE((buf) + 4, (i) >> 8); \
84 : EX_HEXDUMP_BYTE((buf) + 2, (i) >> 16); \
85 : EX_HEXDUMP_BYTE((buf) + 0, (i) >> 24); \
86 : } while (FALSE)
87 :
88 : /* print the address */
89 : # define EX_HEXDUMP_X8(s1, num) do { \
90 : unsigned char xbuf[9]; \
91 : \
92 : xbuf[8] = ':'; \
93 : EX_HEXDUMP_UINT(xbuf, num); \
94 : vstr_add_buf(s1, APOS(), xbuf, sizeof(xbuf)); \
95 : } while (FALSE)
96 : /* print a set of two bytes */
97 : # define EX_HEXDUMP_X2X2(s1, num1, num2) do { \
98 : unsigned char xbuf[5]; \
99 : \
100 : xbuf[0] = ' '; \
101 : EX_HEXDUMP_BYTE(xbuf + 3, num2); \
102 : EX_HEXDUMP_BYTE(xbuf + 1, num1); \
103 : vstr_add_buf(s1, APOS(), xbuf, sizeof(xbuf)); \
104 : } while (FALSE)
105 : /* print a byte and spaces for the missing byte */
106 : # define EX_HEXDUMP_X2__(s1, num1) do { \
107 : unsigned char xbuf[5]; \
108 : \
109 : xbuf[4] = ' '; \
110 : xbuf[3] = ' '; \
111 : EX_HEXDUMP_BYTE(xbuf + 1, num1); \
112 : xbuf[0] = ' '; \
113 : vstr_add_buf(s1, APOS(), xbuf, sizeof(xbuf)); \
114 : } while (FALSE)
115 : #endif
116 :
117 : static unsigned int addr = 0;
118 :
119 : void ex_hexdump_reset(void)
120 128 : {
121 128 : addr = 0;
122 128 : }
123 :
124 : int ex_hexdump_process(Vstr_base *s1, size_t apos,
125 : Vstr_base *s2, size_t fpos, size_t flen,
126 : unsigned int prnt_type, size_t max_sz, int del, int last)
127 128 : {
128 128 : size_t orig_len = s1->len;
129 : /* normal ASCII chars, just allow COMMA and DOT flags */
130 128 : unsigned int flags = VSTR_FLAG02(CONV_UNPRINTABLE_ALLOW, COMMA, DOT);
131 : /* allow spaces, allow COMMA, DOT, underbar _, and space */
132 128 : unsigned int flags_sp = VSTR_FLAG04(CONV_UNPRINTABLE_ALLOW,
133 : COMMA, DOT, _, SP);
134 : /* high ascii too, allow
135 : * COMMA, DOT, underbar _, space, high space and other high characters */
136 128 : unsigned int flags_hsp = VSTR_FLAG06(CONV_UNPRINTABLE_ALLOW,
137 : COMMA, DOT, _, SP, HSP, HIGH);
138 : unsigned char buf[CHRS_PER_LINE];
139 :
140 128 : switch (prnt_type)
141 : {
142 0 : case PRNT_HIGH: flags = flags_hsp; break;
143 0 : case PRNT_SPAC: flags = flags_sp; break;
144 : case PRNT_NONE: break;
145 0 : default: ASSERT(FALSE); break;
146 : }
147 :
148 : /* we don't want to create more data, if we are over our limit */
149 128 : if (s1->len > max_sz)
150 0 : return (FALSE);
151 :
152 : /* while we have a hexdump line ... */
153 848 : while (flen >= CHRS_PER_LINE)
154 : {
155 592 : unsigned int count = 0;
156 592 : size_t tmp = 0;
157 :
158 : /* get a hexdump line from the vstr */
159 592 : vstr_export_buf(s2, fpos, CHRS_PER_LINE, buf, sizeof(buf));
160 :
161 : /* write out a hexdump line address */
162 592 : EX_HEXDUMP_X8(s1, addr);
163 :
164 : /* write out hex values */
165 5920 : while (count < CHRS_PER_LINE)
166 : {
167 4736 : EX_HEXDUMP_X2X2(s1, buf[count], buf[count + 1]);
168 4736 : count += 2;
169 : }
170 :
171 592 : vstr_add_rep_chr(s1, APOS(), ' ', 2);
172 :
173 : /* write out characters, converting reference and pointer nodes to
174 : * _BUF nodes */
175 592 : tmp = APOS();
176 592 : if (vstr_add_vstr(s1, tmp, s2, fpos, CHRS_PER_LINE,
177 : VSTR_TYPE_ADD_ALL_BUF))
178 : /* convert unprintable characters to the '.' character */
179 592 : vstr_conv_unprintable_chr(s1, tmp + 1, CHRS_PER_LINE, flags, '.');
180 :
181 592 : vstr_add_rep_chr(s1, APOS(), '\n', 1);
182 :
183 592 : addr += CHRS_PER_LINE;
184 :
185 592 : flen -= CHRS_PER_LINE;
186 592 : if (del) /* delete the set of characters just processed */
187 0 : vstr_del(s2, fpos, CHRS_PER_LINE);
188 : else
189 592 : fpos += CHRS_PER_LINE;
190 :
191 : /* note that we don't want to create data indefinitely, so stop
192 : * according to in core configuration */
193 592 : if (s1->len > max_sz)
194 0 : return (TRUE);
195 : }
196 :
197 128 : if (last && flen)
198 : { /* do the same as above, but print the partial line for
199 : * the end of a file */
200 120 : size_t got = flen;
201 120 : size_t missing = CHRS_PER_LINE - flen;
202 120 : const unsigned char *ptr = buf;
203 120 : size_t tmp = 0;
204 :
205 120 : missing -= (missing % 2);
206 120 : vstr_export_buf(s2, fpos, flen, buf, sizeof(buf));
207 :
208 120 : EX_HEXDUMP_X8(s1, addr);
209 :
210 592 : while (got >= 2)
211 : {
212 352 : EX_HEXDUMP_X2X2(s1, ptr[0], ptr[1]);
213 352 : got -= 2;
214 352 : ptr += 2;
215 : }
216 120 : if (got)
217 : {
218 48 : EX_HEXDUMP_X2__(s1, ptr[0]);
219 48 : got -= 2;
220 : }
221 :
222 : /* Add spaces until the point where the characters should start */
223 120 : vstr_add_rep_chr(s1, APOS(), ' ', (missing * 2) + (missing / 2) + 2);
224 :
225 120 : tmp = APOS();
226 120 : if (vstr_add_vstr(s1, tmp, s2, fpos, flen, VSTR_TYPE_ADD_ALL_BUF))
227 120 : vstr_conv_unprintable_chr(s1, tmp + 1, flen, flags, '.');
228 :
229 120 : vstr_add_cstr_buf(s1, APOS(), "\n");
230 :
231 120 : addr += flen;
232 120 : if (del)
233 0 : vstr_del(s2, fpos, flen);
234 :
235 120 : return (TRUE);
236 : }
237 :
238 8 : return (FALSE);
239 : }
|