libzypp  10.5.0
UrlUtils.cc
Go to the documentation of this file.
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 */