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 : /****************************************************************************/
|