diff options
Diffstat (limited to 'okio/src/commonMain/kotlin/okio/Path.kt')
-rw-r--r-- | okio/src/commonMain/kotlin/okio/Path.kt | 156 |
1 files changed, 126 insertions, 30 deletions
diff --git a/okio/src/commonMain/kotlin/okio/Path.kt b/okio/src/commonMain/kotlin/okio/Path.kt index ff865167..337abac7 100644 --- a/okio/src/commonMain/kotlin/okio/Path.kt +++ b/okio/src/commonMain/kotlin/okio/Path.kt @@ -69,8 +69,9 @@ import okio.Path.Companion.toPath * * * Segments are always non-empty. * * If the segment is `.`, then the full path must be `.`. - * * If the segment is `..`, then the the path must be relative. All `..` segments precede all - * other segments. + * * For normalized paths, if the segment is `..`, then the path must be relative. All `..` + * segments precede all other segments. In all cases, a segment `..` cannot be the first segment + * of an absolute path. * * The only path that ends with `/` is the file system root, `/`. The dot path `.` is a relative * path that resolves to whichever path it is resolved against. @@ -117,30 +118,46 @@ import okio.Path.Companion.toPath * ------------ * * <table> - * <tr><th> Path <th> Parent <th> Name <th> Notes </tr> - * <tr><td> `/` <td> null <td> (empty) <td> root </tr> - * <tr><td> `/home/jesse/notes.txt` <td> `/home/jesse` <td> `notes.txt` <td> absolute path </tr> - * <tr><td> `project/notes.txt` <td> `project` <td> `notes.txt` <td> relative path </tr> - * <tr><td> `../../project/notes.txt` <td> `../../project` <td> `notes.txt` <td> relative path with traversal </tr> - * <tr><td> `../../..` <td> null <td> `..` <td> relative path with traversal </tr> - * <tr><td> `.` <td> null <td> `.` <td> current working directory </tr> - * <tr><td> `C:\` <td> null <td> (empty) <td> volume root (Windows) </tr> - * <tr><td> `C:\Windows\notepad.exe` <td> `C:\Windows` <td> `notepad.exe` <td> volume absolute path (Windows) </tr> - * <tr><td> `\` <td> null <td> (empty) <td> absolute path (Windows) </tr> - * <tr><td> `\Windows\notepad.exe` <td> `\Windows` <td> `notepad.exe` <td> absolute path (Windows) </tr> - * <tr><td> `C:` <td> null <td> (empty) <td> volume-relative path (Windows) </tr> - * <tr><td> `C:project\notes.txt` <td> `C:project` <td> `notes.txt` <td> volume-relative path (Windows) </tr> - * <tr><td> `\\server` <td> null <td> `server` <td> UNC server (Windows) </tr> - * <tr><td> `\\server\project\notes.txt` <td> `\\server\project` <td> `notes.txt` <td> UNC absolute path (Windows) </tr> + * <tr><th> Path <th> Parent <th> Root <th> Name <th> Notes </tr> + * <tr><td> `/` <td> null <td> `/` <td> (empty) <td> root </tr> + * <tr><td> `/home/jesse/notes.txt` <td> `/home/jesse` <td> `/` <td> `notes.txt` <td> absolute path </tr> + * <tr><td> `project/notes.txt` <td> `project` <td> null <td> `notes.txt` <td> relative path </tr> + * <tr><td> `../../project/notes.txt` <td> `../../project` <td> null <td> `notes.txt` <td> relative path with traversal </tr> + * <tr><td> `../../..` <td> null <td> null <td> `..` <td> relative path with traversal </tr> + * <tr><td> `.` <td> null <td> null <td> `.` <td> current working directory </tr> + * <tr><td> `C:\` <td> null <td> `C:\` <td> (empty) <td> volume root (Windows) </tr> + * <tr><td> `C:\Windows\notepad.exe` <td> `C:\Windows` <td> `C:\` <td> `notepad.exe` <td> volume absolute path (Windows) </tr> + * <tr><td> `\` <td> null <td> `\` <td> (empty) <td> absolute path (Windows) </tr> + * <tr><td> `\Windows\notepad.exe` <td> `\Windows` <td> `\` <td> `notepad.exe` <td> absolute path (Windows) </tr> + * <tr><td> `C:` <td> null <td> null <td> (empty) <td> volume-relative path (Windows) </tr> + * <tr><td> `C:project\notes.txt` <td> `C:project` <td> null <td> `notes.txt` <td> volume-relative path (Windows) </tr> + * <tr><td> `\\server` <td> null <td> `\\server` <td> `server` <td> UNC server (Windows) </tr> + * <tr><td> `\\server\project\notes.txt` <td> `\\server\project` <td> `\\server` <td> `notes.txt` <td> UNC absolute path (Windows) </tr> * </table> */ -@ExperimentalFileSystem -expect class Path internal constructor(slash: ByteString, bytes: ByteString) : Comparable<Path> { - internal val slash: ByteString +expect class Path internal constructor(bytes: ByteString) : Comparable<Path> { + /** + * This is the root path if this is an absolute path, or null if it is a relative path. UNIX paths + * have a single root, `/`. Each volume on Windows is its own root, like `C:\` and `D:\`. The + * path to the current volume `\` is its own root. Windows UNC paths like `\\server` are also + * roots. + */ + val root: Path? + + /** + * The components of this path that are usually delimited by slashes. If the root is not null it + * precedes these segments. If this path is a root its segments list is empty. + */ + val segments: List<String> + + val segmentsBytes: List<ByteString> + internal val bytes: ByteString + /** This is true if [root] is not null. */ val isAbsolute: Boolean + /** This is true if [root] is null. */ val isRelative: Boolean /** @@ -172,15 +189,12 @@ expect class Path internal constructor(slash: ByteString, bytes: ByteString) : C */ val parent: Path? - /** - * Returns true if this is an absolute path with no parent. UNIX paths have a single root, `/`. - * Each volume on Windows is its own root, like `C:\` and `D:\`. Windows UNC paths like `\\server` - * are also roots. - */ + /** Returns true if `this == this.root`. That is, this is an absolute path with no parent. */ val isRoot: Boolean /** - * Returns a path that resolves [child] relative to this path. + * Returns a path that resolves [child] relative to this path. Note that the result isn't + * guaranteed to be normalized even if this and [child] are both normalized themselves. * * If [child] is an [absolute path][isAbsolute] or [has a volume letter][hasVolumeLetter] then * this function is equivalent to `child.toPath()`. @@ -188,13 +202,79 @@ expect class Path internal constructor(slash: ByteString, bytes: ByteString) : C operator fun div(child: String): Path /** - * Returns a path that resolves [child] relative to this path. + * Returns a path that resolves [child] relative to this path. Note that the result isn't + * guaranteed to be normalized even if this and [child] are both normalized themselves. + * + * If [child] is an [absolute path][isAbsolute] or [has a volume letter][hasVolumeLetter] then + * this function is equivalent to `child.toPath()`. + */ + operator fun div(child: ByteString): Path + + /** + * Returns a path that resolves [child] relative to this path. Note that the result isn't + * guaranteed to be normalized even if this and [child] are both normalized themselves. * * If [child] is an [absolute path][isAbsolute] or [has a volume letter][hasVolumeLetter] then * this function is equivalent to `child.toPath()`. */ operator fun div(child: Path): Path + /** + * Returns a path that resolves [child] relative to this path. + * + * Set [normalize] to true to eagerly consume `..` segments on the resolved path. In all cases, + * leading `..` on absolute paths will be removed. If [normalize] is false, note that the result + * isn't guaranteed to be normalized even if this and [child] are both normalized themselves. + * + * If [child] is an [absolute path][isAbsolute] or [has a volume letter][hasVolumeLetter] then + * this function is equivalent to `child.toPath(normalize)`. + */ + fun resolve(child: String, normalize: Boolean = false): Path + + /** + * Returns a path that resolves [child] relative to this path. + * + * Set [normalize] to true to eagerly consume `..` segments on the resolved path. In all cases, + * leading `..` on absolute paths will be removed. If [normalize] is false, note that the result + * isn't guaranteed to be normalized even if this and [child] are both normalized themselves. + * + * If [child] is an [absolute path][isAbsolute] or [has a volume letter][hasVolumeLetter] then + * this function is equivalent to `child.toPath(normalize)`. + */ + fun resolve(child: ByteString, normalize: Boolean = false): Path + + /** + * Returns a path that resolves [child] relative to this path. + * + * Set [normalize] to true to eagerly consume `..` segments on the resolved path. In all cases, + * leading `..` on absolute paths will be removed. If [normalize] is false, note that the result + * isn't guaranteed to be normalized even if this and [child] are both normalized themselves. + * + * If [child] is an [absolute path][isAbsolute] or [has a volume letter][hasVolumeLetter] then + * this function is equivalent to `child.toPath(normalize)`. + */ + fun resolve(child: Path, normalize: Boolean = false): Path + + /** + * Returns this path relative to [other]. This effectively inverts the resolve operator, `/`. For + * any two paths `a` and `b` that have the same root, `a / (b.relativeTo(a))` is equal to `b`. If + * both paths don't use the same slash, the resolved path will use the slash of the [other] path. + * + * @throws IllegalArgumentException if this path and the [other] path are not both + * [absolute paths][isAbsolute] or both [relative paths][isRelative], or if they are both + * [absolute paths][isAbsolute] but of different roots (C: vs D:, or C: vs \\server, etc.). + * It will also throw if the relative path is impossible to resolve. For instance, it is + * impossible to resolve the path `../a` relative to `../../b`. + */ + @Throws(IllegalArgumentException::class) + fun relativeTo(other: Path): Path + + /** + * Returns the normalized version of this path. This has the same effect as + * `this.toString().toPath(normalize = true)`. + */ + fun normalized(): Path + override fun compareTo(other: Path): Int override fun equals(other: Any?): Boolean @@ -204,10 +284,26 @@ expect class Path internal constructor(slash: ByteString, bytes: ByteString) : C override fun toString(): String companion object { + /** + * Either `/` (on UNIX-like systems including Android, iOS, and Linux) or `\` (on Windows + * systems). + * + * This separator is used by `FileSystem.SYSTEM` and possibly other file systems on the host + * system. Some file system implementations may not use this separator. + */ val DIRECTORY_SEPARATOR: String - fun String.toPath(): Path - - fun String.toPath(directorySeparator: String?): Path + /** + * Returns the [Path] representation for this string. + * + * Set [normalize] to true to eagerly consume `..` segments in your path. In all cases, leading + * `..` on absolute paths will be removed. + * + * ``` + * "/Users/jesse/Documents/../notes.txt".toPath(normalize = false).toString() => "/Users/jesse/Documents/../notes.txt" + * "/Users/jesse/Documents/../notes.txt".toPath(normalize = true).toString() => "/Users/jesse/notes.txt" + * ``` + */ + fun String.toPath(normalize: Boolean = false): Path } } |