Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
FileHelpers.cpp
Go to the documentation of this file.
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/****************************************************************************/
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
51bool
52FileHelpers::isReadable(std::string path) {
53 if (path.length() == 0) {
54 return false;
55 }
56 while (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\') {
57 path.erase(path.end() - 1);
58 }
59 if (path.length() == 0) {
60 return false;
61 }
62 return access(XMLSubSys::transcodeToLocal(path).c_str(), R_OK) == 0;
63}
64
65bool
66FileHelpers::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 if (stat(XMLSubSys::transcodeToLocal(path).c_str(), &fileInfo) != 0) {
73#endif
74 throw ProcessError(TLF("Cannot get file attributes for file '%'!", path));
75 }
76 return (fileInfo.st_mode & S_IFMT) == S_IFDIR;
77}
78
79// ---------------------------------------------------------------------------
80// file path evaluating functions
81// ---------------------------------------------------------------------------
82
83std::string
84FileHelpers::getFilePath(const std::string& path) {
85 const auto beg = path.find_last_of("\\/");
86 if (beg == std::string::npos) {
87 return "";
88 }
89 return path.substr(0, beg + 1);
90}
91
92
93std::string
94FileHelpers::getFileFromPath(std::string path, const bool removeExtension) {
95 // first remove extension
96 if (removeExtension) {
97 const auto begExtension = path.find_last_of(".");
98 if (begExtension != std::string::npos) {
99 path = path.substr(0, begExtension);
100 }
101 }
102 // now remove path
103 const auto begPath = path.find_last_of("\\/");
104 if (begPath != std::string::npos) {
105 path = path.substr(begPath + 1, path.size());
106 }
107 return path;
108}
109
110
111std::string
112FileHelpers::addExtension(const std::string& path, const std::string& extension) {
113 if (path.empty()) {
114 return "";
115 } else if (extension.empty()) {
116 return path;
117 } else if (path == extension) {
118 return "";
119 } 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 while (it_extension != extension.rend()) {
127 // if both characters are different, then return path + extension
128 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
140std::string
141FileHelpers::getConfigurationRelative(const std::string& configPath, const std::string& path) {
142 std::string retPath = getFilePath(configPath);
143 return retPath + path;
144}
145
146
147bool
148FileHelpers::isSocket(const std::string& name) {
149 const std::string::size_type colonPos = name.find(":");
150 return (colonPos != std::string::npos) && (colonPos > 1 || name[0] == '[');
151}
152
153
154bool
155FileHelpers::isAbsolute(const std::string& path) {
156 if (isSocket(path)) {
157 return true;
158 }
159 // check UNIX - absolute paths
160 if (path.length() > 0 && path[0] == '/') {
161 return true;
162 }
163 // check Windows - absolute paths
164 if (path.length() > 0 && path[0] == '\\') {
165 return true;
166 }
167 if (path.length() > 1 && path[1] == ':') {
168 return true;
169 }
170 if (path == "nul" || path == "NUL") {
171 return true;
172 }
173 return false;
174}
175
176
177std::string
178FileHelpers::checkForRelativity(const std::string& filename, const std::string& basePath) {
179 if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
180 return "stdout";
181 }
182 if (filename == "stderr" || filename == "STDERR") {
183 return "stderr";
184 }
185 if (filename == "nul" || filename == "NUL") {
186 return "/dev/null";
187 }
188 if (!isAbsolute(filename)) {
189 return getConfigurationRelative(basePath, filename);
190 }
191 return filename;
192}
193
194
195std::string
197 char buffer[1024];
198 char* answer = getcwd(buffer, sizeof(buffer));
199 if (answer) {
200 return answer;
201 }
202 return "";
203}
204
205
206std::vector<std::string>
207FileHelpers::splitDirs(const std::string& filename) {
208 std::vector<std::string> result;
209 for (const std::string& d : StringTokenizer(filename, "\\/", true).getVector()) {
210 if (d == ".." && !result.empty() && result.back() != "..") {
211 result.pop_back();
212 } else if ((d == "" && result.empty()) || (d != "" && d != ".")) {
213 result.push_back(d);
214 }
215 }
216 return result;
217}
218
219
220std::string
221FileHelpers::fixRelative(const std::string& filename, const std::string& basePath, const bool force, std::string curDir) {
222 if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
223 return "stdout";
224 }
225 if (filename == "stderr" || filename == "STDERR") {
226 return "stderr";
227 }
228 if (filename == "nul" || filename == "NUL" || filename == "/dev/null") {
229 return "/dev/null";
230 }
231 if (isSocket(filename) || (isAbsolute(filename) && !force)) {
232 return filename;
233 }
234 std::vector<std::string> filePathSplit = splitDirs(filename);
235 std::vector<std::string> basePathSplit = splitDirs(basePath);
236 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 if (curDir == "") {
240 curDir = getCurrentDir();
241 }
242 if (!isAbsolute(filename)) {
243 filePathSplit = splitDirs(curDir + "/" + filename);
244 }
245 if (!isAbsolute(basePath)) {
246 basePathSplit = splitDirs(curDir + "/" + basePath);
247 }
248 if (filePathSplit[0] != basePathSplit[0]) {
249 // don't try to make something relative on different windows disks
250 return joinToString(filePathSplit, "/");
251 }
252 }
253 while (!filePathSplit.empty() && !basePathSplit.empty() && filePathSplit[0] == basePathSplit[0]) {
254 filePathSplit.erase(filePathSplit.begin());
255 basePathSplit.erase(basePathSplit.begin());
256 }
257 for (int i = 0; i < (int)basePathSplit.size() - 1; i++) {
258 filePathSplit.insert(filePathSplit.begin(), "..");
259 }
260 return joinToString(filePathSplit, "/");
261}
262
263
264std::string
265FileHelpers::prependToLastPathComponent(const std::string& prefix, const std::string& path) {
266 const std::string::size_type sep_index = path.find_last_of("\\/");
267 if (sep_index == std::string::npos) {
268 return prefix + path;
269 } else {
270 return path.substr(0, sep_index + 1) + prefix + path.substr(sep_index + 1);
271 }
272}
273
274
275std::string
276FileHelpers::appendBeforeExtension(const std::string& path, const std::string& suffix, bool checkSep) {
277 if (checkSep) {
278 const std::string::size_type sep_index = path.find_last_of("\\/");
279 if (sep_index == std::string::npos) {
280 return appendBeforeExtension(path, suffix, false);
281 } else {
282 return path.substr(0, sep_index + 1) + appendBeforeExtension(path.substr(sep_index + 1), suffix, false);
283 }
284 }
285 auto components = StringTokenizer(path, ".").getVector();
286 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 if (i == 0 || components[i].size() > 4) {
289 components[i] += suffix;
290 break;
291 }
292 }
293 return joinToString(components, ".");
294}
295
296
297// ---------------------------------------------------------------------------
298// binary reading/writing functions
299// ---------------------------------------------------------------------------
300
301std::ostream&
302FileHelpers::writeInt(std::ostream& strm, int value) {
303 strm.write((char*) &value, sizeof(int));
304 return strm;
305}
306
307
308std::ostream&
309FileHelpers::writeFloat(std::ostream& strm, double value) {
310 strm.write((char*) &value, sizeof(double));
311 return strm;
312}
313
314
315std::ostream&
316FileHelpers::writeByte(std::ostream& strm, unsigned char value) {
317 strm.write((char*) &value, sizeof(char));
318 return strm;
319}
320
321
322std::ostream&
323FileHelpers::writeString(std::ostream& strm, const std::string& value) {
324 int size = (int)value.length();
325 const char* cstr = value.c_str();
326 writeInt(strm, size);
327 strm.write((char*) cstr, (std::streamsize)(sizeof(char)*size));
328 return strm;
329}
330
331
332std::ostream&
333FileHelpers::writeTime(std::ostream& strm, SUMOTime value) {
334 strm.write((char*) &value, sizeof(SUMOTime));
335 return strm;
336}
337
338
339/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define TLF(string,...)
Definition MsgHandler.h:306
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:314
static std::string fixRelative(const std::string &filename, const std::string &basePath, const bool force, std::string curDir="")
Fixes the relative path for the given filename in relation to the basePath (usually a config file).
static bool isAbsolute(const std::string &path)
Returns the information whether the given path is absolute.
static std::ostream & writeFloat(std::ostream &strm, double value)
Writes a float binary.
static std::string getConfigurationRelative(const std::string &configPath, const std::string &path)
Returns the second path as a relative path to the first file.
static std::string checkForRelativity(const std::string &filename, const std::string &basePath)
Returns the path from a configuration so that it is accessible from the current working directory.
static std::string addExtension(const std::string &path, const std::string &extension)
Add an extension to the given file path.
static std::ostream & writeString(std::ostream &strm, const std::string &value)
Writes a string binary.
static bool isReadable(std::string path)
Checks whether the given file is readable.
static std::string appendBeforeExtension(const std::string &path, const std::string &suffix, bool checkSep=true)
append the given suffix after the file name but before the extension
static std::vector< std::string > splitDirs(const std::string &filename)
Splits the given file path into directory components.
static std::string getFilePath(const std::string &path)
Removes the file information from the given path.
static std::ostream & writeTime(std::ostream &strm, SUMOTime value)
Writes a time description binary.
static std::ostream & writeInt(std::ostream &strm, int value)
Writes an integer binary.
static bool isSocket(const std::string &name)
Returns the information whether the given name represents a socket.
static std::string getFileFromPath(std::string path, const bool removeExtension)
Removes the path information from the given path.
static bool isDirectory(std::string path)
Checks whether the given file is a directory.
static std::string getCurrentDir()
Get the current working directory.
static std::ostream & writeByte(std::ostream &strm, unsigned char value)
Writes a byte binary.
static std::string prependToLastPathComponent(const std::string &prefix, const std::string &path)
prepend the given prefix to the last path component of the given file path
std::vector< std::string > getVector()
return vector of strings
static std::string transcodeToLocal(const std::string &utf8String)
convert a string from UTF-8 to the local codepage