yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaMove switch statement bodies to their own lines (#5493)b118451e3

master
8.2 KiB327 linesraw
1#include "slang-memory-file-system.h"
2
3// For Path::
4#include "slang-blob.h"
5#include "slang-implicit-directory-collector.h"
6#include "slang-io.h"
7
8namespace Slang
9{
10
11MemoryFileSystem::MemoryFileSystem()
12{
13    m_rootEntry.initDirectory("/");
14}
15
16void* MemoryFileSystem::getInterface(const Guid& guid)
17{
18    if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangCastable::getTypeGuid() ||
19        guid == ISlangFileSystem::getTypeGuid() || guid == ISlangFileSystemExt::getTypeGuid() ||
20        guid == ISlangMutableFileSystem::getTypeGuid())
21    {
22        return static_cast<ISlangMutableFileSystem*>(this);
23    }
24    return nullptr;
25}
26
27void* MemoryFileSystem::getObject(const Guid& guid)
28{
29    SLANG_UNUSED(guid);
30    return nullptr;
31}
32
33void* MemoryFileSystem::castAs(const Guid& guid)
34{
35    if (auto ptr = getInterface(guid))
36    {
37        return ptr;
38    }
39    return getObject(guid);
40}
41
42void MemoryFileSystem::_clear()
43{
44    m_entries = Dictionary<String, Entry>();
45}
46
47MemoryFileSystem::Entry* MemoryFileSystem::_getEntryFromCanonicalPath(const String& canonicalPath)
48{
49    if (canonicalPath == toSlice("."))
50    {
51        return &m_rootEntry;
52    }
53    else
54    {
55        return m_entries.tryGetValue(canonicalPath);
56    }
57}
58
59MemoryFileSystem::Entry* MemoryFileSystem::_getEntryFromPath(const char* path, String* outPath)
60{
61    StringBuilder buffer;
62    if (SLANG_FAILED(_getCanonical(path, buffer)))
63    {
64        return nullptr;
65    }
66
67    if (outPath)
68    {
69        *outPath = buffer;
70    }
71    return _getEntryFromCanonicalPath(buffer);
72}
73
74SlangResult MemoryFileSystem::_loadFile(const char* path, Entry** outEntry)
75{
76    *outEntry = nullptr;
77    Entry* entry = _getEntryFromPath(path);
78    if (entry == nullptr || entry->m_type != SLANG_PATH_TYPE_FILE)
79    {
80        return SLANG_E_NOT_FOUND;
81    }
82    *outEntry = entry;
83    return SLANG_OK;
84}
85
86SlangResult MemoryFileSystem::loadFile(char const* path, ISlangBlob** outBlob)
87{
88    Entry* entry;
89    SLANG_RETURN_ON_FAIL(_loadFile(path, &entry));
90
91    ISlangBlob* contents = entry->m_contents;
92    contents->addRef();
93    *outBlob = contents;
94
95    return SLANG_OK;
96}
97
98SlangResult MemoryFileSystem::getFileUniqueIdentity(
99    const char* path,
100    ISlangBlob** outUniqueIdentity)
101{
102    return getPath(PathKind::Canonical, path, outUniqueIdentity);
103}
104
105SlangResult MemoryFileSystem::calcCombinedPath(
106    SlangPathType fromPathType,
107    const char* fromPath,
108    const char* path,
109    ISlangBlob** pathOut)
110{
111    String combinedPath;
112    switch (fromPathType)
113    {
114    case SLANG_PATH_TYPE_FILE:
115        {
116            combinedPath = Path::combine(Path::getParentDirectory(fromPath), path);
117            break;
118        }
119    case SLANG_PATH_TYPE_DIRECTORY:
120        {
121            combinedPath = Path::combine(fromPath, path);
122            break;
123        }
124    }
125
126    *pathOut = StringBlob::moveCreate(combinedPath).detach();
127    return SLANG_OK;
128}
129
130SlangResult MemoryFileSystem::getPathType(const char* path, SlangPathType* outPathType)
131{
132    if (auto entry = _getEntryFromPath(path))
133    {
134        *outPathType = entry->m_type;
135        return SLANG_OK;
136    }
137    // Not found
138    return SLANG_E_NOT_FOUND;
139}
140
141SlangResult MemoryFileSystem::getPath(PathKind kind, const char* path, ISlangBlob** outPath)
142{
143    switch (kind)
144    {
145    case PathKind::Simplified:
146        {
147            String simplifiedPath = Path::simplify(path);
148            *outPath = StringBlob::moveCreate(simplifiedPath).detach();
149            return SLANG_OK;
150        }
151    case PathKind::Display:
152    case PathKind::Canonical:
153        {
154            StringBuilder buffer;
155            SLANG_RETURN_ON_FAIL(_getCanonical(path, buffer));
156            *outPath = StringBlob::moveCreate(buffer).detach();
157            return SLANG_OK;
158        }
159    default:
160        break;
161    }
162    return SLANG_E_NOT_AVAILABLE;
163}
164
165SlangResult MemoryFileSystem::enumeratePathContents(
166    const char* path,
167    FileSystemContentsCallBack callback,
168    void* userData)
169{
170    String canonicalPath;
171    Entry* entry = _getEntryFromPath(path, &canonicalPath);
172
173    if (!entry || entry->m_type != SLANG_PATH_TYPE_DIRECTORY)
174    {
175        return SLANG_E_NOT_FOUND;
176    }
177
178    ImplicitDirectoryCollector collector(canonicalPath, true);
179
180    // If it is a directory, we need to see if there is anything in it
181    for (const auto& [_, childEntry] : m_entries)
182    {
183        collector.addPath(childEntry.m_type, childEntry.m_canonicalPath.getUnownedSlice());
184    }
185
186    return collector.enumerate(callback, userData);
187}
188
189SlangResult MemoryFileSystem::saveFile(const char* path, const void* data, size_t size)
190{
191    Entry* entry;
192    SLANG_RETURN_ON_FAIL(_requireFile(path, &entry));
193    auto contents = RawBlob::create(data, size);
194    entry->setContents(size, contents);
195    return SLANG_OK;
196}
197
198SlangResult MemoryFileSystem::saveFileBlob(const char* path, ISlangBlob* dataBlob)
199{
200    if (!dataBlob)
201    {
202        return SLANG_E_INVALID_ARG;
203    }
204
205    Entry* entry;
206    SLANG_RETURN_ON_FAIL(_requireFile(path, &entry));
207    entry->setContents(dataBlob->getBufferSize(), dataBlob);
208    return SLANG_OK;
209}
210
211SlangResult MemoryFileSystem::_getCanonical(const char* path, StringBuilder& outCanonicalPath)
212{
213    StringBuilder canonicalPath;
214    SLANG_RETURN_ON_FAIL(Path::simplify(
215        UnownedStringSlice(path),
216        Path::SimplifyStyle::AbsoluteOnlyAndNoRoot,
217        outCanonicalPath));
218    return SLANG_OK;
219}
220
221SlangResult MemoryFileSystem::_getCanonicalWithExistingParent(
222    const char* path,
223    StringBuilder& outCanonicalPath)
224{
225    SLANG_RETURN_ON_FAIL(_getCanonical(path, outCanonicalPath));
226
227    // Get the parent to the canoncial path (which should be canonical itself)
228    auto parent = Path::getParentDirectory(outCanonicalPath);
229
230    if (parent.getLength())
231    {
232        // The parent has to be a directory
233        Entry* parentEntry = _getEntryFromCanonicalPath(parent);
234        if (parentEntry == nullptr || parentEntry->m_type != SLANG_PATH_TYPE_DIRECTORY)
235        {
236            return SLANG_E_NOT_FOUND;
237        }
238    }
239
240    return SLANG_OK;
241}
242
243SlangResult MemoryFileSystem::_requireFile(const char* path, Entry** outEntry)
244{
245    *outEntry = nullptr;
246
247    StringBuilder canonicalPath;
248    SLANG_RETURN_ON_FAIL(_getCanonicalWithExistingParent(path, canonicalPath));
249
250    Entry* foundEntry = _getEntryFromCanonicalPath(canonicalPath);
251
252    if (foundEntry)
253    {
254        if (foundEntry->m_type != SLANG_PATH_TYPE_FILE)
255        {
256            // Can only set if it's already a file, if it's anything else it's an error
257            return SLANG_FAIL;
258        }
259    }
260    else
261    {
262        Entry entry;
263        entry.initFile(canonicalPath);
264        m_entries.add(canonicalPath, entry);
265
266        foundEntry = _getEntryFromCanonicalPath(canonicalPath);
267    }
268
269    // It must be found and be a file
270    SLANG_ASSERT(
271        foundEntry && foundEntry->m_type == SLANG_PATH_TYPE_FILE &&
272        foundEntry->m_canonicalPath == canonicalPath);
273
274    *outEntry = foundEntry;
275    return SLANG_OK;
276}
277
278SlangResult MemoryFileSystem::remove(const char* path)
279{
280    String canonicalPath;
281    Entry* entry = _getEntryFromPath(path, &canonicalPath);
282
283    // If there is an entry and not the root of the file system
284    if (entry && entry != &m_rootEntry)
285    {
286        if (entry->m_type == SLANG_PATH_TYPE_DIRECTORY)
287        {
288            ImplicitDirectoryCollector collector(canonicalPath);
289
290            // If it is a directory, we need to see if there is anything in it
291            for (const auto& [_, childEntry] : m_entries)
292            {
293                collector.addPath(childEntry.m_type, childEntry.m_canonicalPath.getUnownedSlice());
294                if (collector.hasContent())
295                {
296                    // Directory is not empty
297                    return SLANG_FAIL;
298                }
299            }
300        }
301
302        // Reset so doesn't hold references/keep memory in scope
303        entry->reset();
304        m_entries.remove(canonicalPath);
305        return SLANG_OK;
306    }
307
308    return SLANG_E_NOT_FOUND;
309}
310
311SlangResult MemoryFileSystem::createDirectory(const char* path)
312{
313    StringBuilder canonicalPath;
314    SLANG_RETURN_ON_FAIL(_getCanonicalWithExistingParent(path, canonicalPath));
315
316    if (_getEntryFromCanonicalPath(canonicalPath))
317    {
318        return SLANG_FAIL;
319    }
320
321    Entry entry;
322    entry.initDirectory(canonicalPath);
323    m_entries.add(canonicalPath, entry);
324    return SLANG_OK;
325}
326
327} // namespace Slang