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