]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/base64.c
Cleanup: base64 coder de-duplication and upgrade
[thirdparty/squid.git] / lib / base64.c
CommitLineData
836c3244 1/*
262a0e14 2 * $Id$
8bdd0cec
AJ
3 *
4 * AUTHOR: Markus Moeller
5 *
6 * Encoders adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments.
836c3244 7 */
164f7660 8
0c05d982 9#include "config.h"
25f98340 10#include "base64.h"
0c05d982 11
12#if HAVE_STDIO_H
13#include <stdio.h>
14#endif
15#if HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
2d72d4fd 19
f5b8bbc4 20static void base64_init(void);
0673c0ba 21
0c05d982 22static int base64_initialized = 0;
7ce19a4b 23#define BASE64_VALUE_SZ 256
24#define BASE64_RESULT_SZ 8192
25int base64_value[BASE64_VALUE_SZ];
d5aa0e3b 26const char base64_code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
0c05d982 27
f86a22c5 28
b8d8561b 29static void
0673c0ba 30base64_init(void)
0c05d982 31{
32 int i;
33
7ce19a4b 34 for (i = 0; i < BASE64_VALUE_SZ; i++)
26ac0430 35 base64_value[i] = -1;
0c05d982 36
37 for (i = 0; i < 64; i++)
26ac0430 38 base64_value[(int) base64_code[i]] = i;
0c05d982 39 base64_value['='] = 0;
40
41 base64_initialized = 1;
42}
43
8bdd0cec
AJ
44int
45base64_decode_len(const char *data)
0c05d982 46{
8bdd0cec
AJ
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
63int
64base64_decode(char *result, unsigned int result_size, const char *p)
65{
66 int j = 0;
0c05d982 67 int c;
68 long val;
8bdd0cec
AJ
69 if (!p || !result || result_size == 0)
70 return j;
0c05d982 71 if (!base64_initialized)
26ac0430 72 base64_init();
0c05d982 73 val = c = 0;
8bdd0cec 74 for (; *p; p++) {
26ac0430
AJ
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 */
8bdd0cec
AJ
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;
26ac0430 100 val = c = 0;
0c05d982 101 }
8bdd0cec
AJ
102 return j;
103}
104
105int
106base64_encode_len(int len)
107{
108 // NP: some magic numbers + potential nil-terminator
109 return ((len + 2) / 3 * 4) + 1;
0c05d982 110}
f86a22c5 111
f86a22c5 112const char *
8bdd0cec 113old_base64_encode(const char *decoded_str)
f86a22c5 114{
7ce19a4b 115 static char result[BASE64_RESULT_SZ];
8bdd0cec
AJ
116 base64_encode_str(result, sizeof(result), decoded_str, strlen(decoded_str));
117 return result;
118}
f86a22c5 119
8bdd0cec
AJ
120const char *
121base64_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}
f86a22c5 127
8bdd0cec
AJ
128int
129base64_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';
f86a22c5 141 }
8bdd0cec 142 return used;
f86a22c5 143}
94439e4e 144
145/* adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments */
8bdd0cec
AJ
146int
147base64_encode(char *result, int result_size, const char *data, int data_size)
94439e4e 148{
94439e4e 149 int bits = 0;
150 int char_count = 0;
151 int out_cnt = 0;
94439e4e 152
8bdd0cec
AJ
153 if (!data || !*data || !result || result_size < 1 || data_size < 1)
154 return 0;
94439e4e 155
156 if (!base64_initialized)
26ac0430 157 base64_init();
94439e4e 158
8bdd0cec 159 while (data_size--) {
26ac0430
AJ
160 int c = (unsigned char) *data++;
161 bits += c;
162 char_count++;
163 if (char_count == 3) {
8bdd0cec
AJ
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 }
26ac0430
AJ
184 bits = 0;
185 char_count = 0;
186 } else {
187 bits <<= 8;
188 }
94439e4e 189 }
190 if (char_count != 0) {
26ac0430 191 bits <<= 16 - (8 * char_count);
8bdd0cec
AJ
192 if (out_cnt >= result_size)
193 return result_size;
26ac0430 194 result[out_cnt++] = base64_code[bits >> 18];
8bdd0cec
AJ
195 if (out_cnt >= result_size)
196 return result_size;
26ac0430
AJ
197 result[out_cnt++] = base64_code[(bits >> 12) & 0x3f];
198 if (char_count == 1) {
8bdd0cec
AJ
199 if (out_cnt >= result_size)
200 return result_size;
26ac0430 201 result[out_cnt++] = '=';
8bdd0cec
AJ
202 if (out_cnt >= result_size)
203 return result_size;
26ac0430
AJ
204 result[out_cnt++] = '=';
205 } else {
8bdd0cec
AJ
206 if (out_cnt >= result_size)
207 return result_size;
26ac0430 208 result[out_cnt++] = base64_code[(bits >> 6) & 0x3f];
8bdd0cec
AJ
209 if (out_cnt >= result_size)
210 return result_size;
26ac0430
AJ
211 result[out_cnt++] = '=';
212 }
94439e4e 213 }
8bdd0cec 214 return (out_cnt >= result_size?result_size:out_cnt);
94439e4e 215}