mirror of
https://github.com/GLEGram/GLEGram-iOS.git
synced 2026-04-23 19:36:26 +02:00
4647310322
Based on Swiftgram 12.5 (Telegram iOS 12.5). All GLEGram features ported and organized in GLEGram/ folder. Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass, Font Replacement, Fake Profile, Chat Export, Plugin System, and more. See CHANGELOG_12.5.md for full details.
85 lines
3.7 KiB
Swift
85 lines
3.7 KiB
Swift
import Foundation
|
|
import PathKit
|
|
|
|
extension Path {
|
|
/// Returns a Path without any inner parent directory references.
|
|
///
|
|
/// Similar to `NSString.standardizingPath`, but works with relative paths.
|
|
///
|
|
/// ### Examples
|
|
/// - `a/b/../c` simplifies to `a/c`
|
|
/// - `../a/b` simplifies to `../a/b`
|
|
/// - `a/../../c` simplifies to `../c`
|
|
public func simplifyingParentDirectoryReferences() -> Path {
|
|
if !string.contains("..") { // Skip simplifying if its already simple
|
|
var string = self.string
|
|
while string.hasSuffix(Path.separator) { // Remove all trailing path separators
|
|
string.removeLast()
|
|
}
|
|
return Path(String(string))
|
|
}
|
|
return normalize().components.reduce(Path(), +)
|
|
}
|
|
|
|
/// Returns the relative path necessary to go from `base` to `self`.
|
|
///
|
|
/// Both paths must be absolute or relative paths.
|
|
/// - throws: Throws an error when the path types do not match, or when `base` has so many parent path components
|
|
/// that it refers to an unknown parent directory.
|
|
public func relativePath(from base: Path) throws -> Path {
|
|
enum PathArgumentError: Error {
|
|
/// Can't back out of an unknown parent directory
|
|
case unknownParentDirectory
|
|
/// It's impossible to determine the path between an absolute and a relative path
|
|
case unmatchedAbsolutePath
|
|
}
|
|
|
|
func pathComponents(for path: ArraySlice<String>, relativeTo base: ArraySlice<String>, memo: [String]) throws -> [String] {
|
|
switch (base.first, path.first) {
|
|
// Base case: Paths are equivalent
|
|
case (.none, .none):
|
|
return memo
|
|
|
|
// No path to backtrack from
|
|
case (.none, .some(let rhs)):
|
|
guard rhs != "." else {
|
|
// Skip . instead of appending it
|
|
return try pathComponents(for: path.dropFirst(), relativeTo: base, memo: memo)
|
|
}
|
|
return try pathComponents(for: path.dropFirst(), relativeTo: base, memo: memo + [rhs])
|
|
|
|
// Both sides have a common parent
|
|
case (.some(let lhs), .some(let rhs)) where memo.isEmpty && lhs == rhs:
|
|
return try pathComponents(for: path.dropFirst(), relativeTo: base.dropFirst(), memo: memo)
|
|
|
|
// `base` has a path to back out of
|
|
case (.some(let lhs), _):
|
|
guard lhs != ".." else {
|
|
throw PathArgumentError.unknownParentDirectory
|
|
}
|
|
guard lhs != "." else {
|
|
// Skip . instead of resolving it to ..
|
|
return try pathComponents(for: path, relativeTo: base.dropFirst(), memo: memo)
|
|
}
|
|
return try pathComponents(for: path, relativeTo: base.dropFirst(), memo: memo + [".."])
|
|
}
|
|
}
|
|
|
|
guard isAbsolute && base.isAbsolute || !isAbsolute && !base.isAbsolute else {
|
|
throw PathArgumentError.unmatchedAbsolutePath
|
|
}
|
|
|
|
return Path(components: try pathComponents(for: ArraySlice(simplifyingParentDirectoryReferences().components),
|
|
relativeTo: ArraySlice(base.simplifyingParentDirectoryReferences().components),
|
|
memo: []))
|
|
}
|
|
|
|
/// Returns whether `self` is a strict parent of `child`.
|
|
///
|
|
/// Both paths must be asbolute or relative paths.
|
|
public func isParent(of child: Path) throws -> Bool {
|
|
let relativePath = try child.relativePath(from: self)
|
|
return relativePath.components.allSatisfy { $0 != ".." }
|
|
}
|
|
}
|