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
= {DEFAULT_CHARLIST
, "", 0, 1, 0};
38 initialize_charmap(base64_t
*base64
)
42 memset(base64
->charmap
, BASE64_INVALID
, sizeof(base64
->charmap
));
43 for (i
=0; i
<64; i
++) {
44 base64
->charmap
[(int)base64
->charlist
[i
]] = i
;
46 base64
->charmap
['='] = BASE64_PADDING
;
47 base64
->charmap_inited
= 1;
51 base64_init(const char *charlist
, int use_padding
, int skip_spaces
)
57 charlist
= DEFAULT_CHARLIST
;
59 if (strlen(charlist
) != 64) {
62 for (i
=0; i
<64; i
++) {
63 switch (charlist
[i
]) {
71 base64
= calloc(1, sizeof(base64_t
));
75 strncpy(base64
->charlist
, charlist
, sizeof(base64
->charlist
)-1);
76 base64
->use_padding
= use_padding
;
77 base64
->skip_spaces
= skip_spaces
;
83 base64_destroy(base64_t
*base64
)
89 base64_encoded_length(base64_t
*base64
, int srclen
)
92 base64
= &default_base64
;
95 if (base64
->use_padding
) {
96 return ((srclen
+2)/3*4)+1;
105 strlen
+= srclen
/3*4;
113 base64_encode(base64_t
*base64
, char *dst
, const unsigned char *src
, int srclen
)
115 int src_idx
, dst_idx
;
119 base64
= &default_base64
;
123 for (src_idx
=dst_idx
=0; src_idx
<srclen
; src_idx
++) {
124 residue
|= src
[src_idx
];
128 dst
[dst_idx
++] = base64
->charlist
[(residue
>>2)%64];
132 dst
[dst_idx
++] = base64
->charlist
[residue
>>4];
136 dst
[dst_idx
++] = base64
->charlist
[residue
>>6];
137 dst
[dst_idx
++] = base64
->charlist
[residue
&0x3f];
145 if (src_idx
%3 == 1) {
146 dst
[dst_idx
++] = base64
->charlist
[residue
>>4];
147 if (base64
->use_padding
) {
148 dst
[dst_idx
++] = '=';
149 dst
[dst_idx
++] = '=';
151 } else if (src_idx
%3 == 2) {
152 dst
[dst_idx
++] = base64
->charlist
[residue
>>6];
153 if (base64
->use_padding
) {
154 dst
[dst_idx
++] = '=';
162 base64_decode(base64_t
*base64
, unsigned char **dst
, const char *src
, int srclen
)
166 unsigned char *outbuf
;
172 base64
= &default_base64
;
174 if (!base64
->charmap_inited
) {
175 initialize_charmap(base64
);
178 inbuf
= malloc(srclen
+4);
182 memcpy(inbuf
, src
, srclen
);
183 inbuf
[srclen
] = '\0';
185 /* Remove all whitespaces from inbuf */
186 if (base64
->skip_spaces
) {
187 int i
, inbuflen
= strlen(inbuf
);
188 for (i
=0; i
<inbuflen
; i
++) {
189 if (inbuf
[i
] == '\0') {
191 } else if (isspace(inbuf
[i
])) {
192 memmove(inbuf
+i
, inbuf
+i
+1, inbuflen
-i
);
199 /* Add padding to inbuf if required */
200 inbuflen
= strlen(inbuf
);
201 if (!base64
->use_padding
) {
202 if (inbuflen
%4 == 1) {
206 if (inbuflen
%4 == 2) {
207 inbuf
[inbuflen
] = '=';
208 inbuf
[inbuflen
+1] = '=';
209 inbuf
[inbuflen
+2] = '\0';
211 } else if (inbuflen
%4 == 3) {
212 inbuf
[inbuflen
] = '=';
213 inbuf
[inbuflen
+1] = '\0';
218 /* Make sure data is divisible by 4 */
219 if (inbuflen
%4 != 0) {
224 /* Calculate the output length without padding */
225 outbuflen
= inbuflen
/4*3;
226 if (inbuflen
>= 4 && inbuf
[inbuflen
-1] == '=') {
228 if (inbuf
[inbuflen
-2] == '=') {
233 /* Allocate buffer for outputting data */
234 outbuf
= malloc(outbuflen
);
243 unsigned char a
= base64
->charmap
[(unsigned char)*(srcptr
++)];
244 unsigned char b
= base64
->charmap
[(unsigned char)*(srcptr
++)];
245 unsigned char c
= base64
->charmap
[(unsigned char)*(srcptr
++)];
246 unsigned char d
= base64
->charmap
[(unsigned char)*(srcptr
++)];
248 if (a
== BASE64_INVALID
|| b
== BASE64_INVALID
||
249 c
== BASE64_INVALID
|| d
== BASE64_INVALID
) {
252 if (a
== BASE64_PADDING
|| b
== BASE64_PADDING
) {
256 /* Update the first byte */
257 outbuf
[index
++] = (a
<< 2) | ((b
& 0x30) >> 4);
259 /* Update the second byte */
260 if (c
== BASE64_PADDING
) {
263 outbuf
[index
++] = ((b
& 0x0f) << 4) | ((c
& 0x3c) >> 2);
265 /* Update the third byte */
266 if (d
== BASE64_PADDING
) {
269 outbuf
[index
++] = ((c
& 0x03) << 6) | d
;
271 if (index
!= outbuflen
) {