diff options
Diffstat (limited to 'source/core')
| -rw-r--r-- | source/core/slang-file-system.cpp | 35 | ||||
| -rw-r--r-- | source/core/slang-file-system.h | 4 | ||||
| -rw-r--r-- | source/core/slang-implicit-directory-collector.cpp | 23 | ||||
| -rw-r--r-- | source/core/slang-implicit-directory-collector.h | 2 | ||||
| -rw-r--r-- | source/core/slang-io.cpp | 45 | ||||
| -rw-r--r-- | source/core/slang-io.h | 41 | ||||
| -rw-r--r-- | source/core/slang-memory-file-system.cpp | 24 | ||||
| -rw-r--r-- | source/core/slang-memory-file-system.h | 4 | ||||
| -rw-r--r-- | source/core/slang-zip-file-system.cpp | 35 |
9 files changed, 156 insertions, 57 deletions
diff --git a/source/core/slang-file-system.cpp b/source/core/slang-file-system.cpp index 0697810f4..0369d0a02 100644 --- a/source/core/slang-file-system.cpp +++ b/source/core/slang-file-system.cpp @@ -871,19 +871,35 @@ SlangResult RelativeFileSystem::_calcCombinedPathInner(SlangPathType fromPathTyp } } -SlangResult RelativeFileSystem::_getCanonicalPath(const char* path, StringBuilder& outPath) +SlangResult RelativeFileSystem::_getCanonicalPath(const char* path, String& outPath) { if (m_stripPath) { // We are just using the filename. There is no path that could go outside of the the relative path so we can use as is - auto fileName = Path::getFileName(path); - - outPath.swapWith(fileName); + outPath = Path::getFileName(path); } else { + // NOTE that we don't want the canonical path to be absolute with a leading "/" + // because paths specified which aren't absolute, would produce a different path. + // + // Ie we want (and get with these options) + // "a" -> "a" + // "/a" -> "a". + // + // If we allowed the root to be included then... + // "a" -> "a" + // "/a" -> "/a" + // + // Two identical paths would match to different paths, which wouldn't be canonical. + // + // This could be fixed by making all paths absolute with '/' too, but it's easier to just make all not + // have "/" + + StringBuilder canonicalPath; // We want the input path to be local to this file system - SLANG_RETURN_ON_FAIL(Path::simplifyAbsolute(path, outPath)); + SLANG_RETURN_ON_FAIL(Path::simplify(path, Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, canonicalPath)); + outPath = canonicalPath; } return SLANG_OK; } @@ -892,11 +908,12 @@ SlangResult RelativeFileSystem::_getFixedPath(const char* path, String& outPath) { ComPtr<ISlangBlob> blob; - StringBuilder canonicalPath; + String canonicalPath; SLANG_RETURN_ON_FAIL(_getCanonicalPath(path, canonicalPath)); + SLANG_RETURN_ON_FAIL(_calcCombinedPathInner(SLANG_PATH_TYPE_DIRECTORY, m_relativePath.getBuffer(), canonicalPath.getBuffer(), blob.writeRef())); - outPath = StringUtil::getString(blob); + return SLANG_OK; } @@ -957,8 +974,8 @@ SlangResult RelativeFileSystem::getPath(PathKind kind, const char* path, ISlangB } case PathKind::Canonical: { - StringBuilder canonicalPath; - SLANG_RETURN_ON_FAIL(_getCanonicalPath(path, canonicalPath)); + String canonicalPath; + SLANG_RETURN_ON_FAIL(_getCanonicalPath(path, canonicalPath)); *outPath = StringBlob::moveCreate(canonicalPath).detach(); return SLANG_OK; } diff --git a/source/core/slang-file-system.h b/source/core/slang-file-system.h index a3efbfe68..93d0659ec 100644 --- a/source/core/slang-file-system.h +++ b/source/core/slang-file-system.h @@ -258,8 +258,8 @@ protected: /// Get the fixed path to the item for the backing file system. SlangResult _getFixedPath(const char* path, String& outPath); - /// Get the canonical path - SlangResult _getCanonicalPath(const char* path, StringBuilder& outPath); + + SlangResult _getCanonicalPath(const char* path, String& outPath); ISlangUnknown* getInterface(const Guid& guid); void* getObject(const Guid& guid); diff --git a/source/core/slang-implicit-directory-collector.cpp b/source/core/slang-implicit-directory-collector.cpp index 199fd6155..994ebd4d7 100644 --- a/source/core/slang-implicit-directory-collector.cpp +++ b/source/core/slang-implicit-directory-collector.cpp @@ -1,5 +1,7 @@ #include "slang-implicit-directory-collector.h" +#include "slang-io.h" + namespace Slang { @@ -8,13 +10,28 @@ namespace Slang ImplicitDirectoryCollector::ImplicitDirectoryCollector(const String& canonicalPath, bool directoryExists) : m_directoryExists(directoryExists) { - StringBuilder buffer; - if (canonicalPath != ".") + if (!isRootPath(canonicalPath.getUnownedSlice())) { + StringBuilder buffer; buffer << canonicalPath; buffer.append('/'); + m_prefix = buffer.ProduceString(); + } +} + +/* static */bool ImplicitDirectoryCollector::isRootPath(const UnownedStringSlice& path) +{ + const auto length = path.getLength(); + if (length == 0) + { + return true; + } + else if (length == 1) + { + const auto c = path[0]; + return c == '.' || Path::isDelimiter(c); } - m_prefix = buffer.ProduceString(); + return false; } void ImplicitDirectoryCollector::addRemainingPath(SlangPathType pathType, const UnownedStringSlice& inPathRemainder) diff --git a/source/core/slang-implicit-directory-collector.h b/source/core/slang-implicit-directory-collector.h index 280ba33e6..3b3505df2 100644 --- a/source/core/slang-implicit-directory-collector.h +++ b/source/core/slang-implicit-directory-collector.h @@ -57,6 +57,8 @@ public: /// Ctor ImplicitDirectoryCollector(const String& canonicalPath, bool directoryExists = false); + static bool isRootPath(const UnownedStringSlice& path); + protected: StringSliceIndexMap m_map; String m_prefix; diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index b25d5562d..345a2c353 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -419,7 +419,7 @@ namespace Slang return false; } - /* static */SlangResult Path::simplifyAbsolute(const UnownedStringSlice& path, StringBuilder& outPath) + /* static */SlangResult Path::simplify(const UnownedStringSlice& path, SimplifyStyle style, StringBuilder& outPath) { if (path.getLength() == 0) { @@ -427,27 +427,38 @@ namespace Slang } List<UnownedStringSlice> splitPath; - Path::split(UnownedStringSlice(path), splitPath); + split(UnownedStringSlice(path), splitPath); - // If the first part of a path is "", it means path of form "/some/path". Turn into "some/path". - if (splitPath.getCount() > 1 && splitPath[0].getLength() == 0) - { - splitPath.removeAt(0); - } + simplify(splitPath); - Path::simplify(splitPath); + const auto simplifyIntegral = SimplifyIntegral(style); // If it has a relative part then it's not absolute - if (splitPath.indexOf(UnownedStringSlice::fromLiteral("..")) >= 0) + if ((simplifyIntegral & SimplifyFlag::AbsoluteOnly) && + splitPath.indexOf(UnownedStringSlice::fromLiteral("..")) >= 0) { return SLANG_E_NOT_FOUND; } // We allow splitPath.getCount() == 0, because // the original path could have been '.' or './.' - // Special handling for this is in join + // + // Special handling this case is in Path::join + + // If we want the path produced such that is *not* output with a root (ie SimplifyFlag::NoRoot) + // we detect if we a rooted path (ie in effect starting with "/") and so splitPath[0] == "" + // and remove that part from when doing the join. + if ((simplifyIntegral & SimplifyFlag::NoRoot) && + (splitPath.getCount() && splitPath[0].getLength() == 0)) + { + // If we allow without a root, we remove from the join + Path::join(splitPath.getBuffer() + 1, splitPath.getCount() - 1, outPath); + } + else + { + Path::join(splitPath.getBuffer(), splitPath.getCount(), outPath); + } - Path::join(splitPath.getBuffer(), splitPath.getCount(), outPath); return SLANG_OK; } @@ -485,10 +496,16 @@ namespace Slang if (count == 0) { out << "."; - return; } - - StringUtil::join(slices, count, kPathDelimiter, out); + else if (count == 1 && slices[0].getLength() == 0) + { + // It's the root + out << kPathDelimiter; + } + else + { + StringUtil::join(slices, count, kPathDelimiter, out); + } } diff --git a/source/core/slang-io.h b/source/core/slang-io.h index acdcd0124..292328603 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -39,6 +39,34 @@ namespace Slang class Path { public: + typedef uint32_t SimplifyIntegral; + + struct SimplifyFlag + { + enum Enum : SimplifyIntegral + { + /// Can only simplify to an absolute path. Will return an error if not possible. + /// Useful to constrain a path, such as when wanting something like 'chroot'. + AbsoluteOnly = 0x1, + /// If the simplified path is a root path, remove the root. + /// Will mean that for example + /// "/" -> "." + /// "/a/.." -> "." + /// "/a" -> "a" + /// Its worth noting that a path prefixed "/" will never be returned and if *just* the root it specified + /// it will return as ".". + NoRoot = 0x2, + }; + }; + + // A more convenient typesafe way to specify the SimplifyFlag combinations + enum SimplifyStyle : SimplifyIntegral + { + Normal = 0, + AbsoluteOnly = SimplifyFlag::AbsoluteOnly, + NoRoot = SimplifyFlag::NoRoot, + AbsoluteOnlyAndNoRoot = SimplifyFlag::AbsoluteOnly | SimplifyFlag::NoRoot, + }; enum class Type { @@ -121,16 +149,21 @@ namespace Slang static bool isDriveSpecification(const UnownedStringSlice& pathPrefix); /// Splits the path into it's individual bits + /// Absolute paths of the form "/" will become [""] + /// Absolute paths of the form "a:/" will become ["a:", ""] + /// A drive specification of the form "a:" will become ["a:"] + /// Relative paths that are in effect "." will become [] static void split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut); + /// Strips .. and . as much as it can static String simplify(const UnownedStringSlice& path); static String simplify(const String& path) { return simplify(path.getUnownedSlice()); } /// Given a path simplifies it such the the resultant path is absolute (ie contains no . or ..) - /// Can return '.' as the path as the directory 'root'. - static SlangResult simplifyAbsolute(const UnownedStringSlice& path, StringBuilder& outPath); - static SlangResult simplifyAbsolute(const String& path, StringBuilder& outPath) { return simplifyAbsolute(path.getUnownedSlice(), outPath); } - static SlangResult simplifyAbsolute(const char* path, StringBuilder& outPath) { return simplifyAbsolute(UnownedStringSlice(path), outPath); } + /// Same behavior as simplify around the root + static SlangResult simplify(const UnownedStringSlice& path, SimplifyStyle style, StringBuilder& outPath); + static SlangResult simplify(const String& path, SimplifyStyle style, StringBuilder& outPath) { return simplify(path.getUnownedSlice(), style, outPath); } + static SlangResult simplify(const char* path, SimplifyStyle style, StringBuilder& outPath) { return simplify(UnownedStringSlice(path), style, outPath); } /// Simplifies the path split up static void simplify(List<UnownedStringSlice>& ioSplit); diff --git a/source/core/slang-memory-file-system.cpp b/source/core/slang-memory-file-system.cpp index 06c0a4ebe..a6bc05f24 100644 --- a/source/core/slang-memory-file-system.cpp +++ b/source/core/slang-memory-file-system.cpp @@ -9,6 +9,11 @@ namespace Slang { +MemoryFileSystem::MemoryFileSystem() +{ + m_rootEntry.initDirectory("/"); +} + void* MemoryFileSystem::getInterface(const Guid& guid) { if ( guid == ISlangUnknown::getTypeGuid() || @@ -40,15 +45,18 @@ void* MemoryFileSystem::castAs(const Guid& guid) void MemoryFileSystem::_clear() { m_entries = Dictionary<String, Entry>(); - // Add the root - Entry entry; - entry.initDirectory("."); - m_entries.Add(entry.m_canonicalPath, entry); } MemoryFileSystem::Entry* MemoryFileSystem::_getEntryFromCanonicalPath(const String& canonicalPath) { - return m_entries.TryGetValue(canonicalPath); + if (canonicalPath == toSlice(".")) + { + return &m_rootEntry; + } + else + { + return m_entries.TryGetValue(canonicalPath); + } } MemoryFileSystem::Entry* MemoryFileSystem::_getEntryFromPath(const char* path, String* outPath) @@ -141,7 +149,7 @@ SlangResult MemoryFileSystem::getPath(PathKind kind, const char* path, ISlangBlo case PathKind::Canonical: { StringBuilder buffer; - SLANG_RETURN_ON_FAIL(Path::simplifyAbsolute(path, buffer)); + SLANG_RETURN_ON_FAIL(_getCanonical(path, buffer)); *outPath = StringBlob::moveCreate(buffer).detach(); return SLANG_OK; } @@ -197,7 +205,7 @@ SlangResult MemoryFileSystem::saveFileBlob(const char* path, ISlangBlob* dataBlo SlangResult MemoryFileSystem::_getCanonical(const char* path, StringBuilder& outCanonicalPath) { StringBuilder canonicalPath; - SLANG_RETURN_ON_FAIL(Path::simplifyAbsolute(UnownedStringSlice(path), outCanonicalPath)); + SLANG_RETURN_ON_FAIL(Path::simplify(UnownedStringSlice(path), Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, outCanonicalPath)); return SLANG_OK; } @@ -260,7 +268,7 @@ SlangResult MemoryFileSystem::remove(const char* path) Entry* entry = _getEntryFromPath(path, &canonicalPath); // If there is an entry and not the root of the file system - if (entry && entry->m_canonicalPath != toSlice(".")) + if (entry && entry != &m_rootEntry) { if (entry->m_type == SLANG_PATH_TYPE_DIRECTORY) { diff --git a/source/core/slang-memory-file-system.h b/source/core/slang-memory-file-system.h index cd2701fe4..785335986 100644 --- a/source/core/slang-memory-file-system.h +++ b/source/core/slang-memory-file-system.h @@ -55,7 +55,7 @@ public: virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE; /// Ctor - MemoryFileSystem() { _clear(); } + MemoryFileSystem(); protected: @@ -129,6 +129,8 @@ protected: // Maps canonical paths to an entries (which could be files or directories) Dictionary<String, Entry> m_entries; + + Entry m_rootEntry; }; } diff --git a/source/core/slang-zip-file-system.cpp b/source/core/slang-zip-file-system.cpp index 28782dba7..011fd2aab 100644 --- a/source/core/slang-zip-file-system.cpp +++ b/source/core/slang-zip-file-system.cpp @@ -418,15 +418,8 @@ SlangResult ZipFileSystemImpl::_requireMode(Mode newMode) SlangResult ZipFileSystemImpl::_getFixedPath(const char* path, String& outPath) { - String simplifiedPath = Path::simplify(UnownedStringSlice(path)); - // Can simplify to just ., thats okay, if it otherwise has something relative it means it couldn't be simplified into the - // contents of the archive - if (simplifiedPath != "." && Path::hasRelativeElement(simplifiedPath)) - { - // If it still has a relative element, then it must be 'outside' of the archive - return SLANG_E_NOT_FOUND; - } - + StringBuilder simplifiedPath; + SLANG_RETURN_ON_FAIL(Path::simplify(path, Path::SimplifyStyle::AbsoluteOnlyAndNoRoot, simplifiedPath)); outPath = simplifiedPath; return SLANG_OK; } @@ -528,17 +521,27 @@ SlangResult ZipFileSystemImpl::getPath(PathKind pathKind, const char* path, ISla case PathKind::Display: case PathKind::Canonical: { - mz_uint index; - SLANG_RETURN_ON_FAIL(_findEntryIndex(path, index)); + // Get the fixed path + String fixedPath; + SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath)); - mz_zip_archive_file_stat fileStat; - if (!mz_zip_reader_file_stat(&m_archive, index, &fileStat)) + // See if we can find in the zip explicitly + mz_uint index; + if (SLANG_SUCCEEDED(_findEntryIndexFromFixedPath(fixedPath, index))) { - return SLANG_FAIL; + mz_zip_archive_file_stat fileStat; + if (!mz_zip_reader_file_stat(&m_archive, index, &fileStat)) + { + return SLANG_FAIL; + } + + // Use the path in the archive itself + *outPath = StringUtil::createStringBlob(fileStat.m_filename).detach(); + return SLANG_OK; } - // Use the path in the archive itself - *outPath = StringUtil::createStringBlob(fileStat.m_filename).detach(); + // Else output the fixed path + *outPath = StringUtil::createStringBlob(fixedPath).detach(); return SLANG_OK; } case PathKind::Simplified: |
