]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/base64.c
SourceFormat Enforcement
[thirdparty/squid.git] / lib / base64.c
1 /*
2 * $Id$
3 *
4 * AUTHOR: Markus Moeller
5 *
6 * Encoders adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments.
7 */
8
9 #include "squid.h"
10 #include "base64.h"
11
12 #if HAVE_STDIO_H
13 #include <stdio.h>
14 #endif
15 #if HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18
19 static void base64_init(void);
20
21 static int base64_initialized = 0;
22 #define BASE64_VALUE_SZ 256
23 #define BASE64_RESULT_SZ 8192
24 int base64_value[BASE64_VALUE_SZ];
25 const char base64_code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26
27 static void
28 base64_init(void)
29 {
30 int i;
31
32 for (i = 0; i < BASE64_VALUE_SZ; i++)
33 base64_value[i] = -1;
34
35 for (i = 0; i < 64; i++)
36 base64_value[(int) base64_code[i]] = i;
37 base64_value['='] = 0;
38
39 base64_initialized = 1;
40 }
41
42 int
43 base64_decode_len(const char *data)
44 {
45 if (!data || !*data)
46 return 0;
47
48 int terminatorLen = 0;
49 int dataLen = strlen(data);
50 int i;
51
52 for (i = dataLen - 1; i >= 0; i--) {
53 if (data[i] == '=')
54 terminatorLen++;
55 if (data[i] != '=')
56 break;
57 }
58 return dataLen / 4 * 3 - terminatorLen;
59 }
60
61 int
62 base64_decode(char *result, unsigned int result_size, const char *p)
63 {
64 int j = 0;
65 int c;
66 long val;
67 if (!p || !result || result_size == 0)
68 return j;
69 if (!base64_initialized)
70 base64_init();
71 val = c = 0;
72 for (; *p; p++) {
73 unsigned int k = ((unsigned char) *p) % BASE64_VALUE_SZ;
74 if (base64_value[k] < 0)
75 continue;
76 val <<= 6;
77 val += base64_value[k];
78 if (++c < 4)
79 continue;
80 /* One quantum of four encoding characters/24 bit */
81 if (j+4 <= result_size) {
82 // Speed optimization: plenty of space, avoid some per-byte checks.
83 result[j++] = (val >> 16) & 0xff; /* High 8 bits */
84 result[j++] = (val >> 8) & 0xff; /* Mid 8 bits */
85 result[j++] = val & 0xff; /* Low 8 bits */
86 } else {
87 // part-quantum goes a bit slower with per-byte checks
88 result[j++] = (val >> 16) & 0xff; /* High 8 bits */
89 if (j == result_size)
90 return j;
91 result[j++] = (val >> 8) & 0xff; /* Mid 8 bits */
92 if (j == result_size)
93 return j;
94 result[j++] = val & 0xff; /* Low 8 bits */
95 }
96 if (j == result_size)
97 return j;
98 val = c = 0;
99 }
100 return j;
101 }
102
103 int
104 base64_encode_len(int len)
105 {
106 // NP: some magic numbers + potential nil-terminator
107 return ((len + 2) / 3 * 4) + 1;
108 }
109
110 const char *
111 old_base64_encode(const char *decoded_str)
112 {
113 static char result[BASE64_RESULT_SZ];
114 base64_encode_str(result, sizeof(result), decoded_str, strlen(decoded_str));
115 return result;
116 }
117
118 const char *
119 base64_encode_bin(const char *decoded_str, int len)
120 {
121 static char result[BASE64_RESULT_SZ];
122 base64_encode_str(result, sizeof(result), decoded_str, len);
123 return result;
124 }
125
126 int
127 base64_encode_str(char *result, int result_max_size, const char *data, int data_size)
128 {
129 if (result_max_size < 1)
130 return 0;
131
132 int used = base64_encode(result, result_max_size, data, data_size);
133 /* terminate */
134 if (used >= result_max_size) {
135 result[result_max_size - 1] = '\0';
136 return result_max_size;
137 } else {
138 result[used++] = '\0';
139 }
140 return used;
141 }
142
143 /* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
144 int
145 base64_encode(char *result, int result_size, const char *data, int data_size)
146 {
147 int bits = 0;
148 int char_count = 0;
149 int out_cnt = 0;
150
151 if (!data || !*data || !result || result_size < 1 || data_size < 1)
152 return 0;
153
154 if (!base64_initialized)
155 base64_init();
156
157 while (data_size--) {
158 int c = (unsigned char) *data++;
159 bits += c;
160 char_count++;
161 if (char_count == 3) {
162 if (out_cnt >= result_size)
163 break;
164 if (out_cnt+4 <= result_size) {
165 result[out_cnt++] = base64_code[bits >> 18];
166 result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
167 result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
168 result[out_cnt++] = base64_code[bits & 0x3f];
169 } else {
170 // part-quantum goes a bit slower with per-byte checks
171 result[out_cnt++] = base64_code[bits >> 18];
172 if (out_cnt >= result_size)
173 break;
174 result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
175 if (out_cnt >= result_size)
176 break;
177 result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
178 if (out_cnt >= result_size)
179 break;
180 result[out_cnt++] = base64_code[bits & 0x3f];
181 }
182 bits = 0;
183 char_count = 0;
184 } else {
185 bits <<= 8;
186 }
187 }
188 if (char_count != 0) {
189 bits <<= 16 - (8 * char_count);
190 if (out_cnt >= result_size)
191 return result_size;
192 result[out_cnt++] = base64_code[bits >> 18];
193 if (out_cnt >= result_size)
194 return result_size;
195 result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
196 if (char_count == 1) {
197 if (out_cnt >= result_size)
198 return result_size;
199 result[out_cnt++] = '=';
200 if (out_cnt >= result_size)
201 return result_size;
202 result[out_cnt++] = '=';
203 } else {
204 if (out_cnt >= result_size)
205 return result_size;
206 result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
207 if (out_cnt >= result_size)
208 return result_size;
209 result[out_cnt++] = '=';
210 }
211 }
212 return (out_cnt >= result_size?result_size:out_cnt);
213 }