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