00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <zypp/url/UrlUtils.h>
00013
00014 #include <stdlib.h>
00015 #include <cctype>
00016 #include <stdexcept>
00017
00018
00020 namespace zypp
00021 {
00022
00024 namespace url
00025 {
00026
00027
00028
00029 std::string
00030 encode(const std::string &str, const std::string &safe,
00031 EEncoding eflag)
00032 {
00033 std::string skip("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00034 "abcdefghijklmnopqrstuvwxyz"
00035 "0123456789.~_-");
00036 std::string more(":/?#[]@!$&'()*+,;=");
00037 size_t beg, pos, len;
00038 std::string out;
00039
00040 for(size_t i=0; i<safe.size(); i++)
00041 {
00042 if( more.find(safe.at(i)) != std::string::npos)
00043 skip.append(1, safe.at(i));
00044 }
00045
00046 len = str.length();
00047 beg = 0;
00048 while( beg < len)
00049 {
00050 pos = str.find_first_not_of(skip, beg);
00051 if(pos != std::string::npos)
00052 {
00053 if( pos > beg)
00054 {
00055 out.append(str, beg, pos - beg);
00056 }
00057
00058 if( eflag == E_ENCODED &&
00059 pos + 2 < len &&
00060 str.at(pos) == '%' &&
00061 std::isxdigit(str.at(pos + 1)) &&
00062 std::isxdigit(str.at(pos + 2)))
00063 {
00064 out.append(str, pos, 3);
00065 beg = pos + 3;
00066 }
00067 else
00068 {
00069 out.append( encode_octet( str.at(pos)));
00070 beg = pos + 1;
00071 }
00072 }
00073 else
00074 {
00075 out.append(str, beg, len - beg);
00076 beg = len;
00077 }
00078 }
00079 return out;
00080 }
00081
00082
00083
00084 std::string
00085 decode(const std::string &str, bool allowNUL)
00086 {
00087 size_t pos, end, len;
00088 std::string out(str);
00089
00090 len = out.length();
00091 pos = end = 0;
00092 while(pos < len)
00093 {
00094 out[end] = out[pos];
00095 if( pos + 2 < len && out.at(pos) == '%')
00096 {
00097 int c = decode_octet(out.c_str() + pos + 1);
00098 switch(c)
00099 {
00100 case -1:
00101
00102 break;
00103
00104 case 0:
00105
00106 if( !allowNUL)
00107 {
00108 ZYPP_THROW(UrlDecodingException(
00109 "Encoded string contains a NUL byte"
00110 ));
00111 }
00112 default:
00113
00114 out[end] = c;
00115 pos += 2;
00116 break;
00117 }
00118 }
00119 pos++;
00120 end++;
00121 }
00122 if( end < pos)
00123 out.erase(end);
00124 return out;
00125 }
00126
00127
00128
00129 std::string
00130 encode_octet(const unsigned char c)
00131 {
00132 static const unsigned char tab[] = "0123456789ABCDEF";
00133 unsigned char out[4];
00134
00135 out[0] = '%';
00136 out[1] = tab[0x0f & (c >> 4)];
00137 out[2] = tab[0x0f & c];
00138 out[3] = '\0';
00139
00140
00141 return std::string((char *)out);
00142 }
00143
00144
00145
00146 int
00147 decode_octet(const char *hex)
00148 {
00149 if(hex && std::isxdigit(hex[0]) && std::isxdigit(hex[1]))
00150 {
00151 char x[3] = { hex[0], hex[1], '\0'};
00152 return 0xff & ::strtol(x, NULL, 16);
00153 }
00154 else
00155 {
00156 return -1;
00157 }
00158 }
00159
00160
00161
00162 void
00163 split(ParamVec &pvec,
00164 const std::string &pstr,
00165 const std::string &psep)
00166 {
00167 size_t beg, pos, len;
00168 if( psep.empty())
00169 {
00170 ZYPP_THROW(UrlNotSupportedException(
00171 "Invalid split separator character."
00172 ));
00173 }
00174
00175 len = pstr.length();
00176 beg = 0;
00177
00178 while( beg < len)
00179 {
00180 pos = pstr.find(psep, beg);
00181 if(pos != std::string::npos)
00182 {
00183 pvec.push_back( pstr.substr(beg, pos - beg));
00184 beg = pos + 1;
00185 }
00186 else
00187 {
00188 pvec.push_back( pstr.substr(beg, len - beg));
00189 beg = len;
00190 }
00191 }
00192 }
00193
00194
00195
00196 void
00197 split(ParamMap &pmap,
00198 const std::string &str,
00199 const std::string &psep,
00200 const std::string &vsep,
00201 EEncoding eflag)
00202 {
00203 ParamVec pvec;
00204 ParamVec::const_iterator pitr;
00205 std::string k, v;
00206 size_t pos;
00207
00208 if( psep.empty() || vsep.empty())
00209 {
00210 ZYPP_THROW(UrlNotSupportedException(
00211 "Invalid split separator character."
00212 ));
00213 }
00214
00215 split(pvec, str, psep);
00216
00217 for( pitr = pvec.begin(); pitr != pvec.end(); ++pitr)
00218 {
00219 pos = pitr->find(vsep);
00220 if(pos != std::string::npos)
00221 {
00222 if( eflag == E_DECODED)
00223 {
00224 k = url::decode(pitr->substr(0, pos));
00225 v = url::decode(pitr->substr(pos + 1));
00226 pmap[ k ] = v;
00227 }
00228 else
00229 {
00230 k = pitr->substr(0, pos);
00231 v = pitr->substr(pos + 1);
00232 pmap[ k ] = v;
00233 }
00234 }
00235 else
00236 {
00237 if( eflag == E_DECODED)
00238 {
00239 pmap[ url::decode(*pitr) ] = "";
00240 }
00241 else
00242 {
00243 pmap[ *pitr ] = "";
00244 }
00245 }
00246 }
00247 }
00248
00249
00250
00251 std::string
00252 join(const ParamVec &pvec,
00253 const std::string &psep)
00254 {
00255 std::string str;
00256 ParamVec::const_iterator i( pvec.begin());
00257
00258 if( i != pvec.end())
00259 {
00260 str = *i;
00261 while( ++i != pvec.end())
00262 {
00263 str += psep + *i;
00264 }
00265 }
00266
00267 return str;
00268 }
00269
00270
00271
00272 std::string
00273 join(const ParamMap &pmap,
00274 const std::string &psep,
00275 const std::string &vsep,
00276 const std::string &safe)
00277 {
00278 if( psep.empty() || vsep.empty())
00279 {
00280 ZYPP_THROW(UrlNotSupportedException(
00281 "Invalid join separator character."
00282 ));
00283 }
00284
00285 std::string join_safe;
00286 for(std::string::size_type i=0; i<safe.size(); i++)
00287 {
00288 if( psep.find(safe[i]) == std::string::npos &&
00289 vsep.find(safe[i]) == std::string::npos)
00290 {
00291 join_safe.append(1, safe[i]);
00292 }
00293 }
00294 std::string str;
00295 ParamMap::const_iterator i( pmap.begin());
00296
00297 if( i != pmap.end())
00298 {
00299 str = encode(i->first, join_safe);
00300 if( !i->second.empty())
00301 str += vsep + encode(i->second, join_safe);
00302
00303 while( ++i != pmap.end())
00304 {
00305 str += psep + encode(i->first, join_safe);
00306 if( !i->second.empty())
00307 str += vsep + encode(i->second, join_safe);
00308 }
00309 }
00310
00311 return str;
00312 }
00313
00314
00316 }
00318
00320 }
00322
00323
00324