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