blob: 7765f107e6d55e9c424e919674b8dbf5c8d1c266 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001
2//*********************************************************************
3//* Base64 - a simple base64 encoder and decoder.
4//*
5//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
6//*
7//* This code may be freely used for any purpose, either personal
8//* or commercial, provided the authors copyright notice remains
9//* intact.
10//*
11//* Enhancements by Stanley Yamane:
12//* o reverse lookup table for the decode function
13//* o reserve string buffer space in advance
14//*
15//*********************************************************************
16
17#include "talk/base/base64.h"
18
19#include <string.h>
20
21#include "talk/base/common.h"
22
23using std::string;
24using std::vector;
25
26namespace talk_base {
27
28static const char kPad = '=';
29static const unsigned char pd = 0xFD; // Padding
30static const unsigned char sp = 0xFE; // Whitespace
31static const unsigned char il = 0xFF; // Illegal base64 character
32
33const char Base64::Base64Table[] =
34// 0000000000111111111122222222223333333333444444444455555555556666
35// 0123456789012345678901234567890123456789012345678901234567890123
36 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
37
38// Decode Table gives the index of any valid base64 character in the
39// Base64 table
40// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
41
42const unsigned char Base64::DecodeTable[] = {
43// 0 1 2 3 4 5 6 7 8 9
44 il,il,il,il,il,il,il,il,il,sp, // 0 - 9
45 sp,sp,sp,sp,il,il,il,il,il,il, // 10 - 19
46 il,il,il,il,il,il,il,il,il,il, // 20 - 29
47 il,il,sp,il,il,il,il,il,il,il, // 30 - 39
48 il,il,il,62,il,il,il,63,52,53, // 40 - 49
49 54,55,56,57,58,59,60,61,il,il, // 50 - 59
50 il,pd,il,il,il, 0, 1, 2, 3, 4, // 60 - 69
51 5, 6, 7, 8, 9,10,11,12,13,14, // 70 - 79
52 15,16,17,18,19,20,21,22,23,24, // 80 - 89
53 25,il,il,il,il,il,il,26,27,28, // 90 - 99
54 29,30,31,32,33,34,35,36,37,38, // 100 - 109
55 39,40,41,42,43,44,45,46,47,48, // 110 - 119
56 49,50,51,il,il,il,il,il,il,il, // 120 - 129
57 il,il,il,il,il,il,il,il,il,il, // 130 - 139
58 il,il,il,il,il,il,il,il,il,il, // 140 - 149
59 il,il,il,il,il,il,il,il,il,il, // 150 - 159
60 il,il,il,il,il,il,il,il,il,il, // 160 - 169
61 il,il,il,il,il,il,il,il,il,il, // 170 - 179
62 il,il,il,il,il,il,il,il,il,il, // 180 - 189
63 il,il,il,il,il,il,il,il,il,il, // 190 - 199
64 il,il,il,il,il,il,il,il,il,il, // 200 - 209
65 il,il,il,il,il,il,il,il,il,il, // 210 - 219
66 il,il,il,il,il,il,il,il,il,il, // 220 - 229
67 il,il,il,il,il,il,il,il,il,il, // 230 - 239
68 il,il,il,il,il,il,il,il,il,il, // 240 - 249
69 il,il,il,il,il,il // 250 - 255
70};
71
72bool Base64::IsBase64Char(char ch) {
73 return (('A' <= ch) && (ch <= 'Z')) ||
74 (('a' <= ch) && (ch <= 'z')) ||
75 (('0' <= ch) && (ch <= '9')) ||
76 (ch == '+') || (ch == '/');
77}
78
79bool Base64::GetNextBase64Char(char ch, char* next_ch) {
80 if (next_ch == NULL) {
81 return false;
82 }
83 const char* p = strchr(Base64Table, ch);
84 if (!p)
85 return false;
86 ++p;
87 *next_ch = (*p) ? *p : Base64Table[0];
88 return true;
89}
90
91bool Base64::IsBase64Encoded(const std::string& str) {
92 for (size_t i = 0; i < str.size(); ++i) {
93 if (!IsBase64Char(str.at(i)))
94 return false;
95 }
96 return true;
97}
98
99void Base64::EncodeFromArray(const void* data, size_t len, string* result) {
100 ASSERT(NULL != result);
101 result->clear();
102 result->resize(((len + 2) / 3) * 4);
103 const unsigned char* byte_data = static_cast<const unsigned char*>(data);
104
105 unsigned char c;
106 size_t i = 0;
107 size_t dest_ix = 0;
108 while (i < len) {
109 c = (byte_data[i] >> 2) & 0x3f;
110 (*result)[dest_ix++] = Base64Table[c];
111
112 c = (byte_data[i] << 4) & 0x3f;
113 if (++i < len) {
114 c |= (byte_data[i] >> 4) & 0x0f;
115 }
116 (*result)[dest_ix++] = Base64Table[c];
117
118 if (i < len) {
119 c = (byte_data[i] << 2) & 0x3f;
120 if (++i < len) {
121 c |= (byte_data[i] >> 6) & 0x03;
122 }
123 (*result)[dest_ix++] = Base64Table[c];
124 } else {
125 (*result)[dest_ix++] = kPad;
126 }
127
128 if (i < len) {
129 c = byte_data[i] & 0x3f;
130 (*result)[dest_ix++] = Base64Table[c];
131 ++i;
132 } else {
133 (*result)[dest_ix++] = kPad;
134 }
135 }
136}
137
138size_t Base64::GetNextQuantum(DecodeFlags parse_flags, bool illegal_pads,
139 const char* data, size_t len, size_t* dpos,
140 unsigned char qbuf[4], bool* padded)
141{
142 size_t byte_len = 0, pad_len = 0, pad_start = 0;
143 for (; (byte_len < 4) && (*dpos < len); ++*dpos) {
144 qbuf[byte_len] = DecodeTable[static_cast<unsigned char>(data[*dpos])];
145 if ((il == qbuf[byte_len]) || (illegal_pads && (pd == qbuf[byte_len]))) {
146 if (parse_flags != DO_PARSE_ANY)
147 break;
148 // Ignore illegal characters
149 } else if (sp == qbuf[byte_len]) {
150 if (parse_flags == DO_PARSE_STRICT)
151 break;
152 // Ignore spaces
153 } else if (pd == qbuf[byte_len]) {
154 if (byte_len < 2) {
155 if (parse_flags != DO_PARSE_ANY)
156 break;
157 // Ignore unexpected padding
158 } else if (byte_len + pad_len >= 4) {
159 if (parse_flags != DO_PARSE_ANY)
160 break;
161 // Ignore extra pads
162 } else {
163 if (1 == ++pad_len) {
164 pad_start = *dpos;
165 }
166 }
167 } else {
168 if (pad_len > 0) {
169 if (parse_flags != DO_PARSE_ANY)
170 break;
171 // Ignore pads which are followed by data
172 pad_len = 0;
173 }
174 ++byte_len;
175 }
176 }
177 for (size_t i = byte_len; i < 4; ++i) {
178 qbuf[i] = 0;
179 }
180 if (4 == byte_len + pad_len) {
181 *padded = true;
182 } else {
183 *padded = false;
184 if (pad_len) {
185 // Roll back illegal padding
186 *dpos = pad_start;
187 }
188 }
189 return byte_len;
190}
191
192bool Base64::DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
193 string* result, size_t* data_used) {
194 return DecodeFromArrayTemplate<string>(data, len, flags, result, data_used);
195}
196
197bool Base64::DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
198 vector<char>* result, size_t* data_used) {
199 return DecodeFromArrayTemplate<vector<char> >(data, len, flags, result,
200 data_used);
201}
202
203template<typename T>
204bool Base64::DecodeFromArrayTemplate(const char* data, size_t len,
205 DecodeFlags flags, T* result,
206 size_t* data_used)
207{
208 ASSERT(NULL != result);
209 ASSERT(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
210
211 const DecodeFlags parse_flags = flags & DO_PARSE_MASK;
212 const DecodeFlags pad_flags = flags & DO_PAD_MASK;
213 const DecodeFlags term_flags = flags & DO_TERM_MASK;
214 ASSERT(0 != parse_flags);
215 ASSERT(0 != pad_flags);
216 ASSERT(0 != term_flags);
217
218 result->clear();
219 result->reserve(len);
220
221 size_t dpos = 0;
222 bool success = true, padded;
223 unsigned char c, qbuf[4];
224 while (dpos < len) {
225 size_t qlen = GetNextQuantum(parse_flags, (DO_PAD_NO == pad_flags),
226 data, len, &dpos, qbuf, &padded);
227 c = (qbuf[0] << 2) | ((qbuf[1] >> 4) & 0x3);
228 if (qlen >= 2) {
229 result->push_back(c);
230 c = ((qbuf[1] << 4) & 0xf0) | ((qbuf[2] >> 2) & 0xf);
231 if (qlen >= 3) {
232 result->push_back(c);
233 c = ((qbuf[2] << 6) & 0xc0) | qbuf[3];
234 if (qlen >= 4) {
235 result->push_back(c);
236 c = 0;
237 }
238 }
239 }
240 if (qlen < 4) {
241 if ((DO_TERM_ANY != term_flags) && (0 != c)) {
242 success = false; // unused bits
243 }
244 if ((DO_PAD_YES == pad_flags) && !padded) {
245 success = false; // expected padding
246 }
247 break;
248 }
249 }
250 if ((DO_TERM_BUFFER == term_flags) && (dpos != len)) {
251 success = false; // unused chars
252 }
253 if (data_used) {
254 *data_used = dpos;
255 }
256 return success;
257}
258
259} // namespace talk_base