~ubuntu-branches/ubuntu/trusty/miro/trusty

« back to all changes in this revision

Viewing changes to portable/libtorrent/src/escape_string.cpp

  • Committer: Daniel Hahler
  • Date: 2010-04-13 18:51:35 UTC
  • mfrom: (1.2.10 upstream)
  • Revision ID: ubuntu-launchpad@thequod.de-20100413185135-xi24v1diqg8w406x
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 
3
 
Copyright (c) 2003, Arvid Norberg
4
 
All rights reserved.
5
 
 
6
 
Redistribution and use in source and binary forms, with or without
7
 
modification, are permitted provided that the following conditions
8
 
are met:
9
 
 
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.
18
 
 
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.
30
 
 
31
 
*/
32
 
 
33
 
#include "libtorrent/pch.hpp"
34
 
 
35
 
#include <string>
36
 
#include <stdexcept>
37
 
#include <sstream>
38
 
#include <iomanip>
39
 
#include <cctype>
40
 
#include <algorithm>
41
 
#include <iostream>
42
 
#include <limits>
43
 
#include <cstring>
44
 
 
45
 
#include <boost/optional.hpp>
46
 
#include <boost/array.hpp>
47
 
 
48
 
#include "libtorrent/assert.hpp"
49
 
#include "libtorrent/escape_string.hpp"
50
 
 
51
 
namespace libtorrent
52
 
{
53
 
 
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)
57
 
        {
58
 
                boost::array<char, 3 + std::numeric_limits<size_type>::digits10> ret;
59
 
                char *p = &ret.back();;
60
 
                *p = '\0';
61
 
                unsigned_size_type un = n;
62
 
                if (n < 0)  un = -un;
63
 
                do {
64
 
                        *--p = '0' + un % 10;
65
 
                        un /= 10;
66
 
                } while (un);
67
 
                if (n < 0) *--p = '-';
68
 
                std::memmove(&ret.front(), p, sizeof(ret.elems));
69
 
                return ret;
70
 
        }
71
 
 
72
 
        bool is_digit(char c)
73
 
        {
74
 
                return c >= '0' && c <= '9';
75
 
        }
76
 
 
77
 
        bool isprint(char c)
78
 
        {
79
 
                return c >= 32 && c < 127;
80
 
        }
81
 
 
82
 
        std::string unescape_string(std::string const& s)
83
 
        {
84
 
                std::string ret;
85
 
                for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
86
 
                {
87
 
                        if(*i == '+')
88
 
                        {
89
 
                                ret += ' ';
90
 
                        }
91
 
                        else if (*i != '%')
92
 
                        {
93
 
                                ret += *i;
94
 
                        }
95
 
                        else
96
 
                        {
97
 
                                ++i;
98
 
                                if (i == s.end())
99
 
#ifdef BOOST_NO_EXCEPTIONS
100
 
                                        return ret;
101
 
#else
102
 
                                        throw std::runtime_error("invalid escaped string");
103
 
#endif
104
 
 
105
 
                                int high;
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';
109
 
                                else
110
 
#ifdef BOOST_NO_EXCEPTIONS
111
 
                                        return ret;
112
 
#else
113
 
                                        throw std::runtime_error("invalid escaped string");
114
 
#endif
115
 
 
116
 
                                ++i;
117
 
                                if (i == s.end())
118
 
#ifdef BOOST_NO_EXCEPTIONS
119
 
                                        return ret;
120
 
#else
121
 
                                        throw std::runtime_error("invalid escaped string");
122
 
#endif
123
 
 
124
 
                                int low;
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';
128
 
                                else
129
 
#ifdef BOOST_NO_EXCEPTIONS
130
 
                                        return ret;
131
 
#else
132
 
                                        throw std::runtime_error("invalid escaped string");
133
 
#endif
134
 
 
135
 
                                ret += char(high * 16 + low);
136
 
                        }
137
 
                }
138
 
                return ret;
139
 
        }
140
 
 
141
 
        std::string escape_string(const char* str, int len)
