#include "string_utils.h" //#include "../../include/petscii.h" #include "../../include/debug.h" #include "U8Char.h" #include #include #include #include #include #include // Copy string to char buffer void copyString(const std::string& input, char *dst, size_t dst_size) { strncpy(dst, input.c_str(), dst_size - 1); dst[dst_size - 1] = '\0'; } constexpr unsigned int hash(const char *s, int off = 0) { return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off]; } namespace mstr { // trim from start (in place) void ltrim(std::string &s) { s.erase( s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); } // trim from end (in place) void rtrim(std::string &s) { s.erase( std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } void rtrimA0(std::string &s) { s.erase( std::find_if(s.rbegin(), s.rend(), [](int ch) { return !isA0Space(ch); }).base(), s.end()); } // trim from both ends (in place) void trim(std::string &s) { ltrim(s); rtrim(s); } // is space or petscii shifted space bool isA0Space(int ch) { return ch == '\xA0' || std::isspace(ch); } std::string drop(std::string str, size_t count) { if(count>str.length()) return ""; else return str.substr(count); } std::string dropLast(std::string str, size_t count) { if(count>str.length()) return ""; else return str.substr(0, str.length()-count); } bool startsWith(std::string s, const char *pattern, bool case_sensitive) { if (s.empty() && pattern == nullptr) return true; if (s.empty() || pattern == nullptr) return false; if(s.length() split(std::string toSplit, char ch, int limit) { std::vector parts; limit--; while(limit > 0 && toSplit.size()>0) { auto pos = toSplit.find(ch); if(pos == std::string::npos) { parts.push_back(toSplit); return parts; } parts.push_back(toSplit.substr(0, pos)); toSplit = toSplit.substr(pos+1); limit--; } parts.push_back(toSplit); return parts; } std::string joinToString(std::vector::iterator* start, std::vector::iterator* end, std::string separator) { std::string res; if((*start)>=(*end)) { //Debug_printv("start >= end"); return std::string(); } for(auto i = (*start); i<(*end); i++) { //Debug_printv("b %d res [%s]", i, res.c_str()); res+=(*i); if(i<(*end)) res+=separator; //Debug_printv("a %d res [%s]", i, res.c_str()); } //Debug_printv("res[%s] length[%d] size[%d]", res.c_str(), res.length(), res.size()); return res.erase(res.length()-1,1); } std::string joinToString(std::vector strings, std::string separator) { auto st = strings.begin(); auto ed = strings.end(); return joinToString(&st, &ed, separator); } std::string urlEncode(const std::string &s) { std::ostringstream escaped; escaped.fill('0'); escaped << std::hex; for (std::string::const_iterator i = s.begin(), n = s.end(); i != n; ++i) { std::string::value_type c = (*i); // Keep alphanumeric and other accepted characters intact if (isalnum((unsigned char)c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '/' || c == ' ') { escaped << c; continue; } // Any other characters are percent-encoded escaped << std::uppercase; escaped << '%' << std::setw(2) << int((unsigned char)c); escaped << std::nouppercase; } return escaped.str(); } std::string urlDecode(std::string s){ std::string ret; char ch; int i, ii, len = s.length(); for (i = 0; i < len; i++) { if (s[i] != '%') { if (s[i] == '+') ret += ' '; else ret += s[i]; } else { sscanf(s.substr(i + 1, 2).c_str(), "%x", &ii); ch = static_cast(ii); ret += ch; i += 2; } } return ret; } std::string format(const char *format, ...) { // Format our string va_list args; va_start(args, format); char text[vsnprintf(NULL, 0, format, args) + 1]; vsnprintf(text, sizeof text, format, args); va_end(args); return text; } std::string formatBytes(uint64_t size) { std::string byteSuffixes[9] = { "", "K", "M", "G", "T"}; //, "P", "E", "Z", "Y" }; uint8_t i = 0; double n = 0; //Debug_printv("bytes[%llu]", size); do { n = size / std::pow(1024, ++i); //Debug_printv("i[%d] n[%llu]", i, n); } while ( n >= 1 ); n = size / std::pow(1024, --i); return format("%.2f %s", n, byteSuffixes[i].c_str()); } void cd( std::string &path, std::string newDir) { //Debug_printv("cd requested: [%s]", newDir.c_str()); // OK to clarify - coming here there should be ONLY path or magicSymbol-path combo! // NO "cd:xxxxx", no "/cd:xxxxx" ALLOWED here! ****************** // // if you want to support LOAD"CDxxxxxx" just parse/drop the CD BEFORE calling this function // and call it ONLY with the path you want to change into! if(newDir[0]=='/' && newDir[1]=='/') { if(newDir.size()==2) { // user entered: CD:// or CD// // means: change to the root of roots path = "/"; // chedked, works ad flash root! return; } else { // user entered: CD://DIR or CD//DIR // means: change to a dir in root of roots path = mstr::drop(newDir,2); return; } } // else if(newDir[0]=='/' || newDir[0]=='^') { // if(newDir.size()==1) { // // user entered: CD:/ or CD/ // // means: change to container root // // *** might require a fix for flash fs! // //return MFSOwner::File(streamPath); // return MFSOwner::File("/"); // } // else { // // user entered: CD:/DIR or CD/DIR // // means: change to a dir in container root // return localRoot(mstr::drop(newDir,1)); // } // } else if(newDir[0]=='_') { if(newDir.size()==1) { // user entered: CD:_ or CD_ // means: go up one directory path = parent(path); return; } else { // user entered: CD:_DIR or CD_DIR // means: go to a directory in the same directory as this one path = parent(path, mstr::drop(newDir,1)); return; } } if(newDir[0]=='.' && newDir[1]=='.') { if(newDir.size()==2) { // user entered: CD:.. or CD.. // means: go up one directory path = parent(path); return; } else { // user entered: CD:..DIR or CD..DIR // meaning: Go back one directory path = localParent(path, mstr::drop(newDir,2)); return; } } //Debug_printv("> url[%s] newDir[%s]", url.c_str(), newDir.c_str()); // Add new directory to path if ( !mstr::endsWith(path, "/") && newDir.size() ) path.push_back('/'); path += newDir; return; } std::string parent(std::string path, std::string plus) { //Debug_printv("url[%s] path[%s]", url.c_str(), path.c_str()); // drop last dir // add plus if(path.empty()) { // from here we can go only to flash root! return "/"; } else { int lastSlash = path.find_last_of('/'); if ( lastSlash == path.size() - 1 ) { lastSlash = path.find_last_of('/', path.size() - 2); } std::string newDir = mstr::dropLast(path, path.size() - lastSlash); if(!plus.empty()) newDir+= ("/" + plus); return newDir; } } std::string localParent(std::string path, std::string plus) { //Debug_printv("url[%s] path[%s]", url.c_str(), path.c_str()); // drop last dir // check if it isn't shorter than streamFile // add plus int lastSlash = path.find_last_of('/'); if ( lastSlash == path.size() - 1 ) { lastSlash = path.find_last_of('/', path.size() - 2); } std::string parent = mstr::dropLast(path, path.size() - lastSlash); // if(parent.length()-streamFile->url.length()>1) // parent = streamFile->url; return parent + "/" + plus; } }