1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    FileHelpers.h
11 /// @author  Daniel Krajzewicz
12 /// @author  Michael Behrisch
13 /// @author  Jakob Erdmann
14 /// @date    Mon, 17 Dec 2001
15 /// @version $Id$
16 ///
17 // Functions for an easier usage of files
18 /****************************************************************************/
19 #ifndef FileHelpers_h
20 #define FileHelpers_h
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 
27 #include <cassert>
28 #include <fstream>
29 #include <string>
30 #include <vector>
31 #include "SUMOTime.h"
32 
33 
34 // ===========================================================================
35 // class definitions
36 // ===========================================================================
37 /**
38  * @class FileHelpers
39  * @brief Functions for an easier usage of files and paths
40  */
41 class FileHelpers {
42 public:
43     /// @name file access functions
44     //@{
45 
46     /** @brief Checks whether the given file is readable
47      *
48      * @param[in] path The path to the file that shall be examined
49      * @return Whether the named file is readable
50      */
51     static bool isReadable(std::string path);
52     //@}
53 
54 
55 
56     /// @name file path evaluating functions
57     //@{
58 
59     /** @brief Removes the file information from the given path
60      *
61      * @param[in] path The path to the file to return the folder it is located in
62      * @return The directory of the named file
63      */
64     static std::string getFilePath(const std::string& path);
65 
66 
67     /** @brief Returns the second path as a relative path to the first file
68      *
69      * Given the position of the configuration file, and the information where a second
70      *  file is relative to the configuration file's position, we want to known where
71      *  this second file can be found. This method gets the path to the configuration file
72      *  (including the configuration file name) and the path to get the relative position
73      *  of and returns this relative position.
74      *
75      * @param[in] configPath The path the configuration file (including the config's file name)
76      * @param[in] path The path to the references file (relativ to configuration path)
77      * @return The file's position (relative to curent working directory)
78      */
79     static std::string getConfigurationRelative(const std::string& configPath,
80             const std::string& path);
81 
82 
83     /** @brief Returns the information whether the given name represents a socket
84      *
85      * A file name is meant to describe a socket address if a colon is found at a position
86      *  larger than one.
87      *
88      * @param[in] name The name of a file
89      * @return Whether the name names a socket
90      */
91     static bool isSocket(const std::string& name);
92 
93 
94     /** @brief Returns the information whether the given path is absolute
95      *
96      * A path is meant to be absolute, if
97      * @arg it is a socket
98      * @arg it starts with a "/" (Linux)
99      * @arg it has a ':' at the second position (Windows)
100      *
101      * @param[in] path The path to examine
102      * @return Whether the path is absolute
103      */
104     static bool isAbsolute(const std::string& path);
105 
106 
107     /** @brief Returns the path from a configuration so that it is accessable from the current working directory
108      *
109      * If the path is absolute, it is returned. Otherwise, the file's position
110      *  is computed regarding the configuration path (see getConfigurationRelative).
111      *
112      * @see isAbsolute
113      * @see getConfigurationRelative
114      * @param[in] filename The path to the file to be examined
115      * @param[in] basePath The path the configuration file (including the config's file name)
116      * @return The file's position
117      */
118     static std::string checkForRelativity(const std::string& filename,
119                                           const std::string& basePath);
120 
121     /// @brief prepend the given prefix to the last path component of the given file path
122     static std::string prependToLastPathComponent(const std::string& prefix, const std::string& path);
123 
124     //@}
125 
126 
127 
128     /// @name binary writing functions
129     //@{
130 
131     /** @brief Writes an integer binary
132      *
133      * @param[in, out] strm The stream to write into
134      * @param[in] value The integer to write
135      * @return Reference to the stream
136      */
137     static std::ostream& writeInt(std::ostream& strm, int value);
138 
139 
140     /** @brief Writes a float binary
141      *
142      * This method behaves differently depending on the definition of double at compile time.
143      *
144      * @param[in, out] strm The stream to write into
145      * @param[in] value The float to write
146      * @return Reference to the stream
147      */
148     static std::ostream& writeFloat(std::ostream& strm, double value);
149 
150 
151     /** @brief Writes a byte binary
152      *
153      * @param[in, out] strm The stream to write into
154      * @param[in] value The byte to write
155      * @return Reference to the stream
156      */
157     static std::ostream& writeByte(std::ostream& strm, unsigned char value);
158 
159 
160     /** @brief Writes a string binary
161      *
162      * Writes the length of the string, first, using writeInt. Writes then the string's
163      *  characters.
164      *
165      * @see writeInt
166      * @param[in, out] strm The stream to write into
167      * @param[in] value The string to write
168      * @return Reference to the stream
169      */
170     static std::ostream& writeString(std::ostream& strm, const std::string& value);
171 
172 
173     /** @brief Writes a time description binary
174      *
175      * This method behaves differently depending on the definition of SUMOTime at compile time,
176      *  which in turn depends on the enabling of subsecond timesteps.
177      *
178      * @param[in, out] strm The stream to write into
179      * @param[in] value The time to write
180      * @return Reference to the stream
181      */
182     static std::ostream& writeTime(std::ostream& strm, SUMOTime value);
183 
184 
185     /** @brief Writes an edge vector binary
186      *
187      * @param[in, out] os The stream to write into
188      * @param[in] edges The edges to write
189      * @return Reference to the stream
190      */
191     template <typename E>
192     static std::ostream& writeEdgeVector(std::ostream& os, const std::vector<E>& edges);
193 
194 
195     /** @brief Reads an edge vector binary
196      *
197      * @param[in] is The stream to read from
198      * @param[out] edges The edge vector to write into
199      * @return Reference to the stream
200      */
201     template <typename E>
202     static void readEdgeVector(std::istream& in, std::vector<const E*>& edges, const std::string& rid);
203     //@}
204 
205 
206 };
207 
208 
209 template <typename E>
writeEdgeVector(std::ostream & os,const std::vector<E> & edges)210 std::ostream& FileHelpers::writeEdgeVector(std::ostream& os, const std::vector<E>& edges) {
211     FileHelpers::writeInt(os, (int)edges.size());
212     std::vector<int> follow;
213     int maxFollow = 0;
214     E prev = edges.front();
215     for (typename std::vector<E>::const_iterator i = edges.begin() + 1; i != edges.end(); ++i) {
216         int idx = 0;
217         for (; idx < prev->getNumSuccessors(); ++idx) {
218             if (idx > 15) {
219                 break;
220             }
221             if (prev->getSuccessors()[idx] == (*i)) {
222                 follow.push_back(idx);
223                 if (idx > maxFollow) {
224                     maxFollow = idx;
225                 }
226                 break;
227             }
228         }
229         if (idx > 15 || idx == prev->getNumSuccessors()) {
230             follow.clear();
231             break;
232         }
233         prev = *i;
234     }
235     if (follow.empty()) {
236         for (typename std::vector<E>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
237             FileHelpers::writeInt(os, (*i)->getNumericalID());
238         }
239     } else {
240         const int bits = maxFollow > 3 ? 4 : 2;
241         const int numFields = 8 * sizeof(int) / bits;
242         FileHelpers::writeInt(os, -bits);
243         FileHelpers::writeInt(os, edges.front()->getNumericalID());
244         int data = 0;
245         int field = 0;
246         for (std::vector<int>::const_iterator i = follow.begin(); i != follow.end(); ++i) {
247             data |= *i;
248             field++;
249             if (field == numFields) {
250                 FileHelpers::writeInt(os, data);
251                 data = 0;
252                 field = 0;
253             } else {
254                 data <<= bits;
255             }
256         }
257         if (field > 0) {
258             FileHelpers::writeInt(os, data << ((numFields - field - 1) * bits));
259         }
260     }
261     return os;
262 }
263 
264 
265 template <typename E>
readEdgeVector(std::istream & in,std::vector<const E * > & edges,const std::string & rid)266 void FileHelpers::readEdgeVector(std::istream& in, std::vector<const E*>& edges, const std::string& rid) {
267     int size;
268     in.read((char*) &size, sizeof(int));
269     edges.reserve(size);
270     int bitsOrEntry;
271     in.read((char*) &bitsOrEntry, sizeof(int));
272     if (bitsOrEntry < 0) {
273         const int bits = -bitsOrEntry;
274         const int numFields = 8 * sizeof(int) / bits;
275         const int mask = (1 << bits) - 1;
276         int edgeID;
277         in.read((char*) &edgeID, sizeof(int));
278         const E* prev = E::getAllEdges()[edgeID];
279         assert(prev != 0);
280         edges.push_back(prev);
281         size--;
282         int data = 0;
283         int field = numFields;
284         for (; size > 0; size--) {
285             if (field == numFields) {
286                 in.read((char*) &data, sizeof(int));
287                 field = 0;
288             }
289             int followIndex = (data >> ((numFields - field - 1) * bits)) & mask;
290             if (followIndex >= prev->getNumSuccessors()) {
291                 throw ProcessError("Invalid follower index in route '" + rid + "'!");
292             }
293             prev = prev->getSuccessors()[followIndex];
294             edges.push_back(prev);
295             field++;
296         }
297     } else {
298         while (size > 0) {
299             const E* edge = E::getAllEdges()[bitsOrEntry];
300             if (edge == 0) {
301                 throw ProcessError("An edge within the route '" + rid + "' is not known!");
302             }
303             edges.push_back(edge);
304             size--;
305             if (size > 0) {
306                 in.read((char*) &bitsOrEntry, sizeof(int));
307             }
308         }
309     }
310 }
311 #endif
312 
313 /****************************************************************************/
314 
315