libzypp: zypp-core/url/UrlUtils.cc Source File

libzypp 17.38.7

UrlUtils.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include <zypp-core/base/Gettext.h>
13#include <zypp-core/base/String.h>
14#include <zypp-core/url/UrlUtils.h>
15
16#include <stdlib.h> // strtol
17#include <cctype> // isxdigit
18#include <stdexcept>
19
20
22namespace zypp
23{
24
26 namespace url
27 {
28
29
30 // ---------------------------------------------------------------
31 std::string
32 encode(const std::string &str, const std::string &safe,
33 EEncoding eflag)
34 {
35 std::string skip("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
36 "abcdefghijklmnopqrstuvwxyz"
37 "0123456789.~_-");
38 static const std::string more(URL_SAFE_CHARS); // ":/?#[]@!$&'()*+,;="
39 size_t beg = 0, len = 0;
40 std::string out;
41
42 for(size_t i=0; i<safe.size(); i++)
43 {
44 if( more.find(safe.at(i)) != std::string::npos)
45 skip.append(1, safe.at(i));
46 }
47
48 len = str.length();
49 beg = 0;
50 while( beg < len)
51 {
52 size_t pos = str.find_first_not_of(skip, beg);
53 if(pos != std::string::npos)
54 {
55 if( pos > beg)
56 {
57 out.append(str, beg, pos - beg);
58 }
59
60 if( eflag == E_ENCODED &&
61 pos + 2 < len &&
62 str.at(pos) == '%' &&
63 std::isxdigit(str.at(pos + 1)) &&
64 std::isxdigit(str.at(pos + 2)))
65 {
66 out.append(str, pos, 3);
67 beg = pos + 3;
68 }
69 else
70 {
71 out.append( encode_octet( str.at(pos)));
72 beg = pos + 1;
73 }
74 }
75 else
76 {
77 out.append(str, beg, len - beg);
78 beg = len;
79 }
80 }
81 return out;
82 }
83
84
85 // ---------------------------------------------------------------
86 std::string
87 decode(const std::string &str, bool allowNUL)
88 {
89 size_t pos = 0, end = 0, len = 0;
90 std::string out(str);
91
92 len = out.length();
93 pos = end = 0;
94 while(pos < len)
95 {
96 out[end] = out[pos];
97 if( pos + 2 < len && out.at(pos) == '%')
98 {
99 int c = decode_octet(out.c_str() + pos + 1);
100 switch(c)
101 {
102 case -1:
103 // not a hex noted octet...
104 break;
105
106 case 0:
107 // is a %00 octet allowed ?
108 if( !allowNUL)
109 {
110 ZYPP_THROW(UrlDecodingException(
111 _("Encoded string contains a NUL byte")
112 ));
113 }
114 default:
115 // other octets are fine...
116 out[end] = c;
117 pos += 2;
118 break;
119 }
120 }
121 pos++;
122 end++;
123 }
124 if( end < pos)
125 out.erase(end);
126 return out;
127 }
128
129
130 // ---------------------------------------------------------------
131 std::string
132 encode_octet(const unsigned char c)
133 {
134 static const char tab[] = "0123456789ABCDEF";
135 char out[4];
136
137 out[0] = '%';
138 out[1] = tab[0x0f & (c >> 4)];
139 out[2] = tab[0x0f & c];
140 out[3] = '\0';
141
142 return std::string(out);
143 }
144
145
146 // ---------------------------------------------------------------
147 int
148 decode_octet(const char *hex)
149 {
150 if(hex && std::isxdigit(hex[0]) && std::isxdigit(hex[1]))
151 {
152 char x[3] = { hex[0], hex[1], '\0'};
153 return 0xff & ::strtol(x, NULL, 16);
154 }
155 else
156 {
157 return -1;
158 }
159 }
160
161
162 // ---------------------------------------------------------------
163 void
164 split(ParamVec &pvec,
165 const std::string &pstr,
166 const std::string &psep)
167 {
168 size_t beg = 0, len = 0;
169 if( psep.empty())
170 {
171 ZYPP_THROW(UrlNotSupportedException(
172 _("Invalid parameter array split separator character")
173 ));
174 }
175
176 len = pstr.length();
177 beg = 0;
178
179 while( beg < len)
180 {
181 size_t pos = pstr.find(psep, beg);
182 if(pos != std::string::npos)
183 {
184 pvec.push_back( pstr.substr(beg, pos - beg));
185 beg = pos + 1;
186 }
187 else
188 {
189 pvec.push_back( pstr.substr(beg, len - beg));
190 beg = len;
191 }
192 }
193 }
194
195
196 // ---------------------------------------------------------------
197 void
198 split(ParamMap &pmap,
199 const std::string &str,
200 const std::string &psep,
201 const std::string &vsep,
202 EEncoding eflag)
203 {
204 ParamVec pvec;
205 ParamVec::const_iterator pitr;
206 std::string k, v;
207
208 if( psep.empty() || vsep.empty())
209 {
210 ZYPP_THROW(UrlNotSupportedException(
211 _("Invalid parameter map split separator character")
212 ));
213 }
214
215 split(pvec, str, psep);
216
217 for( pitr = pvec.begin(); pitr != pvec.end(); ++pitr)
218 {
219 size_t pos = pitr->find(vsep);
220 if(pos != std::string::npos)
221 {
222 if( eflag == E_DECODED)
223 {
224 k = url::decode(pitr->substr(0, pos));
225 v = url::decode(pitr->substr(pos + 1));
226 pmap[ k ] = v;
227 }
228 else
229 {
230 k = pitr->substr(0, pos);
231 v = pitr->substr(pos + 1);
232 pmap[ k ] = v;
233 }
234 }
235 else
236 {
237 if( eflag == E_DECODED)
238 {
239 pmap[ url::decode(*pitr) ] = "";
240 }
241 else
242 {
243 pmap[ *pitr ] = "";
244 }
245 }
246 }
247 }
248
249
250 // ---------------------------------------------------------------
251 std::string
252 join(const ParamVec &pvec,
253 const std::string &psep)
254 {
255 std::string str;
256 ParamVec::const_iterator i( pvec.begin());
257
258 if( i != pvec.end())
259 {
260 str = *i;
261 while( ++i != pvec.end())
262 {
263 str += psep + *i;
264 }
265 }
266
267 return str;
268 }
269
270
271 // ---------------------------------------------------------------
272 std::string
273 join(const ParamMap &pmap,
274 const std::string &psep,
275 const std::string &vsep,
276 const std::string &safe,
277 EEncoding eflag)
278 {
279 if( psep.empty() || vsep.empty())
280 {
281 ZYPP_THROW(UrlNotSupportedException(
282 _("Invalid parameter array join separator character")
283 ));
284 }
285
286 std::string str;
287
288 if ( eflag == E_DECODED )
289 {
290 std::string safeKey;
291 std::string safeVal;
292
293 for(std::string::size_type i=0; i<safe.size(); i++)
294 {
295 if( psep.find(safe[i]) == std::string::npos ) {
296 if ( vsep.find(safe[i]) == std::string::npos ) {
297 safeKey.append(1, safe[i]);
298 safeVal.append(1, safe[i]);
299 } else {
300 safeVal.append(1, safe[i]);
301 }
302 }
303 }
304
305 ParamMap::const_iterator i( pmap.begin());
306
307 if( i != pmap.end())
308 {
309 str = encode(i->first, safeKey);
310 if( !i->second.empty())
311 str += vsep + encode(i->second, safeVal);
312
313 while( ++i != pmap.end())
314 {
315 str += psep + encode(i->first, safeKey);
316 if( !i->second.empty())
317 str += vsep + encode(i->second, safeVal);
318 }
319 }
320 }
321 else
322 {
323 for ( const auto & [k,v] : pmap ) {
324 if ( not str.empty() )
325 str += psep;
326 str += k;
327 if ( not v.empty() ) {
328 str += vsep;
329 str += v;
330 }
331 }
332 }
333
334 return str;
335 }
336
337
339 } // namespace url
341
343} // namespace zypp
345/*
346** vim: set ts=2 sts=2 sw=2 ai et:
347*/
ZYPP_THROW
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
Gettext.h
_
#define _(MSG)
Definition Gettext.h:39
String.h
UrlUtils.h
URL_SAFE_CHARS
#define URL_SAFE_CHARS
Characters that are safe for URL without percent-encoding.
Definition UrlUtils.h:22
zypp::url::UrlDecodingException
Thrown if the encoded string contains a NUL byte (%00).
Definition UrlException.h:50
zypp::url::UrlNotSupportedException
Thrown if a feature e.g.
Definition UrlException.h:125
str
String related utilities and Regular expression matching.
zypp::url
Url details namespace.
Definition UrlBase.cc:58
zypp::url::encode
std::string encode(const std::string &str, const std::string &safe, EEncoding eflag)
Encodes a string using URL percent encoding.
Definition UrlUtils.cc:32
zypp::url::decode_octet
int decode_octet(const char *hex)
Decode one character.
Definition UrlUtils.cc:148
zypp::url::ParamVec
std::vector< std::string > ParamVec
A parameter vector container.
Definition UrlUtils.h:40
zypp::url::encode_octet
std::string encode_octet(const unsigned char c)
Encode one character.
Definition UrlUtils.cc:132
zypp::url::split
void split(ParamVec &pvec, const std::string &pstr, const std::string &psep)
Split into a parameter vector.
Definition UrlUtils.cc:164
zypp::url::join
std::string join(const ParamVec &pvec, const std::string &psep)
Join parameter vector to a string.
Definition UrlUtils.cc:252
zypp::url::ParamMap
std::map< std::string, std::string > ParamMap
A parameter map container.
Definition UrlUtils.h:47
zypp::url::EEncoding
EEncoding
Encoding flags.
Definition UrlUtils.h:52
zypp::url::E_DECODED
@ E_DECODED
Flag to request decoded string(s).
Definition UrlUtils.h:54
zypp::url::E_ENCODED
@ E_ENCODED
Flag to request encoded string(s).
Definition UrlUtils.h:53
zypp::url::decode
std::string decode(const std::string &str, bool allowNUL)
Decodes a URL percent encoded string.
Definition UrlUtils.cc:87
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition CodePitfalls.doc:2