blob: 667e58814bd760729f74a231a7efcf03124af3d0 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 2001-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <cc++/config.h>
40#ifdef CCXX_WITHOUT_EXTRAS
41#include <cc++/export.h>
42#endif
43#include <cc++/exception.h>
44#include <cc++/thread.h>
45#include <cc++/address.h>
46#include <cc++/socket.h>
47#ifndef CCXX_WITHOUT_EXTRAS
48#include <cc++/export.h>
49#endif
50#include <cc++/url.h>
51
52#include <string>
53#include <cstdio>
54#include <cstdlib>
55#include <fcntl.h>
56#include <cerrno>
57#include <iostream>
58#ifdef WIN32
59#include <io.h>
60#endif
61#include <cctype>
62
63#ifdef CCXX_NAMESPACES
64namespace ost {
65using namespace std;
66#endif
67
68static const unsigned char alphabet[65] =
69 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
70
71char* b64Encode(const char *source, char *dest, size_t limit)
72{
73 b64Encode((const unsigned char*)source,strlen(source),
74 dest,limit);
75 return dest;
76}
77
78char* b64Decode(char *source, char *dest)
79{
80 size_t srcsize = strlen(source);
81 char* dst = dest?dest:source;
82 size_t dstsize =
83 b64Decode(source,(unsigned char*)dst,srcsize+1);
84 dst[dstsize] = 0;
85 return dst;
86}
87
88size_t b64Encode(const unsigned char *src, size_t srcsize,
89 char *dst, size_t dstsize)
90{
91 if (!dstsize) return 0;
92
93 char* pdst = dst;
94 unsigned bits;
95
96 while(srcsize >= 3 && dstsize > 4) {
97 bits = (((unsigned)src[0])<<16) | (((unsigned)src[1])<<8)
98 | ((unsigned)src[2]);
99 src += 3;
100 srcsize -= 3;
101 *(pdst++) = alphabet[bits >> 18];
102 *(pdst++) = alphabet[(bits >> 12) & 0x3f];
103 *(pdst++) = alphabet[(bits >> 6) & 0x3f];
104 *(pdst++) = alphabet[bits & 0x3f];
105 dstsize -= 4;
106 }
107 if (srcsize && dstsize > 4) {
108 bits = ((unsigned)src[0])<<16;
109 *(pdst++) = alphabet[bits >> 18];
110 if (srcsize == 1) {
111 *(pdst++) = alphabet[(bits >> 12) & 0x3f];
112 *(pdst++) = '=';
113 }
114 else {
115 bits |= ((unsigned)src[1])<<8;
116 *(pdst++) = alphabet[(bits >> 12) & 0x3f];
117 *(pdst++) = alphabet[(bits >> 6) & 0x3f];
118 }
119 *(pdst++) = '=';
120 }
121 *pdst = 0;
122 return pdst-dst;
123}
124
125size_t b64Decode(const char *src,
126 unsigned char *dst, size_t dstsize)
127{
128 char decoder[256];
129 int i, bits, c;
130
131 unsigned char *pdst = dst;
132
133 for (i = 0; i < 256; ++i)
134 decoder[i] = 64;
135 for (i = 0; i < 64 ; ++i)
136 decoder[alphabet[i]] = i;
137
138 bits = 1;
139
140 while(*src) {
141 c = (unsigned char)(*(src++));
142 if (c == '=') {
143 if (bits & 0x40000) {
144 if (dstsize < 2) break;
145 *(pdst++) = (bits >> 10);
146 *(pdst++) = (bits >> 2) & 0xff;
147 break;
148 }
149 if (bits & 0x1000 && dstsize)
150 *(pdst++) = (bits >> 4);
151 break;
152 }
153 // skip invalid chars
154 if (decoder[c] == 64)
155 continue;
156 bits = (bits << 6) + decoder[c];
157 if (bits & 0x1000000) {
158 if (dstsize < 3) break;
159 *(pdst++) = (bits >> 16);
160 *(pdst++) = (bits >> 8) & 0xff;
161 *(pdst++) = (bits & 0xff);
162 bits = 1;
163 dstsize -= 3;
164 }
165 }
166 return pdst-dst;
167}
168
169
170char* urlDecode(char *source, char *dest)
171{
172 char *ret;
173 char hex[3];
174
175 if(!dest)
176 dest = source;
177 else
178 *dest = 0;
179
180 ret = dest;
181
182 if(!source)
183 return dest;
184
185 while(*source) {
186 switch(*source) {
187 case '+':
188 *(dest++) = ' ';
189 break;
190 case '%':
191 // NOTE: wrong input can finish with "...%" giving
192 // buffer overflow, cut string here
193 if(source[1]) {
194 hex[0] = source[1];
195 ++source;
196 if(source[1]) {
197 hex[1] = source[1];
198 ++source;
199 }
200 else
201 hex[1] = 0;
202 }
203 else
204 hex[0] = hex[1] = 0;
205 hex[2] = 0;
206 *(dest++) = (char)strtol(hex, NULL, 16);
207 break;
208 default:
209 *(dest++) = *source;
210 }
211 ++source;
212 }
213 *dest = 0;
214 return ret;
215}
216
217char* urlEncode(const char *source, char *dest, size_t max)
218{
219 static const char *hex = "0123456789abcdef";
220 size_t len = 0;
221 unsigned char ch;
222 char *ret = dest;
223
224 *dest = 0;
225 if(!source)
226 return dest;
227
228 while(len < max - 4 && *source) {
229 ch = (unsigned char)*source;
230 if(*source == ' ')
231 *(dest++) = '+';
232 else if(isalnum(*source) || strchr("/.-:;,", *source))
233 *(dest++) = *source;
234 else {
235 *(dest++) = '%';
236 // char in C++ can be more than 8bit
237 *(dest++) = hex[(ch >> 4)&0xF];
238 *(dest++) = hex[ch % 16];
239 }
240 ++source;
241 }
242 *dest = 0;
243 return ret;
244}
245
246#if defined(DYNAMIC_LOCAL_ARRAYS)
247
248/** @relates URLStream
249 * Encode a STL string using base64 coding into a STL string
250 * @return base 64 encoded string
251 * @param src source string
252 */
253String b64Encode(const String& src)
254{
255 size_t limit = (src.length()+2)/3*4+1; // size + null must be included
256 char buffer[limit];
257
258 unsigned size = b64Encode((const unsigned char *)src.c_str(), src.length(), buffer, limit);
259 buffer[size] = '\0';
260
261 return String(buffer);
262}
263
264/** @relates URLStream
265 * Decode a STL string using base64 coding into an STL String.
266 * Destination size should be at least strlen(src)/4*3.
267 * Destination are not string terminated (It's just a octet stream).
268 * @return decoded string
269 * @param src source string
270 */
271String b64Decode(const String& src)
272{
273 size_t limit = src.length()/4*3;
274 unsigned char buffer[limit+1];
275
276 unsigned size = b64Decode(src.c_str(), buffer, limit);
277 buffer[size] = '\0';
278
279 return String((char *)buffer);
280}
281
282/** @relates URLStream
283 * Encode a octet stream using base64 coding into a STL string
284 * @return base 64 encoded string
285 * @param src source buffer
286 * @param srcsize source buffer size
287 */
288String b64Encode(const unsigned char *src, size_t srcsize)
289{
290 size_t limit = (srcsize+2)/3*4+1;
291 char buffer[limit];
292
293 unsigned size = b64Encode(src, srcsize, buffer, limit);
294 buffer[size] = '\0';
295
296 return String(buffer);
297}
298
299/** @relates URLStream
300 * Decode an STL string encoded using base64.
301 * Destination size should be at least strlen(src)/4*3.
302 * Destination are not string terminated (It's just a octet stream).
303 * @return number of octets written into destination buffer
304 * @param src source string
305 * @param dst destination octet buffer
306 * @param dstsize destination buffer size
307 */
308size_t b64Decode(const String& src,
309 unsigned char *dst, size_t dstsize)
310{
311 return b64Decode(src.c_str(), dst, dstsize);
312}
313#endif
314
315#ifdef CCXX_NAMESPACES
316}
317#endif