Sync usage with man page.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / base64_code.c
blobee56562f9fd958d27c1fb7ab5664b8127e6ba8ba
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* base64_code 3
6 /* SUMMARY
7 /* encode/decode data, base 64 style
8 /* SYNOPSIS
9 /* #include <base64_code.h>
11 /* VSTRING *base64_encode(result, in, len)
12 /* VSTRING *result;
13 /* const char *in;
14 /* ssize_t len;
16 /* VSTRING *base64_decode(result, in, len)
17 /* VSTRING *result;
18 /* const char *in;
19 /* ssize_t len;
20 /* DESCRIPTION
21 /* base64_encode() takes a block of len bytes and encodes it as one
22 /* null-terminated string. The result value is the result argument.
24 /* base64_decode() performs the opposite transformation. The result
25 /* value is the result argument. The result is null terminated, whether
26 /* or not that makes sense.
27 /* DIAGNOSTICS
28 /* base64_decode () returns a null pointer when the input contains
29 /* characters not in the base 64 alphabet.
30 /* LICENSE
31 /* .ad
32 /* .fi
33 /* The Secure Mailer license must be distributed with this software.
34 /* AUTHOR(S)
35 /* Wietse Venema
36 /* IBM T.J. Watson Research
37 /* P.O. Box 704
38 /* Yorktown Heights, NY 10598, USA
39 /*--*/
41 /* System library. */
43 #include "sys_defs.h"
44 #include <ctype.h>
45 #include <string.h>
46 #include <limits.h>
48 #ifndef UCHAR_MAX
49 #define UCHAR_MAX 0xff
50 #endif
52 /* Utility library. */
54 #include <msg.h>
55 #include <mymalloc.h>
56 #include <vstring.h>
57 #include <base64_code.h>
59 /* Application-specific. */
61 static unsigned char to_b64[] =
62 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64 #define UNSIG_CHAR_PTR(x) ((unsigned char *)(x))
66 /* base64_encode - raw data to encoded */
68 VSTRING *base64_encode(VSTRING *result, const char *in, ssize_t len)
70 const unsigned char *cp;
71 ssize_t count;
74 * Encode 3 -> 4.
76 VSTRING_RESET(result);
77 for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 3, cp += 3) {
78 VSTRING_ADDCH(result, to_b64[cp[0] >> 2]);
79 if (count > 1) {
80 VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]);
81 if (count > 2) {
82 VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]);
83 VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]);
84 } else {
85 VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]);
86 VSTRING_ADDCH(result, '=');
87 break;
89 } else {
90 VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]);
91 VSTRING_ADDCH(result, '=');
92 VSTRING_ADDCH(result, '=');
93 break;
96 VSTRING_TERMINATE(result);
97 return (result);
100 /* base64_decode - encoded data to raw */
102 VSTRING *base64_decode(VSTRING *result, const char *in, ssize_t len)
104 static unsigned char *un_b64 = 0;
105 const unsigned char *cp;
106 ssize_t count;
107 unsigned int ch0;
108 unsigned int ch1;
109 unsigned int ch2;
110 unsigned int ch3;
112 #define CHARS_PER_BYTE (UCHAR_MAX + 1)
113 #define INVALID 0xff
116 * Sanity check.
118 if (len % 4)
119 return (0);
122 * Once: initialize the decoding lookup table on the fly.
124 if (un_b64 == 0) {
125 un_b64 = (unsigned char *) mymalloc(CHARS_PER_BYTE);
126 memset(un_b64, INVALID, CHARS_PER_BYTE);
127 for (cp = to_b64; cp < to_b64 + sizeof(to_b64); cp++)
128 un_b64[*cp] = cp - to_b64;
132 * Decode 4 -> 3.
134 VSTRING_RESET(result);
135 for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 4) {
136 if ((ch0 = un_b64[*cp++]) == INVALID
137 || (ch1 = un_b64[*cp++]) == INVALID)
138 return (0);
139 VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4);
140 if ((ch2 = *cp++) == '=')
141 break;
142 if ((ch2 = un_b64[ch2]) == INVALID)
143 return (0);
144 VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2);
145 if ((ch3 = *cp++) == '=')
146 break;
147 if ((ch3 = un_b64[ch3]) == INVALID)
148 return (0);
149 VSTRING_ADDCH(result, ch2 << 6 | ch3);
151 VSTRING_TERMINATE(result);
152 return (result);
155 #ifdef TEST
158 * Proof-of-concept test program: convert to base 64 and back.
161 #define STR(x) vstring_str(x)
162 #define LEN(x) VSTRING_LEN(x)
164 int main(int unused_argc, char **unused_argv)
166 VSTRING *b1 = vstring_alloc(1);
167 VSTRING *b2 = vstring_alloc(1);
168 char *test = "this is a test";
170 #define DECODE(b,x,l) { \
171 if (base64_decode((b),(x),(l)) == 0) \
172 msg_panic("bad base64: %s", (x)); \
174 #define VERIFY(b,t) { \
175 if (strcmp((b), (t)) != 0) \
176 msg_panic("bad test: %s", (b)); \
179 base64_encode(b1, test, strlen(test));
180 DECODE(b2, STR(b1), LEN(b1));
181 VERIFY(STR(b2), test);
183 base64_encode(b1, test, strlen(test));
184 base64_encode(b2, STR(b1), LEN(b1));
185 base64_encode(b1, STR(b2), LEN(b2));
186 DECODE(b2, STR(b1), LEN(b1));
187 DECODE(b1, STR(b2), LEN(b2));
188 DECODE(b2, STR(b1), LEN(b1));
189 VERIFY(STR(b2), test);
191 base64_encode(b1, test, strlen(test));
192 base64_encode(b2, STR(b1), LEN(b1));
193 base64_encode(b1, STR(b2), LEN(b2));
194 base64_encode(b2, STR(b1), LEN(b1));
195 base64_encode(b1, STR(b2), LEN(b2));
196 DECODE(b2, STR(b1), LEN(b1));
197 DECODE(b1, STR(b2), LEN(b2));
198 DECODE(b2, STR(b1), LEN(b1));
199 DECODE(b1, STR(b2), LEN(b2));
200 DECODE(b2, STR(b1), LEN(b1));
201 VERIFY(STR(b2), test);
203 vstring_free(b1);
204 vstring_free(b2);
205 return (0);
208 #endif