7 #define DEFAULT_CHARLIST "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
9 #define BASE64_PADDING 0x40
10 #define BASE64_INVALID 0x80
21 static base64_t default_base64
=
22 { .charlist
= DEFAULT_CHARLIST
,
26 initialize_charmap(base64_t
*base64
)
30 memset(base64
->charmap
, BASE64_INVALID
, sizeof(base64
->charmap
));
31 for (i
=0; i
<64; i
++) {
32 base64
->charmap
[(int)base64
->charlist
[i
]] = i
;
34 base64
->charmap
['='] = BASE64_PADDING
;
35 base64
->charmap_inited
= 1;
39 base64_init(const char *charlist
, int use_padding
, int skip_spaces
)
45 charlist
= DEFAULT_CHARLIST
;
47 if (strlen(charlist
) != 64) {
50 for (i
=0; i
<64; i
++) {
51 switch (charlist
[i
]) {
59 base64
= calloc(1, sizeof(base64_t
));
63 strncpy(base64
->charlist
, charlist
, sizeof(base64
->charlist
)-1);
64 base64
->use_padding
= use_padding
;
65 base64
->skip_spaces
= skip_spaces
;
71 base64_destroy(base64_t
*base64
)
77 base64_encoded_length(base64_t
*base64
, int srclen
)
80 base64
= &default_base64
;
83 if (base64
->use_padding
) {
84 return ((srclen
+2)/3*4)+1;
101 base64_encode(base64_t
*base64
, char *dst
, const unsigned char *src
, int srclen
)
103 int src_idx
, dst_idx
;
107 base64
= &default_base64
;
111 for (src_idx
=dst_idx
=0; src_idx
<srclen
; src_idx
++) {
112 residue
|= src
[src_idx
];
116 dst
[dst_idx
++] = base64
->charlist
[(residue
>>2)%64];
120 dst
[dst_idx
++] = base64
->charlist
[residue
>>4];
124 dst
[dst_idx
++] = base64
->charlist
[residue
>>6];
125 dst
[dst_idx
++] = base64
->charlist
[residue
&0x3f];
133 if (src_idx
%3 == 1) {
134 dst
[dst_idx
++] = base64
->charlist
[residue
>>4];
135 if (base64
->use_padding
) {
136 dst
[dst_idx
++] = '=';
137 dst
[dst_idx
++] = '=';
139 } else if (src_idx
%3 == 2) {
140 dst
[dst_idx
++] = base64
->charlist
[residue
>>6];
141 if (base64
->use_padding
) {
142 dst
[dst_idx
++] = '=';
150 base64_decode(base64_t
*base64
, unsigned char **dst
, const char *src
, int srclen
)
154 unsigned char *outbuf
;
160 base64
= &default_base64
;
162 if (!base64
->charmap_inited
) {
163 initialize_charmap(base64
);
166 inbuf
= malloc(srclen
+4);
170 memcpy(inbuf
, src
, srclen
);
171 inbuf
[srclen
] = '\0';
173 /* Remove all whitespaces from inbuf */
174 if (base64
->skip_spaces
) {
175 int i
, inbuflen
= strlen(inbuf
);
176 for (i
=0; i
<inbuflen
; i
++) {
177 if (inbuf
[i
] == '\0') {
179 } else if (isspace(inbuf
[i
])) {
180 memmove(inbuf
+i
, inbuf
+i
+1, inbuflen
-i
);
187 /* Add padding to inbuf if required */
188 inbuflen
= strlen(inbuf
);
189 if (!base64
->use_padding
) {
190 if (inbuflen
%4 == 1) {
194 if (inbuflen
%4 == 2) {
195 inbuf
[inbuflen
] = '=';
196 inbuf
[inbuflen
+1] = '=';
197 inbuf
[inbuflen
+2] = '\0';
199 } else if (inbuflen
%4 == 3) {
200 inbuf
[inbuflen
] = '=';
201 inbuf
[inbuflen
+1] = '\0';
206 /* Make sure data is divisible by 4 */
207 if (inbuflen
%4 != 0) {
212 /* Calculate the output length without padding */
213 outbuflen
= inbuflen
/4*3;
214 if (inbuflen
>= 4 && inbuf
[inbuflen
-1] == '=') {
216 if (inbuf
[inbuflen
-2] == '=') {
221 /* Allocate buffer for outputting data */
222 outbuf
= malloc(outbuflen
);
231 unsigned char a
= base64
->charmap
[(unsigned char)*(srcptr
++)];
232 unsigned char b
= base64
->charmap
[(unsigned char)*(srcptr
++)];
233 unsigned char c
= base64
->charmap
[(unsigned char)*(srcptr
++)];
234 unsigned char d
= base64
->charmap
[(unsigned char)*(srcptr
++)];
236 if (a
== BASE64_INVALID
|| b
== BASE64_INVALID
||
237 c
== BASE64_INVALID
|| d
== BASE64_INVALID
) {
240 if (a
== BASE64_PADDING
|| b
== BASE64_PADDING
) {
244 /* Update the first byte */
245 outbuf
[index
++] = (a
<< 2) | ((b
& 0x30) >> 4);
247 /* Update the second byte */
248 if (c
== BASE64_PADDING
) {
251 outbuf
[index
++] = ((b
& 0x0f) << 4) | ((c
& 0x3c) >> 2);
253 /* Update the third byte */
254 if (d
== BASE64_PADDING
) {
257 outbuf
[index
++] = ((c
& 0x03) << 6) | d
;
259 if (index
!= outbuflen
) {