summaryrefslogtreecommitdiff
path: root/source/slang/slang-file-system.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-file-system.cpp')
-rw-r--r--source/slang/slang-file-system.cpp888
1 files changed, 0 insertions, 888 deletions
diff --git a/source/slang/slang-file-system.cpp b/source/slang/slang-file-system.cpp
deleted file mode 100644
index 992ae4155..000000000
--- a/source/slang/slang-file-system.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-#include "slang-file-system.h"
-
-#include "../../slang-com-ptr.h"
-#include "../core/slang-io.h"
-#include "../core/slang-string-util.h"
-
-namespace Slang
-{
-
-// Allocate static const storage for the various interface IDs that the Slang API needs to expose
-static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown;
-static const Guid IID_ISlangFileSystem = SLANG_UUID_ISlangFileSystem;
-static const Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt;
-static const Guid IID_ISlangMutableFileSystem = SLANG_UUID_ISlangMutableFileSystem;
-
-static const Guid IID_SlangCacheFileSystem = SLANG_UUID_CacheFileSystem;
-
-SLANG_FORCE_INLINE static SlangResult _checkExt(FileSystemStyle style) { return Index(style) >= Index(FileSystemStyle::Ext) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; }
-SLANG_FORCE_INLINE static SlangResult _checkMutable(FileSystemStyle style) { return Index(style) >= Index(FileSystemStyle::Mutable) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; }
-
-SLANG_FORCE_INLINE static bool _canCast(FileSystemStyle style, const Guid& guid)
-{
- if (guid == IID_ISlangUnknown || guid == IID_ISlangFileSystem)
- {
- return true;
- }
- else if (guid == IID_ISlangFileSystemExt)
- {
- return Index(style) >= Index(FileSystemStyle::Ext);
- }
- else if (guid == IID_ISlangMutableFileSystem)
- {
- return Index(style) >= Index(FileSystemStyle::Mutable);
- }
- return false;
-}
-
-static FileSystemStyle _getFileSystemStyle(ISlangFileSystem* system, ComPtr<ISlangFileSystem>& out)
-{
- SLANG_ASSERT(system);
-
- FileSystemStyle style = FileSystemStyle::Load;
-
- if (SLANG_SUCCEEDED(system->queryInterface(IID_ISlangMutableFileSystem, (void**)out.writeRef())))
- {
- style = FileSystemStyle::Mutable;
- }
- else if (SLANG_SUCCEEDED(system->queryInterface(IID_ISlangFileSystemExt, (void**)out.writeRef())))
- {
- style = FileSystemStyle::Ext;
- }
- else
- {
- style = FileSystemStyle::Load;
- out = system;
- }
-
- SLANG_ASSERT(out);
- return style;
-}
-
-// Cacluate a combined path, just using Path:: string processing
-static SlangResult _calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
-{
- String relPath;
- switch (fromPathType)
- {
- case SLANG_PATH_TYPE_FILE:
- {
- relPath = Path::combine(Path::getParentDirectory(fromPath), path);
- break;
- }
- case SLANG_PATH_TYPE_DIRECTORY:
- {
- relPath = Path::combine(fromPath, path);
- break;
- }
- }
-
- *pathOut = StringUtil::createStringBlob(relPath).detach();
- return SLANG_OK;
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! OSFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
-
-/* static */OSFileSystem OSFileSystem::g_load(FileSystemStyle::Load);
-/* static */OSFileSystem OSFileSystem::g_ext(FileSystemStyle::Ext);
-/* static */OSFileSystem OSFileSystem::g_mutable(FileSystemStyle::Mutable);
-
-ISlangUnknown* OSFileSystem::getInterface(const Guid& guid)
-{
- return _canCast(m_style, guid) ? static_cast<ISlangFileSystem*>(this) : nullptr;
-}
-
-static String _fixPathDelimiters(const char* pathIn)
-{
-#if SLANG_WINDOWS_FAMILY
- return pathIn;
-#else
- // To allow windows style \ delimiters on other platforms, we convert to our standard delimiter
- String path(pathIn);
- return StringUtil::calcCharReplaced(pathIn, '\\', Path::kPathDelimiter);
-#endif
-}
-
-SlangResult OSFileSystem::getFileUniqueIdentity(const char* pathIn, ISlangBlob** outUniqueIdentity)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- // By default we use the canonical path to uniquely identify a file
- return getCanonicalPath(pathIn, outUniqueIdentity);
-}
-
-SlangResult OSFileSystem::getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- String canonicalPath;
- SLANG_RETURN_ON_FAIL(Path::getCanonical(_fixPathDelimiters(path), canonicalPath));
- *outCanonicalPath = StringUtil::createStringBlob(canonicalPath).detach();
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::getSimplifiedPath(const char* pathIn, ISlangBlob** outSimplifiedPath)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- String simplifiedPath = Path::simplify(pathIn);
- *outSimplifiedPath = StringUtil::createStringBlob(simplifiedPath).detach();
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- // Don't need to fix delimiters - because combine path handles both path delimiter types
- return _calcCombinedPath(fromPathType, fromPath, path, pathOut);
-}
-
-SlangResult SLANG_MCALL OSFileSystem::getPathType(const char* pathIn, SlangPathType* pathTypeOut)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- return Path::getPathType(_fixPathDelimiters(pathIn), pathTypeOut);
-}
-
-
-SlangResult OSFileSystem::loadFile(char const* pathIn, ISlangBlob** outBlob)
-{
- // Default implementation that uses the `core` libraries facilities for talking to the OS filesystem.
- //
- // TODO: we might want to conditionally compile these in, so that
- // a user could create a build of Slang that doesn't include any OS
- // filesystem calls.
-
- const String path = _fixPathDelimiters(pathIn);
- if (!File::exists(path))
- {
- return SLANG_E_NOT_FOUND;
- }
-
- ScopedAllocation alloc;
- SLANG_RETURN_ON_FAIL(File::readAllBytes(path, alloc));
- *outBlob = RawBlob::moveCreate(alloc).detach();
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- struct Visitor : Path::Visitor
- {
- void accept(Path::Type type, const UnownedStringSlice& filename) SLANG_OVERRIDE
- {
- m_buffer.Clear();
- m_buffer.append(filename);
-
- SlangPathType pathType;
- switch (type)
- {
- case Path::Type::File: pathType = SLANG_PATH_TYPE_FILE; break;
- case Path::Type::Directory: pathType = SLANG_PATH_TYPE_DIRECTORY; break;
- default: return;
- }
-
- m_callback(pathType, m_buffer.getBuffer(), m_userData);
- }
-
- Visitor(FileSystemContentsCallBack callback, void* userData) :
- m_callback(callback),
- m_userData(userData)
- {
- }
- StringBuilder m_buffer;
- FileSystemContentsCallBack m_callback;
- void* m_userData;
- };
-
- Visitor visitor(callback, userData);
- Path::find(path, nullptr, &visitor);
-
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::saveFile(const char* pathIn, const void* data, size_t size)
-{
- SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
-
- const String path = _fixPathDelimiters(pathIn);
-
- try
- {
- FileStream stream(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite);
-
- int64_t numWritten = stream.write(data, size);
-
- if (numWritten != int64_t(size))
- {
- return SLANG_FAIL;
- }
-
- }
- catch (const IOException&)
- {
- return SLANG_E_CANNOT_OPEN;
- }
-
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::remove(const char* path)
-{
- SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
- return Path::remove(path);
-}
-
-SlangResult OSFileSystem::createDirectory(const char* path)
-{
- SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
- return Path::createDirectory(path);
-}
-
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CacheFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-/* static */ const Result CacheFileSystem::s_compressedResultToResult[] =
-{
- SLANG_E_UNINITIALIZED,
- SLANG_OK, ///< Ok
- SLANG_E_NOT_FOUND, ///< File not found
- SLANG_E_CANNOT_OPEN, ///< CannotOpen,
- SLANG_FAIL, ///< Fail
-};
-
-/* static */CacheFileSystem::CompressedResult CacheFileSystem::toCompressedResult(Result res)
-{
- if (SLANG_SUCCEEDED(res))
- {
- return CompressedResult::Ok;
- }
- switch (res)
- {
- case SLANG_E_CANNOT_OPEN: return CompressedResult::CannotOpen;
- case SLANG_E_NOT_FOUND: return CompressedResult::NotFound;
- default: return CompressedResult::Fail;
- }
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL CacheFileSystem::queryInterface(SlangUUID const& uuid, void** outObject)
-{
- if (uuid == IID_SlangCacheFileSystem)
- {
- *outObject = this;
- return SLANG_OK;
- }
-
- if (_canCast(FileSystemStyle::Ext, uuid))
- {
- addReference();
- *outObject = static_cast<ISlangFileSystemExt*>(this);
- return SLANG_OK;
- }
- return SLANG_E_NO_INTERFACE;
-}
-
-CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle)
-{
- setInnerFileSystem(fileSystem, uniqueIdentityMode, pathStyle);
-}
-
-CacheFileSystem::~CacheFileSystem()
-{
- for (const auto& pair : m_uniqueIdentityMap)
- {
- PathInfo* pathInfo = pair.Value;
- delete pathInfo;
- }
-}
-
-void CacheFileSystem::setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle)
-{
- m_fileSystem = fileSystem;
-
- m_uniqueIdentityMode = uniqueIdentityMode;
- m_pathStyle = pathStyle;
-
- m_fileSystemExt.setNull();
-
- if (fileSystem)
- {
- // Try to get the more sophisticated interface
- fileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)m_fileSystemExt.writeRef());
- }
-
- switch (m_uniqueIdentityMode)
- {
- case UniqueIdentityMode::Default:
- case UniqueIdentityMode::FileSystemExt:
- {
- // If it's not a complete file system, we will default to SimplifyAndHash style by default
- m_uniqueIdentityMode = m_fileSystemExt ? UniqueIdentityMode::FileSystemExt : UniqueIdentityMode::SimplifyPathAndHash;
- break;
- }
- default: break;
- }
-
- if (pathStyle == PathStyle::Default)
- {
- // We'll assume it's simplify-able
- m_pathStyle = PathStyle::Simplifiable;
- // If we have fileSystemExt, we defer to that
- if (m_fileSystemExt)
- {
- // We just defer to the m_fileSystem
- m_pathStyle = PathStyle::FileSystemExt;
- }
- }
-
- // It can't be default
- SLANG_ASSERT(m_uniqueIdentityMode != UniqueIdentityMode::Default);
-}
-
-void CacheFileSystem::clearCache()
-{
- for (const auto& pair : m_uniqueIdentityMap)
- {
- PathInfo* pathInfo = pair.Value;
- delete pathInfo;
- }
-
- m_uniqueIdentityMap.Clear();
- m_pathMap.Clear();
-
- if (m_fileSystemExt)
- {
- m_fileSystemExt->clearCache();
- }
-}
-
-
-// Determines if we can simplify a path for a given mode
-static bool _canSimplifyPath(CacheFileSystem::UniqueIdentityMode mode)
-{
- typedef CacheFileSystem::UniqueIdentityMode UniqueIdentityMode;
- switch (mode)
- {
- case UniqueIdentityMode::SimplifyPath:
- case UniqueIdentityMode::SimplifyPathAndHash:
- {
- return true;
- }
- default:
- {
- return false;
- }
- }
-}
-
-SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData)
-{
- if (m_fileSystemExt)
- {
- return m_fileSystemExt->enumeratePathContents(path, callback, userData);
- }
-
- // Okay.. the contents of the 'cache' *is* the filesystem. So lets iterate over that
- // This will win no prizes for efficiency, but that is unlikely to matter for typical usage
-
- if (!_canSimplifyPath(m_uniqueIdentityMode))
- {
- // As it stands if we can't simplify paths, it's kind of hard to make this
- // all work. As we use the simplified path cache
- return SLANG_E_NOT_IMPLEMENTED;
- }
-
- // Simplify the path
- String simplifiedPath = Path::simplify(path);
-
- // If the simplified path is just a . then we don't have any prefix
- if (simplifiedPath == ".")
- {
- simplifiedPath = "";
- }
-
- for (auto& pair : m_pathMap)
- {
- // NOTE! The currentPath can be a *non* simplified path (the m_pathMap is the cache of paths simplified and other to a file/directory)
- // Also note that there will always be the simplified version of the path in cache.
- const String& currentPath = pair.Key;
-
- // If it doesn't start with simplified path, then it can't be a hit
- if (!currentPath.startsWith(simplifiedPath))
- {
- continue;
- }
-
- UnownedStringSlice remaining(currentPath.getBuffer() + simplifiedPath.getLength(), currentPath.end());
-
- // If it starts with a / delimiter strip it
- if (remaining.getLength() > 0 && remaining[0] == '/')
- {
- remaining = UnownedStringSlice(remaining.begin() + 1, remaining.end());
- }
-
- // If it has a path separator then it's either not simplified - so we ignore (we only want to invoke on the simplified path version as there is only one
- // of these for every PathInfo)
- // or it is a child file/directory, and so we ignore that too.
- if (remaining.indexOf('/') >= 0 || remaining.indexOf('\\') >= 0)
- {
- continue;
- }
-
- // We *know* that remaining comes from the end of currentPath .We also know currentPath is zero terminated.
- // So we can just use (normally this would be a problem because UnownedStringSlice is generally *not* followed by zero termination.
- const char* foundPath = remaining.begin();
- // Let's check that fact...
- SLANG_ASSERT(foundPath[remaining.getLength()] == 0);
-
- PathInfo* pathInfo = pair.Value;
-
- SlangPathType pathType;
- if (SLANG_FAILED(_getPathType(pathInfo, currentPath.getBuffer(), &pathType)))
- {
- continue;
- }
-
- callback(pathType, foundPath, userData);
- }
-
- return SLANG_OK;
-}
-
-
-SlangResult CacheFileSystem::_calcUniqueIdentity(const String& path, String& outUniqueIdentity, ComPtr<ISlangBlob>& outFileContents)
-{
- switch (m_uniqueIdentityMode)
- {
- case UniqueIdentityMode::FileSystemExt:
- {
- // Try getting the uniqueIdentity by asking underlying file system
- ComPtr<ISlangBlob> uniqueIdentity;
- SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef()));
- // Get the path as a string
- outUniqueIdentity = StringUtil::getString(uniqueIdentity);
- return SLANG_OK;
- }
- case UniqueIdentityMode::Path:
- {
- outUniqueIdentity = path;
- return SLANG_OK;
- }
- case UniqueIdentityMode::SimplifyPath:
- {
- outUniqueIdentity = Path::simplify(path);
- // If it still has relative elements can't uniquely identify, so give up
- return Path::hasRelativeElement(outUniqueIdentity) ? SLANG_FAIL : SLANG_OK;
- }
- case UniqueIdentityMode::SimplifyPathAndHash:
- case UniqueIdentityMode::Hash:
- {
- // If we don't have a file system -> assume cannot be found
- if (m_fileSystem == nullptr)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- // I can only see if this is the same file as already loaded by loading the file and doing a hash
- Result res = m_fileSystem->loadFile(path.getBuffer(), outFileContents.writeRef());
- if (SLANG_FAILED(res) || outFileContents == nullptr)
- {
- return SLANG_FAIL;
- }
-
- // Calculate the hash on the contents
- const uint64_t hash = getHashCode64((const char*)outFileContents->getBufferPointer(), outFileContents->getBufferSize());
-
- String hashString = Path::getFileName(path);
- hashString = hashString.toLower();
-
- hashString.append(':');
-
- // The uniqueIdentity is a combination of name and hash
- hashString.append(hash, 16);
-
- outUniqueIdentity = hashString;
- return SLANG_OK;
- }
- }
-
- return SLANG_FAIL;
-}
-
-CacheFileSystem::PathInfo* CacheFileSystem::_resolveUniqueIdentityCacheInfo(const String& path)
-{
- // Use the path to produce uniqueIdentity information
- ComPtr<ISlangBlob> fileContents;
- String uniqueIdentity;
-
- SlangResult res = _calcUniqueIdentity(path, uniqueIdentity, fileContents);
- if (SLANG_FAILED(res))
- {
- // Was not able to create a uniqueIdentity - return failure as nullptr
- return nullptr;
- }
-
- // Now try looking up by uniqueIdentity path. If not found, add a new result
- PathInfo* pathInfo = nullptr;
- if (!m_uniqueIdentityMap.TryGetValue(uniqueIdentity, pathInfo))
- {
- // Create with found uniqueIdentity
- pathInfo = new PathInfo(uniqueIdentity);
- m_uniqueIdentityMap.Add(uniqueIdentity, pathInfo);
- }
-
- // At this point they must have same uniqueIdentity
- SLANG_ASSERT(pathInfo->getUniqueIdentity() == uniqueIdentity);
-
- // If we have the file contents (because of calc-ing uniqueIdentity), and there isn't a read file blob already
- // store the data as if read, so doesn't get read again
- if (fileContents && !pathInfo->m_fileBlob)
- {
- pathInfo->m_fileBlob = fileContents;
- pathInfo->m_loadFileResult = CompressedResult::Ok;
- }
-
- return pathInfo;
-}
-
-CacheFileSystem::PathInfo* CacheFileSystem::_resolveSimplifiedPathCacheInfo(const String& path)
-{
- // If we can simplify the path, try looking up in path cache with simplified path (as long as it's different!)
- if (_canSimplifyPath(m_uniqueIdentityMode))
- {
- const String simplifiedPath = Path::simplify(path);
- // Only lookup if the path is different - because otherwise will recurse forever...
- if (simplifiedPath != path)
- {
- // This is a recursive call - and will ensure the simplified path is added to the cache
- return _resolvePathCacheInfo(simplifiedPath);
- }
- }
-
- return _resolveUniqueIdentityCacheInfo(path);
-}
-
-CacheFileSystem::PathInfo* CacheFileSystem::_resolvePathCacheInfo(const String& path)
-{
- // Lookup in path cache
- PathInfo* pathInfo;
- if (m_pathMap.TryGetValue(path, pathInfo))
- {
- // Found so done
- return pathInfo;
- }
-
- // Try getting or creating taking into account possible path simplification
- pathInfo = _resolveSimplifiedPathCacheInfo(path);
- // Always add the result to the path cache (even if null)
- m_pathMap.Add(path, pathInfo);
- return pathInfo;
-}
-
-SlangResult CacheFileSystem::loadFile(char const* pathIn, ISlangBlob** blobOut)
-{
- *blobOut = nullptr;
- String path(pathIn);
- PathInfo* info = _resolvePathCacheInfo(path);
- if (!info)
- {
- return SLANG_FAIL;
- }
-
- if (info->m_loadFileResult == CompressedResult::Uninitialized)
- {
- info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(path.getBuffer(), info->m_fileBlob.writeRef()));
- }
-
- *blobOut = info->m_fileBlob;
- if (*blobOut)
- {
- (*blobOut)->addRef();
- }
- return toResult(info->m_loadFileResult);
-}
-
-SlangResult CacheFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity)
-{
- PathInfo* info = _resolvePathCacheInfo(path);
- if (!info)
- {
- return SLANG_E_NOT_FOUND;
- }
- info->m_uniqueIdentity->addRef();
- *outUniqueIdentity = info->m_uniqueIdentity;
- return SLANG_OK;
-}
-
-SlangResult CacheFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
-{
- // Just defer to contained implementation
- switch (m_pathStyle)
- {
- case PathStyle::FileSystemExt:
- {
- return m_fileSystemExt->calcCombinedPath(fromPathType, fromPath, path, pathOut);
- }
- default:
- {
- // Just use the default implementation
- return _calcCombinedPath(fromPathType, fromPath, path, pathOut);
- }
- }
-}
-
-SlangResult CacheFileSystem::_getPathType(PathInfo* info, const char* inPath, SlangPathType* outPathType)
-{
- if (info->m_getPathTypeResult == CompressedResult::Uninitialized)
- {
- if (m_fileSystemExt)
- {
- info->m_getPathTypeResult = toCompressedResult(m_fileSystemExt->getPathType(inPath, &info->m_pathType));
- }
- else
- {
- // Okay try to load the file
- if (info->m_loadFileResult == CompressedResult::Uninitialized)
- {
- info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(inPath, info->m_fileBlob.writeRef()));
- }
-
- // Make the getPathResult the same as the load result
- info->m_getPathTypeResult = info->m_loadFileResult;
- // Just set to file... the result is what matters in this case
- info->m_pathType = SLANG_PATH_TYPE_FILE;
- }
- }
-
- *outPathType = info->m_pathType;
- return toResult(info->m_getPathTypeResult);
-}
-
-SlangResult CacheFileSystem::getPathType(const char* inPath, SlangPathType* outPathType)
-{
- PathInfo* info = _resolvePathCacheInfo(inPath);
- if (!info)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- return _getPathType(info, inPath, outPathType);
-}
-
-SlangResult CacheFileSystem::getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath)
-{
- // If we have a ISlangFileSystemExt we can just pass on the request to it
- switch (m_pathStyle)
- {
- case PathStyle::FileSystemExt:
- {
- return m_fileSystemExt->getSimplifiedPath(path, outSimplifiedPath);
- }
- case PathStyle::Simplifiable:
- {
- String simplifiedPath = Path::simplify(path);
- *outSimplifiedPath = StringUtil::createStringBlob(simplifiedPath).detach();
- return SLANG_OK;
- }
- default: return SLANG_E_NOT_IMPLEMENTED;
- }
-}
-
-SlangResult CacheFileSystem::getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath)
-{
- // A file must exist to get a canonical path...
- PathInfo* info = _resolvePathCacheInfo(path);
- if (!info)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- // We don't have this -> so read it ...
- if (info->m_getCanonicalPathResult == CompressedResult::Uninitialized)
- {
- if (!m_fileSystemExt)
- {
- return SLANG_E_NOT_IMPLEMENTED;
- }
-
- // Try getting the canonicalPath by asking underlying file system
- ComPtr<ISlangBlob> canonicalPathBlob;
- SlangResult res = m_fileSystemExt->getCanonicalPath(path, canonicalPathBlob.writeRef());
-
- if (SLANG_SUCCEEDED(res))
- {
- // Get the path as a string
- String canonicalPath = StringUtil::getString(canonicalPathBlob);
- if (canonicalPath.getLength() > 0)
- {
- info->m_canonicalPath = new StringBlob(canonicalPath);
- }
- else
- {
- res = SLANG_FAIL;
- }
- }
-
- // Save the result
- info->m_getCanonicalPathResult = toCompressedResult(res);
- }
-
- if (info->m_canonicalPath)
- {
- info->m_canonicalPath->addRef();
- }
- *outCanonicalPath = info->m_canonicalPath;
- return SLANG_OK;
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RelativeFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-RelativeFileSystem::RelativeFileSystem(ISlangFileSystem* fileSystem, const String& relativePath, bool stripPath) :
- m_relativePath(relativePath),
- m_stripPath(stripPath)
-{
- m_style = _getFileSystemStyle(fileSystem, m_fileSystem);
-}
-
-ISlangUnknown* RelativeFileSystem::getInterface(const Guid& guid)
-{
- return _canCast(m_style, guid) ? static_cast<ISlangMutableFileSystem*>(this) : nullptr;
-}
-
-SlangResult RelativeFileSystem::_calcCombinedPathInner(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** outPath)
-{
- ISlangFileSystemExt* fileSystem = _getExt();
- if (fileSystem)
- {
- return fileSystem->calcCombinedPath(fromPathType, fromPath, path, outPath);
- }
- else
- {
- return _calcCombinedPath(fromPathType, fromPath, path, outPath);
- }
-}
-
-SlangResult RelativeFileSystem::_getFixedPath(const char* path, String& outPath)
-{
- ComPtr<ISlangBlob> blob;
- if (m_stripPath)
- {
- String strippedPath = Path::getFileName(path);
- SLANG_RETURN_ON_FAIL(_calcCombinedPathInner(SLANG_PATH_TYPE_DIRECTORY, m_relativePath.getBuffer(), strippedPath.getBuffer(), blob.writeRef()));
- }
- else
- {
- SLANG_RETURN_ON_FAIL(_calcCombinedPathInner(SLANG_PATH_TYPE_DIRECTORY, m_relativePath.getBuffer(), path, blob.writeRef()));
- }
-
- outPath = StringUtil::getString(blob);
- return SLANG_OK;
-}
-
-SlangResult RelativeFileSystem::loadFile(char const* path, ISlangBlob** outBlob)
-{
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return m_fileSystem->loadFile(fixedPath.getBuffer(), outBlob);
-}
-
-SlangResult RelativeFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->getFileUniqueIdentity(fixedPath.getBuffer(), outUniqueIdentity);
-}
-
-SlangResult RelativeFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** outPath)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedFromPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(fromPath, fixedFromPath));
-
- return fileSystem->calcCombinedPath(fromPathType, fixedFromPath.getBuffer(), path, outPath);
-}
-
-SlangResult RelativeFileSystem::getPathType(const char* path, SlangPathType* outPathType)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->getPathType(fixedPath.getBuffer(), outPathType);
-}
-
-SlangResult RelativeFileSystem::getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- return fileSystem->getSimplifiedPath(path, outSimplifiedPath);
-}
-
-SlangResult RelativeFileSystem::getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->getCanonicalPath(fixedPath.getBuffer(), outCanonicalPath);
-}
-
-void RelativeFileSystem::clearCache()
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return;
-
- fileSystem->clearCache();
-}
-
-SlangResult RelativeFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->enumeratePathContents(fixedPath.getBuffer(), callback, userData);
-}
-
-SlangResult RelativeFileSystem::saveFile(const char* path, const void* data, size_t size)
-{
- auto fileSystem = _getMutable();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->saveFile(fixedPath.getBuffer(), data, size);
-}
-
-SlangResult RelativeFileSystem::remove(const char* path)
-{
- auto fileSystem = _getMutable();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->remove(fixedPath.getBuffer());
-}
-
-SlangResult RelativeFileSystem::createDirectory(const char* path)
-{
- auto fileSystem = _getMutable();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->createDirectory(fixedPath.getBuffer());
-}
-
-}