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