| 1961 | } |
| 1962 | |
| 1963 | bool Document::saveToFile(const char* filename) const |
| 1964 | { |
| 1965 | signalStartSave(*this, filename); |
| 1966 | |
| 1967 | auto hGrp = GetApplication().GetParameterGroupByPath( |
| 1968 | "User parameter:BaseApp/Preferences/Document"); |
| 1969 | int compression = static_cast<int>(hGrp->GetInt("CompressionLevel", 7)); |
| 1970 | compression = Base::clamp<int>(compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION); |
| 1971 | |
| 1972 | bool policy = GetApplication() |
| 1973 | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document") |
| 1974 | ->GetBool("BackupPolicy", true); |
| 1975 | |
| 1976 | auto canonical_path = [](const char* filename) { |
| 1977 | try { |
| 1978 | #ifdef FC_OS_WIN32 |
| 1979 | QString utf8Name = QString::fromUtf8(filename); |
| 1980 | auto realpath = fs::weakly_canonical(fs::absolute(fs::path(utf8Name.toStdWString()))); |
| 1981 | std::string nativePath = QString::fromStdWString(realpath.native()).toStdString(); |
| 1982 | #else |
| 1983 | auto realpath = fs::weakly_canonical(fs::absolute(fs::path(filename))); |
| 1984 | std::string nativePath = realpath.native(); |
| 1985 | #endif |
| 1986 | // In case some folders in the path do not exist |
| 1987 | auto parentPath = realpath.parent_path(); |
| 1988 | fs::create_directories(parentPath); |
| 1989 | |
| 1990 | return nativePath; |
| 1991 | } |
| 1992 | catch (const std::exception&) { |
| 1993 | #ifdef FC_OS_WIN32 |
| 1994 | QString utf8Name = QString::fromUtf8(filename); |
| 1995 | auto parentPath = fs::absolute(fs::path(utf8Name.toStdWString())).parent_path(); |
| 1996 | #else |
| 1997 | auto parentPath = fs::absolute(fs::path(filename)).parent_path(); |
| 1998 | #endif |
| 1999 | fs::create_directories(parentPath); |
| 2000 | |
| 2001 | return std::string(filename); |
| 2002 | } |
| 2003 | }; |
| 2004 | |
| 2005 | // realpath is canonical filename i.e. without symlink |
| 2006 | std::string nativePath = canonical_path(filename); |
| 2007 | |
| 2008 | // check if file is writeable, then block the save if it is not. |
| 2009 | Base::FileInfo originalFileInfo(nativePath); |
| 2010 | if (originalFileInfo.exists() && !originalFileInfo.isWritable()) { |
| 2011 | throw Base::FileException("Unable to save document because file is marked as read-only or write permission is not available.", originalFileInfo); |
| 2012 | } |
| 2013 | |
| 2014 | // make a tmp. file where to save the project data first and then rename to |
| 2015 | // the actual file name. This may be useful if overwriting an existing file |
| 2016 | // fails so that the data of the work up to now isn't lost. |
| 2017 | std::string uuid = Base::Uuid::createUuid(); |
| 2018 | std::string fn = nativePath; |
| 2019 | if (policy) { |
| 2020 | fn += "."; |
nothing calls this directly
no test coverage detected