]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "url_escape.h" | |
5 | ||
6 | #include <stdexcept> | |
7 | #include <sstream> | |
8 | ||
9 | std::string url_escape(const std::string& s) | |
10 | { | |
11 | std::string out; | |
12 | for (auto c : s) { | |
13 | if (std::isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~' || | |
14 | c == '/') { | |
15 | out.push_back(c); | |
16 | } else { | |
17 | char t[4]; | |
18 | snprintf(t, sizeof(t), "%%%02x", (int)(unsigned char)c); | |
19 | out.append(t); | |
20 | } | |
21 | } | |
22 | return out; | |
23 | } | |
24 | ||
25 | std::string url_unescape(const std::string& s) | |
26 | { | |
27 | std::string out; | |
28 | const char *end = s.c_str() + s.size(); | |
29 | for (const char *c = s.c_str(); c < end; ++c) { | |
30 | switch (*c) { | |
31 | case '%': | |
32 | { | |
33 | unsigned char v = 0; | |
34 | for (unsigned i=0; i<2; ++i) { | |
35 | ++c; | |
36 | if (c >= end) { | |
37 | std::ostringstream ss; | |
38 | ss << "invalid escaped string at pos " << (c - s.c_str()) << " of '" | |
39 | << s << "'"; | |
40 | throw std::runtime_error(ss.str()); | |
41 | } | |
42 | v <<= 4; | |
43 | if (*c >= '0' && *c <= '9') { | |
44 | v += *c - '0'; | |
45 | } else if (*c >= 'a' && *c <= 'f') { | |
46 | v += *c - 'a' + 10; | |
47 | } else if (*c >= 'A' && *c <= 'F') { | |
48 | v += *c - 'A' + 10; | |
49 | } else { | |
50 | std::ostringstream ss; | |
51 | ss << "invalid escaped string at pos " << (c - s.c_str()) << " of '" | |
52 | << s << "'"; | |
53 | throw std::runtime_error(ss.str()); | |
54 | } | |
55 | } | |
56 | out.push_back(v); | |
57 | } | |
58 | break; | |
59 | default: | |
60 | out.push_back(*c); | |
61 | } | |
62 | } | |
63 | return out; | |
64 | } |