Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/common/FileHelpers.h
193873 views
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.h
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Jakob Erdmann
18
/// @date Mon, 17 Dec 2001
19
///
20
// Functions for an easier usage of files
21
/****************************************************************************/
22
#pragma once
23
#include <config.h>
24
#include <cassert>
25
#include <fstream>
26
#include <string>
27
#include <vector>
28
#include "SUMOTime.h"
29
30
31
// ===========================================================================
32
// class definitions
33
// ===========================================================================
34
/**
35
* @class FileHelpers
36
* @brief Functions for an easier usage of files and paths
37
*/
38
class FileHelpers {
39
public:
40
/// @name file access functions
41
/// @{
42
43
/** @brief Checks whether the given file is readable
44
*
45
* @param[in] path The path to the file that shall be examined
46
* @return Whether the named file is readable
47
*/
48
static bool isReadable(std::string path);
49
50
/** @brief Checks whether the given file is a directory
51
*
52
* @param[in] path The path to the file that shall be examined
53
* @return Whether the named file is a directory.
54
*/
55
static bool isDirectory(std::string path);
56
/// @}
57
58
/// @name file path evaluating functions
59
/// @{
60
61
/** @brief Removes the file information from the given path
62
*
63
* @param[in] path The path to the file to return the folder it is located in
64
* @return The directory of the named file
65
*/
66
static std::string getFilePath(const std::string& path);
67
68
/** @brief Removes the path information from the given path
69
*
70
* @param[in] path The path to the file to return the file (with extension)
71
* @return the named file (with extension)
72
*/
73
static std::string getFileFromPath(std::string path, const bool removeExtension);
74
75
/** @brief Add an extension to the given file path
76
*
77
* @param[in] path The path to the file
78
* @param[in] extension new extension (with dot, example: '.xml')
79
* @return the new path with extension, the same path if it already has the extension, or a empty string if path is invalid
80
*/
81
static std::string addExtension(const std::string& path, const std::string& extension);
82
83
/** @brief Returns the second path as a relative path to the first file
84
*
85
* Given the position of the configuration file, and the information where a second
86
* file is relative to the configuration file's position, we want to known where
87
* this second file can be found. This method gets the path to the configuration file
88
* (including the configuration file name) and the path to get the relative position
89
* of and returns this relative position.
90
*
91
* @param[in] configPath The path the configuration file (including the config's file name)
92
* @param[in] path The path to the references file (relativ to configuration path)
93
* @return The file's position (relative to curent working directory)
94
*/
95
static std::string getConfigurationRelative(const std::string& configPath, const std::string& path);
96
97
/** @brief Returns the information whether the given name represents a socket
98
*
99
* A file name is meant to describe a socket address if a colon is found at a position
100
* larger than one.
101
*
102
* @param[in] name The name of a file
103
* @return Whether the name names a socket
104
*/
105
static bool isSocket(const std::string& name);
106
107
/** @brief Returns the information whether the given path is absolute
108
*
109
* A path is meant to be absolute, if
110
* @arg it is a socket
111
* @arg it starts with a "/" (Linux)
112
* @arg it has a ':' at the second position (Windows)
113
*
114
* @param[in] path The path to examine
115
* @return Whether the path is absolute
116
*/
117
static bool isAbsolute(const std::string& path);
118
119
/** @brief Returns the path from a configuration so that it is accessible from the current working directory
120
*
121
* If the path is absolute, it is returned. Otherwise, the file's position
122
* is computed regarding the configuration path (see getConfigurationRelative).
123
*
124
* @see isAbsolute
125
* @see getConfigurationRelative
126
* @param[in] filename The path to the file to be examined
127
* @param[in] basePath The path the configuration file (including the config's file name)
128
* @return The file's position
129
*/
130
static std::string checkForRelativity(const std::string& filename, const std::string& basePath);
131
132
/** @brief Get the current working directory
133
*
134
* @return The working directory (pwd)
135
*/
136
static std::string getCurrentDir();
137
138
/** @brief Splits the given file path into directory components.
139
*
140
* The path gets normalized such that redundant "." and empty components are removed.
141
* Furthermore it will not contain a ".." after a directory name.
142
*
143
* @param[in] filename The path of a file
144
* @return the list parent directories
145
*/
146
static std::vector<std::string> splitDirs(const std::string& filename);
147
148
/** @brief Fixes the relative path for the given filename in relation to the basePath (usually a config file).
149
*
150
* @param[in] filename The path of a file
151
* @param[in] basePath The path of another file referring to the former
152
* @param[in] force whether the replacement should be made even if the filename is absolute
153
* @param[in] curDir the current working dir (mainly for easier testing), "" will trigger a call of getCurrentDir
154
* @return the corrected relative file path
155
*/
156
static std::string fixRelative(const std::string& filename, const std::string& basePath, const bool force, std::string curDir = "");
157
158
/// @brief prepend the given prefix to the last path component of the given file path
159
static std::string prependToLastPathComponent(const std::string& prefix, const std::string& path);
160
161
/// @brief append the given suffix after the file name but before the extension
162
static std::string appendBeforeExtension(const std::string& path, const std::string& suffix, bool checkSep = true);
163
/// @}
164
165
/// @name binary writing functions
166
/// @{
167
168
/** @brief Writes an integer binary
169
*
170
* @param[in, out] strm The stream to write into
171
* @param[in] value The integer to write
172
* @return Reference to the stream
173
*/
174
static std::ostream& writeInt(std::ostream& strm, int value);
175
176
/** @brief Writes a float binary
177
*
178
* This method behaves differently depending on the definition of double at compile time.
179
*
180
* @param[in, out] strm The stream to write into
181
* @param[in] value The float to write
182
* @return Reference to the stream
183
*/
184
static std::ostream& writeFloat(std::ostream& strm, double value);
185
186
/** @brief Writes a byte binary
187
*
188
* @param[in, out] strm The stream to write into
189
* @param[in] value The byte to write
190
* @return Reference to the stream
191
*/
192
static std::ostream& writeByte(std::ostream& strm, unsigned char value);
193
194
/** @brief Writes a string binary
195
*
196
* Writes the length of the string, first, using writeInt. Writes then the string's
197
* characters.
198
*
199
* @see writeInt
200
* @param[in, out] strm The stream to write into
201
* @param[in] value The string to write
202
* @return Reference to the stream
203
*/
204
static std::ostream& writeString(std::ostream& strm, const std::string& value);
205
206
/** @brief Writes a time description binary
207
*
208
* This method behaves differently depending on the definition of SUMOTime at compile time,
209
* which in turn depends on the enabling of subsecond timesteps.
210
*
211
* @param[in, out] strm The stream to write into
212
* @param[in] value The time to write
213
* @return Reference to the stream
214
*/
215
static std::ostream& writeTime(std::ostream& strm, SUMOTime value);
216
217
/** @brief Writes an edge vector binary
218
*
219
* @param[in, out] os The stream to write into
220
* @param[in] edges The edges to write
221
* @return Reference to the stream
222
*/
223
template <typename E>
224
static std::ostream& writeEdgeVector(std::ostream& os, const std::vector<E>& edges);
225
226
/** @brief Reads an edge vector binary
227
*
228
* @param[in] is The stream to read from
229
* @param[out] edges The edge vector to write into
230
* @return Reference to the stream
231
*/
232
template <typename E>
233
static void readEdgeVector(std::istream& in, std::vector<const E*>& edges, const std::string& rid);
234
/// @}
235
};
236
237
238
template <typename E>
239
std::ostream& FileHelpers::writeEdgeVector(std::ostream& os, const std::vector<E>& edges) {
240
FileHelpers::writeInt(os, (int)edges.size());
241
std::vector<int> follow;
242
int maxFollow = 0;
243
E prev = edges.front();
244
for (typename std::vector<E>::const_iterator i = edges.begin() + 1; i != edges.end(); ++i) {
245
int idx = 0;
246
for (; idx < prev->getNumSuccessors(); ++idx) {
247
if (idx > 15) {
248
break;
249
}
250
if (prev->getSuccessors()[idx] == (*i)) {
251
follow.push_back(idx);
252
if (idx > maxFollow) {
253
maxFollow = idx;
254
}
255
break;
256
}
257
}
258
if (idx > 15 || idx == prev->getNumSuccessors()) {
259
follow.clear();
260
break;
261
}
262
prev = *i;
263
}
264
if (follow.empty()) {
265
for (typename std::vector<E>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
266
FileHelpers::writeInt(os, (*i)->getNumericalID());
267
}
268
} else {
269
const int bits = maxFollow > 3 ? 4 : 2;
270
const int numFields = 8 * sizeof(int) / bits;
271
FileHelpers::writeInt(os, -bits);
272
FileHelpers::writeInt(os, edges.front()->getNumericalID());
273
int data = 0;
274
int field = 0;
275
for (std::vector<int>::const_iterator i = follow.begin(); i != follow.end(); ++i) {
276
data |= *i;
277
field++;
278
if (field == numFields) {
279
FileHelpers::writeInt(os, data);
280
data = 0;
281
field = 0;
282
} else {
283
data <<= bits;
284
}
285
}
286
if (field > 0) {
287
FileHelpers::writeInt(os, data << ((numFields - field - 1) * bits));
288
}
289
}
290
return os;
291
}
292
293
294
template <typename E>
295
void FileHelpers::readEdgeVector(std::istream& in, std::vector<const E*>& edges, const std::string& rid) {
296
int size;
297
in.read((char*) &size, sizeof(int));
298
edges.reserve(size);
299
int bitsOrEntry;
300
in.read((char*) &bitsOrEntry, sizeof(int));
301
if (bitsOrEntry < 0) {
302
const int bits = -bitsOrEntry;
303
const int numFields = 8 * sizeof(int) / bits;
304
const int mask = (1 << bits) - 1;
305
int edgeID;
306
in.read((char*) &edgeID, sizeof(int));
307
const E* prev = E::getAllEdges()[edgeID];
308
assert(prev != 0);
309
edges.push_back(prev);
310
size--;
311
int data = 0;
312
int field = numFields;
313
for (; size > 0; size--) {
314
if (field == numFields) {
315
in.read((char*) &data, sizeof(int));
316
field = 0;
317
}
318
int followIndex = (data >> ((numFields - field - 1) * bits)) & mask;
319
if (followIndex >= prev->getNumSuccessors()) {
320
throw ProcessError(TLF("Invalid follower index in route '%'!", rid));
321
}
322
prev = prev->getSuccessors()[followIndex];
323
edges.push_back(prev);
324
field++;
325
}
326
} else {
327
while (size > 0) {
328
const E* edge = E::getAllEdges()[bitsOrEntry];
329
if (edge == 0) {
330
throw ProcessError(TLF("An edge within the route '%' is not known!", rid));
331
}
332
edges.push_back(edge);
333
size--;
334
if (size > 0) {
335
in.read((char*) &bitsOrEntry, sizeof(int));
336
}
337
}
338
}
339
}
340
341