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