2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
21 #define DEFAULT_CHARLIST "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
23 #define BASE64_PADDING 0x40
24 #define BASE64_INVALID 0x80
35 static base64_t default_base64
=
36 { .charlist
= DEFAULT_CHARLIST
,
40 initialize_charmap(base64_t
*base64
)
44 memset(base64
->charmap
, BASE64_INVALID
, sizeof(base64
->charmap
));
45 for (i
=0; i
<64; i
++) {
46 base64
->charmap
[(int)base64
->charlist
[i
]] = i
;
48 base64
->charmap
['='] = BASE64_PADDING
;
49 base64
->charmap_inited
= 1;
53 base64_init(const char *charlist
, int use_padding
, int skip_spaces
)
59 charlist
= DEFAULT_CHARLIST
;
61 if (strlen(charlist
) != 64) {
64 for (i
=0; i
<64; i
++) {
65 switch (charlist
[i
]) {
73 base64
= calloc(1, sizeof(base64_t
));
77 strncpy(base64
->charlist
, charlist
, sizeof(base64
->charlist
)-1);
78 base64
->use_padding
= use_padding
;
79 base64
->skip_spaces
= skip_spaces
;
85 base64_destroy(base64_t
*base64
)
91 base64_encoded_length(base64_t
*base64
, int srclen
)
94 base64
= &default_base64
;
97 if (base64
->use_padding
) {
98 return ((srclen
+2)/3*4)+1;
101 switch (srclen
% 3) {
107 strlen
+= srclen
/3*4;
115 base64_encode(base64_t
*base64
, char *dst
, const unsigned char *src
, int srclen
)
117 int src_idx
, dst_idx
;
121 base64
= &default_base64
;
125 for (src_idx
=dst_idx
=0; src_idx
<srclen
; src_idx
++) {
126 residue
|= src
[src_idx
];
130 dst
[dst_idx
++] = base64
->charlist
[(residue
>>2)%64];
134 dst
[dst_idx
++] = base64
->charlist
[residue
>>4];
138 dst
[dst_idx
++] = base64
->charlist
[residue
>>6];
139 dst
[dst_idx
++] = base64
->charlist
[residue
&0x3f];
147 if (src_idx
%3 == 1) {
148 dst
[dst_idx
++] = base64
->charlist
[residue
>>4];
149 if (base64
->use_padding
) {
150 dst
[dst_idx
++] = '=';
151 dst
[dst_idx
++] = '=';
153 } else if (src_idx
%3 == 2) {
154 dst
[dst_idx
++] = base64
->charlist
[residue
>>6];
155 if (base64
->use_padding
) {
156 dst
[dst_idx
++] = '=';
164 base64_decode(base64_t
*base64
, unsigned char **dst
, const char *src
, int srclen
)
168 unsigned char *outbuf
;
174 base64
= &default_base64
;
176 if (!base64
->charmap_inited
) {
177 initialize_charmap(base64
);
180 inbuf
= malloc(srclen
+4);
184 memcpy(inbuf
, src
, srclen
);
185 inbuf
[srclen
] = '\0';
187 /* Remove all whitespaces from inbuf */
188 if (base64
->skip_spaces
) {
189 int i
, inbuflen
= strlen(inbuf
);
190 for (i
=0; i
<inbuflen
; i
++) {
191 if (inbuf
[i
] == '\0') {
193 } else if (isspace(inbuf
[i
])) {
194 memmove(inbuf
+i
, inbuf
+i
+1, inbuflen
-i
);
201 /* Add padding to inbuf if required */
202 inbuflen
= strlen(inbuf
);
203 if (!base64
->use_padding
) {
204 if (inbuflen
%4 == 1) {
208 if (inbuflen
%4 == 2) {
209 inbuf
[inbuflen
] = '=';
210 inbuf
[inbuflen
+1] = '=';
211 inbuf
[inbuflen
+2] = '\0';
213 } else if (inbuflen
%4 == 3) {
214 inbuf
[inbuflen
] = '=';
215 inbuf
[inbuflen
+1] = '\0';
220 /* Make sure data is divisible by 4 */
221 if (inbuflen
%4 != 0) {
226 /* Calculate the output length without padding */
227 outbuflen
= inbuflen
/4*3;
228 if (inbuflen
>= 4 && inbuf
[inbuflen
-1] == '=') {
230 if (inbuf
[inbuflen
-2] == '=') {
235 /* Allocate buffer for outputting data */
236 outbuf
= malloc(outbuflen
);
245 unsigned char a
= base64
->charmap
[(unsigned char)*(srcptr
++)];
246 unsigned char b
= base64
->charmap
[(unsigned char)*(srcptr
++)];
247 unsigned char c
= base64
->charmap
[(unsigned char)*(srcptr
++)];
248 unsigned char d
= base64
->charmap
[(unsigned char)*(srcptr
++)];
250 if (a
== BASE64_INVALID
|| b
== BASE64_INVALID
||
251 c
== BASE64_INVALID
|| d
== BASE64_INVALID
) {
254 if (a
== BASE64_PADDING
|| b
== BASE64_PADDING
) {
258 /* Update the first byte */
259 outbuf
[index
++] = (a
<< 2) | ((b
& 0x30) >> 4);
261 /* Update the second byte */
262 if (c
== BASE64_PADDING
) {
265 outbuf
[index
++] = ((b
& 0x0f) << 4) | ((c
& 0x3c) >> 2);
267 /* Update the third byte */
268 if (d
== BASE64_PADDING
) {
271 outbuf
[index
++] = ((c
& 0x03) << 6) | d
;
273 if (index
!= outbuflen
) {