Line data Source code
1 : /****************************************************************************/ 2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo 3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others. 4 : // This program and the accompanying materials are made available under the 5 : // terms of the Eclipse Public License 2.0 which is available at 6 : // https://www.eclipse.org/legal/epl-2.0/ 7 : // This Source Code may also be made available under the following Secondary 8 : // Licenses when the conditions for such availability set forth in the Eclipse 9 : // Public License 2.0 are satisfied: GNU General Public License, version 2 10 : // or later which is available at 11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html 12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later 13 : /****************************************************************************/ 14 : /// @file FileHelpers.cpp 15 : /// @author Daniel Krajzewicz 16 : /// @author Michael Behrisch 17 : /// @date Mon, 17 Dec 2001 18 : /// 19 : // Functions for an easier usage of files 20 : /****************************************************************************/ 21 : #include <config.h> 22 : 23 : #include <string> 24 : #ifdef WIN32 25 : // this is how fox does it in xincs.h 26 : #include <io.h> 27 : #define access _access 28 : #define R_OK 4 /* Test for read permission. */ 29 : #include <direct.h> 30 : #define getcwd _getcwd // stupid MSFT "deprecation" warning 31 : #else 32 : #include <unistd.h> 33 : #endif 34 : #include <fstream> 35 : #include <sys/stat.h> 36 : #include "FileHelpers.h" 37 : #include "StringTokenizer.h" 38 : #include "StringUtils.h" 39 : #include "MsgHandler.h" 40 : 41 : 42 : // =========================================================================== 43 : // method definitions 44 : // =========================================================================== 45 : 46 : // --------------------------------------------------------------------------- 47 : // file access functions 48 : // --------------------------------------------------------------------------- 49 : 50 : bool 51 289858 : FileHelpers::isReadable(std::string path) { 52 289858 : if (path.length() == 0) { 53 : return false; 54 : } 55 289858 : while (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\') { 56 : path.erase(path.end() - 1); 57 : } 58 289858 : if (path.length() == 0) { 59 : return false; 60 : } 61 501409 : return access(StringUtils::transcodeToLocal(path).c_str(), R_OK) == 0; 62 : } 63 : 64 : bool 65 134747 : FileHelpers::isDirectory(std::string path) { 66 : #ifdef _MSC_VER 67 : struct _stat64 fileInfo; 68 : if (_stat64(StringUtils::transcodeToLocal(path).c_str(), &fileInfo) != 0) { 69 : #else 70 : struct stat fileInfo; 71 269494 : if (stat(StringUtils::transcodeToLocal(path).c_str(), &fileInfo) != 0) { 72 : #endif 73 0 : throw ProcessError(TLF("Cannot get file attributes for file '%'!", path)); 74 : } 75 134747 : return (fileInfo.st_mode & S_IFMT) == S_IFDIR; 76 : } 77 : 78 : // --------------------------------------------------------------------------- 79 : // file path evaluating functions 80 : // --------------------------------------------------------------------------- 81 : 82 : std::string 83 147048 : FileHelpers::getFilePath(const std::string& path) { 84 : const auto beg = path.find_last_of("\\/"); 85 147048 : if (beg == std::string::npos) { 86 129268 : return ""; 87 : } 88 17780 : return path.substr(0, beg + 1); 89 : } 90 : 91 : 92 : std::string 93 0 : FileHelpers::getFileFromPath(std::string path, const bool removeExtension) { 94 : // first remove extension 95 0 : if (removeExtension) { 96 : const auto begExtension = path.find_last_of("."); 97 0 : if (begExtension != std::string::npos) { 98 0 : path = path.substr(0, begExtension); 99 : } 100 : } 101 : // now remove path 102 : const auto begPath = path.find_last_of("\\/"); 103 0 : if (begPath != std::string::npos) { 104 0 : path = path.substr(begPath + 1, path.size()); 105 : } 106 0 : return path; 107 : } 108 : 109 : 110 : std::string 111 0 : FileHelpers::addExtension(const std::string& path, const std::string& extension) { 112 0 : if (path.empty()) { 113 0 : return ""; 114 0 : } else if (extension.empty()) { 115 : return path; 116 0 : } else if (path == extension) { 117 0 : return ""; 118 0 : } else if (path.size() < extension.size()) { 119 0 : return path + extension; 120 : } else { 121 : // declare two reverse iterator for every string 122 : std::string::const_reverse_iterator it_path = path.rbegin(); 123 : std::string::const_reverse_iterator it_extension = extension.rbegin(); 124 : // iterate over extension and compare both characters 125 0 : while (it_extension != extension.rend()) { 126 : // if both characters are different, then return path + extension 127 0 : if (*it_path != *it_extension) { 128 0 : return path + extension; 129 : } 130 : it_path++; 131 : it_extension++; 132 : } 133 : // if comparison was successful, then the path has already the extension 134 : return path; 135 : } 136 : } 137 : 138 : 139 : std::string 140 146209 : FileHelpers::getConfigurationRelative(const std::string& configPath, const std::string& path) { 141 146209 : std::string retPath = getFilePath(configPath); 142 292418 : return retPath + path; 143 : } 144 : 145 : 146 : bool 147 204537 : FileHelpers::isSocket(const std::string& name) { 148 : const std::string::size_type colonPos = name.find(":"); 149 204537 : return (colonPos != std::string::npos) && (colonPos > 1); 150 : } 151 : 152 : 153 : bool 154 156731 : FileHelpers::isAbsolute(const std::string& path) { 155 156731 : if (isSocket(path)) { 156 : return true; 157 : } 158 : // check UNIX - absolute paths 159 156719 : if (path.length() > 0 && path[0] == '/') { 160 : return true; 161 : } 162 : // check Windows - absolute paths 163 156489 : if (path.length() > 0 && path[0] == '\\') { 164 : return true; 165 : } 166 156489 : if (path.length() > 1 && path[1] == ':') { 167 : return true; 168 : } 169 312978 : if (path == "nul" || path == "NUL") { 170 0 : return true; 171 : } 172 : return false; 173 : } 174 : 175 : 176 : std::string 177 140947 : FileHelpers::checkForRelativity(const std::string& filename, const std::string& basePath) { 178 422497 : if (filename == "stdout" || filename == "STDOUT" || filename == "-") { 179 174 : return "stdout"; 180 : } 181 281438 : if (filename == "stderr" || filename == "STDERR") { 182 108 : return "stderr"; 183 : } 184 281318 : if (filename == "nul" || filename == "NUL") { 185 878 : return "/dev/null"; 186 : } 187 139787 : if (!isAbsolute(filename)) { 188 139581 : return getConfigurationRelative(basePath, filename); 189 : } 190 : return filename; 191 : } 192 : 193 : 194 : std::string 195 0 : FileHelpers::getCurrentDir() { 196 : char buffer[1024]; 197 : char* answer = getcwd(buffer, sizeof(buffer)); 198 0 : if (answer) { 199 0 : return answer; 200 : } 201 0 : return ""; 202 : } 203 : 204 : 205 : std::vector<std::string> 206 6876 : FileHelpers::splitDirs(const std::string& filename) { 207 : std::vector<std::string> result; 208 31462 : for (const std::string& d : StringTokenizer(filename, "\\/", true).getVector()) { 209 11486 : if (d == ".." && !result.empty() && result.back() != "..") { 210 10 : result.pop_back(); 211 34338 : } else if ((d == "" && result.empty()) || (d != "" && d != ".")) { 212 11462 : result.push_back(d); 213 : } 214 6876 : } 215 6876 : return result; 216 0 : } 217 : 218 : 219 : std::string 220 3445 : FileHelpers::fixRelative(const std::string& filename, const std::string& basePath, const bool force, std::string curDir) { 221 10331 : if (filename == "stdout" || filename == "STDOUT" || filename == "-") { 222 2 : return "stdout"; 223 : } 224 6886 : if (filename == "stderr" || filename == "STDERR") { 225 0 : return "stderr"; 226 : } 227 10329 : if (filename == "nul" || filename == "NUL" || filename == "/dev/null") { 228 0 : return "/dev/null"; 229 : } 230 3443 : if (isSocket(filename) || (isAbsolute(filename) && !force)) { 231 : return filename; 232 : } 233 3431 : std::vector<std::string> filePathSplit = splitDirs(filename); 234 3431 : std::vector<std::string> basePathSplit = splitDirs(basePath); 235 6854 : if (isAbsolute(filename) || isAbsolute(basePath) || basePathSplit[0] == "..") { 236 : // if at least one is absolute we need to make the other absolute too 237 : // the same is true if the basePath refers to a parent dir 238 12 : if (curDir == "") { 239 0 : curDir = getCurrentDir(); 240 : } 241 12 : if (!isAbsolute(filename)) { 242 16 : filePathSplit = splitDirs(curDir + "/" + filename); 243 : } 244 12 : if (!isAbsolute(basePath)) { 245 12 : basePathSplit = splitDirs(curDir + "/" + basePath); 246 : } 247 12 : if (filePathSplit[0] != basePathSplit[0]) { 248 : // don't try to make something relative on different windows disks 249 0 : return joinToString(filePathSplit, "/"); 250 : } 251 : } 252 4108 : while (!filePathSplit.empty() && !basePathSplit.empty() && filePathSplit[0] == basePathSplit[0]) { 253 : filePathSplit.erase(filePathSplit.begin()); 254 : basePathSplit.erase(basePathSplit.begin()); 255 : } 256 5991 : for (int i = 0; i < (int)basePathSplit.size() - 1; i++) { 257 5120 : filePathSplit.insert(filePathSplit.begin(), ".."); 258 : } 259 3431 : return joinToString(filePathSplit, "/"); 260 3431 : } 261 : 262 : 263 : std::string 264 1318 : FileHelpers::prependToLastPathComponent(const std::string& prefix, const std::string& path) { 265 : const std::string::size_type sep_index = path.find_last_of("\\/"); 266 1318 : if (sep_index == std::string::npos) { 267 84 : return prefix + path; 268 : } else { 269 3070 : return path.substr(0, sep_index + 1) + prefix + path.substr(sep_index + 1); 270 : } 271 : } 272 : 273 : // --------------------------------------------------------------------------- 274 : // binary reading/writing functions 275 : // --------------------------------------------------------------------------- 276 : 277 : std::ostream& 278 0 : FileHelpers::writeInt(std::ostream& strm, int value) { 279 0 : strm.write((char*) &value, sizeof(int)); 280 0 : return strm; 281 : } 282 : 283 : 284 : std::ostream& 285 0 : FileHelpers::writeFloat(std::ostream& strm, double value) { 286 0 : strm.write((char*) &value, sizeof(double)); 287 0 : return strm; 288 : } 289 : 290 : 291 : std::ostream& 292 0 : FileHelpers::writeByte(std::ostream& strm, unsigned char value) { 293 0 : strm.write((char*) &value, sizeof(char)); 294 0 : return strm; 295 : } 296 : 297 : 298 : std::ostream& 299 0 : FileHelpers::writeString(std::ostream& strm, const std::string& value) { 300 0 : int size = (int)value.length(); 301 : const char* cstr = value.c_str(); 302 0 : writeInt(strm, size); 303 0 : strm.write((char*) cstr, (std::streamsize)(sizeof(char)*size)); 304 0 : return strm; 305 : } 306 : 307 : 308 : std::ostream& 309 0 : FileHelpers::writeTime(std::ostream& strm, SUMOTime value) { 310 0 : strm.write((char*) &value, sizeof(SUMOTime)); 311 0 : return strm; 312 : } 313 : 314 : 315 : /****************************************************************************/