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