3
Copyright (c) 2003, Arvid Norberg
6
Redistribution and use in source and binary forms, with or without
7
modification, are permitted provided that the following conditions
10
* Redistributions of source code must retain the above copyright
11
notice, this list of conditions and the following disclaimer.
12
* Redistributions in binary form must reproduce the above copyright
13
notice, this list of conditions and the following disclaimer in
14
the documentation and/or other materials provided with the distribution.
15
* Neither the name of the author nor the names of its
16
contributors may be used to endorse or promote products derived
17
from this software without specific prior written permission.
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
POSSIBILITY OF SUCH DAMAGE.
33
#include "libtorrent/pch.hpp"
45
#include <boost/optional.hpp>
46
#include <boost/array.hpp>
48
#include "libtorrent/assert.hpp"
49
#include "libtorrent/escape_string.hpp"
54
// lexical_cast's result depends on the locale. We need
55
// a well defined result
56
boost::array<char, 3 + std::numeric_limits<size_type>::digits10> to_string(size_type n)
58
boost::array<char, 3 + std::numeric_limits<size_type>::digits10> ret;
59
char *p = &ret.back();;
61
unsigned_size_type un = n;
67
if (n < 0) *--p = '-';
68
std::memmove(&ret.front(), p, sizeof(ret.elems));
74
return c >= '0' && c <= '9';
79
return c >= 32 && c < 127;
82
std::string unescape_string(std::string const& s)
85
for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
99
#ifdef BOOST_NO_EXCEPTIONS
102
throw std::runtime_error("invalid escaped string");
106
if(*i >= '0' && *i <= '9') high = *i - '0';
107
else if(*i >= 'A' && *i <= 'F') high = *i + 10 - 'A';
108
else if(*i >= 'a' && *i <= 'f') high = *i + 10 - 'a';
110
#ifdef BOOST_NO_EXCEPTIONS
113
throw std::runtime_error("invalid escaped string");
118
#ifdef BOOST_NO_EXCEPTIONS
121
throw std::runtime_error("invalid escaped string");
125
if(*i >= '0' && *i <= '9') low = *i - '0';
126
else if(*i >= 'A' && *i <= 'F') low = *i + 10 - 'A';
127
else if(*i >= 'a' && *i <= 'f') low = *i + 10 - 'a';
129
#ifdef BOOST_NO_EXCEPTIONS
132
throw std::runtime_error("invalid escaped string");
135
ret += char(high * 16 + low);
141
std::string escape_string(const char* str, int len)
143
TORRENT_ASSERT(str != 0);
144
TORRENT_ASSERT(len >= 0);
145
// http://www.ietf.org/rfc/rfc2396.txt
147
// some trackers seems to require that ' is escaped
148
// static const char unreserved_chars[] = "-_.!~*'()";
149
static const char unreserved_chars[] = "-_.!~*()"
150
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
153
std::stringstream ret;
154
ret << std::hex << std::setfill('0');
155
for (int i = 0; i < len; ++i)
159
, unreserved_chars+sizeof(unreserved_chars)-1
168
<< (int)static_cast<unsigned char>(*str);
175
std::string escape_path(const char* str, int len)
177
TORRENT_ASSERT(str != 0);
178
TORRENT_ASSERT(len >= 0);
179
static const char unreserved_chars[] = "/-_.!~*()"
180
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
183
std::stringstream ret;
184
ret << std::hex << std::setfill('0');
185
for (int i = 0; i < len; ++i)
189
, unreserved_chars+sizeof(unreserved_chars)-1
198
<< (int)static_cast<unsigned char>(*str);
205
std::string base64encode(const std::string& s)
207
static const char base64_table[] =
209
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
210
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
211
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
212
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
213
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
214
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
215
'w', 'x', 'y', 'z', '0', '1', '2', '3',
216
'4', '5', '6', '7', '8', '9', '+', '/'
219
unsigned char inbuf[3];
220
unsigned char outbuf[4];
223
for (std::string::const_iterator i = s.begin(); i != s.end();)
225
// available input is 1,2 or 3 bytes
226
// since we read 3 bytes at a time at most
227
int available_input = (std::min)(3, (int)std::distance(i, s.end()));
229
// clear input buffer
230
std::fill(inbuf, inbuf+3, 0);
232
// read a chunk of input into inbuf
233
std::copy(i, i + available_input, inbuf);
234
i += available_input;
236
// encode inbuf to outbuf
237
outbuf[0] = (inbuf[0] & 0xfc) >> 2;
238
outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
239
outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
240
outbuf[3] = inbuf[2] & 0x3f;
243
for (int j = 0; j < available_input+1; ++j)
245
ret += base64_table[outbuf[j]];
249
for (int j = 0; j < 3 - available_input; ++j)
257
std::string base32encode(std::string const& s)
259
static const char base32_table[] =
261
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
262
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
263
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
264
'Y', 'Z', '2', '3', '4', '5', '6', '7'
267
int input_output_mapping[] = {0, 2, 4, 5, 7, 8};
269
unsigned char inbuf[5];
270
unsigned char outbuf[8];
273
for (std::string::const_iterator i = s.begin(); i != s.end();)
275
int available_input = (std::min)(5, (int)std::distance(i, s.end()));
277
// clear input buffer
278
std::fill(inbuf, inbuf+5, 0);
280
// read a chunk of input into inbuf
281
std::copy(i, i + available_input, inbuf);
282
i += available_input;
284
// encode inbuf to outbuf
285
outbuf[0] = (inbuf[0] & 0xf8) >> 3;
286
outbuf[1] = ((inbuf[0] & 0x07) << 2) | ((inbuf[1] & 0xc0) >> 6);
287
outbuf[2] = ((inbuf[1] & 0x3e) >> 1);
288
outbuf[3] = ((inbuf[1] & 0x01) << 4) | ((inbuf[2] & 0xf0) >> 4);
289
outbuf[4] = ((inbuf[2] & 0x0f) << 1) | ((inbuf[3] & 0x80) >> 7);
290
outbuf[5] = ((inbuf[3] & 0x7c) >> 2);
291
outbuf[6] = ((inbuf[3] & 0x03) << 3) | ((inbuf[4] & 0xe0) >> 5);
292
outbuf[7] = inbuf[4] & 0x1f;
295
int num_out = input_output_mapping[available_input];
296
for (int j = 0; j < num_out; ++j)
298
ret += base32_table[outbuf[j]];
302
for (int j = 0; j < 8 - num_out; ++j)
310
std::string base32decode(std::string const& s)
312
unsigned char inbuf[8];
313
unsigned char outbuf[5];
316
for (std::string::const_iterator i = s.begin(); i != s.end();)
318
int available_input = (std::min)(8, (int)std::distance(i, s.end()));
321
if (available_input < 8) pad_start = available_input;
323
// clear input buffer
324
std::fill(inbuf, inbuf+8, 0);
325
for (int j = 0; j < available_input; ++j)
327
char in = std::toupper(*i++);
328
if (in >= 'A' && in <= 'Z')
330
else if (in >= '2' && in <= '7')
331
inbuf[j] = in - '2' + ('Z' - 'A') + 1;
335
if (pad_start == 0) pad_start = j;
338
inbuf[j] = 'I' - 'A';
340
return std::string();
341
TORRENT_ASSERT(inbuf[j] == (inbuf[j] & 0x1f));
344
// decode inbuf to outbuf
345
outbuf[0] = inbuf[0] << 3;
346
outbuf[0] |= inbuf[1] >> 2;
347
outbuf[1] = (inbuf[1] & 0x3) << 6;
348
outbuf[1] |= inbuf[2] << 1;
349
outbuf[1] |= (inbuf[3] & 0x10) >> 4;
350
outbuf[2] = (inbuf[3] & 0x0f) << 4;
351
outbuf[2] |= (inbuf[4] & 0x1e) >> 1;
352
outbuf[3] = (inbuf[4] & 0x01) << 7;
353
outbuf[3] |= (inbuf[5] & 0x1f) << 2;
354
outbuf[3] |= (inbuf[6] & 0x18) >> 3;
355
outbuf[4] = (inbuf[6] & 0x07) << 5;
356
outbuf[4] |= inbuf[7];
358
int input_output_mapping[] = {5, 1, 1, 2, 2, 3, 4, 4, 5};
359
int num_out = input_output_mapping[pad_start];
362
std::copy(outbuf, outbuf + num_out, std::back_inserter(ret));
367
boost::optional<std::string> url_has_argument(
368
std::string const& url, std::string argument)
370
size_t i = url.find('?');
371
if (i == std::string::npos) return boost::optional<std::string>();
376
if (url.compare(i, argument.size(), argument) == 0)
378
size_t pos = i + argument.size();
379
return url.substr(pos, url.find('&', pos) - pos);
381
argument.insert(0, "&");
382
i = url.find(argument, i);
383
if (i == std::string::npos) return boost::optional<std::string>();
384
size_t pos = i + argument.size();
385
return url.substr(pos, url.find('&', pos) - pos);
388
TORRENT_EXPORT std::string to_hex(std::string const& s)
391
char const* digits = "0123456789abcdef";
392
for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
394
ret += digits[((unsigned char)*i) >> 4];
395
ret += digits[((unsigned char)*i) & 0xf];