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