#include "Debug.h" #include "Utility.h" #include #include #include #include // #include #include #include #include #include #include #include #include #include // NOTE: to use filesystem, you must also include the fs library such // as via the `-lstdc++fs` linker option -- see b3view.pro // #include // requires C++17 #include // requires C++14 such as gcc 8.2.1 // C++14: namespace filesystem = std::experimental::filesystem; // namespace fs = std::filesystem; // doesn't work (not a namespace in gcc's C++17) // using namespace std::filesystem; // doesn't work (not a namespace in gcc's C++17) namespace fs = std::experimental::filesystem; // namespace fs = std::filesystem; // doesn't work (not a namespace in gcc's C++17) using namespace irr::core; using namespace irr::scene; using namespace irr::video; using namespace std; const std::string Utility::WHITESPACE = " \n\r\t\f\v"; void Utility::dumpVectorToConsole(const vector3df& vector) { debug() << "X: " << vector.X << " Y: " << vector.Y << " Z: " << vector.Z << endl; } int Utility::getTextureCount(const SMaterial& material) { int count = 0; for (irr::u32 ti = 0; ti < MATERIAL_MAX_TEXTURES; ti++) if (material.getTexture(ti) != nullptr) count++; return count; } int Utility::getTextureCount(IAnimatedMeshSceneNode* node) { int count = 0; for (irr::u32 matIndex = 0; matIndex < node->getMaterialCount(); matIndex++) { count += getTextureCount(node->getMaterial(matIndex)); } return count; } void Utility::dumpMeshInfoToConsole(IAnimatedMeshSceneNode* node) { if (node == nullptr) { debug() << "[MESH]: # node: nullptr" << endl; return; } if (node->getMesh() == nullptr) { debug() << "[MESH]: # node->getMesh(): nullptr" << endl; return; } // Dump some information about the mesh to the console IAnimatedMesh* mesh = node->getMesh(); debug() << "[MESH]: # of frames : " << mesh->getFrameCount() << endl; debug() << "[MESH]: # of materials : " << node->getMaterialCount() << endl; for (irr::u32 matIndex = 0; matIndex < node->getMaterialCount(); matIndex++) { debug() << "[MESH]: Material # " << matIndex << endl; const SMaterial& material = node->getMaterial(matIndex); debug() << "[MESH]: Diffuse Color : A" << material.DiffuseColor.getAlpha() << " R" << material.DiffuseColor.getRed() << " G" << material.DiffuseColor.getGreen() << " B" << material.DiffuseColor.getBlue() << endl; debug() << "[MESH]: Specular Color : A" << material.SpecularColor.getAlpha() << " R" << material.SpecularColor.getRed() << " G" << material.SpecularColor.getGreen() << " B" << material.SpecularColor.getBlue() << endl; debug() << "[MESH]: Specular Shininess : " << material.Shininess << endl; // check for # textures debug() << "[MESH]: # of textures : " << Utility::getTextureCount(material) << endl; } } std::wstring Utility::parentOfPath(const wstring& path) { std::wstring ret = L"."; if (path == L".") { ret = L".."; } else { std::wstring::size_type lastSlashPos = path.find_last_of(L"/"); if (lastSlashPos == std::wstring::npos) { lastSlashPos = path.find_last_of(L"\\"); } if (lastSlashPos != std::wstring::npos) { ret = path.substr(0, lastSlashPos); } } return ret; } /// Filename without path (may still have extension) wstring Utility::basename(const wstring& path) { std::wstring ret = path; std::wstring::size_type lastSlashPos = path.find_last_of(L"/"); if (lastSlashPos == std::wstring::npos) { lastSlashPos = path.find_last_of(L"\\"); } if (lastSlashPos != std::wstring::npos) { ret = path.substr(lastSlashPos + 1); } return ret; } /// Get any substring to the right of the first delimiter. /// allIfNotFound: Return whole string on no delimiter, vs empty string. wstring Utility::rightOf(const wstring& path, const wstring& delimiter, bool allIfNotFound) { std::wstring ret = allIfNotFound ? path : L""; std::wstring::size_type lastPos = path.find(delimiter); if (lastPos != std::wstring::npos) { ret = path.substr(lastPos + delimiter.length()); } return ret; } /// Get any substring to the right of the last delimiter. /// allIfNotFound: Return whole string on no delimiter, vs empty string. wstring Utility::rightOfLast(const wstring& path, const wstring& delimiter, bool allIfNotFound) { std::wstring ret = allIfNotFound ? path : L""; std::wstring::size_type lastPos = path.find_last_of(delimiter); if (lastPos != std::wstring::npos) { ret = path.substr(lastPos + delimiter.length()); } return ret; } /// Get any substring to the left of the first delimiter. /// allIfNotFound: Return whole string on no delimiter, vs empty string. wstring Utility::leftOf(const wstring& path, const wstring& delimiter, bool allIfNotFound) { std::wstring ret = allIfNotFound ? path : L""; std::wstring::size_type lastPos = path.find(delimiter); if (lastPos != std::wstring::npos) { ret = path.substr(0, lastPos); } return ret; } bool Utility::startsWith(const std::wstring& haystack, const std::wstring& needle) { bool found = false; if (haystack.length() >= needle.length()) { if (haystack.substr(0, needle.length())==needle) { found = true; } } return found; } bool Utility::endsWith(const std::wstring& haystack, const std::wstring& needle) { bool found = false; if (haystack.length() >= needle.length()) { if (haystack.substr(haystack.length()-needle.length())==needle) { found = true; } } return found; } bool Utility::startsWith(const std::string& haystack, const std::string& needle) { bool found = false; if (haystack.length() >= needle.length()) { if (haystack.substr(0, needle.length())==needle) { found = true; } } return found; } bool Utility::endsWith(const std::string& haystack, const std::string& needle) { bool found = false; if (haystack.length() >= needle.length()) { if (haystack.substr(haystack.length()-needle.length())==needle) { found = true; } } return found; } wstring Utility::replaceAll(const wstring &subject, const wstring &from, const wstring &to) { size_t i = 0; if (from.length() == 0) { return subject; } wstring result = subject; while (i < result.length()) { if (result.substr(i, from.length()) == from) { result = result.substr(0, i) + to + result.substr(i + from.length()); i += to.length(); } else { i++; } } return result; } std::string Utility::replaceAll(const std::string &subject, const std::string &from, const std::string &to) { size_t i = 0; if (from.length() == 0) { return subject; } std::string result = subject; while (i < result.length()) { if (result.substr(i, from.length()) == from) { result = result.substr(0, i) + to + result.substr(i + from.length()); i += to.length(); } else { i++; } } return result; } bool Utility::startsWithAny(const std::wstring& haystack, const std::vector& needles, bool CI) { return getPrefix(haystack, needles, CI).length() > 0; } bool Utility::endsWithAny(const std::wstring& haystack, const std::vector& needles, bool CI) { return getSuffix(haystack, needles, CI).length() > 0; } std::wstring Utility::getPrefix(const std::wstring& haystack, const std::vector& needles, bool CI) { if (CI) { std::wstring haystackLower = Utility::toLower(haystack); for (auto needle : needles) { if (Utility::startsWith(haystackLower, Utility::toLower(needle))) return needle; } } else { for (auto needle : needles) { if (Utility::startsWith(haystack, needle)) return needle; } } return L""; } std::wstring Utility::getSuffix(const std::wstring& haystack, const std::vector& needles, bool CI) { if (CI) { std::wstring haystackLower = Utility::toLower(haystack); for (auto needle : needles) { if (Utility::endsWith(haystackLower, Utility::toLower(needle))) return needle; } } else { for (auto needle : needles) { if (Utility::endsWith(haystack, needle)) return needle; } } return L""; } /// Get any substring to the left of the last delimiter. /// allIfNotFound: Return whole string on no delimiter, vs empty string. wstring Utility::leftOfLast(const wstring& path, const wstring& delimiter, bool allIfNotFound) { std::wstring ret = allIfNotFound ? path : L""; std::wstring::size_type lastPos = path.find_last_of(delimiter); if (lastPos != std::wstring::npos) { ret = path.substr(0, lastPos); } return ret; } wstring Utility::withoutExtension(const wstring& path) { std::wstring ret = path; std::wstring::size_type lastDotPos = path.find_last_of(L"."); if (lastDotPos != std::wstring::npos) { std::wstring::size_type lastSlashPos = path.find_last_of(L"/"); if (lastSlashPos == std::wstring::npos) { lastSlashPos = path.find_last_of(L"\\"); } if (lastSlashPos != std::wstring::npos) { if (lastDotPos > lastSlashPos) ret = path.substr(0, lastDotPos); } else ret = path.substr(0, lastDotPos); } return ret; } wstring Utility::extensionOf(const wstring& path) { std::wstring ret = L""; std::wstring::size_type lastDotPos = path.find_last_of(L"."); if (lastDotPos != std::wstring::npos) { std::wstring::size_type lastSlashPos = path.find_last_of(L"/"); if (lastSlashPos == std::wstring::npos) { lastSlashPos = path.find_last_of(L"\\"); } if (lastSlashPos != std::wstring::npos) { if (lastDotPos > lastSlashPos) ret = path.substr(lastDotPos + 1); } else ret = path.substr(lastDotPos + 1); } return ret; } wstring Utility::delimiter(const wstring& path) { std::wstring ret = L"/"; std::wstring::size_type lastSlashPos = path.find_last_of(L"/"); if (lastSlashPos == std::wstring::npos) { // ret = L"/"; } else { std::wstring::size_type lastSlashPos = path.find_last_of(L"\\"); if (lastSlashPos != std::wstring::npos) { ret = L"\\"; } } return ret; } bool Utility::isFile(const std::string& name) { if (FILE* file = fopen(name.c_str(), "r")) { fclose(file); return true; } else { return false; } } std::string Utility::toString(const std::wstring& ws) { std::string ret; if (ws.length() > 0) { // std::string str = "Hello"; ret = std::string(ws.length(), L' '); // Make room for characters // Copy string to wstring. std::copy(ws.begin(), ws.end(), ret.begin()); } return ret; // below sometimes results in "internal_utf8_loop_single: Assertion // `inptr - bytebuf > (state->__count & 7)' failed." // on the converter.out call: // if (ws.length() > 0) { // // convert to w_string using locale: see Phillipp on // // // std::setlocale(LC_ALL, ""); // const std::locale locale(""); // typedef std::codecvt converter_type; // const converter_type& converter = std::use_facet(locale); // std::vector to(ws.length() * converter.max_length()); // std::mbstate_t state; // const wchar_t* from_next = nullptr; // char* to_next = nullptr; // const converter_type::result result = converter.out( // state, ws.data(), // ws.data() + ws.length(), // from_next, // &to[0], // &to[0] + to.size(), // to_next // ); // if (result == converter_type::ok or result == converter_type::noconv) { // const std::string s(&to[0], to_next); // // std::cout <<"std::string = "< 0) { // std::string str = "Hello"; ret = std::wstring(str.length(), L' '); // Make room for characters // Copy string to wstring. std::copy(str.begin(), str.end(), ret.begin()); } return ret; } std::string Utility::dateTimePathString(const time_t& rawtime) { // see http://www.cplusplus.com/reference/ctime/strftime/ std::string ret = ""; struct tm * timeinfo; char buffer[80]; timeinfo = localtime (&rawtime); strftime (buffer,80,"%F_%H%M%S",timeinfo); // %F is same as %Y-%m-%d (zero-padded) ret.assign(buffer); return ret; } std::string Utility::dateTimeNowPathString() { time_t rawtime; time (&rawtime); return dateTimePathString(rawtime); } irr::f32 Utility::toF32(wstring val) { std::wstringstream ss(val); irr::f32 ret = 0; ss >> ret; return ret; } irr::f32 Utility::distance(const vector3df &start, const vector3df &end) { vector3df offsetVec3(end.X - start.X, end.Y - start.Y, end.Z - start.Z); return offsetVec3.getLength(); } bool Utility::isFile(const std::wstring& name) { std::string name_s = toString(name); if (FILE* file = fopen(name_s.c_str(), "r")) { fclose(file); return true; } else { return false; } } bool Utility::is_directory(const std::string &path) { return fs::is_directory(fs::status(path)); /* //pre C++17: struct stat info; if (stat(path, &info) != 0) { // TODO: ^ fails on OSX 10.11 according to a comment on the // accepted answer on // https://stackoverflow.com/questions/18100097/portable-way-to-check-if-directory-exists-windows-linux-c } */ } bool Utility::is_directory(const std::wstring &path) { return fs::is_directory(fs::status(path)); /* //pre C++17: struct stat info; if (stat(path, &info) != 0) { // TODO: ^ fails on OSX 10.11 according to a comment on the // accepted answer on // https://stackoverflow.com/questions/18100097/portable-way-to-check-if-directory-exists-windows-linux-c } */ } void Utility::create_directory(const std::string &path) { fs::create_directory(path); } std::string Utility::toString(int val) { return std::to_string(val); // The only throw is std::bad_alloc according to // } std::string Utility::toString(irr::f32 val) { return std::to_string(val); // The only throw is std::bad_alloc according to // } std::string Utility::ltrim(const std::string& s) { // based on https://www.techiedelight.com/trim-string-cpp-remove-leading-trailing-spaces/ size_t start = s.find_first_not_of(Utility::WHITESPACE); return (start == std::string::npos) ? "" : s.substr(start); } std::string Utility::rtrim(const std::string& s) { // based on https://www.techiedelight.com/trim-string-cpp-remove-leading-trailing-spaces/ size_t end = s.find_last_not_of(Utility::WHITESPACE); return (end == std::string::npos) ? "" : s.substr(0, end + 1); } std::string Utility::trim(const std::string& s) { // based on https://www.techiedelight.com/trim-string-cpp-remove-leading-trailing-spaces/ return rtrim(ltrim(s)); } // don't do late instantiation (see header file) // template // bool Utility::equalsApprox(T f1, T f2) // { // return abs(f2-f1) < .00000001; // TODO: kEpsilon? (see also // // ) // } TestUtility::TestUtility() { std::cerr << "TestUtility..." << std::flush; testReplaceAll(L"***water_dragon***", L"_", L"", L"***waterdragon***"); testReplaceAll(L"*water_dragon*", L"*", L"***", L"***water_dragon***"); testReplaceAll(L"***water_dragon***", L"***", L"", L"water_dragon"); testReplaceAll(L"***water_dragon***", L"", L"***", L"***water_dragon***"); // do nothing testLTrim(" apple", "apple"); testLTrim(" banana ", "banana "); testRTrim(" cantelope ", " cantelope"); testRTrim("dragon fruit ", "dragon fruit"); testTrim(" elderberry ", "elderberry"); testTrim("fig ", "fig"); testTrim(" grape", "grape"); testTrim("horned melon ", "horned melon"); std::cerr << "OK" << std::endl; } void TestUtility::testReplaceAll(const wstring &subject, const wstring &from, const wstring &to, const wstring &expectedResult) { this->assertEqual(Utility::replaceAll(subject, from, to), expectedResult); }; void TestUtility::testReplaceAll(const std::string &subject, const std::string &from, const std::string &to, const std::string &expectedResult) { std::string result = Utility::replaceAll(subject, from, to); this->assertEqual(result, expectedResult); } void TestUtility::testTrim(const std::string &subject, const std::string &expectedResult) { assertEqual(Utility::trim(subject), expectedResult); } void TestUtility::testLTrim(const std::string &subject, const std::string &expectedResult) { assertEqual(Utility::ltrim(subject), expectedResult); } void TestUtility::testRTrim(const std::string &subject, const std::string &expectedResult) { assertEqual(Utility::rtrim(subject), expectedResult); } void TestUtility::assertEqual(const wstring& subject, const wstring& expectedResult) { if (subject != expectedResult) { cerr << "The test expected \"" << Utility::toString(expectedResult) << "\" but got \"" << Utility::toString(subject) << "\"" << std::endl; } assert(subject == expectedResult); } void TestUtility::assertEqual(const std::string subject, const std::string expectedResult) { if (subject != expectedResult) { cerr << "The test expected \"" << expectedResult << "\" but got \"" << subject << "\"" << std::endl; } assert(subject == expectedResult); } #ifdef DEBUG static TestUtility testutility; // Run tests (Creating the first instance runs the static constructor). #elif QT_DEBUG static TestUtility testutility; // Run tests (Creating the first instance runs the static constructor). #endif