Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/common/FileHelpers.h
169678 views
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.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
/// @}
162
163
/// @name binary writing functions
164
/// @{
165
166
/** @brief Writes an integer binary
167
*
168
* @param[in, out] strm The stream to write into
169
* @param[in] value The integer to write
170
* @return Reference to the stream
171
*/
172
static std::ostream& writeInt(std::ostream& strm, int value);
173
174
/** @brief Writes a float binary
175
*
176
* This method behaves differently depending on the definition of double at compile time.
177
*
178
* @param[in, out] strm The stream to write into
179
* @param[in] value The float to write
180
* @return Reference to the stream
181
*/
182
static std::ostream& writeFloat(std::ostream& strm, double value);
183
184
/** @brief Writes a byte binary
185
*
186
* @param[in, out] strm The stream to write into
187
* @param[in] value The byte to write
188
* @return Reference to the stream
189
*/
190
static std::ostream& writeByte(std::ostream& strm, unsigned char value);
191
192
/** @brief Writes a string binary
193
*
194
* Writes the length of the string, first, using writeInt. Writes then the string's
195
* characters.
196
*
197
* @see writeInt
198
* @param[in, out] strm The stream to write into
199
* @param[in] value The string to write
200
* @return Reference to the stream
201
*/
202
static std::ostream& writeString(std::ostream& strm, const std::string& value);
203
204
/** @brief Writes a time description binary
205
*
206
* This method behaves differently depending on the definition of SUMOTime at compile time,
207
* which in turn depends on the enabling of subsecond timesteps.
208
*
209
* @param[in, out] strm The stream to write into
210
* @param[in] value The time to write
211
* @return Reference to the stream
212
*/
213
static std::ostream& writeTime(std::ostream& strm, SUMOTime value);
214
215
/** @brief Writes an edge vector binary
216
*
217
* @param[in, out] os The stream to write into
218
* @param[in] edges The edges to write
219
* @return Reference to the stream
220
*/
221
template <typename E>
222
static std::ostream& writeEdgeVector(std::ostream& os, const std::vector<E>& edges);
223
224
/** @brief Reads an edge vector binary
225
*
226
* @param[in] is The stream to read from
227
* @param[out] edges The edge vector to write into
228
* @return Reference to the stream
229
*/
230
template <typename E>
231
static void readEdgeVector(std::istream& in, std::vector<const E*>& edges, const std::string& rid);
232
/// @}
233
};
234
235
236
template <typename E>
237
std::ostream& FileHelpers::writeEdgeVector(std::ostream& os, const std::vector<E>& edges) {
238
FileHelpers::writeInt(os, (int)edges.size());
239
std::vector<int> follow;
240
int maxFollow = 0;
241
E prev = edges.front();
242
for (typename std::vector<E>::const_iterator i = edges.begin() + 1; i != edges.end(); ++i) {
243
int idx = 0;
244
for (; idx < prev->getNumSuccessors(); ++idx) {
245
if (idx > 15) {
246
break;
247
}
248
if (prev->getSuccessors()[idx] == (*i)) {
249
follow.push_back(idx);
250
if (idx > maxFollow) {
251
maxFollow = idx;
252
}
253
break;
254
}
255
}
256
if (idx > 15 || idx == prev->getNumSuccessors()) {
257
follow.clear();
258
break;
259
}
260
prev = *i;
261
}
262
if (follow.empty()) {
263
for (typename std::vector<E>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
264
FileHelpers::writeInt(os, (*i)->getNumericalID());
265
}
266
} else {
267
const int bits = maxFollow > 3 ? 4 : 2;
268
const int numFields = 8 * sizeof(int) / bits;
269
FileHelpers::writeInt(os, -bits);
270
FileHelpers::writeInt(os, edges.front()->getNumericalID());
271
int data = 0;
272
int field = 0;
273
for (std::vector<int>::const_iterator i = follow.begin(); i != follow.end(); ++i) {
274
data |= *i;
275
field++;
276
if (field == numFields) {
277
FileHelpers::writeInt(os, data);
278
data = 0;
279
field = 0;
280
} else {
281
data <<= bits;
282
}
283
}
284
if (field > 0) {
285
FileHelpers::writeInt(os, data << ((numFields - field - 1) * bits));
286
}
287
}
288
return os;
289
}
290
291
292
template <typename E>
293
void FileHelpers::readEdgeVector(std::istream& in, std::vector<const E*>& edges, const std::string& rid) {
294
int size;
295
in.read((char*) &size, sizeof(int));
296
edges.reserve(size);
297
int bitsOrEntry;
298
in.read((char*) &bitsOrEntry, sizeof(int));
299
if (bitsOrEntry < 0) {
300
const int bits = -bitsOrEntry;
301
const int numFields = 8 * sizeof(int) / bits;
302
const int mask = (1 << bits) - 1;
303
int edgeID;
304
in.read((char*) &edgeID, sizeof(int));
305
const E* prev = E::getAllEdges()[edgeID];
306
assert(prev != 0);
307
edges.push_back(prev);
308
size--;
309
int data = 0;
310
int field = numFields;
311
for (; size > 0; size--) {
312
if (field == numFields) {
313
in.read((char*) &data, sizeof(int));
314
field = 0;
315
}
316
int followIndex = (data >> ((numFields - field - 1) * bits)) & mask;
317
if (followIndex >= prev->getNumSuccessors()) {
318
throw ProcessError(TLF("Invalid follower index in route '%'!", rid));
319
}
320
prev = prev->getSuccessors()[followIndex];
321
edges.push_back(prev);
322
field++;
323
}
324
} else {
325
while (size > 0) {
326
const E* edge = E::getAllEdges()[bitsOrEntry];
327
if (edge == 0) {
328
throw ProcessError(TLF("An edge within the route '%' is not known!", rid));
329
}
330
edges.push_back(edge);
331
size--;
332
if (size > 0) {
333
in.read((char*) &bitsOrEntry, sizeof(int));
334
}
335
}
336
}
337
}
338
339