1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
#ifndef SLANG_CORE_IO_H
#define SLANG_CORE_IO_H
#include "slang-string.h"
#include "slang-stream.h"
#include "slang-text-io.h"
#include "slang-secure-crt.h"
namespace Slang
{
class File
{
public:
static bool exists(const String& fileName);
static String readAllText(const String& fileName);
static List<unsigned char> readAllBytes(const String& fileName);
static void writeAllText(const String& fileName, const String& text);
static SlangResult remove(const String& fileName);
static SlangResult makeExecutable(const String& fileName);
static SlangResult generateTemporary(const UnownedStringSlice& prefix, String& outFileName);
};
class Path
{
public:
enum class Type
{
Unknown,
File,
Directory,
};
typedef uint32_t TypeFlags;
struct TypeFlag
{
enum Enum : TypeFlags
{
Unknown = TypeFlags(1) << int(Type::Unknown),
File = TypeFlags(1) << int(Type::File),
Directory = TypeFlags(1) << int(Type::Directory),
};
};
class Visitor
{
public:
virtual void accept(Type type, const UnownedStringSlice& filename) = 0;
};
static const char kPathDelimiter = '/';
/// Finds all all the items in the specified directory, that matches the pattern.
///
/// @param directoryPath The directory to do the search in. If the directory is not found, SLANG_E_NOT_FOUND is returned
/// @param pattern. The pattern to match against. The pattern matching is targtet specific (ie window matching is different to linux/unix). Passing nullptr means no matching.
/// @return is SLANG_E_NOT_FOUND if the directoryPath is not found
static SlangResult find(const String& directoryPath, const char* pattern, Visitor* visitor);
/// Returns -1 if no separator is found
static Index findLastSeparatorIndex(String const& path);
/// Finds the index of the last dot in a path, else returns -1
static Index findExtIndex(String const& path);
static String replaceExt(const String& path, const char* newExt);
static String getFileName(const String& path);
static String getPathWithoutExt(const String& path);
static String getPathExt(const String& path);
static String getParentDirectory(const String& path);
static String getFileNameWithoutExt(const String& path);
static String combine(const String& path1, const String& path2);
static String combine(const String& path1, const String& path2, const String& path3);
/// Combine path sections and store the result in outBuilder
static void combineIntoBuilder(const UnownedStringSlice& path1, const UnownedStringSlice& path2, StringBuilder& outBuilder);
/// Append a path, taking into account path separators onto the end of ioBuilder
static void append(StringBuilder& ioBuilder, const UnownedStringSlice& path);
static bool createDirectory(const String& path);
/// Accept either style of delimiter
SLANG_FORCE_INLINE static bool isDelimiter(char c) { return c == '/' || c == '\\'; }
/// True if the element appears to be a drive specification (where element is the prefix to a path that isn't a directory)
/// @param pathPrefix The path prefix to test if it's a drive specification
static bool isDriveSpecification(const UnownedStringSlice& pathPrefix);
/// Splits the path into it's individual bits
static void split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut);
/// Strips .. and . as much as it can
static String simplify(const UnownedStringSlice& path);
static String simplify(const String& path) { return simplify(path.getUnownedSlice()); }
/// Returns true if the path is absolute
static bool isAbsolute(const UnownedStringSlice& path);
static bool isAbsolute(const String& path) { return isAbsolute(path.getUnownedSlice()); }
/// Returns true if path contains contains an element of . or ..
static bool hasRelativeElement(const UnownedStringSlice& path);
static bool hasRelativeElement(const String& path) { return hasRelativeElement(path.getUnownedSlice()); }
/// Determines the type of file at the path
/// @param path The path to test
/// @param outPathType Holds the object type at the path on success
/// @return SLANG_OK on success
static SlangResult getPathType(const String& path, SlangPathType* outPathType);
/// Determines the canonical equivalent path to path.
/// The path returned should reference the identical object - and two different references to the same path should return the same canonical path
/// @param path Path to get the canonical path for
/// @param outCanonicalPath The canonical path for 'path' is call is successful
/// @return SLANG_OK on success
static SlangResult getCanonical(const String& path, String& outCanonicalPath);
/// Returns the executable path
/// @return The path in platform native format. Returns empty string if failed.
static String getExecutablePath();
/// Returns the first element of the path or an empty slice if there is none
/// This broadly equivalent to returning the first element of split
/// @param path Path to extract first element from
/// @return The first element of the path, or empty
static UnownedStringSlice getFirstElement(const UnownedStringSlice& path);
/// Remove a file or directory at specified path. The directory must be empty for it to be removed
/// @param path
/// @return SLANG_OK if file or directory is removed
static SlangResult remove(const String& path);
};
// Helper class to clean up temporary files on dtor
class TemporaryFileSet: public RefObject
{
public:
typedef RefObject Super;
typedef TemporaryFileSet ThisType;
void remove(const String& path)
{
if (const Index index = m_paths.indexOf(path) >= 0)
{
m_paths.removeAt(index);
}
}
void add(const String& path)
{
if (m_paths.indexOf(path) < 0)
{
m_paths.add(path);
}
}
void add(const List<String>& paths)
{
for (const auto& path : paths)
{
add(path);
}
}
void clear()
{
m_paths.clear();
}
void swapWith(ThisType& rhs)
{
m_paths.swapWith(rhs.m_paths);
}
~TemporaryFileSet()
{
for (const auto& path : m_paths)
{
File::remove(path);
}
}
/// Default Ctor
TemporaryFileSet() {}
List<String> m_paths;
private:
// Disable ctor/assignment
TemporaryFileSet(const ThisType& rhs) = delete;
void operator=(const ThisType& rhs) = delete;
};
}
#endif
|