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
ex_hexdump_reset(void)119 void ex_hexdump_reset(void)
120 {
121 addr = 0;
122 }
123
ex_hexdump_process(Vstr_base * s1,size_t apos,Vstr_base * s2,size_t fpos,size_t flen,unsigned int prnt_type,size_t max_sz,int del,int last)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 size_t orig_len = s1->len;
129 /* normal ASCII chars, just allow COMMA and DOT flags */
130 unsigned int flags = VSTR_FLAG02(CONV_UNPRINTABLE_ALLOW, COMMA, DOT);
131 /* allow spaces, allow COMMA, DOT, underbar _, and space */
132 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 unsigned int flags_hsp = VSTR_FLAG06(CONV_UNPRINTABLE_ALLOW,
137 COMMA, DOT, _, SP, HSP, HIGH);
138 unsigned char buf[CHRS_PER_LINE];
139
140 switch (prnt_type)
141 {
142 case PRNT_HIGH: flags = flags_hsp; break;
143 case PRNT_SPAC: flags = flags_sp; break;
144 case PRNT_NONE: break;
145 default: ASSERT(FALSE); break;
146 }
147
148 /* we don't want to create more data, if we are over our limit */
149 if (s1->len > max_sz)
150 return (FALSE);
151
152 /* while we have a hexdump line ... */
153 while (flen >= CHRS_PER_LINE)
154 {
155 unsigned int count = 0;
156 size_t tmp = 0;
157
158 /* get a hexdump line from the vstr */
159 vstr_export_buf(s2, fpos, CHRS_PER_LINE, buf, sizeof(buf));
160
161 /* write out a hexdump line address */
162 EX_HEXDUMP_X8(s1, addr);
163
164 /* write out hex values */
165 while (count < CHRS_PER_LINE)
166 {
167 EX_HEXDUMP_X2X2(s1, buf[count], buf[count + 1]);
168 count += 2;
169 }
170
171 vstr_add_rep_chr(s1, APOS(), ' ', 2);
172
173 /* write out characters, converting reference and pointer nodes to
174 * _BUF nodes */
175 tmp = APOS();
176 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 vstr_conv_unprintable_chr(s1, tmp + 1, CHRS_PER_LINE, flags, '.');
180
181 vstr_add_rep_chr(s1, APOS(), '\n', 1);
182
183 addr += CHRS_PER_LINE;
184
185 flen -= CHRS_PER_LINE;
186 if (del) /* delete the set of characters just processed */
187 vstr_del(s2, fpos, CHRS_PER_LINE);
188 else
189 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 if (s1->len > max_sz)
194 return (TRUE);
195 }
196
197 if (last && flen)
198 { /* do the same as above, but print the partial line for
199 * the end of a file */
200 size_t got = flen;
201 size_t missing = CHRS_PER_LINE - flen;
202 const unsigned char *ptr = buf;
203 size_t tmp = 0;
204
205 missing -= (missing % 2);
206 vstr_export_buf(s2, fpos, flen, buf, sizeof(buf));
207
208 EX_HEXDUMP_X8(s1, addr);
209
210 while (got >= 2)
211 {
212 EX_HEXDUMP_X2X2(s1, ptr[0], ptr[1]);
213 got -= 2;
214 ptr += 2;
215 }
216 if (got)
217 {
218 EX_HEXDUMP_X2__(s1, ptr[0]);
219 got -= 2;
220 }
221
222 /* Add spaces until the point where the characters should start */
223 vstr_add_rep_chr(s1, APOS(), ' ', (missing * 2) + (missing / 2) + 2);
224
225 tmp = APOS();
226 if (vstr_add_vstr(s1, tmp, s2, fpos, flen, VSTR_TYPE_ADD_ALL_BUF))
227 vstr_conv_unprintable_chr(s1, tmp + 1, flen, flags, '.');
228
229 vstr_add_cstr_buf(s1, APOS(), "\n");
230
231 addr += flen;
232 if (del)
233 vstr_del(s2, fpos, flen);
234
235 return (TRUE);
236 }
237
238 return (FALSE);
239 }
240