New action: move-cursor-line-start.
[elinks/kon.git] / src / util / base64.c
blob8046cc9c8fe1d0c557f09aa435d4daedd90acb9d
1 /** Base64 encode/decode implementation.
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <string.h>
10 #include "elinks.h"
12 #include "util/base64.h"
13 #include "util/error.h"
14 #include "util/memory.h"
16 static unsigned char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
18 unsigned char *
19 base64_encode(register unsigned char *in)
21 assert(in && *in);
22 if_assert_failed return NULL;
24 return base64_encode_bin(in, strlen(in), NULL);
27 unsigned char *
28 base64_encode_bin(register unsigned char *in, int inlen, int *outlen)
30 unsigned char *out;
31 unsigned char *outstr;
33 assert(in && *in);
34 if_assert_failed return NULL;
36 out = outstr = mem_alloc((inlen / 3) * 4 + 4 + 1);
37 if (!out) return NULL;
39 while (inlen >= 3) {
40 *out++ = base64_chars[ *in >> 2 ];
41 *out++ = base64_chars[ (*in << 4 | *(in + 1) >> 4) & 63 ];
42 *out++ = base64_chars[ (*(in + 1) << 2 | *(in + 2) >> 6) & 63 ];
43 *out++ = base64_chars[ *(in + 2) & 63 ];
44 inlen -= 3; in += 3;
46 if (inlen == 1) {
47 *out++ = base64_chars[ *in >> 2 ];
48 *out++ = base64_chars[ *in << 4 & 63 ];
49 *out++ = '=';
50 *out++ = '=';
52 if (inlen == 2) {
53 *out++ = base64_chars[ *in >> 2 ];
54 *out++ = base64_chars[ (*in << 4 | *(in + 1) >> 4) & 63 ];
55 *out++ = base64_chars[ (*(in + 1) << 2) & 63 ];
56 *out++ = '=';
58 *out = 0;
60 if (outlen)
61 *outlen = out-outstr;
63 return outstr;
66 /* Base64 decoding is used only with the CONFIG_FORMHIST or CONFIG_GSSAPI
67 feature, so i'll #ifdef it */
68 #if defined(CONFIG_FORMHIST) || defined(CONFIG_GSSAPI)
70 unsigned char *
71 base64_decode(register unsigned char *in)
73 assert(in && *in);
74 if_assert_failed return NULL;
76 return base64_decode_bin(in, strlen(in), NULL);
79 /** Decode a Base64 string.
80 * @param in Input Base64 string
81 * @param inlen Length of @a in, in bytes
82 * @param[out] outlen Length of decoded string
84 * @returns the string decoded (must be freed by the caller)
85 * or NULL if an error occurred (syntax error or out of memory) */
86 unsigned char *
87 base64_decode_bin(register unsigned char *in, int inlen, int *outlen)
89 static unsigned char is_base64_char[256]; /* static to force initialization at zero */
90 static unsigned char decode[256];
91 unsigned char *out;
92 unsigned char *outstr;
93 int count = 0;
94 unsigned int bits = 0;
95 static int once = 0;
97 assert(in && *in);
98 if_assert_failed return NULL;
100 outstr = out = mem_alloc(inlen / 4 * 3 + 1);
101 if (!outstr) return NULL;
103 if (!once) {
104 int i = sizeof(base64_chars) - 1;
106 while (i >= 0) {
107 is_base64_char[base64_chars[i]] = 1;
108 decode[base64_chars[i]] = i;
109 i--;
111 once = 1;
114 while (*in) {
115 if (*in == '=') break;
116 if (!is_base64_char[*in])
117 goto decode_error;
119 bits += decode[*in];
120 count++;
121 if (count == 4) {
122 *out++ = bits >> 16;
123 *out++ = (bits >> 8) & 0xff;
124 *out++ = bits & 0xff;
125 bits = 0;
126 count = 0;
127 } else {
128 bits <<= 6;
131 ++in;
134 if (!*in) {
135 if (count) goto decode_error;
136 } else { /* '=' */
137 switch (count) {
138 case 1:
139 goto decode_error;
140 break;
141 case 2:
142 *out++ = bits >> 10;
143 break;
144 case 3:
145 *out++ = bits >> 16;
146 *out++ = (bits >> 8) & 0xff;
147 break;
151 *out = 0;
153 if (outlen)
154 *outlen = out-outstr;
156 return outstr;
158 decode_error:
159 mem_free(outstr);
160 return NULL;
163 #endif /* CONFIG_FORMHIST */