diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 928febffd08..82c0a72a651 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -230,8 +230,13 @@ static std::string appconfig_md5_hash_line(const std::string_view data) return "# MD5 checksum " + md5_digest_str + "\n"; }; +struct ConfigFileInfo { + bool correct_checksum {false}; + bool contains_null {false}; +}; + // Assume that the last line with the comment inside the config file contains a checksum and that the user didn't modify the config file. -static bool verify_config_file_checksum(boost::nowide::ifstream &ifs) +static ConfigFileInfo check_config_file_and_verify_checksum(boost::nowide::ifstream &ifs) { auto read_whole_config_file = [&ifs]() -> std::string { std::stringstream ss; @@ -240,7 +245,8 @@ static bool verify_config_file_checksum(boost::nowide::ifstream &ifs) }; ifs.seekg(0, boost::nowide::ifstream::beg); - std::string whole_config = read_whole_config_file(); + const std::string whole_config = read_whole_config_file(); + const bool contains_null = whole_config.find_first_of('\0') != std::string::npos; // The checksum should be on the last line in the config file. if (size_t last_comment_pos = whole_config.find_last_of('#'); last_comment_pos != std::string::npos) { @@ -249,9 +255,9 @@ static bool verify_config_file_checksum(boost::nowide::ifstream &ifs) // When the checksum isn't found, the checksum was not saved correctly, it was removed or it is an older config file without the checksum. // If the checksum is incorrect, then the file was either not saved correctly or modified. if (std::string_view(whole_config.c_str() + last_comment_pos, whole_config.size() - last_comment_pos) == appconfig_md5_hash_line({ whole_config.data(), last_comment_pos })) - return true; + return {true, contains_null}; } - return false; + return {false, contains_null}; } #endif @@ -269,14 +275,25 @@ std::string AppConfig::load(const std::string &path) ifs.open(path); #ifdef WIN32 // Verify the checksum of the config file without taking just for debugging purpose. - if (!verify_config_file_checksum(ifs)) - BOOST_LOG_TRIVIAL(info) << "The configuration file " << path << - " has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit."; + const ConfigFileInfo config_file_info = check_config_file_and_verify_checksum(ifs); + if (!config_file_info.correct_checksum) + BOOST_LOG_TRIVIAL(info) + << "The configuration file " << path + << " has a wrong MD5 checksum or the checksum is missing. This may indicate a file corruption or a harmless user edit."; + + if (!config_file_info.correct_checksum && config_file_info.contains_null) { + BOOST_LOG_TRIVIAL(info) << "The configuration file " + path + " is corrupted, because it is contains null characters."; + throw Slic3r::CriticalException("The configuration file contains null characters."); + } ifs.seekg(0, boost::nowide::ifstream::beg); #endif - pt::read_ini(ifs, tree); - } catch (pt::ptree_error& ex) { + try { + pt::read_ini(ifs, tree); + } catch (pt::ptree_error &ex) { + throw Slic3r::CriticalException(ex.what()); + } + } catch (Slic3r::CriticalException &ex) { #ifdef WIN32 // The configuration file is corrupted, try replacing it with the backup configuration. ifs.close(); @@ -284,29 +301,29 @@ std::string AppConfig::load(const std::string &path) if (boost::filesystem::exists(backup_path)) { // Compute checksum of the configuration backup file and try to load configuration from it when the checksum is correct. boost::nowide::ifstream backup_ifs(backup_path); - if (!verify_config_file_checksum(backup_ifs)) { - BOOST_LOG_TRIVIAL(error) << format("Both \"%1%\" and \"%2%\" are corrupted. It isn't possible to restore configuration from the backup.", path, backup_path); + if (const ConfigFileInfo config_file_info = check_config_file_and_verify_checksum(backup_ifs); !config_file_info.correct_checksum || config_file_info.contains_null) { + BOOST_LOG_TRIVIAL(error) << format(R"(Both "%1%" and "%2%" are corrupted. It isn't possible to restore configuration from the backup.)", path, backup_path); backup_ifs.close(); boost::filesystem::remove(backup_path); } else if (std::string error_message; copy_file(backup_path, path, error_message, false) != SUCCESS) { - BOOST_LOG_TRIVIAL(error) << format("Configuration file \"%1%\" is corrupted. Failed to restore from backup \"%2%\": %3%", path, backup_path, error_message); + BOOST_LOG_TRIVIAL(error) << format(R"(Configuration file "%1%" is corrupted. Failed to restore from backup "%2%": %3%)", path, backup_path, error_message); backup_ifs.close(); boost::filesystem::remove(backup_path); } else { - BOOST_LOG_TRIVIAL(info) << format("Configuration file \"%1%\" was corrupted. It has been succesfully restored from the backup \"%2%\".", path, backup_path); + BOOST_LOG_TRIVIAL(info) << format(R"(Configuration file "%1%" was corrupted. It has been successfully restored from the backup "%2%".)", path, backup_path); // Try parse configuration file after restore from backup. try { ifs.open(path); pt::read_ini(ifs, tree); recovered = true; } catch (pt::ptree_error& ex) { - BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\" after it has been restored from backup: %2%", path, ex.what()); + BOOST_LOG_TRIVIAL(info) << format(R"(Failed to parse configuration file "%1%" after it has been restored from backup: %2%)", path, ex.what()); } } } else #endif // WIN32 - BOOST_LOG_TRIVIAL(info) << format("Failed to parse configuration file \"%1%\": %2%", path, ex.what()); - if (! recovered) { + BOOST_LOG_TRIVIAL(info) << format(R"(Failed to parse configuration file "%1%": %2%)", path, ex.what()); + if (!recovered) { // Report the initial error of parsing PrusaSlicer.ini. // Error while parsing config file. We'll customize the error message and rethrow to be displayed. // ! But to avoid the use of _utf8 (related to use of wxWidgets)