LCOV - code coverage report
Current view: top level - src/utils/common - FileHelpers.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 62.1 % 116 72
Test Date: 2026-06-15 15:46:12 Functions: 57.9 % 19 11

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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              : #include <utils/xml/XMLSubSys.h>
      23              : 
      24              : #include <string>
      25              : #ifdef WIN32
      26              : // this is how fox does it in xincs.h
      27              : #include <io.h>
      28              : #define access _access
      29              : #define R_OK    4       /* Test for read permission.  */
      30              : #include <direct.h>
      31              : #define getcwd _getcwd // stupid MSFT "deprecation" warning
      32              : #else
      33              : #include <unistd.h>
      34              : #endif
      35              : #include <fstream>
      36              : #include <sys/stat.h>
      37              : #include "FileHelpers.h"
      38              : #include "StringTokenizer.h"
      39              : #include "StringUtils.h"
      40              : #include "MsgHandler.h"
      41              : 
      42              : 
      43              : // ===========================================================================
      44              : // method definitions
      45              : // ===========================================================================
      46              : 
      47              : // ---------------------------------------------------------------------------
      48              : // file access functions
      49              : // ---------------------------------------------------------------------------
      50              : 
      51              : bool
      52       453440 : FileHelpers::isReadable(std::string path) {
      53       453440 :     if (path.length() == 0) {
      54              :         return false;
      55              :     }
      56       453440 :     while (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\') {
      57              :         path.erase(path.end() - 1);
      58              :     }
      59       453440 :     if (path.length() == 0) {
      60              :         return false;
      61              :     }
      62       453440 :     return access(XMLSubSys::transcodeToLocal(path).c_str(), R_OK) == 0;
      63              : }
      64              : 
      65              : bool
      66       186984 : FileHelpers::isDirectory(std::string path) {
      67              : #ifdef _MSC_VER
      68              :     struct _stat64 fileInfo;
      69              :     if (_stat64(XMLSubSys::transcodeToLocal(path).c_str(), &fileInfo) != 0) {
      70              : #else
      71              :     struct stat fileInfo;
      72       373968 :     if (stat(XMLSubSys::transcodeToLocal(path).c_str(), &fileInfo) != 0) {
      73              : #endif
      74            0 :         throw ProcessError(TLF("Cannot get file attributes for file '%'!", path));
      75              :     }
      76       186984 :     return (fileInfo.st_mode & S_IFMT) == S_IFDIR;
      77              : }
      78              : 
      79              : // ---------------------------------------------------------------------------
      80              : // file path evaluating functions
      81              : // ---------------------------------------------------------------------------
      82              : 
      83              : std::string
      84       232992 : FileHelpers::getFilePath(const std::string& path) {
      85              :     const auto beg = path.find_last_of("\\/");
      86       232992 :     if (beg == std::string::npos) {
      87       220289 :         return "";
      88              :     }
      89        12703 :     return path.substr(0, beg + 1);
      90              : }
      91              : 
      92              : 
      93              : std::string
      94            0 : FileHelpers::getFileFromPath(std::string path, const bool removeExtension) {
      95              :     // first remove extension
      96            0 :     if (removeExtension) {
      97              :         const auto begExtension = path.find_last_of(".");
      98            0 :         if (begExtension != std::string::npos) {
      99            0 :             path = path.substr(0, begExtension);
     100              :         }
     101              :     }
     102              :     // now remove path
     103              :     const auto begPath = path.find_last_of("\\/");
     104            0 :     if (begPath != std::string::npos) {
     105            0 :         path = path.substr(begPath + 1, path.size());
     106              :     }
     107            0 :     return path;
     108              : }
     109              : 
     110              : 
     111              : std::string
     112            0 : FileHelpers::addExtension(const std::string& path, const std::string& extension) {
     113            0 :     if (path.empty()) {
     114            0 :         return "";
     115            0 :     } else if (extension.empty()) {
     116              :         return path;
     117            0 :     } else if (path == extension) {
     118            0 :         return "";
     119            0 :     } else if (path.size() < extension.size()) {
     120              :         return path + extension;
     121              :     } else {
     122              :         // declare two reverse iterator for every string
     123              :         std::string::const_reverse_iterator it_path = path.rbegin();
     124              :         std::string::const_reverse_iterator it_extension = extension.rbegin();
     125              :         // iterate over extension and compare both characters
     126            0 :         while (it_extension != extension.rend()) {
     127              :             // if both characters are different, then return path + extension
     128            0 :             if (*it_path != *it_extension) {
     129              :                 return path + extension;
     130              :             }
     131              :             it_path++;
     132              :             it_extension++;
     133              :         }
     134              :         // if comparison was successful, then the path has already the extension
     135              :         return path;
     136              :     }
     137              : }
     138              : 
     139              : 
     140              : std::string
     141       232155 : FileHelpers::getConfigurationRelative(const std::string& configPath, const std::string& path) {
     142       232155 :     std::string retPath = getFilePath(configPath);
     143       232155 :     return retPath + path;
     144              : }
     145              : 
     146              : 
     147              : bool
     148       330573 : FileHelpers::isSocket(const std::string& name) {
     149              :     const std::string::size_type colonPos = name.find(":");
     150       330573 :     return (colonPos != std::string::npos) && (colonPos > 1 || name[0] == '[');
     151              : }
     152              : 
     153              : 
     154              : bool
     155       240100 : FileHelpers::isAbsolute(const std::string& path) {
     156       240100 :     if (isSocket(path)) {
     157              :         return true;
     158              :     }
     159              :     // check UNIX - absolute paths
     160       240095 :     if (path.length() > 0 && path[0] == '/') {
     161              :         return true;
     162              :     }
     163              :     // check Windows - absolute paths
     164       239835 :     if (path.length() > 0 && path[0] == '\\') {
     165              :         return true;
     166              :     }
     167       239835 :     if (path.length() > 1 && path[1] == ':') {
     168              :         return true;
     169              :     }
     170       239835 :     if (path == "nul" || path == "NUL") {
     171              :         return true;
     172              :     }
     173              :     return false;
     174              : }
     175              : 
     176              : 
     177              : std::string
     178       228752 : FileHelpers::checkForRelativity(const std::string& filename, const std::string& basePath) {
     179       228752 :     if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
     180          145 :         return "stdout";
     181              :     }
     182       228607 :     if (filename == "stderr" || filename == "STDERR") {
     183          112 :         return "stderr";
     184              :     }
     185       228495 :     if (filename == "nul" || filename == "NUL") {
     186         1029 :         return "/dev/null";
     187              :     }
     188       227466 :     if (!isAbsolute(filename)) {
     189       227218 :         return getConfigurationRelative(basePath, filename);
     190              :     }
     191              :     return filename;
     192              : }
     193              : 
     194              : 
     195              : std::string
     196            0 : FileHelpers::getCurrentDir() {
     197              :     char buffer[1024];
     198              :     char* answer = getcwd(buffer, sizeof(buffer));
     199            0 :     if (answer) {
     200            0 :         return answer;
     201              :     }
     202            0 :     return "";
     203              : }
     204              : 
     205              : 
     206              : std::vector<std::string>
     207         5135 : FileHelpers::splitDirs(const std::string& filename) {
     208              :     std::vector<std::string> result;
     209        23785 :     for (const std::string& d : StringTokenizer(filename, "\\/", true).getVector()) {
     210         8380 :         if (d == ".." && !result.empty() && result.back() != "..") {
     211              :             result.pop_back();
     212         8375 :         } else if ((d == "" && result.empty()) || (d != "" && d != ".")) {
     213         8375 :             result.push_back(d);
     214              :         }
     215         5135 :     }
     216         5135 :     return result;
     217            0 : }
     218              : 
     219              : 
     220              : std::string
     221         2571 : FileHelpers::fixRelative(const std::string& filename, const std::string& basePath, const bool force, std::string curDir) {
     222         2571 :     if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
     223            1 :         return "stdout";
     224              :     }
     225         2570 :     if (filename == "stderr" || filename == "STDERR") {
     226            0 :         return "stderr";
     227              :     }
     228         2570 :     if (filename == "nul" || filename == "NUL" || filename == "/dev/null") {
     229            0 :         return "/dev/null";
     230              :     }
     231         2570 :     if (isSocket(filename) || (isAbsolute(filename) && !force)) {
     232              :         return filename;
     233              :     }
     234         2564 :     std::vector<std::string> filePathSplit = splitDirs(filename);
     235         2564 :     std::vector<std::string> basePathSplit = splitDirs(basePath);
     236         2564 :     if (isAbsolute(filename) || isAbsolute(basePath) || basePathSplit[0] == "..") {
     237              :         // if at least one is absolute we need to make the other absolute too
     238              :         // the same is true if the basePath refers to a parent dir
     239            6 :         if (curDir == "") {
     240            0 :             curDir = getCurrentDir();
     241              :         }
     242            6 :         if (!isAbsolute(filename)) {
     243           12 :             filePathSplit = splitDirs(curDir + "/" + filename);
     244              :         }
     245            6 :         if (!isAbsolute(basePath)) {
     246            9 :             basePathSplit = splitDirs(curDir + "/" + basePath);
     247              :         }
     248            6 :         if (filePathSplit[0] != basePathSplit[0]) {
     249              :             // don't try to make something relative on different windows disks
     250            0 :             return joinToString(filePathSplit, "/");
     251              :         }
     252              :     }
     253         3045 :     while (!filePathSplit.empty() && !basePathSplit.empty() && filePathSplit[0] == basePathSplit[0]) {
     254              :         filePathSplit.erase(filePathSplit.begin());
     255              :         basePathSplit.erase(basePathSplit.begin());
     256              :     }
     257         4530 :     for (int i = 0; i < (int)basePathSplit.size() - 1; i++) {
     258         3932 :         filePathSplit.insert(filePathSplit.begin(), "..");
     259              :     }
     260         2564 :     return joinToString(filePathSplit, "/");
     261         2564 : }
     262              : 
     263              : 
     264              : std::string
     265         1096 : FileHelpers::prependToLastPathComponent(const std::string& prefix, const std::string& path) {
     266              :     const std::string::size_type sep_index = path.find_last_of("\\/");
     267         1096 :     if (sep_index == std::string::npos) {
     268              :         return prefix + path;
     269              :     } else {
     270         3063 :         return path.substr(0, sep_index + 1) + prefix + path.substr(sep_index + 1);
     271              :     }
     272              : }
     273              : 
     274              : 
     275              : std::string
     276          214 : FileHelpers::appendBeforeExtension(const std::string& path, const std::string& suffix, bool checkSep) {
     277          214 :     if (checkSep) {
     278              :         const std::string::size_type sep_index = path.find_last_of("\\/");
     279          107 :         if (sep_index == std::string::npos) {
     280          107 :             return appendBeforeExtension(path, suffix, false);
     281              :         } else {
     282            0 :             return path.substr(0, sep_index + 1) + appendBeforeExtension(path.substr(sep_index + 1), suffix, false);
     283              :         }
     284              :     }
     285          321 :     auto components = StringTokenizer(path, ".").getVector();
     286          214 :     for (int i = (int)components.size() - 1; i >= 0; i--) {
     287              :         // assume anything after a dot with less then 5 letters is part of the extension
     288          214 :         if (i == 0 || components[i].size() > 4) {
     289          107 :             components[i] += suffix;
     290              :             break;
     291              :         }
     292              :     }
     293          107 :     return joinToString(components, ".");
     294          107 : }
     295              : 
     296              : 
     297              : // ---------------------------------------------------------------------------
     298              : // binary reading/writing functions
     299              : // ---------------------------------------------------------------------------
     300              : 
     301              : std::ostream&
     302            0 : FileHelpers::writeInt(std::ostream& strm, int value) {
     303            0 :     strm.write((char*) &value, sizeof(int));
     304            0 :     return strm;
     305              : }
     306              : 
     307              : 
     308              : std::ostream&
     309            0 : FileHelpers::writeFloat(std::ostream& strm, double value) {
     310            0 :     strm.write((char*) &value, sizeof(double));
     311            0 :     return strm;
     312              : }
     313              : 
     314              : 
     315              : std::ostream&
     316            0 : FileHelpers::writeByte(std::ostream& strm, unsigned char value) {
     317            0 :     strm.write((char*) &value, sizeof(char));
     318            0 :     return strm;
     319              : }
     320              : 
     321              : 
     322              : std::ostream&
     323            0 : FileHelpers::writeString(std::ostream& strm, const std::string& value) {
     324            0 :     int size = (int)value.length();
     325              :     const char* cstr = value.c_str();
     326            0 :     writeInt(strm, size);
     327            0 :     strm.write((char*) cstr, (std::streamsize)(sizeof(char)*size));
     328            0 :     return strm;
     329              : }
     330              : 
     331              : 
     332              : std::ostream&
     333            0 : FileHelpers::writeTime(std::ostream& strm, SUMOTime value) {
     334            0 :     strm.write((char*) &value, sizeof(SUMOTime));
     335            0 :     return strm;
     336              : }
     337              : 
     338              : 
     339              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1