UrlUtils.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <zypp/url/UrlUtils.h>
00013 
00014 #include <stdlib.h>   // strtol
00015 #include <cctype>     // isxdigit
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               // not a hex noted octet...
00102             break;
00103 
00104             case 0:
00105               // is a %00 octet allowed ?
00106               if( !allowNUL)
00107               {
00108                 ZYPP_THROW(UrlDecodingException(
00109                   "Encoded string contains a NUL byte"
00110                 ));
00111               }
00112             default:
00113               // other octets are fine...
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       //snprintf(out, sizeof(out), "%%%02X", c);
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   } // namespace url
00318 
00320 } // namespace zypp
00322 /*
00323 ** vim: set ts=2 sts=2 sw=2 ai et:
00324 */

Generated on Thu Jul 6 00:07:29 2006 for zypp by  doxygen 1.4.6