142
 
        {
143
 
                TORRENT_ASSERT(str != 0);
144
 
                TORRENT_ASSERT(len >= 0);
145
 
                // http://www.ietf.org/rfc/rfc2396.txt
146
 
                // section 2.3
147
 
                // some trackers seems to require that ' is escaped
148
 
//              static const char unreserved_chars[] = "-_.!~*'()";
149
 
                static const char unreserved_chars[] = "-_.!~*()"
150
 
                        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
151
 
                        "0123456789";
152
 
 
153
 
                std::stringstream ret;
154
 
                ret << std::hex << std::setfill('0');
155
 
                for (int i = 0; i < len; ++i)
156
 
                {
157
 
                        if (std::count(
158
 
                                        unreserved_chars
159
 
                                        , unreserved_chars+sizeof(unreserved_chars)-1
160
 
                                        , *str))
161
 
                        {
162
 
                                ret << *str;
163
 
                        }
164
 
                        else
165
 
                        {
166
 
                                ret << '%'
167
 
                                        << std::setw(2)
168
 
                                        << (int)static_cast<unsigned char>(*str);
169
 
                        }
170
 
                        ++str;
171
 
                }
172
 
                return ret.str();
173
 
        }
174
 
        
175
 
        std::string escape_path(const char* str, int len)
176
 
        {
177
 
                TORRENT_ASSERT(str != 0);
178
 
                TORRENT_ASSERT(len >= 0);
179
 
                static const char unreserved_chars[] = "/-_.!~*()"
180
 
                        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
181
 
                        "0123456789";
182
 
 
183
 
                std::stringstream ret;
184
 
                ret << std::hex << std::setfill('0');
185
 
                for (int i = 0; i < len; ++i)
186
 
                {
187
 
                        if (std::count(
188
 
                                        unreserved_chars
189
 
                                        , unreserved_chars+sizeof(unreserved_chars)-1
190
 
                                        , *str))
191
 
                        {
192
 
                                ret << *str;
193
 
                        }
194
 
                        else
195
 
                        {
196
 
                                ret << '%'
197
 
                                        << std::setw(2)
198
 
                                        << (int)static_cast<unsigned char>(*str);
199
 
                        }
200
 
                        ++str;
201
 
                }
202
 
                return ret.str();
203
 
        }
204
 
 
205
 
        std::string base64encode(const std::string& s)
206
 
        {
207
 
                static const char base64_table[] =
208
 
                {
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', '+', '/'
217
 
                };
218
 
 
219
 
                unsigned char inbuf[3];
220
 
                unsigned char outbuf[4];
221
 
        
222
 
                std::string ret;
223
 
                for (std::string::const_iterator i = s.begin(); i != s.end();)
224
 
                {
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()));
228
 
 
229
 
                        // clear input buffer
230
 
                        std::fill(inbuf, inbuf+3, 0);
231
 
 
232
 
                        // read a chunk of input into inbuf
233
 
                        std::copy(i, i + available_input, inbuf);
234
 
                        i += available_input;
235
 
 
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;
241
 
 
242
 
                        // write output
243
 
                        for (int j = 0; j < available_input+1; ++j)
244
 
                        {
245
 
                                ret += base64_table[outbuf[j]];
246
 
                        }
247
 
 
248
 
                        // write pad
249
 
                        for (int j = 0; j < 3 - available_input; ++j)
250
 
                        {
251
 
                                ret += '=';
252
 
                        }
253
 
                }
254
 
                return ret;
255
 
        }
256
 
 
257
 
        std::string base32encode(std::string const& s)
