yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
4c76b2759
master
1#include "slang-riff-file-system.h" 2 3#include "slang-blob.h" 4#include "slang-com-helper.h" 5#include "slang-com-ptr.h" 6 7// Compression systems 8#include "slang-deflate-compression-system.h" 9#include "slang-lz4-compression-system.h" 10 11namespace Slang 12{ 13 14RiffFileSystem ::RiffFileSystem (ICompressionSystem * compressionSystem ) 15 :m_compressionSystem (compressionSystem ) 16{ 17} 18 19void * RiffFileSystem ::getInterface (const Guid & guid ) 20{ 21if (auto ptr = Super ::getInterface (guid )) 22 { 23return ptr ; 24 } 25else if (guid == IArchiveFileSystem ::getTypeGuid ()) 26 { 27return static_cast < IArchiveFileSystem *> (this ); 28 } 29return nullptr ; 30} 31 32void * RiffFileSystem ::getObject (const Guid & guid ) 33{ 34SLANG_UNUSED (guid ); 35return nullptr ; 36} 37 38void * RiffFileSystem ::castAs (const Guid & guid ) 39{ 40if (auto ptr = getInterface (guid )) 41 { 42return ptr ; 43 } 44return getObject (guid ); 45} 46 47SlangResult RiffFileSystem ::loadFile (char const * path ,ISlangBlob ** outBlob ) 48{ 49Entry * entry ; 50SLANG_RETURN_ON_FAIL (_loadFile (path ,& entry )); 51 52ISlangBlob * contents = entry -> m_contents ; 53 54if (m_compressionSystem ) 55 { 56// Okay lets decompress into a blob 57ScopedAllocation alloc ; 58void * dst = alloc .allocateTerminated (entry -> m_uncompressedSizeInBytes ); 59SLANG_RETURN_ON_FAIL (m_compressionSystem -> decompress ( 60contents -> getBufferPointer (), 61contents -> getBufferSize (), 62entry -> m_uncompressedSizeInBytes , 63dst )); 64 65auto blob = RawBlob ::moveCreate (alloc ); 66 67* outBlob = blob .detach (); 68return SLANG_OK ; 69 } 70else 71 { 72// Just return as is 73contents -> addRef (); 74* outBlob = contents ; 75return SLANG_OK ; 76 } 77} 78 79SlangResult RiffFileSystem ::saveFile (const char * path ,const void * data ,size_t size ) 80{ 81Entry * entry ; 82SLANG_RETURN_ON_FAIL (_requireFile (path ,& entry )); 83 84ComPtr < ISlangBlob > contents ; 85if (m_compressionSystem ) 86 { 87// Lets try compressing the input 88SLANG_RETURN_ON_FAIL ( 89m_compressionSystem -> compress (& m_compressionStyle ,data ,size ,contents .writeRef ())); 90 } 91else 92 { 93// Just store the data directly. 94contents = RawBlob ::create (data ,size ); 95 } 96entry -> setContents (size ,contents ); 97return SLANG_OK ; 98} 99 100SlangResult RiffFileSystem ::saveFileBlob (const char * path ,ISlangBlob * dataBlob ) 101{ 102if (!dataBlob ) 103 { 104return SLANG_E_INVALID_ARG ; 105 } 106 107if (m_compressionSystem ) 108 { 109return saveFile (path ,dataBlob -> getBufferPointer (),dataBlob -> getBufferSize ()); 110 } 111else 112 { 113return Super ::saveFileBlob (path ,dataBlob ); 114 } 115} 116 117SlangResult RiffFileSystem ::loadArchive (const void * archive ,size_t archiveSizeInBytes ) 118{ 119// Load the riff 120auto rootList = RIFF ::RootChunk ::getFromBlob (archive ,archiveSizeInBytes ); 121 122// Make sure it's the right type 123if (rootList == nullptr || rootList -> getType ()!= RiffFileSystemBinary ::kContainerFourCC ) 124 { 125return SLANG_FAIL ; 126 } 127 128// Clear the contents 129_clear (); 130 131// Find the header 132auto headerChunk = rootList -> findDataChunk (RiffFileSystemBinary ::kHeaderFourCC ); 133 134const auto header = headerChunk -> readPayloadAs < RiffFileSystemBinary ::Header > (); 135 136CompressionSystemType compressionType = CompressionSystemType (header .compressionSystemType ); 137switch (compressionType ) 138 { 139case CompressionSystemType ::None : 140 { 141// Null m_compressionSystem means no compression 142m_compressionSystem .setNull (); 143break ; 144 } 145case CompressionSystemType ::Deflate : 146 { 147m_compressionSystem = DeflateCompressionSystem ::getSingleton (); 148break ; 149 } 150case CompressionSystemType ::LZ4 : 151 { 152m_compressionSystem = LZ4CompressionSystem ::getSingleton (); 153break ; 154 } 155default : 156return SLANG_FAIL ; 157 } 158 159// Read all of the contained data 160 161 { 162for (auto chunk :rootList -> getChildren ()) 163 { 164auto dataChunk = as < RIFF ::DataChunk > (chunk ); 165if (!dataChunk ) 166continue ; 167 168if (dataChunk -> getType ()!= RiffFileSystemBinary ::kEntryFourCC ) 169continue ; 170 171auto payloadData = (const uint8_t * )dataChunk -> getPayload (); 172auto payloadSize = dataChunk -> getPayloadSize (); 173 174if (payloadSize < sizeof (RiffFileSystemBinary ::Entry )) 175 { 176return SLANG_FAIL ; 177 } 178 179MemoryReader reader (payloadData ,payloadSize ); 180 181RiffFileSystemBinary ::Entry srcEntry ; 182reader .read (srcEntry ); 183 184// Check if seems plausible 185if (sizeof (RiffFileSystemBinary ::Entry )+ srcEntry .compressedSize + srcEntry .pathSize != 186payloadSize ) 187 { 188return SLANG_FAIL ; 189 } 190 191Entry dstEntry ; 192 193const char * path = (const char * )reader .getRemainingData (); 194reader .skip (srcEntry .pathSize ); 195 196dstEntry .m_canonicalPath = UnownedStringSlice (path ,srcEntry .pathSize - 1 ); 197dstEntry .m_type = (SlangPathType )srcEntry .pathType ; 198dstEntry .m_uncompressedSizeInBytes = srcEntry .uncompressedSize ; 199 200switch (dstEntry .m_type ) 201 { 202case SLANG_PATH_TYPE_FILE : 203 { 204if (reader .getRemainingSize ()!= srcEntry .compressedSize ) 205 { 206return SLANG_FAIL ; 207 } 208 209// Get the compressed data 210dstEntry .m_contents = 211RawBlob ::create (reader .getRemainingData (),srcEntry .compressedSize ); 212break ; 213 } 214case SLANG_PATH_TYPE_DIRECTORY : 215break ; 216default : 217return SLANG_FAIL ; 218 } 219 220// If it's the root entry we can ignore (as already added) 221if (dstEntry .m_canonicalPath == "." ) 222 { 223continue ; 224 } 225 226// Add to the list of entries 227m_entries .add (dstEntry .m_canonicalPath ,dstEntry ); 228 } 229 } 230 231return SLANG_OK ; 232} 233 234SlangResult RiffFileSystem ::storeArchive (bool blobOwnsContent ,ISlangBlob ** outBlob ) 235{ 236// All blobs are owned in this style 237SLANG_UNUSED (blobOwnsContent ) 238 239RIFF ::Builder builder ; 240RIFF ::BuildCursor cursor (builder ); 241SLANG_SCOPED_RIFF_BUILDER_LIST_CHUNK (cursor ,RiffFileSystemBinary ::kContainerFourCC ); 242 243 { 244RiffFileSystemBinary ::Header header ; 245CompressionSystemType compressionSystemType = m_compressionSystem 246 ?m_compressionSystem -> getSystemType () 247 :CompressionSystemType ::None ; 248header .compressionSystemType = uint32_t (compressionSystemType ); 249cursor .addDataChunk (RiffFileSystemBinary ::kHeaderFourCC ,& header ,sizeof (header )); 250 } 251 252for (const auto & [_ ,srcEntry ] :m_entries ) 253 { 254// Ignore the root entry 255if (srcEntry .m_canonicalPath == toSlice ("." )) 256 { 257continue ; 258 } 259 260SLANG_SCOPED_RIFF_BUILDER_DATA_CHUNK (cursor ,RiffFileSystemBinary ::kEntryFourCC ); 261 262RiffFileSystemBinary ::Entry dstEntry ; 263dstEntry .uncompressedSize = 0 ; 264dstEntry .compressedSize = 0 ; 265dstEntry .pathSize = uint32_t (srcEntry .m_canonicalPath .getLength ()+ 1 ); 266dstEntry .pathType = srcEntry .m_type ; 267 268ISlangBlob * blob = srcEntry .m_contents ; 269 270if (srcEntry .m_type == SLANG_PATH_TYPE_FILE ) 271 { 272dstEntry .compressedSize = uint32_t (blob -> getBufferSize ()); 273dstEntry .uncompressedSize = uint32_t (srcEntry .m_uncompressedSizeInBytes ); 274 } 275 276// Entry header 277cursor .addData (& dstEntry ,sizeof (dstEntry )); 278 279// Path 280cursor .addData ( 281srcEntry .m_canonicalPath .getBuffer (), 282srcEntry .m_canonicalPath .getLength ()+ 1 ); 283 284// Add the contained data without copying 285if (blob ) 286 { 287cursor .addUnownedData ( 288const_cast < void *> (blob -> getBufferPointer ()), 289blob -> getBufferSize ()); 290 } 291 } 292 293SLANG_RETURN_ON_FAIL (builder .writeToBlob (outBlob )); 294return SLANG_OK ; 295} 296 297/* static */ bool RiffFileSystem ::isArchive (const void * data ,size_t sizeInBytes ) 298{ 299auto rootList = RIFF ::RootChunk ::getFromBlob (data ,sizeInBytes ); 300if (!rootList ) 301return false; 302 303return rootList -> getType ()== RiffFileSystemBinary ::kContainerFourCC ; 304} 305 306}// namespace Slang