Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 445245 : FileHelpers::isReadable(std::string path) {
52 445245 : if (path.length() == 0) {
53 : return false;
54 : }
55 445245 : while (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\') {
56 : path.erase(path.end() - 1);
57 : }
58 445245 : if (path.length() == 0) {
59 : return false;
60 : }
61 445245 : return access(StringUtils::transcodeToLocal(path).c_str(), R_OK) == 0;
62 : }
63 :
64 : bool
65 188799 : 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 377598 : 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 188799 : return (fileInfo.st_mode & S_IFMT) == S_IFDIR;
76 : }
77 :
78 : // ---------------------------------------------------------------------------
79 : // file path evaluating functions
80 : // ---------------------------------------------------------------------------
81 :
82 : std::string
83 171093 : FileHelpers::getFilePath(const std::string& path) {
84 : const auto beg = path.find_last_of("\\/");
85 171093 : if (beg == std::string::npos) {
86 161085 : return "";
87 : }
88 10008 : 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 170256 : FileHelpers::getConfigurationRelative(const std::string& configPath, const std::string& path) {
141 170256 : std::string retPath = getFilePath(configPath);
142 170256 : return retPath + path;
143 : }
144 :
145 :
146 : bool
147 243351 : FileHelpers::isSocket(const std::string& name) {
148 : const std::string::size_type colonPos = name.find(":");
149 243351 : return (colonPos != std::string::npos) && (colonPos > 1 || name[0] == '[');
150 : }
151 :
152 :
153 : bool
154 175582 : FileHelpers::isAbsolute(const std::string& path) {
155 175582 : if (isSocket(path)) {
156 : return true;
157 : }
158 : // check UNIX - absolute paths
159 175575 : if (path.length() > 0 && path[0] == '/') {
160 : return true;
161 : }
162 : // check Windows - absolute paths
163 175419 : if (path.length() > 0 && path[0] == '\\') {
164 : return true;
165 : }
166 175419 : if (path.length() > 1 && path[1] == ':') {
167 : return true;
168 : }
169 175419 : if (path == "nul" || path == "NUL") {
170 : return true;
171 : }
172 : return false;
173 : }
174 :
175 :
176 : std::string
177 167087 : FileHelpers::checkForRelativity(const std::string& filename, const std::string& basePath) {
178 167087 : if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
179 141 : return "stdout";
180 : }
181 166946 : if (filename == "stderr" || filename == "STDERR") {
182 108 : return "stderr";
183 : }
184 166838 : if (filename == "nul" || filename == "NUL") {
185 766 : return "/dev/null";
186 : }
187 166072 : if (!isAbsolute(filename)) {
188 165928 : 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 3455 : FileHelpers::splitDirs(const std::string& filename) {
207 : std::vector<std::string> result;
208 16077 : for (const std::string& d : StringTokenizer(filename, "\\/", true).getVector()) {
209 5712 : if (d == ".." && !result.empty() && result.back() != "..") {
210 : result.pop_back();
211 5707 : } else if ((d == "" && result.empty()) || (d != "" && d != ".")) {
212 5707 : result.push_back(d);
213 : }
214 3455 : }
215 3455 : return result;
216 0 : }
217 :
218 :
219 : std::string
220 1731 : FileHelpers::fixRelative(const std::string& filename, const std::string& basePath, const bool force, std::string curDir) {
221 1731 : if (filename == "stdout" || filename == "STDOUT" || filename == "-") {
222 1 : return "stdout";
223 : }
224 1730 : if (filename == "stderr" || filename == "STDERR") {
225 0 : return "stderr";
226 : }
227 1730 : if (filename == "nul" || filename == "NUL" || filename == "/dev/null") {
228 0 : return "/dev/null";
229 : }
230 1730 : if (isSocket(filename) || (isAbsolute(filename) && !force)) {
231 : return filename;
232 : }
233 1724 : std::vector<std::string> filePathSplit = splitDirs(filename);
234 1724 : std::vector<std::string> basePathSplit = splitDirs(basePath);
235 1724 : 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 2063 : while (!filePathSplit.empty() && !basePathSplit.empty() && filePathSplit[0] == basePathSplit[0]) {
253 : filePathSplit.erase(filePathSplit.begin());
254 : basePathSplit.erase(basePathSplit.begin());
255 : }
256 3004 : for (int i = 0; i < (int)basePathSplit.size() - 1; i++) {
257 2560 : filePathSplit.insert(filePathSplit.begin(), "..");
258 : }
259 1724 : return joinToString(filePathSplit, "/");
260 1724 : }
261 :
262 :
263 : std::string
264 674 : FileHelpers::prependToLastPathComponent(const std::string& prefix, const std::string& path) {
265 : const std::string::size_type sep_index = path.find_last_of("\\/");
266 674 : if (sep_index == std::string::npos) {
267 : return prefix + path;
268 : } else {
269 1851 : return path.substr(0, sep_index + 1) + prefix + path.substr(sep_index + 1);
270 : }
271 : }
272 :
273 : // ---------------------------------------------------------------------------
274 : // binary reading/writing functions
275 : // ---------------------------------------------------------------------------
276 :
277 : std::ostream&
278 0 : FileHelpers::writeInt(std::ostream& strm, int value) {
279 0 : strm.write((char*) &value, sizeof(int));
280 0 : return strm;
281 : }
282 :
283 :
284 : std::ostream&
285 0 : FileHelpers::writeFloat(std::ostream& strm, double value) {
286 0 : strm.write((char*) &value, sizeof(double));
287 0 : return strm;
288 : }
289 :
290 :
291 : std::ostream&
292 0 : FileHelpers::writeByte(std::ostream& strm, unsigned char value) {
293 0 : strm.write((char*) &value, sizeof(char));
294 0 : return strm;
295 : }
296 :
297 :
298 : std::ostream&
299 0 : FileHelpers::writeString(std::ostream& strm, const std::string& value) {
300 0 : int size = (int)value.length();
301 : const char* cstr = value.c_str();
302 0 : writeInt(strm, size);
303 0 : strm.write((char*) cstr, (std::streamsize)(sizeof(char)*size));
304 0 : return strm;
305 : }
306 :
307 :
308 : std::ostream&
309 0 : FileHelpers::writeTime(std::ostream& strm, SUMOTime value) {
310 0 : strm.write((char*) &value, sizeof(SUMOTime));
311 0 : return strm;
312 : }
313 :
314 :
315 : /****************************************************************************/
|