chiark / gitweb /
Ooops. Fix distribution.
[mLib] / hex.c
1 /* -*-c-*-
2  *
3  * $Id: hex.c,v 1.2 2003/05/16 00:22:58 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 /*----- Revision history --------------------------------------------------*
31  *
32  * $Log: hex.c,v $
33  * Revision 1.2  2003/05/16 00:22:58  mdw
34  * Test base64 and hex encoding.
35  *
36  * Revision 1.1  2002/01/13 13:26:30  mdw
37  * New hex encoding stuff.
38  *
39  */
40
41 /*----- Header files ------------------------------------------------------*/
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include "dstr.h"
48 #include "hex.h"
49
50 /*----- Important tables --------------------------------------------------*/
51
52 static const char encodemap[] = { "0123456789abcdef" };
53
54 static const signed char decodemap[] = {
55   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x */
56   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 1x */
57   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 2x */
58    0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  1, -1, -1, -1, -1, -1,  /* 3x */
59   -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 4x */
60   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 5x */
61   -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 6x */
62   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 7x */
63  };  
64
65 /*----- Main code ---------------------------------------------------------*/
66
67 /* --- @hex_encode@ --- *
68  *
69  * Arguments:   @hex_ctx *ctx@ = pointer to a context block
70  *              @const void *p@ = pointer to a source buffer
71  *              @size_t sz@ = size of the source buffer
72  *              @dstr *d@ = pointer to destination string
73  *
74  * Returns:     ---
75  *
76  * Use:         Encodes a binary string in hex.
77  */
78
79 void hex_encode(hex_ctx *ctx, const void *p, size_t sz, dstr *d)
80 {
81   if (p) {
82     const unsigned char *src = p;
83
84     while (sz) {
85       unsigned x = *src++;
86       sz--;
87       DPUTC(d, encodemap[(x >> 4) & 0xf]);
88       DPUTC(d, encodemap[(x >> 0) & 0xf]);
89       ctx->lnlen += 2;
90       if (ctx->maxline && ctx->lnlen >= ctx->maxline) {
91         dstr_puts(d, ctx->indent);
92         ctx->lnlen = 0;
93       }
94     }
95   }
96 }
97
98 /* --- @hex_decode@ --- *
99  *
100  * Arguments:   @hex_ctx *ctx@ = pointer to a context block
101  *              @const void *p@ = pointer to a source buffer
102  *              @size_t sz@ = size of the source buffer
103  *              @dstr *d@ = pointer to destination string
104  *
105  * Returns:     ---
106  *
107  * Use:         Decodes a binary string in hex.  Pass in a null source
108  *              pointer when you thing you've finished.
109  */
110
111 void hex_decode(hex_ctx *ctx, const void *p, size_t sz, dstr *d)
112 {
113   if (p) {
114     unsigned long acc = ctx->acc;
115     unsigned qsz = ctx->qsz;
116     const char *src = p;
117     int ch;
118
119     while (sz) {
120
121       /* --- Get the next character and convert it --- */
122
123       ch = *src++;
124       if (ch >= 128 || ch < 0)
125         ch = -1;
126       else
127         ch = decodemap[ch];
128       sz--;
129       if (ch == -1)
130         continue;
131
132       /* --- Bung it in the accumulator --- */
133
134       acc = (acc << 4) | ch;
135       qsz++;
136
137       /* --- Maybe write out a completed triplet --- */
138
139       if (qsz == 2) {
140         DPUTC(d, acc & 0xff);
141         acc = 0;
142         qsz = 0;
143       }
144     }
145
146     ctx->acc = acc;
147     ctx->qsz = qsz;
148   } else {
149     if (ctx->qsz)
150       DPUTC(d, ctx->acc << 4);
151   }
152 }
153
154 /* --- @hex_init@ --- *
155  *
156  * Arguments:   @hex_ctx *ctx@ = pointer to context block to initialize
157  *
158  * Returns:     ---
159  *
160  * Use:         Initializes a hex context properly.
161  */
162
163 void hex_init(hex_ctx *ctx)
164 {
165   ctx->acc = 0;
166   ctx->qsz = 0;
167   ctx->lnlen = 0;
168   ctx->indent = "\n";
169   ctx->maxline = 72;
170 }
171
172 /*----- Test driver code --------------------------------------------------*/
173
174 #ifdef TEST_RIG
175
176 int main(int argc, char *argv[])
177 {
178   unsigned char buf[BUFSIZ];
179   dstr d = DSTR_INIT;
180   hex_ctx ctx;
181   void (*proc)(hex_ctx *, const void *, size_t, dstr *);
182   size_t sz;
183
184   hex_init(&ctx);
185
186   if (argc > 1 && strcmp(argv[1], "-d") == 0)
187     proc = hex_decode;
188   else {
189     proc = hex_encode;
190     putchar('\t');
191     ctx.indent = "\n\t";
192     ctx.maxline = 64;
193   }
194
195   do {
196     sz = fread(buf, 1, sizeof(buf), stdin);
197     if (sz) {
198       proc(&ctx, buf, sz, &d);
199       dstr_write(&d, stdout);
200       dstr_destroy(&d);
201     }
202   } while (sz == sizeof(buf));
203
204   proc(&ctx, 0, 0, &d);
205   dstr_write(&d, stdout);
206
207   if (proc == hex_encode)
208     putchar('\n');
209
210   return (0);
211 }
212
213 #endif
214
215 /*----- That's all, folks -------------------------------------------------*/