forked from luxonis/depthai-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
3 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#pragma once | ||
#include <codecvt> | ||
#if(__cplusplus >= 201703L) || (_MSVC_LANG >= 201703L) | ||
#include <filesystem> | ||
#endif | ||
#include <locale> | ||
#include <string> | ||
|
||
namespace dai { | ||
|
||
/** | ||
* @brief accepts utf-8, Windows wchar_t, or std::filesystem::path | ||
* and returns the path in a type accepted by fstream() | ||
* | ||
*/ | ||
class Path { | ||
public: | ||
#if defined(_WIN32) && defined(_MSC_VER) | ||
using value_type = wchar_t; | ||
#else | ||
// TODO C++20 char8_t | ||
using value_type = char; | ||
#endif | ||
using string_type = std::basic_string<value_type>; | ||
|
||
public: | ||
Path() = default; | ||
~Path() = default; | ||
Path(const Path&) = default; | ||
Path(Path&&) = default; | ||
Path& operator=(const Path&) = default; | ||
Path& operator=(Path&&) = default; | ||
|
||
Path(string_type&& source) noexcept : nativePath(std::move(source)) {} | ||
Path(const string_type& source) : nativePath(source) {} | ||
Path(const value_type* source) : nativePath(string_type(source)) {} | ||
|
||
#if defined(__cpp_lib_filesystem) | ||
// Path(std::filesystem::path source) : nativePath(source) {} | ||
Path(const std::filesystem::path& source) : nativePath(source) {} | ||
#endif | ||
|
||
#if defined(_WIN32) && defined(_MSC_VER) | ||
// Path(std::string source) : nativePath(convert_utf8_to_wide(source)) {} | ||
Path(const std::string& source) : nativePath(convert_utf8_to_wide(source)) {} | ||
Path(const char* source) : nativePath(convert_utf8_to_wide(std::string(source))) {} | ||
#endif | ||
|
||
// implicitly convert *this into a string containing the native format | ||
operator string_type() const noexcept { | ||
return nativePath; | ||
} | ||
|
||
private: | ||
string_type nativePath; | ||
|
||
std::wstring convert_utf8_to_wide(const std::string& utf8string) { | ||
//#pragma warning(suppress : 4996) | ||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; | ||
return converter.from_bytes(utf8string); | ||
} | ||
}; | ||
|
||
} // namespace dai |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
#define CATCH_CONFIG_MAIN | ||
#include <catch2/catch.hpp> | ||
|
||
// Include depthai library | ||
#include <cstdio> | ||
#include <depthai/depthai.hpp> | ||
#if(__cplusplus >= 201703L) || (_MSVC_LANG >= 201703L) | ||
#include <filesystem> | ||
#endif | ||
#include <string> | ||
|
||
#include "depthai/utility/Path.hpp" | ||
|
||
#if defined(_WIN32) && defined(_MSC_VER) | ||
#define NATIVETYPE std::wstring | ||
#define MAKENATIVEx(x) L##x | ||
#define MAKENATIVE(x) MAKENATIVEx(x) | ||
#define DELETEFILE _wremove | ||
#define NATIVELENGTH(x) static_cast<std::wstring>(x).length() | ||
#else | ||
#define NATIVETYPE std::string | ||
#define MAKENATIVE(x) x | ||
#define DELETEFILE std::remove | ||
#define NATIVELENGTH(x) u8length(static_cast<std::string>(x).c_str()) | ||
#endif | ||
|
||
#define PATH1 "C:\\dir1\\file1.txt" | ||
#define PATH2 "file2.txt" | ||
#define PATH3 "/dir3/dir33/file3.txt" | ||
#define PATH4 u8"\u00e4\u00eb\u00ef\u00f6\u00fc\u00e1\u00e9\u00ed\u00f3\u00fa\u00df\u00c6\u002e\u010c\u011a\u0141" | ||
#define FILETEXT "This is a test\n" | ||
|
||
int u8length(const char* str) noexcept { | ||
int count = 0; | ||
for(; *str != 0; ++str) count += ((*str & 0xc0) != 0x80); | ||
return count; | ||
} | ||
|
||
TEST_CASE("dai::Path utf-8 and native char set handling") { | ||
const dai::Path emptyPath; | ||
const dai::Path::string_type emptyString = emptyPath; | ||
REQUIRE(emptyString.empty()); | ||
|
||
const dai::Path path1(PATH1); | ||
const NATIVETYPE string1(path1); | ||
REQUIRE(string1 == MAKENATIVE(PATH1)); | ||
|
||
const dai::Path path2(PATH2); | ||
const NATIVETYPE string2(path2); | ||
REQUIRE(string2 == MAKENATIVE(PATH2)); | ||
|
||
const dai::Path path3(PATH3); | ||
const NATIVETYPE string3(path3); | ||
REQUIRE(string3 == MAKENATIVE(PATH3)); | ||
|
||
char tmp_name4[L_tmpnam]; | ||
REQUIRE(std::tmpnam(tmp_name4) != nullptr); | ||
std::string string4(tmp_name4); | ||
string4 += PATH4; | ||
const dai::Path path4(string4); | ||
REQUIRE(u8length(string4.c_str()) == NATIVELENGTH(path4)); | ||
|
||
REQUIRE_NOTHROW([&]() { | ||
std::ofstream file(path4); | ||
file.write(FILETEXT, sizeof(FILETEXT) - 1); | ||
}()); | ||
REQUIRE_NOTHROW([&]() { | ||
std::ifstream file(path4, std::ios::binary); | ||
if(!file.is_open() || !file.good() || file.bad()) { | ||
throw std::runtime_error("file not found or corrupted"); | ||
} | ||
file.exceptions(std::ifstream::failbit | std::ifstream::badbit); | ||
const char c1 = file.get(); | ||
}()); | ||
REQUIRE(0 == DELETEFILE(static_cast<NATIVETYPE>(path4).c_str())); | ||
|
||
auto getBlob = [](const dai::Path& path) -> bool { return !static_cast<NATIVETYPE>(path).empty(); }; | ||
REQUIRE(getBlob(string4)); | ||
REQUIRE(getBlob("mypath/myfile.blob")); | ||
REQUIRE(getBlob([]() -> std::string { return "mypath/rvalue.blob"; }())); | ||
#if defined(_WIN32) && defined(_MSC_VER) | ||
REQUIRE(getBlob(L"mywidepath/myfile.blob")); | ||
std::wstring move2ndTry(L"move my data on the second try"); | ||
REQUIRE(getBlob(move2ndTry)); | ||
REQUIRE(getBlob(std::move(move2ndTry))); | ||
#endif | ||
|
||
auto wrapper = [&getBlob](const dai::Path& path) -> bool { return getBlob(path); }; | ||
REQUIRE(wrapper("pass dai::Path across functions")); | ||
|
||
#if defined(__cpp_lib_filesystem) | ||
const std::filesystem::path fspath1(PATH1); | ||
const std::filesystem::path fspath2(PATH2); | ||
const std::filesystem::path fspath3(PATH3); | ||
REQUIRE(getBlob(fspath1)); | ||
REQUIRE(getBlob(fspath2)); | ||
REQUIRE(getBlob(fspath3)); | ||
#endif | ||
} |