#include "string.h" #include using namespace std; namespace ept { namespace str { std::string basename(const std::string& pathname) { size_t pos = pathname.rfind("/"); if (pos == std::string::npos) return pathname; else return pathname.substr(pos+1); } std::string dirname(const std::string& pathname) { if (pathname.empty()) return "."; // Skip trailing separators size_t end = pathname.size(); while (end > 0 && pathname[end - 1] == '/') --end; // If the result is empty again, then the string was only / characters if (!end) return "/"; // Find the previous separator end = pathname.rfind("/", end - 1); if (end == std::string::npos) // No previous separator found, everything should be chopped return std::string("."); else { while (end > 0 && pathname[end - 1] == '/') --end; if (!end) return "/"; return pathname.substr(0, end); } } void appendpath(std::string& dest, const char* path2) { if (!*path2) return; if (dest.empty()) { dest = path2; return; } if (dest[dest.size() - 1] == '/') if (path2[0] == '/') dest += (path2 + 1); else dest += path2; else if (path2[0] == '/') dest += path2; else { dest += '/'; dest += path2; } } void appendpath(std::string& dest, const std::string& path2) { if (path2.empty()) return; if (dest.empty()) { dest = path2; return; } if (dest[dest.size() - 1] == '/') if (path2[0] == '/') dest += path2.substr(1); else dest += path2; else if (path2[0] == '/') dest += path2; else { dest += '/'; dest += path2; } } std::string joinpath(const std::string& path1, const std::string& path2) { string res = path1; appendpath(res, path2); return res; } std::string normpath(const std::string& pathname) { vector st; if (pathname[0] == '/') st.push_back("/"); Split split(pathname, "/"); for (const auto& i: split) { if (i == "." || i.empty()) continue; if (i == "..") if (st.back() == "..") st.emplace_back(i); else if (st.back() == "/") continue; else st.pop_back(); else st.emplace_back(i); } if (st.empty()) return "."; string res; for (const auto& i: st) appendpath(res, i); return res; } Split::const_iterator::const_iterator(const Split& split) : split(&split) { // Ignore leading separators if skip_end is true if (split.skip_empty) skip_separators(); ++*this; } Split::const_iterator::~const_iterator() { } std::string Split::const_iterator::remainder() const { if (end == std::string::npos) return std::string(); else return split->str.substr(end); }; void Split::const_iterator::skip_separators() { const std::string& str = split->str; const std::string& sep = split->sep; while (end + sep.size() <= str.size()) { unsigned i = 0; for ( ; i < sep.size(); ++i) if (str[end + i] != sep[i]) break; if (i < sep.size()) break; else end += sep.size(); } } Split::const_iterator& Split::const_iterator::operator++() { if (!split) return *this; const std::string& str = split->str; const std::string& sep = split->sep; bool skip_empty = split->skip_empty; /// Convert into an end iterator if (end == std::string::npos) { split = nullptr; return *this; } /// The string ended with an iterator, and we do not skip empty tokens: /// return it if (end == str.size()) { cur = string(); end = std::string::npos; return *this; } /// Position of the first character past the token that starts at 'end' size_t tok_end; if (sep.empty()) /// If separator is empty, advance one character at a time tok_end = end + 1; else { /// The token ends at the next separator tok_end = str.find(sep, end); } /// No more separators found, return from end to the end of the string if (tok_end == std::string::npos) { cur = str.substr(end); end = std::string::npos; return *this; } /// We have the boundaries of the current token cur = str.substr(end, tok_end - end); /// Skip the separator end = tok_end + sep.size(); /// Skip all the following separators if skip_empty is true if (skip_empty) { skip_separators(); if (end == str.size()) { end = std::string::npos; return *this; } } return *this; } const std::string& Split::const_iterator::operator*() const { return cur; } const std::string* Split::const_iterator::operator->() const { return &cur; } bool Split::const_iterator::operator==(const const_iterator& ti) const { if (!split && !ti.split) return true; if (split != ti.split) return false; return end == ti.end; } bool Split::const_iterator::operator!=(const const_iterator& ti) const { if (!split && !ti.split) return false; if (split != ti.split) return true; return end != ti.end; } std::string encode_cstring(const std::string& str) { string res; for (string::const_iterator i = str.begin(); i != str.end(); ++i) if (*i == '\n') res += "\\n"; else if (*i == '\t') res += "\\t"; else if (*i == 0 || iscntrl(*i)) { char buf[5]; snprintf(buf, 5, "\\x%02x", (unsigned int)*i); res += buf; } else if (*i == '"' || *i == '\\') { res += "\\"; res += *i; } else res += *i; return res; } std::string decode_cstring(const std::string& str, size_t& lenParsed) { string res; string::const_iterator i = str.begin(); for ( ; i != str.end() && *i != '"'; ++i) if (*i == '\\' && (i+1) != str.end()) { switch (*(i+1)) { case 'n': res += '\n'; break; case 't': res += '\t'; break; case 'x': { size_t j; char buf[5] = "0x\0\0"; // Read up to 2 extra hex digits for (j = 0; j < 2 && i+2+j != str.end() && isxdigit(*(i+2+j)); ++j) buf[2+j] = *(i+2+j); i += j; res += (char)atoi(buf); break; } default: res += *(i+1); break; } ++i; } else res += *i; if (i != str.end() && *i == '"') ++i; lenParsed = i - str.begin(); return res; } std::string encode_url(const std::string& str) { string res; for (string::const_iterator i = str.begin(); i != str.end(); ++i) { if ( (*i >= '0' && *i <= '9') || (*i >= 'A' && *i <= 'Z') || (*i >= 'a' && *i <= 'z') || *i == '-' || *i == '_' || *i == '!' || *i == '*' || *i == '\'' || *i == '(' || *i == ')') res += *i; else { char buf[4]; snprintf(buf, 4, "%%%02x", static_cast(static_cast(*i))); res += buf; } } return res; } std::string decode_url(const std::string& str) { string res; for (size_t i = 0; i < str.size(); ++i) { if (str[i] == '%') { // If there's a partial %something at the end, ignore it if (i >= str.size() - 2) return res; res += static_cast(strtoul(str.substr(i+1, 2).c_str(), 0, 16)); i += 2; } else res += str[i]; } return res; } static const char* base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; template static const char invbase64(const T& idx) { static const char data[] = {62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; if (idx < 43) return 0; if (static_cast(idx) > 43 + (sizeof(data)/sizeof(data[0]))) return 0; return data[idx - 43]; } std::string encode_base64(const std::string& str) { std::string res; for (size_t i = 0; i < str.size(); i += 3) { // Pack every triplet into 24 bits unsigned int enc; if (i + 3 < str.size()) enc = ((unsigned char)str[i] << 16) | ((unsigned char)str[i + 1] << 8) | (unsigned char)str[i + 2]; else { enc = ((unsigned char)str[i] << 16); if (i + 1 < str.size()) enc |= (unsigned char)str[i + 1] << 8; if (i + 2 < str.size()) enc |= (unsigned char)str[i + 2]; } // Divide in 4 6-bit values and use them as indexes in the base64 char // array for (int j = 18; j >= 0; j -= 6) res += base64[(enc >> j) & 63]; } // Replace padding characters with '=' if (str.size() % 3) for (size_t i = 0; i < 3 - (str.size() % 3); ++i) res[res.size() - i - 1] = '='; return res; } std::string decode_base64(const std::string& str) { std::string res; for (size_t i = 0; i < str.size(); i += 4) { // Pack every quadruplet into 24 bits unsigned int enc; if (i+4 < str.size()) { enc = (invbase64(str[i]) << 18) + (invbase64(str[i+1]) << 12) + (invbase64(str[i+2]) << 6) + (invbase64(str[i+3])); } else { enc = (invbase64(str[i]) << 18); if (i+1 < str.size()) enc += (invbase64(str[i+1]) << 12); if (i+2 < str.size()) enc += (invbase64(str[i+2]) << 6); if (i+3 < str.size()) enc += (invbase64(str[i+3])); } // Divide in 3 8-bit values and append them to the result res += enc >> 16 & 0xff; res += enc >> 8 & 0xff; res += enc & 0xff; } // Remove trailing padding if (str.size() > 0) for (size_t i = str.size() - 1; str[i] == '='; --i) { if (res.size() > 0) res.resize(res.size() - 1); if (i == 0 || res.size() == 0 ) break; } return res; } } }