forked from jwerle/b64.c
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decode.c
130 lines (110 loc) · 2.86 KB
/
decode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* `decode.c' - b64
*
* copyright (c) 2014 joseph werle
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "b64.h"
#ifdef b64_USE_CUSTOM_MALLOC
extern void* b64_malloc(size_t);
#endif
#ifdef b64_USE_CUSTOM_REALLOC
extern void* b64_realloc(void*, size_t);
#endif
unsigned char *
b64_decode (const char *src, size_t len) {
return b64_decode_ex(src, len, NULL);
}
unsigned char *
b64_decode_ex (const char *src, size_t len, size_t *decsize) {
int i = 0;
int j = 0;
int l = 0;
size_t size = 0;
unsigned char *dec = NULL;
unsigned char buf[3];
unsigned char tmp[4];
// alloc
dec = (unsigned char *) b64_buf_malloc();
if (NULL == dec) { return NULL; }
// parse until end of source
while (len--) {
// break if char is `=' or not base64 char
if ('=' == src[j]) { break; }
if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { break; }
// read up to 4 bytes at a time into `tmp'
tmp[i++] = src[j++];
// if 4 bytes read then decode into `buf'
if (4 == i) {
// translate values in `tmp' from table
for (i = 0; i < 4; ++i) {
// find translation char in `b64_table'
for (l = 0; l < 64; ++l) {
if (tmp[i] == b64_table[l]) {
tmp[i] = l;
break;
}
}
}
// decode
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
// write decoded buffer to `dec'
dec = (unsigned char *) b64_buf_realloc(dec, size + 3);
if (dec != NULL){
for (i = 0; i < 3; ++i) {
dec[size++] = buf[i];
}
} else {
return NULL;
}
// reset
i = 0;
}
}
// remainder
if (i > 0) {
// fill `tmp' with `\0' at most 4 times
for (j = i; j < 4; ++j) {
tmp[j] = '\0';
}
// translate remainder
for (j = 0; j < 4; ++j) {
// find translation char in `b64_table'
for (l = 0; l < 64; ++l) {
if (tmp[j] == b64_table[l]) {
tmp[j] = l;
break;
}
}
}
// decode remainder
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
// write remainer decoded buffer to `dec'
dec = (unsigned char *)b64_buf_realloc(dec, size + (i - 1));
if (dec != NULL){
for (j = 0; (j < i - 1); ++j) {
dec[size++] = buf[j];
}
} else {
return NULL;
}
}
// Make sure we have enough space to add '\0' character at end.
dec = (unsigned char *)b64_buf_realloc(dec, size + 1);
if (dec != NULL){
dec[size] = '\0';
} else {
return NULL;
}
// Return back the size of decoded string if demanded.
if (decsize != NULL) {
*decsize = size;
}
return dec;
}