Botan  1.11.15
src/lib/utils/parsing.cpp
Go to the documentation of this file.
00001 /*
00002 * Various string utils and parsing functions
00003 * (C) 1999-2007,2013,2014 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/parsing.h>
00009 #include <botan/exceptn.h>
00010 #include <botan/charset.h>
00011 #include <botan/get_byte.h>
00012 #include <set>
00013 #include <stdexcept>
00014 
00015 namespace Botan {
00016 
00017 u32bit to_u32bit(const std::string& str)
00018    {
00019    try
00020       {
00021       return std::stoul(str, nullptr);
00022       }
00023    catch(std::exception&)
00024       {
00025       throw std::runtime_error("Could not read '" + str + "' as decimal string");
00026       }
00027    }
00028 
00029 /*
00030 * Convert a string into a time duration
00031 */
00032 u32bit timespec_to_u32bit(const std::string& timespec)
00033    {
00034    if(timespec == "")
00035       return 0;
00036 
00037    const char suffix = timespec[timespec.size()-1];
00038    std::string value = timespec.substr(0, timespec.size()-1);
00039 
00040    u32bit scale = 1;
00041 
00042    if(Charset::is_digit(suffix))
00043       value += suffix;
00044    else if(suffix == 's')
00045       scale = 1;
00046    else if(suffix == 'm')
00047       scale = 60;
00048    else if(suffix == 'h')
00049       scale = 60 * 60;
00050    else if(suffix == 'd')
00051       scale = 24 * 60 * 60;
00052    else if(suffix == 'y')
00053       scale = 365 * 24 * 60 * 60;
00054    else
00055       throw Decoding_Error("timespec_to_u32bit: Bad input " + timespec);
00056 
00057    return scale * to_u32bit(value);
00058    }
00059 
00060 /*
00061 * Parse a SCAN-style algorithm name
00062 */
00063 std::vector<std::string> parse_algorithm_name(const std::string& namex)
00064    {
00065    if(namex.find('(') == std::string::npos &&
00066       namex.find(')') == std::string::npos)
00067       return std::vector<std::string>(1, namex);
00068 
00069    std::string name = namex, substring;
00070    std::vector<std::string> elems;
00071    size_t level = 0;
00072 
00073    elems.push_back(name.substr(0, name.find('(')));
00074    name = name.substr(name.find('('));
00075 
00076    for(auto i = name.begin(); i != name.end(); ++i)
00077       {
00078       char c = *i;
00079 
00080       if(c == '(')
00081          ++level;
00082       if(c == ')')
00083          {
00084          if(level == 1 && i == name.end() - 1)
00085             {
00086             if(elems.size() == 1)
00087                elems.push_back(substring.substr(1));
00088             else
00089                elems.push_back(substring);
00090             return elems;
00091             }
00092 
00093          if(level == 0 || (level == 1 && i != name.end() - 1))
00094             throw Invalid_Algorithm_Name(namex);
00095          --level;
00096          }
00097 
00098       if(c == ',' && level == 1)
00099          {
00100          if(elems.size() == 1)
00101             elems.push_back(substring.substr(1));
00102          else
00103             elems.push_back(substring);
00104          substring.clear();
00105          }
00106       else
00107          substring += c;
00108       }
00109 
00110    if(substring != "")
00111       throw Invalid_Algorithm_Name(namex);
00112 
00113    return elems;
00114    }
00115 
00116 std::vector<std::string> split_on(const std::string& str, char delim)
00117    {
00118    return split_on_pred(str, [delim](char c) { return c == delim; });
00119    }
00120 
00121 std::vector<std::string> split_on_pred(const std::string& str,
00122                                        std::function<bool (char)> pred)
00123    {
00124    std::vector<std::string> elems;
00125    if(str == "") return elems;
00126 
00127    std::string substr;
00128    for(auto i = str.begin(); i != str.end(); ++i)
00129       {
00130       if(pred(*i))
00131          {
00132          if(substr != "")
00133             elems.push_back(substr);
00134          substr.clear();
00135          }
00136       else
00137          substr += *i;
00138       }
00139 
00140    if(substr == "")
00141       throw Invalid_Argument("Unable to split string: " + str);
00142    elems.push_back(substr);
00143 
00144    return elems;
00145    }
00146 
00147 /*
00148 * Join a string
00149 */
00150 std::string string_join(const std::vector<std::string>& strs, char delim)
00151    {
00152    std::string out = "";
00153 
00154    for(size_t i = 0; i != strs.size(); ++i)
00155       {
00156       if(i != 0)
00157          out += delim;
00158       out += strs[i];
00159       }
00160 
00161    return out;
00162    }
00163 
00164 /*
00165 * Parse an ASN.1 OID string
00166 */
00167 std::vector<u32bit> parse_asn1_oid(const std::string& oid)
00168    {
00169    std::string substring;
00170    std::vector<u32bit> oid_elems;
00171 
00172    for(auto i = oid.begin(); i != oid.end(); ++i)
00173       {
00174       char c = *i;
00175 
00176       if(c == '.')
00177          {
00178          if(substring == "")
00179             throw Invalid_OID(oid);
00180          oid_elems.push_back(to_u32bit(substring));
00181          substring.clear();
00182          }
00183       else
00184          substring += c;
00185       }
00186 
00187    if(substring == "")
00188       throw Invalid_OID(oid);
00189    oid_elems.push_back(to_u32bit(substring));
00190 
00191    if(oid_elems.size() < 2)
00192       throw Invalid_OID(oid);
00193 
00194    return oid_elems;
00195    }
00196 
00197 /*
00198 * X.500 String Comparison
00199 */
00200 bool x500_name_cmp(const std::string& name1, const std::string& name2)
00201    {
00202    auto p1 = name1.begin();
00203    auto p2 = name2.begin();
00204 
00205    while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
00206    while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
00207 
00208    while(p1 != name1.end() && p2 != name2.end())
00209       {
00210       if(Charset::is_space(*p1))
00211          {
00212          if(!Charset::is_space(*p2))
00213             return false;
00214 
00215          while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
00216          while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
00217 
00218          if(p1 == name1.end() && p2 == name2.end())
00219             return true;
00220          }
00221 
00222       if(!Charset::caseless_cmp(*p1, *p2))
00223          return false;
00224       ++p1;
00225       ++p2;
00226       }
00227 
00228    while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
00229    while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
00230 
00231    if((p1 != name1.end()) || (p2 != name2.end()))
00232       return false;
00233    return true;
00234    }
00235 
00236 /*
00237 * Convert a decimal-dotted string to binary IP
00238 */
00239 u32bit string_to_ipv4(const std::string& str)
00240    {
00241    std::vector<std::string> parts = split_on(str, '.');
00242 
00243    if(parts.size() != 4)
00244       throw Decoding_Error("Invalid IP string " + str);
00245 
00246    u32bit ip = 0;
00247 
00248    for(auto part = parts.begin(); part != parts.end(); ++part)
00249       {
00250       u32bit octet = to_u32bit(*part);
00251 
00252       if(octet > 255)
00253          throw Decoding_Error("Invalid IP string " + str);
00254 
00255       ip = (ip << 8) | (octet & 0xFF);
00256       }
00257 
00258    return ip;
00259    }
00260 
00261 /*
00262 * Convert an IP address to decimal-dotted string
00263 */
00264 std::string ipv4_to_string(u32bit ip)
00265    {
00266    std::string str;
00267 
00268    for(size_t i = 0; i != sizeof(ip); ++i)
00269       {
00270       if(i)
00271          str += ".";
00272       str += std::to_string(get_byte(i, ip));
00273       }
00274 
00275    return str;
00276    }
00277 
00278 std::string erase_chars(const std::string& str, const std::set<char>& chars)
00279    {
00280    std::string out;
00281 
00282    for(auto c: str)
00283       if(chars.count(c) == 0)
00284          out += c;
00285 
00286    return out;
00287    }
00288 
00289 std::string replace_chars(const std::string& str,
00290                           const std::set<char>& chars,
00291                           char to_char)
00292    {
00293    std::string out = str;
00294 
00295    for(size_t i = 0; i != out.size(); ++i)
00296       if(chars.count(out[i]))
00297          out[i] = to_char;
00298 
00299    return out;
00300    }
00301 
00302 std::string replace_char(const std::string& str, char from_char, char to_char)
00303    {
00304    std::string out = str;
00305 
00306    for(size_t i = 0; i != out.size(); ++i)
00307       if(out[i] == from_char)
00308          out[i] = to_char;
00309 
00310    return out;
00311    }
00312 
00313 }