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