258
 
        {
259
 
                static const char base32_table[] =
260
 
                {
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'
265
 
                };
266
 
 
267
 
                int input_output_mapping[] = {0, 2, 4, 5, 7, 8};
268
 
                
269
 
                unsigned char inbuf[5];
270
 
                unsigned char outbuf[8];
271
 
        
272
 
                std::string ret;
273
 
                for (std::string::const_iterator i = s.begin(); i != s.end();)
274
 
                {
275
 
                        int available_input = (std::min)(5, (int)std::distance(i, s.end()));
276
 
 
277
 
                        // clear input buffer
278
 
                        std::fill(inbuf, inbuf+5, 0);
279
 
 
280
 
                        // read a chunk of input into inbuf
281
 
                        std::copy(i, i + available_input, inbuf);
282
 
                        i += available_input;
283
 
 
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;
293
 
 
294
 
                        // write output
295
 
                        int num_out = input_output_mapping[available_input];
296
 
                        for (int j = 0; j < num_out; ++j)
297
 
                        {
298
 
                                ret += base32_table[outbuf[j]];
299
 
                        }
300
 
 
301
 
                        // write pad
302
 
                        for (int j = 0; j < 8 - num_out; ++j)
303
 
                        {
304
 
                                ret += '=';
305
 
                        }
306
 
                }
307
 
                return ret;
308
 
        }
309
 
 
310
 
        std::string base32decode(std::string const& s)
311
 
        {
312
 
                unsigned char inbuf[8];
313
 
                unsigned char outbuf[5];
314
 
        
315
 
                std::string ret;
316
 
                for (std::string::const_iterator i = s.begin(); i != s.end();)
317
 
                {
318
 
                        int available_input = (std::min)(8, (int)std::distance(i, s.end()));
319
 
 
320
 
                        int pad_start = 0;
321
 
                        if (available_input < 8) pad_start = available_input;
322
 
 
323
 
                        // clear input buffer
324
 
                        std::fill(inbuf, inbuf+8, 0);
325
 
                        for (int j = 0; j < available_input; ++j)
326
 
                        {
327
 
                                char in = std::toupper(*i++);
328
 
                                if (in >= 'A' && in <= 'Z')
329
 
                                        inbuf[j] = in - 'A';
330
 
                                else if (in >= '2' && in <= '7')
331
 
                                        inbuf[j] = in - '2' + ('Z' - 'A') + 1;
332
 
                                else if (in == '=')
333
 
                                {
334
 
                                        inbuf[j] = 0;
335
 
                                        if (pad_start == 0) pad_start = j;
336
 
                                }
337
 
                                else if (in == '1')
338
 
                                        inbuf[j] = 'I' - 'A';
339
 
                                else
340
 
                                        return std::string();
341
 
                                TORRENT_ASSERT(inbuf[j] == (inbuf[j] & 0x1f));
342
 
                        }
343
 
 
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];
357
 
 
358
 
                        int input_output_mapping[] = {5, 1, 1, 2, 2, 3, 4, 4, 5};
359
 
                        int num_out = input_output_mapping[pad_start];
360
 
 
361
 
                        // write output
362
 
                        std::copy(outbuf, outbuf + num_out, std::back_inserter(ret));
363
 
                }
364
 
                return ret;
365
 
        }
366
 
 
367
 
        boost::optional<std::string> url_has_argument(
368
 
                std::string const& url, std::string argument)
369
 
        {
370
 
                size_t i = url.find('?');
371
 
                if (i == std::string::npos) return boost::optional<std::string>();
372
 
                ++i;
373
 
 
374
 
                argument += '=';
375
 
 
376
 
                if (url.compare(i, argument.size(), argument) == 0)
377
 
                {
378
 
                        size_t pos = i + argument.size();
379
 
                        return url.substr(pos, url.find('&', pos) - pos);
380
 
                }
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);
386
 
        }
387
 
 
388
 
        TORRENT_EXPORT std::string to_hex(std::string const& s)
389
 
        {
390
 
                std::string ret;
391
 
                char const* digits = "0123456789abcdef";
392
 
                for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
393
 
                {
394
 
                        ret += digits[((unsigned char)*i) >> 4];
395
 
                        ret += digits[((unsigned char)*i) & 0xf];
396
 
                }
397
 
                return ret;
398
 
        }
399
 
 
400
 
}
401