libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 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> // strtol 00017 #include <cctype> // isxdigit 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 // not a hex noted octet... 00104 break; 00105 00106 case 0: 00107 // is a %00 octet allowed ? 00108 if( !allowNUL) 00109 { 00110 ZYPP_THROW(UrlDecodingException( 00111 _("Encoded string contains a NUL byte") 00112 )); 00113 } 00114 default: 00115 // other octets are fine... 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 //snprintf(out, sizeof(out), "%%%02X", c); 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 } // namespace url 00320 00322 } // namespace zypp 00324 /* 00325 ** vim: set ts=2 sts=2 sw=2 ai et: 00326 */