LCOV - code coverage report
Current view: top level - src/utils/common - FileHelpers.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 53.4 % 116 62
Test Date: 2025-12-06 15:35:27 Functions: 52.6 % 19 10

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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       393916 : FileHelpers::isReadable(std::string path) {
      52       393916 :     if (path.length() == 0) {
      53              :         return false;
      54              :     }
      55       393916 :     while (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\') {
      56              :         path.erase(path.end() - 1);
      57              :     }
      58       393916 :     if (path.length() == 0) {
      59              :         return false;
      60              :     }
      61       393916 :     return access(StringUtils::transcodeToLocal(path).c_str(), R_OK) == 0;
      62              : }
      63              : 
      64              : bool
      65       163709 : 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       327418 :     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       163709 :     return (fileInfo.st_mode & S_IFMT) == S_IFDIR;
      76              : }
      77              : 
      78              : // ---------------------------------------------------------------------------
      79              : // file path evaluating functions
      80              : // ---------------------------------------------------------------------------
      81              : 
      82              : std::string
      83       200514 : FileHelpers::getFilePath(const std::string& path) {
      84              :     const auto beg = path.find_last_of("\\/");
      85       200514 :     if (beg == std::string::npos) {
      86       187811 :         return "";
      87              :     }
      88        12703 :     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              :         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              :                 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       199677 : FileHelpers::getConfigurationRelative(const std::string& configPath, const std::string& path) {
     141       199677 :     std::string retPath = getFilePath(configPath);
     142       199677 :     return retPath + path;
     143              : }
     144              : 
     145              : 
     146              : bool
     147       289705 : FileHelpers::isSocket(const std::string& name) {
     148              :     const std::string::size_type colonPos = name.find(":");
     149       289705 :     return (colonPos != std::string::npos) && (colonPos > 1 || name[0] == '[');
     150              : }
     151              : 
     152              : 
     153              : bool
     154       207478 : FileHelpers::isAbsolute(const std::string& path) {
     155       207478 :     if (isSocket(path)) {
     156              :         return true;
     157              :     }
     158              :     // check UNIX - absolute paths
     159       207471 :     if (path.length() > 0 && path[0] == '/') {
     160              :         return true;
     161              :     }
     162              :     // check Windows - absolute paths
     163       207358 :     if (path.length() > 0 && path[0] == '\\') {
     164              :         return true;
     165              :     }
     166       207358 :     if (path.length() > 1 && path[1] == ':') {
     167              :         return true;
     168              :     }
     169       207358 :     if (path == "nul" || path == "NUL") {
     170              :         return true;
     171              :     }
     172              :     return false;
     173              : }
     174              : 
     175              : 
     176              : std::string
     177       195893 : FileHelpers::checkForRelativity(const std::string& filename, const std::string& basePath) {
     178       195893 :     if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
     179          145 :         return "stdout";
     180              :     }
     181       195748 :     if (filename == "stderr" || filename == "STDERR") {
     182          112 :         return "stderr";
     183              :     }
     184       195636 :     if (filename == "nul" || filename == "NUL") {
     185          790 :         return "/dev/null";
     186              :     }
     187       194846 :     if (!isAbsolute(filename)) {
     188       194743 :         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         5135 : FileHelpers::splitDirs(const std::string& filename) {
     207              :     std::vector<std::string> result;
     208        23785 :     for (const std::string& d : StringTokenizer(filename, "\\/", true).getVector()) {
     209         8380 :         if (d == ".." && !result.empty() && result.back() != "..") {
     210              :             result.pop_back();
     211         8375 :         } else if ((d == "" && result.empty()) || (d != "" && d != ".")) {
     212         8375 :             result.push_back(d);
     213              :         }
     214         5135 :     }
     215         5135 :     return result;
     216            0 : }
     217              : 
     218              : 
     219              : std::string
     220         2571 : FileHelpers::fixRelative(const std::string& filename, const std::string& basePath, const bool force, std::string curDir) {
     221         2571 :     if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
     222            1 :         return "stdout";
     223              :     }
     224         2570 :     if (filename == "stderr" || filename == "STDERR") {
     225            0 :         return "stderr";
     226              :     }
     227         2570 :     if (filename == "nul" || filename == "NUL" || filename == "/dev/null") {
     228            0 :         return "/dev/null";
     229              :     }
     230         2570 :     if (isSocket(filename) || (isAbsolute(filename) && !force)) {
     231              :         return filename;
     232              :     }
     233         2564 :     std::vector<std::string> filePathSplit = splitDirs(filename);
     234         2564 :     std::vector<std::string> basePathSplit = splitDirs(basePath);
     235         2564 :     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            6 :         if (curDir == "") {
     239            0 :             curDir = getCurrentDir();
     240              :         }
     241            6 :         if (!isAbsolute(filename)) {
     242           12 :             filePathSplit = splitDirs(curDir + "/" + filename);
     243              :         }
     244            6 :         if (!isAbsolute(basePath)) {
     245            9 :             basePathSplit = splitDirs(curDir + "/" + basePath);
     246              :         }
     247            6 :         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         3045 :     while (!filePathSplit.empty() && !basePathSplit.empty() && filePathSplit[0] == basePathSplit[0]) {
     253              :         filePathSplit.erase(filePathSplit.begin());
     254              :         basePathSplit.erase(basePathSplit.begin());
     255              :     }
     256         4530 :     for (int i = 0; i < (int)basePathSplit.size() - 1; i++) {
     257         3932 :         filePathSplit.insert(filePathSplit.begin(), "..");
     258              :     }
     259         2564 :     return joinToString(filePathSplit, "/");
     260         2564 : }
     261              : 
     262              : 
     263              : std::string
     264         1078 : FileHelpers::prependToLastPathComponent(const std::string& prefix, const std::string& path) {
     265              :     const std::string::size_type sep_index = path.find_last_of("\\/");
     266         1078 :     if (sep_index == std::string::npos) {
     267              :         return prefix + path;
     268              :     } else {
     269         3063 :         return path.substr(0, sep_index + 1) + prefix + path.substr(sep_index + 1);
     270              :     }
     271              : }
     272              : 
     273              : 
     274              : std::string
     275            0 : FileHelpers::appendBeforeExtension(const std::string& path, const std::string& suffix, bool checkSep) {
     276            0 :     if (checkSep) {
     277              :         const std::string::size_type sep_index = path.find_last_of("\\/");
     278            0 :         if (sep_index == std::string::npos) {
     279            0 :             return appendBeforeExtension(path, suffix, false);
     280              :         } else {
     281            0 :             return path.substr(0, sep_index + 1) + appendBeforeExtension(path.substr(sep_index + 1), suffix, false);
     282              :         }
     283              :     }
     284            0 :     auto components = StringTokenizer(path, ".").getVector();
     285            0 :     for (int i = components.size() - 1; i >= 0; i--) {
     286              :         // assume anything after a dot with less then 5 letters is part of the extension
     287            0 :         if (i == 0 || components[i].size() > 4) {
     288            0 :             components[i] += suffix;
     289              :             break;
     290              :         }
     291              :     }
     292            0 :     return joinToString(components, ".");
     293            0 : }
     294              : 
     295              : 
     296              : // ---------------------------------------------------------------------------
     297              : // binary reading/writing functions
     298              : // ---------------------------------------------------------------------------
     299              : 
     300              : std::ostream&
     301            0 : FileHelpers::writeInt(std::ostream& strm, int value) {
     302            0 :     strm.write((char*) &value, sizeof(int));
     303            0 :     return strm;
     304              : }
     305              : 
     306              : 
     307              : std::ostream&
     308            0 : FileHelpers::writeFloat(std::ostream& strm, double value) {
     309            0 :     strm.write((char*) &value, sizeof(double));
     310            0 :     return strm;
     311              : }
     312              : 
     313              : 
     314              : std::ostream&
     315            0 : FileHelpers::writeByte(std::ostream& strm, unsigned char value) {
     316            0 :     strm.write((char*) &value, sizeof(char));
     317            0 :     return strm;
     318              : }
     319              : 
     320              : 
     321              : std::ostream&
     322            0 : FileHelpers::writeString(std::ostream& strm, const std::string& value) {
     323            0 :     int size = (int)value.length();
     324              :     const char* cstr = value.c_str();
     325            0 :     writeInt(strm, size);
     326            0 :     strm.write((char*) cstr, (std::streamsize)(sizeof(char)*size));
     327            0 :     return strm;
     328              : }
     329              : 
     330              : 
     331              : std::ostream&
     332            0 : FileHelpers::writeTime(std::ostream& strm, SUMOTime value) {
     333            0 :     strm.write((char*) &value, sizeof(SUMOTime));
     334            0 :     return strm;
     335              : }
     336              : 
     337              : 
     338              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1