chiark / gitweb /
Extract Subversion ignore data.
[mLib] / hex.c
1 /* -*-c-*-
2  *
3  * $Id: hex.c,v 1.3 2004/04/08 01:36:11 mdw Exp $
4  *
5  * Hexadecimal encoding and decoding.
6  *
7  * (c) 2001 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the mLib utilities library.
13  *
14  * mLib is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * mLib is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with mLib; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "dstr.h"
37 #include "hex.h"
38
39 /*----- Important tables --------------------------------------------------*/
40
41 static const char encodemap[] = { "0123456789abcdef" };
42
43 static const signed char decodemap[] = {
44   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x */
45   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 1x */
46   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 2x */
47    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  1, -1, -1, -1, -1, -1,  /* 3x */
48   -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 4x */
49   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 5x */
50   -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 6x */
51   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 7x */
52  };  
53
54 /*----- Main code ---------------------------------------------------------*/
55
56 /* --- @hex_encode@ --- *
57  *
58  * Arguments:   @hex_ctx *ctx@ = pointer to a context block
59  *              @const void *p@ = pointer to a source buffer
60  *              @size_t sz@ = size of the source buffer
61  *              @dstr *d@ = pointer to destination string
62  *
63  * Returns:     ---
64  *
65  * Use:         Encodes a binary string in hex.
66  */
67
68 void hex_encode(hex_ctx *ctx, const void *p, size_t sz, dstr *d)
69 {
70   if (p) {
71     const unsigned char *src = p;
72
73     while (sz) {
74       unsigned x = *src++;
75       sz--;
76       DPUTC(d, encodemap[(x >> 4) & 0xf]);
77       DPUTC(d, encodemap[(x >> 0) & 0xf]);
78       ctx->lnlen += 2;
79       if (ctx->maxline && ctx->lnlen >= ctx->maxline) {
80         dstr_puts(d, ctx->indent);
81         ctx->lnlen = 0;
82       }
83     }
84   }
85 }
86
87 /* --- @hex_decode@ --- *
88  *
89  * Arguments:   @hex_ctx *ctx@ = pointer to a context block
90  *              @const void *p@ = pointer to a source buffer
91  *              @size_t sz@ = size of the source buffer
92  *              @dstr *d@ = pointer to destination string
93  *
94  * Returns:     ---
95  *
96  * Use:         Decodes a binary string in hex.  Pass in a null source
97  *              pointer when you thing you've finished.
98  */
99
100 void hex_decode(hex_ctx *ctx, const void *p, size_t sz, dstr *d)
101 {
102   if (p) {
103     unsigned long acc = ctx->acc;
104     unsigned qsz = ctx->qsz;
105     const char *src = p;
106     int ch;
107
108     while (sz) {
109
110       /* --- Get the next character and convert it --- */
111
112       ch = *src++;
113       if (ch >= 128 || ch < 0)
114         ch = -1;
115       else
116         ch = decodemap[ch];
117       sz--;
118       if (ch == -1)
119         continue;
120
121       /* --- Bung it in the accumulator --- */
122
123       acc = (acc << 4) | ch;
124       qsz++;
125
126       /* --- Maybe write out a completed triplet --- */
127
128       if (qsz == 2) {
129         DPUTC(d, acc & 0xff);
130         acc = 0;
131         qsz = 0;
132       }
133     }
134
135     ctx->acc = acc;
136     ctx->qsz = qsz;
137   } else {
138     if (ctx->qsz)
139       DPUTC(d, ctx->acc << 4);
140   }
141 }
142
143 /* --- @hex_init@ --- *
144  *
145  * Arguments:   @hex_ctx *ctx@ = pointer to context block to initialize
146  *
147  * Returns:     ---
148  *
149  * Use:         Initializes a hex context properly.
150  */
151
152 void hex_init(hex_ctx *ctx)
153 {
154   ctx->acc = 0;
155   ctx->qsz = 0;
156   ctx->lnlen = 0;
157   ctx->indent = "\n";
158   ctx->maxline = 72;
159 }
160
161 /*----- Test driver code --------------------------------------------------*/
162
163 #ifdef TEST_RIG
164
165 int main(int argc, char *argv[])
166 {
167   unsigned char buf[BUFSIZ];
168   dstr d = DSTR_INIT;
169   hex_ctx ctx;
170   void (*proc)(hex_ctx *, const void *, size_t, dstr *);
171   size_t sz;
172
173   hex_init(&ctx);
174
175   if (argc > 1 && strcmp(argv[1], "-d") == 0)
176     proc = hex_decode;
177   else {
178     proc = hex_encode;
179     putchar('\t');
180     ctx.indent = "\n\t";
181     ctx.maxline = 64;
182   }
183
184   do {
185     sz = fread(buf, 1, sizeof(buf), stdin);
186     if (sz) {
187       proc(&ctx, buf, sz, &d);
188       dstr_write(&d, stdout);
189       dstr_destroy(&d);
190     }
191   } while (sz == sizeof(buf));
192
193   proc(&ctx, 0, 0, &d);
194   dstr_write(&d, stdout);
195
196   if (proc == hex_encode)
197     putchar('\n');
198
199   return (0);
200 }
201
202 #endif
203
204 /*----- That's all, folks -------------------------------------------------*/