diff options
Diffstat (limited to 'src/libslic3r/utils.cpp')
-rw-r--r-- | src/libslic3r/utils.cpp | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp new file mode 100644 index 000000000..4ff15175b --- /dev/null +++ b/src/libslic3r/utils.cpp @@ -0,0 +1,345 @@ +#include "Utils.hpp" +#include "I18N.hpp" + +#include <locale> +#include <ctime> + +#ifdef WIN32 +#include <windows.h> +#else +#include <unistd.h> +#endif + +#include <boost/log/core.hpp> +#include <boost/log/trivial.hpp> +#include <boost/log/expressions.hpp> + +#include <boost/locale.hpp> + +#include <boost/algorithm/string/predicate.hpp> +#include <boost/date_time/local_time/local_time.hpp> +#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/nowide/fstream.hpp> +#include <boost/nowide/integration/filesystem.hpp> +#include <boost/nowide/convert.hpp> +#include <boost/nowide/cstdio.hpp> + +#include <tbb/task_scheduler_init.h> + +namespace Slic3r { + +static boost::log::trivial::severity_level logSeverity = boost::log::trivial::error; + +void set_logging_level(unsigned int level) +{ + switch (level) { + // Report fatal errors only. + case 0: logSeverity = boost::log::trivial::fatal; break; + // Report fatal errors and errors. + case 1: logSeverity = boost::log::trivial::error; break; + // Report fatal errors, errors and warnings. + case 2: logSeverity = boost::log::trivial::warning; break; + // Report all errors, warnings and infos. + case 3: logSeverity = boost::log::trivial::info; break; + // Report all errors, warnings, infos and debugging. + case 4: logSeverity = boost::log::trivial::debug; break; + // Report everyting including fine level tracing information. + default: logSeverity = boost::log::trivial::trace; break; + } + + boost::log::core::get()->set_filter + ( + boost::log::trivial::severity >= logSeverity + ); +} + +// Force set_logging_level(<=error) after loading of the DLL. +// Switch boost::filesystem to utf8. +static struct RunOnInit { + RunOnInit() { + boost::nowide::nowide_filesystem(); + set_logging_level(1); + } +} g_RunOnInit; + +void trace(unsigned int level, const char *message) +{ + boost::log::trivial::severity_level severity = boost::log::trivial::trace; + switch (level) { + // Report fatal errors only. + case 0: severity = boost::log::trivial::fatal; break; + // Report fatal errors and errors. + case 1: severity = boost::log::trivial::error; break; + // Report fatal errors, errors and warnings. + case 2: severity = boost::log::trivial::warning; break; + // Report all errors, warnings and infos. + case 3: severity = boost::log::trivial::info; break; + // Report all errors, warnings, infos and debugging. + case 4: severity = boost::log::trivial::debug; break; + // Report everyting including fine level tracing information. + default: severity = boost::log::trivial::trace; break; + } + + BOOST_LOG_STREAM_WITH_PARAMS(::boost::log::trivial::logger::get(),\ + (::boost::log::keywords::severity = severity)) << message; +} + +void disable_multi_threading() +{ + // Disable parallelization so the Shiny profiler works + static tbb::task_scheduler_init *tbb_init = nullptr; + if (tbb_init == nullptr) + tbb_init = new tbb::task_scheduler_init(1); +} + +static std::string g_var_dir; + +void set_var_dir(const std::string &dir) +{ + g_var_dir = dir; +} + +const std::string& var_dir() +{ + return g_var_dir; +} + +std::string var(const std::string &file_name) +{ + auto file = (boost::filesystem::path(g_var_dir) / file_name).make_preferred(); + return file.string(); +} + +static std::string g_resources_dir; + +void set_resources_dir(const std::string &dir) +{ + g_resources_dir = dir; +} + +const std::string& resources_dir() +{ + return g_resources_dir; +} + +static std::string g_local_dir; + +void set_local_dir(const std::string &dir) +{ + g_local_dir = dir; +} + +const std::string& localization_dir() +{ + return g_local_dir; +} + +// Translate function callback, to call wxWidgets translate function to convert non-localized UTF8 string to a localized one. +Slic3r::I18N::translate_fn_type Slic3r::I18N::translate_fn = nullptr; + +static std::string g_data_dir; + +void set_data_dir(const std::string &dir) +{ + g_data_dir = dir; +} + +const std::string& data_dir() +{ + return g_data_dir; +} + + +// borrowed from LVVM lib/Support/Windows/Path.inc +int rename_file(const std::string &from, const std::string &to) +{ + int ec = 0; + +#ifdef _WIN32 + + // Convert to utf-16. + std::wstring wide_from = boost::nowide::widen(from); + std::wstring wide_to = boost::nowide::widen(to); + + // Retry while we see recoverable errors. + // System scanners (eg. indexer) might open the source file when it is written + // and closed. + bool TryReplace = true; + + // This loop may take more than 2000 x 1ms to finish. + for (int i = 0; i < 2000; ++ i) { + if (i > 0) + // Sleep 1ms + ::Sleep(1); + if (TryReplace) { + // Try ReplaceFile first, as it is able to associate a new data stream + // with the destination even if the destination file is currently open. + if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) + return 0; + DWORD ReplaceError = ::GetLastError(); + ec = -1; // ReplaceError + // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or + // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). + if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || + ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { + TryReplace = false; + continue; + } + // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry + // using ReplaceFileW(). + if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) + continue; + // We get ERROR_FILE_NOT_FOUND if the destination file is missing. + // MoveFileEx can handle this case. + if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION) + break; + } + if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) + return 0; + DWORD MoveError = ::GetLastError(); + ec = -1; // MoveError + if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION) + break; + } + +#else + + boost::nowide::remove(to.c_str()); + ec = boost::nowide::rename(from.c_str(), to.c_str()); + +#endif + + return ec; +} + +int copy_file(const std::string &from, const std::string &to) +{ + const boost::filesystem::path source(from); + const boost::filesystem::path target(to); + static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644 + + // Make sure the file has correct permission both before and after we copy over it. + try { + if (boost::filesystem::exists(target)) + boost::filesystem::permissions(target, perms); + boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists); + boost::filesystem::permissions(target, perms); + } catch (std::exception & /* ex */) { + return -1; + } + return 0; +} + +} // namespace Slic3r + +#ifdef WIN32 + #ifndef NOMINMAX + # define NOMINMAX + #endif + #include <windows.h> +#endif /* WIN32 */ + +namespace Slic3r { + +// Encode an UTF-8 string to the local code page. +std::string encode_path(const char *src) +{ +#ifdef WIN32 + // Convert the source utf8 encoded string to a wide string. + std::wstring wstr_src = boost::nowide::widen(src); + if (wstr_src.length() == 0) + return std::string(); + // Convert a wide string to a local code page. + int size_needed = ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), nullptr, 0, nullptr, nullptr); + std::string str_dst(size_needed, 0); + ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), const_cast<char*>(str_dst.data()), size_needed, nullptr, nullptr); + return str_dst; +#else /* WIN32 */ + return src; +#endif /* WIN32 */ +} + +// Encode an 8-bit string from a local code page to UTF-8. +std::string decode_path(const char *src) +{ +#ifdef WIN32 + int len = int(strlen(src)); + if (len == 0) + return std::string(); + // Convert the string encoded using the local code page to a wide string. + int size_needed = ::MultiByteToWideChar(0, 0, src, len, nullptr, 0); + std::wstring wstr_dst(size_needed, 0); + ::MultiByteToWideChar(0, 0, src, len, const_cast<wchar_t*>(wstr_dst.data()), size_needed); + // Convert a wide string to utf8. + return boost::nowide::narrow(wstr_dst.c_str()); +#else /* WIN32 */ + return src; +#endif /* WIN32 */ +} + +std::string normalize_utf8_nfc(const char *src) +{ + static std::locale locale_utf8(boost::locale::generator().generate("")); + return boost::locale::normalize(src, boost::locale::norm_nfc, locale_utf8); +} + +namespace PerlUtils { + // Get a file name including the extension. + std::string path_to_filename(const char *src) { return boost::filesystem::path(src).filename().string(); } + // Get a file name without the extension. + std::string path_to_stem(const char *src) { return boost::filesystem::path(src).stem().string(); } + // Get just the extension. + std::string path_to_extension(const char *src) { return boost::filesystem::path(src).extension().string(); } + // Get a directory without the trailing slash. + std::string path_to_parent_path(const char *src) { return boost::filesystem::path(src).parent_path().string(); } +}; + +std::string timestamp_str() +{ + const auto now = boost::posix_time::second_clock::local_time(); + char buf[2048]; + sprintf(buf, "on %04d-%02d-%02d at %02d:%02d:%02d", + // Local date in an ANSII format. + int(now.date().year()), int(now.date().month()), int(now.date().day()), + int(now.time_of_day().hours()), int(now.time_of_day().minutes()), int(now.time_of_day().seconds())); + return buf; +} + +unsigned get_current_pid() +{ +#ifdef WIN32 + return GetCurrentProcessId(); +#else + return ::getpid(); +#endif +} + +std::string xml_escape(std::string text) +{ + std::string::size_type pos = 0; + for (;;) + { + pos = text.find_first_of("\"\'&<>", pos); + if (pos == std::string::npos) + break; + + std::string replacement; + switch (text[pos]) + { + case '\"': replacement = """; break; + case '\'': replacement = "'"; break; + case '&': replacement = "&"; break; + case '<': replacement = "<"; break; + case '>': replacement = ">"; break; + default: break; + } + + text.replace(pos, 1, replacement); + pos += replacement.size(); + } + + return text; +} + +}; // namespace Slic3r |