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
24.1 KiB891 linesraw
1// slang-artifact-container-util.cpp
2#include "slang-artifact-container-util.h"
3
4#include "../core/slang-castable.h"
5#include "../core/slang-file-system.h"
6#include "../core/slang-io.h"
7#include "../core/slang-string-slice-pool.h"
8#include "../core/slang-zip-file-system.h"
9#include "slang-artifact-desc-util.h"
10#include "slang-artifact-representation-impl.h"
11#include "slang-artifact-util.h"
12
13namespace Slang
14{
15
16/*
17Artifact file structure
18=======================
19
20There is many ways this could work, with different trade offs. The approach taken here is
21to make *every* artifact be a directory. There are two special case directories "associated" and
22"children", which hold the artifacts associated/chidren artifacts.
23
24So for example if we have
25
26```
27thing.spv
28  associated
29    diagnostics
30```
31
32It will become
33
34```
35thing.spv
36associated/0/diagnostics.diag
37```
38
39```
40somemodule
41  associated
42    diagnostics
43    0a0a0a.map
44    0b0b0b.map
45```
46
47Becomes
48
49```
50somemodule.slang-module
51associated/0/diagnostics
52associated/0a0a0a/0a0a0a.map
53associated/0b0b0b/0b0b0b.map
54```
55
56That is a little verbose, but if the associated artifacts have children/associated, then things
57still work.
58
59```
60container
61  a.spv
62    associated
63        diagnostics
64  b.dxil
65    associated
66        diagnostics
67        sourcemap
68```
69
70```
71a/a.spv
72a/associated/0/diagnostics.diagnostics
73b/b.spv
74b/associated/0/diagnostics.diagnostics
75b/associated/1/sourcemap.map
76```
77
78*/
79
80struct ArtifactContainerWriter
81{
82    struct Entry
83    {
84        String path;
85        Index uniqueIndex = 0;
86    };
87
88    struct Scope
89    {
90        SlangResult pushAndRequireDirectory(ArtifactContainerWriter* writer, const String& name)
91        {
92            SLANG_ASSERT(writer);
93            SLANG_ASSERT(m_writer == nullptr);
94
95            SlangResult res = writer->pushAndRequireDirectory(name);
96
97            if (SLANG_SUCCEEDED(res))
98            {
99                m_writer = writer;
100            }
101
102            return res;
103        }
104
105        ~Scope()
106        {
107            if (m_writer)
108            {
109                m_writer->pop();
110            }
111        }
112
113        ArtifactContainerWriter* m_writer = nullptr;
114    };
115
116    void push(const String& name)
117    {
118        auto path = Path::combine(m_entry.path, name);
119
120        m_entryStack.add(m_entry);
121
122        Entry entry;
123        entry.path = path;
124
125        m_entry = entry;
126    }
127    SlangResult pushAndRequireDirectory(const String& name)
128    {
129        push(name);
130
131        const char* const path = m_entry.path.getBuffer();
132
133        SlangPathType pathType;
134        if (SLANG_SUCCEEDED(m_fileSystem->getPathType(path, &pathType)))
135        {
136            if (pathType != SLANG_PATH_TYPE_DIRECTORY)
137            {
138                return SLANG_FAIL;
139            }
140        }
141
142        // Make sure there is a path to this
143        return m_fileSystem->createDirectory(m_entry.path.getBuffer());
144    }
145    void pop()
146    {
147        SLANG_ASSERT(m_entryStack.getCount() > 0);
148        m_entry = m_entryStack.getLast();
149        m_entryStack.removeLast();
150    }
151
152    SlangResult getBaseName(IArtifact* artifact, String& out);
153
154    /// Write the artifact in the current scope
155    SlangResult write(IArtifact* artifact);
156    SlangResult writeInDirectory(IArtifact* artifact, const String& baseName);
157
158    ArtifactContainerWriter(ISlangMutableFileSystem* fileSystem)
159        : m_fileSystem(fileSystem)
160    {
161    }
162
163    List<Entry> m_entryStack;
164    Entry m_entry;
165
166    ISlangMutableFileSystem* m_fileSystem;
167};
168
169SlangResult ArtifactContainerWriter::getBaseName(IArtifact* artifact, String& out)
170{
171    String baseName;
172
173    const auto artifactDesc = artifact->getDesc();
174
175    {
176        auto artifactName = artifact->getName();
177        if (artifactName && artifactName[0] != 0)
178        {
179            baseName = ArtifactDescUtil::getBaseNameFromPath(
180                artifactDesc,
181                UnownedStringSlice(artifactName));
182        }
183    }
184
185    // If we don't have name, use a generated one
186    if (baseName.getLength() == 0)
187    {
188        baseName.append(m_entry.uniqueIndex++);
189    }
190
191    out = baseName;
192    return SLANG_OK;
193}
194
195SlangResult ArtifactContainerWriter::writeInDirectory(IArtifact* artifact, const String& baseName)
196{
197    // TODO(JS):
198    // We could now output information about the desc/artifact, say as some json.
199    // For now we assume the extension is good enough for most purposes.
200
201    // If it's an "arbitrary" container, we don't need to write it
202    if (artifact->getDesc().kind != ArtifactKind::Container)
203    {
204        // We can't write it without a blob
205        ComPtr<ISlangBlob> blob;
206        SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()));
207
208        // Get the name of the artifact
209        StringBuilder artifactName;
210        SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcNameForDesc(
211            artifact->getDesc(),
212            baseName.getUnownedSlice(),
213            artifactName));
214
215        const auto combinedPath = Path::combine(m_entry.path, artifactName);
216        // Write out the blob
217        SLANG_RETURN_ON_FAIL(m_fileSystem->saveFileBlob(combinedPath.getBuffer(), blob));
218    }
219
220    {
221        auto children = artifact->getChildren();
222        if (children.count)
223        {
224            Scope childrenScope;
225            SLANG_RETURN_ON_FAIL(childrenScope.pushAndRequireDirectory(this, "children"));
226
227            for (IArtifact* child : children)
228            {
229                SLANG_RETURN_ON_FAIL(write(child));
230            }
231        }
232    }
233    {
234        auto associatedSlice = artifact->getAssociated();
235        if (associatedSlice.count)
236        {
237            Scope associatedScope;
238            SLANG_RETURN_ON_FAIL(associatedScope.pushAndRequireDirectory(this, "associated"));
239
240            for (IArtifact* associated : associatedSlice)
241            {
242                SLANG_RETURN_ON_FAIL(write(associated));
243            }
244        }
245    }
246
247    return SLANG_OK;
248}
249
250SlangResult ArtifactContainerWriter::write(IArtifact* artifact)
251{
252    String baseName;
253    SLANG_RETURN_ON_FAIL(getBaseName(artifact, baseName));
254
255    // We don't special case if the artifact contains no children/associated.
256    // We always create a directory for all artifacts. This makes it more verbose,
257    // but simplifies things, because *generally* an artifact including it's children/associated
258    // meta data is all contained in a single directory
259
260    {
261        Scope artifactScope;
262        SLANG_RETURN_ON_FAIL(artifactScope.pushAndRequireDirectory(this, baseName));
263        SLANG_RETURN_ON_FAIL(writeInDirectory(artifact, baseName));
264    }
265
266    return SLANG_OK;
267}
268
269/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactContainerParser !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
270
271struct FileSystemContents
272{
273    // The first entry is always the root path
274
275    struct IndexRange
276    {
277        SLANG_FORCE_INLINE Index getCount() const { return endIndex - startIndex; }
278
279        SLANG_FORCE_INLINE Index begin() const { return startIndex; }
280        SLANG_FORCE_INLINE Index end() const { return endIndex; }
281
282        void set(Index inStart, Index inEnd)
283        {
284            startIndex = inStart;
285            endIndex = inEnd;
286        }
287
288        static IndexRange make(Index inStart, Index inEnd)
289        {
290            IndexRange range;
291            range.set(inStart, inEnd);
292            return range;
293        }
294
295        Index startIndex;
296        Index endIndex;
297    };
298
299    struct Entry
300    {
301        bool isFile() const { return range.startIndex < 0; }
302        bool isDirectory() const { return range.startIndex >= 0; }
303
304        void setDirectory() { range.set(0, 0); }
305        void setFile() { range.set(-1, -1); }
306
307        void setType(SlangPathType type)
308        {
309            (type == SLANG_PATH_TYPE_FILE) ? setFile() : setDirectory();
310        }
311
312        void setDirectoryRange(Index inStartIndex, Index inEndIndex)
313        {
314            SLANG_ASSERT(inEndIndex >= inStartIndex);
315            SLANG_ASSERT(isDirectory());
316            range.set(inStartIndex, inEndIndex);
317        }
318
319        Index parentDirectoryIndex = -1; ///< The directory this entry is in. -1 is root.
320        UnownedStringSlice name;         ///< Name of this entry
321        IndexRange range = IndexRange::make(-1, -1); ///< Default to file
322    };
323
324    void clear()
325    {
326        m_pool.clear();
327        m_entries.clear();
328    }
329
330    IndexRange getContentsRange(Index index) const { return m_entries[index].range; }
331
332    ConstArrayView<Entry> getContents(Index index) const { return getContents(m_entries[index]); }
333    ConstArrayView<Entry> getContents(const Entry& entry) const
334    {
335        return entry.range.getCount() ? makeConstArrayView(
336                                            m_entries.getBuffer() + entry.range.startIndex,
337                                            entry.range.getCount())
338                                      : makeConstArrayView<Entry>(nullptr, 0);
339    }
340
341    void appendPath(Index entryIndex, StringBuilder& buf);
342
343    SlangResult find(ISlangFileSystemExt* fileSyste, const UnownedStringSlice& path);
344
345    FileSystemContents()
346        : m_pool(StringSlicePool::Style::Default)
347    {
348        clear();
349    }
350
351    static void _add(SlangPathType pathType, const char* name, void* userData)
352    {
353        FileSystemContents* contents = (FileSystemContents*)userData;
354
355        Entry entry;
356
357        entry.parentDirectoryIndex = contents->m_currentParent;
358        entry.name = contents->m_pool.addAndGetSlice(name);
359        entry.setType(pathType);
360
361        contents->m_entries.add(entry);
362    }
363
364    Index m_currentParent = -1; ///< Convenience for adding entries when using enumerate
365
366    StringSlicePool m_pool; ///< Holds strings
367    List<Entry> m_entries;  ///< The entries
368};
369
370void FileSystemContents::appendPath(Index entryIndex, StringBuilder& buf)
371{
372    const auto& entry = m_entries[entryIndex];
373    if (entry.parentDirectoryIndex >= 0)
374    {
375        // If there is a parent recurse to append that first
376        appendPath(entry.parentDirectoryIndex, buf);
377    }
378
379    // If the buffer is non zero, we need to add a separator
380    if (buf.getLength() > 0)
381    {
382        buf.appendChar('/');
383    }
384
385    buf.append(entry.name);
386}
387
388SlangResult FileSystemContents::find(
389    ISlangFileSystemExt* fileSystem,
390    const UnownedStringSlice& inPath)
391{
392    clear();
393
394    StringBuilder currentPath;
395    currentPath.append(inPath);
396
397    // If there is no name, just go with .
398    const char* checkPath = currentPath.getLength() ? currentPath.getBuffer() : ".";
399
400    SlangPathType pathType;
401    SLANG_RETURN_ON_FAIL(fileSystem->getPathType(checkPath, &pathType));
402
403    if (pathType == SLANG_PATH_TYPE_FILE)
404    {
405        Entry directoryEntry;
406        directoryEntry.parentDirectoryIndex = -1;
407        directoryEntry.name = m_pool.addAndGetSlice(Path::getParentDirectory(inPath));
408        directoryEntry.range.set(1, 2);
409        SLANG_ASSERT(directoryEntry.isDirectory());
410
411        m_entries.add(directoryEntry);
412
413        Entry entry;
414        entry.parentDirectoryIndex = 0;
415        entry.name = m_pool.addAndGetSlice(Path::getFileName(inPath));
416        SLANG_ASSERT(entry.isFile());
417
418        m_entries.add(entry);
419    }
420    else
421    {
422        Entry directoryEntry;
423        directoryEntry.setDirectory();
424
425        directoryEntry.name = m_pool.addAndGetSlice(inPath);
426        m_entries.add(directoryEntry);
427
428        for (Index i = 0; i < m_entries.getCount(); ++i)
429        {
430            const Entry entry = m_entries[i];
431
432            if (entry.isDirectory())
433            {
434                // Clear the current path
435                currentPath.clear();
436
437                appendPath(i, currentPath);
438
439                // Makes all the items added have this set as their parent
440                m_currentParent = i;
441
442                const auto startIndex = m_entries.getCount();
443
444                const char* const path = currentPath.getLength() ? currentPath.getBuffer() : ".";
445
446                const auto res = fileSystem->enumeratePathContents(path, _add, this);
447
448                m_entries[i].setDirectoryRange(startIndex, m_entries.getCount());
449
450                SLANG_RETURN_ON_FAIL(res);
451            }
452        }
453    }
454
455    return SLANG_OK;
456}
457
458/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactContainerUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
459
460/* static */ SlangResult ArtifactContainerUtil::writeContainer(
461    IArtifact* artifact,
462    const String& defaultFileName,
463    ISlangMutableFileSystem* fileSystem)
464{
465    ArtifactContainerWriter writer(fileSystem);
466
467    String baseName;
468
469    {
470        const char* name = artifact->getName();
471        if (name == nullptr || name[0] == 0)
472        {
473            // Try to get the name from the defaultFileName
474            baseName = Path::getFileNameWithoutExt(defaultFileName);
475        }
476    }
477
478    // If it's still not set try generating it.
479    if (baseName.getLength() == 0)
480    {
481        SLANG_RETURN_ON_FAIL(writer.getBaseName(artifact, baseName));
482    }
483
484    SLANG_RETURN_ON_FAIL(writer.writeInDirectory(artifact, baseName));
485
486    return SLANG_OK;
487}
488
489static SlangResult _remove(ISlangMutableFileSystem* fileSystem, const String& path)
490{
491    SlangPathType pathType;
492    if (SLANG_SUCCEEDED(fileSystem->getPathType(path.getBuffer(), &pathType)))
493    {
494        fileSystem->remove(path.getBuffer());
495    }
496    return SLANG_OK;
497}
498
499/* static */ SlangResult ArtifactContainerUtil::writeContainer(
500    IArtifact* artifact,
501    const String& fileName)
502{
503    auto osFileSystem = OSFileSystem::getMutableSingleton();
504
505    const auto ext = Path::getPathExt(fileName);
506
507    if (ext == toSlice("zip"))
508    {
509        SLANG_RETURN_ON_FAIL(_remove(osFileSystem, fileName));
510
511        // Create the zip
512        ComPtr<ISlangMutableFileSystem> fileSystem;
513        SLANG_RETURN_ON_FAIL(ZipFileSystem::create(fileSystem));
514
515        // Write everything out
516        SLANG_RETURN_ON_FAIL(writeContainer(artifact, fileName, fileSystem));
517
518        // Now write out to the output file
519        IArchiveFileSystem* archiveFileSystem = as<IArchiveFileSystem>(fileSystem);
520        SLANG_ASSERT(archiveFileSystem);
521
522        ComPtr<ISlangBlob> blob;
523        SLANG_RETURN_ON_FAIL(archiveFileSystem->storeArchive(false, blob.writeRef()));
524
525        // Okay we can now write out the zip
526        SLANG_RETURN_ON_FAIL(osFileSystem->saveFileBlob(fileName.getBuffer(), blob));
527        return SLANG_OK;
528    }
529    else if (ext == toSlice("dir"))
530    {
531        // We use the special extension "dir" to write out to a directory.
532        // This is a little hokey arguably...
533        auto path = Path::getPathWithoutExt(fileName);
534
535        SLANG_RETURN_ON_FAIL(_remove(osFileSystem, path));
536
537        SLANG_RETURN_ON_FAIL(osFileSystem->createDirectory(path.getBuffer()));
538
539        ComPtr<ISlangMutableFileSystem> fileSystem(new RelativeFileSystem(osFileSystem, path));
540
541        SLANG_RETURN_ON_FAIL(writeContainer(artifact, fileName, fileSystem));
542        return SLANG_OK;
543    }
544
545    // In order to write out as a artifact hierarchy we need a file system. If we don't have that
546    // we only write out the "main" (or root) artifact. All associated/children are typically
547    // ignored.
548    {
549        // Get the artifact as a blob
550        ComPtr<ISlangBlob> containerBlob;
551        SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::Yes, containerBlob.writeRef()));
552
553        // Write out the blob
554        SLANG_RETURN_ON_FAIL(osFileSystem->saveFileBlob(fileName.getBuffer(), containerBlob));
555    }
556
557    return SLANG_OK;
558}
559
560struct ArtifactContainerReader
561{
562    SlangResult read(ISlangFileSystemExt* fileSystem, ComPtr<IArtifact>& outArtifact);
563
564    /// A directory that contains multiple artifact directories
565    SlangResult _readContainerDirectory(
566        Index directoryIndex,
567        IArtifact::ContainedKind kind,
568        IArtifact* container);
569    /// A directory that holds a single
570    SlangResult _readArtifactDirectory(Index directoryIndex, ComPtr<IArtifact>& outArtifact);
571
572    SlangResult _readFile(Index fileIndex, ComPtr<IArtifact>& outArtifact);
573
574    FileSystemContents m_contents;
575    ISlangFileSystemExt* m_fileSystem;
576};
577
578SlangResult ArtifactContainerReader::read(
579    ISlangFileSystemExt* fileSystem,
580    ComPtr<IArtifact>& outArtifact)
581{
582    m_fileSystem = fileSystem;
583    m_contents.find(fileSystem, toSlice(""));
584
585    return _readArtifactDirectory(0, outArtifact);
586}
587
588SlangResult ArtifactContainerReader::_readFile(Index fileIndex, ComPtr<IArtifact>& outArtifact)
589{
590    outArtifact.setNull();
591
592    const auto& entry = m_contents.m_entries[fileIndex];
593    SLANG_ASSERT(entry.isFile());
594
595    ArtifactDesc desc;
596
597    auto ext = Path::getPathExt(entry.name);
598    if (ext.getLength() == 0)
599    {
600        // I guess we'll assume it's an executable for now. We should use some kind of associated
601        // information/manifest probly
602        desc = ArtifactDesc::make(ArtifactKind::Executable, ArtifactPayload::HostCPU);
603    }
604    else
605    {
606        desc = ArtifactDescUtil::getDescFromPath(entry.name);
607    }
608
609    // Don't know what this is.
610    if (desc.kind == ArtifactKind::Unknown || desc.kind == ArtifactKind::Invalid)
611    {
612        return SLANG_OK;
613    }
614
615    // We don't have manifest, so for now well assume if the name ends in "-obfuscated" and it's a
616    // source map it's an obfuscated one
617    if (desc.kind == ArtifactKind::Json && desc.payload == ArtifactPayload::SourceMap)
618    {
619        auto name = Path::getFileNameWithoutExt(entry.name);
620
621        if (name.endsWith(toSlice("-obfuscated")))
622        {
623            desc.style = ArtifactStyle::Obfuscated;
624        }
625    }
626
627    // I guess I can just make an artifact for this
628    auto artifact = ArtifactUtil::createArtifact(desc);
629
630    if (entry.name.getLength())
631    {
632        // We can set the name on the artifact if set
633        // We know it's 0 terminated, because all names are in the pool
634        // and therefore have to have 0 termination
635        artifact->setName(entry.name.begin());
636    }
637
638    StringBuilder path;
639    m_contents.appendPath(fileIndex, path);
640
641    IExtFileArtifactRepresentation* rep =
642        new ExtFileArtifactRepresentation(path.getUnownedSlice(), m_fileSystem);
643    artifact->addRepresentation(rep);
644
645    outArtifact = artifact;
646    return SLANG_OK;
647}
648
649SlangResult ArtifactContainerReader::_readContainerDirectory(
650    Index directoryIndex,
651    IArtifact::ContainedKind kind,
652    IArtifact* containerArtifact)
653{
654    // This directory only contains other directories which are artifacts
655    // Files are ignored
656
657    auto indexRange = m_contents.getContentsRange(directoryIndex);
658
659    for (Index i = indexRange.startIndex; i < indexRange.endIndex; ++i)
660    {
661        const auto& entry = m_contents.m_entries[i];
662
663        // We ignore files
664        if (entry.isFile())
665        {
666            continue;
667        }
668
669        ComPtr<IArtifact> artifact;
670
671        SLANG_RETURN_ON_FAIL(_readArtifactDirectory(i, artifact));
672
673        if (artifact)
674        {
675            switch (kind)
676            {
677            case IArtifact::ContainedKind::Associated:
678                containerArtifact->addAssociated(artifact);
679                break;
680            case IArtifact::ContainedKind::Children:
681                containerArtifact->addChild(artifact);
682                break;
683            default:
684                SLANG_ASSERT(!"Can't add artifact to this kind");
685                return SLANG_FAIL;
686            }
687        }
688    }
689
690    return SLANG_OK;
691}
692
693SlangResult ArtifactContainerReader::_readArtifactDirectory(
694    Index directoryIndex,
695    ComPtr<IArtifact>& outArtifact)
696{
697    auto indexRange = m_contents.getContentsRange(directoryIndex);
698
699    Index childrenIndex = -1;
700    Index associatedIndex = -1;
701
702    ComPtr<IArtifact> artifact;
703
704    // Look for files
705    for (Index i = indexRange.startIndex; i < indexRange.endIndex; ++i)
706    {
707        const auto& entry = m_contents.m_entries[i];
708        if (entry.isFile())
709        {
710            ComPtr<IArtifact> readArtifact;
711            SLANG_RETURN_ON_FAIL(_readFile(i, readArtifact));
712
713            if (readArtifact)
714            {
715                if (artifact)
716                {
717                    // We can only have one artifact in the directory
718                    return SLANG_FAIL;
719                }
720                artifact = readArtifact;
721            }
722        }
723        else if (entry.isDirectory())
724        {
725            if (entry.name == toSlice("associated"))
726            {
727                associatedIndex = i;
728            }
729            else if (entry.name == toSlice("children"))
730            {
731                childrenIndex = i;
732            }
733        }
734    }
735
736    // If we didn't find an artifact so far
737    if (!artifact)
738    {
739        // If we have children/associated we can assume it's a container
740        if (childrenIndex >= 0 || associatedIndex >= 0)
741        {
742            artifact = ArtifactUtil::createArtifact(
743                ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::Unknown));
744            artifact->setName(m_contents.m_entries[directoryIndex].name.begin());
745        }
746        else
747        {
748            // Didn't find anything
749            return SLANG_OK;
750        }
751    }
752
753    if (childrenIndex >= 0)
754    {
755        SLANG_RETURN_ON_FAIL(
756            _readContainerDirectory(childrenIndex, IArtifact::ContainedKind::Children, artifact));
757    }
758    if (associatedIndex >= 0)
759    {
760        SLANG_RETURN_ON_FAIL(_readContainerDirectory(
761            associatedIndex,
762            IArtifact::ContainedKind::Associated,
763            artifact));
764    }
765
766    outArtifact = artifact;
767    return SLANG_OK;
768}
769
770SlangResult ArtifactContainerUtil::readContainer(
771    IArtifact* artifact,
772    ComPtr<IArtifact>& outArtifact)
773{
774    auto desc = artifact->getDesc();
775
776    ComPtr<ISlangMutableFileSystem> fileSystem;
777
778    switch (desc.kind)
779    {
780    case ArtifactKind::Zip:
781        {
782            SLANG_RETURN_ON_FAIL(ZipFileSystem::create(fileSystem));
783
784            ComPtr<ISlangBlob> blob;
785            SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef()));
786
787            // Load into the zip
788
789            // Now write out to the output file
790            IArchiveFileSystem* archiveFileSystem = as<IArchiveFileSystem>(fileSystem);
791            SLANG_ASSERT(archiveFileSystem);
792
793            SLANG_RETURN_ON_FAIL(
794                archiveFileSystem->loadArchive(blob->getBufferPointer(), blob->getBufferSize()));
795            break;
796        }
797    default:
798        {
799            return SLANG_FAIL;
800        }
801    }
802
803    SLANG_RETURN_ON_FAIL(readContainer(fileSystem, outArtifact));
804    return SLANG_OK;
805}
806
807/* static */ SlangResult ArtifactContainerUtil::readContainer(
808    ISlangFileSystemExt* fileSystem,
809    ComPtr<IArtifact>& outArtifact)
810{
811    SLANG_UNUSED(outArtifact);
812
813    ArtifactContainerReader reader;
814    SLANG_RETURN_ON_FAIL(reader.read(fileSystem, outArtifact));
815
816    return SLANG_OK;
817}
818
819/* static */ SlangResult ArtifactContainerUtil::filter(
820    IArtifact* artifact,
821    ComPtr<IArtifact>& outArtifact)
822{
823    outArtifact.setNull();
824
825    // Copy the artifact
826    auto dstArtifact = ArtifactUtil::createArtifact(artifact->getDesc(), artifact->getName());
827
828    ComPtr<ISlangBlob> blob;
829
830    if (artifact->getDesc().kind != ArtifactKind::Container)
831    {
832        // We can't write it without a blob
833        const auto res = artifact->loadBlob(ArtifactKeep::No, blob.writeRef());
834
835        if (SLANG_FAILED(res))
836        {
837            // If it failed and it's significant the whole write fails
838            if (ArtifactUtil::isSignificant(artifact))
839            {
840                return res;
841            }
842        }
843        else
844        {
845            // Add the blob to the destination
846            dstArtifact->addRepresentationUnknown(blob);
847        }
848    }
849
850    // Copy the children after filtering
851    {
852        for (IArtifact* child : artifact->getChildren())
853        {
854            ComPtr<IArtifact> dstChild;
855            SLANG_RETURN_ON_FAIL(filter(child, dstChild));
856
857            if (dstChild)
858            {
859                dstArtifact->addChild(dstChild);
860            }
861        }
862    }
863
864    // Copy the associated after filtering
865    {
866        for (IArtifact* assoc : artifact->getAssociated())
867        {
868            ComPtr<IArtifact> dstAssoc;
869            SLANG_RETURN_ON_FAIL(filter(assoc, dstAssoc));
870
871            if (dstAssoc)
872            {
873                dstArtifact->addAssociated(dstAssoc);
874            }
875        }
876    }
877
878    // We only return the artifact if any of the following are true
879    // 1) It has a blob representation
880    // 2) It contains children or associated artifacts
881
882    if (blob || dstArtifact->getChildren().count || dstArtifact->getAssociated().count)
883    {
884        outArtifact = dstArtifact;
885    }
886
887    // If we return an artifact or not, this was successful
888    return SLANG_OK;
889}
890
891} // namespace Slang