generated from korlibs/korlibs-library-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,418 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
# korlibs-library-template | ||
# korlibs-io-vfs |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
product: | ||
type: lib | ||
platforms: [jvm, js, wasm, android, linuxX64, linuxArm64, tvosArm64, tvosX64, tvosSimulatorArm64, macosX64, macosArm64, iosArm64, iosSimulatorArm64, iosX64, watchosArm64, watchosArm32, watchosDeviceArm64, watchosSimulatorArm64, mingwX64] | ||
|
||
apply: [ ../common.module-template.yaml ] | ||
|
||
aliases: | ||
- posix: [linuxX64, linuxArm64, tvosArm64, tvosX64, tvosSimulatorArm64, macosX64, macosArm64, iosArm64, iosSimulatorArm64, iosX64, watchosArm64, watchosArm32, watchosDeviceArm64, watchosSimulatorArm64] | ||
- jvmAndAndroid: [jvm, android] | ||
- concurrent: [jvm, android, linuxX64, linuxArm64, tvosArm64, tvosX64, tvosSimulatorArm64, macosX64, macosArm64, iosArm64, iosSimulatorArm64, iosX64, watchosArm64, watchosArm32, watchosDeviceArm64, watchosSimulatorArm64, mingwX64] | ||
|
||
dependencies: | ||
- com.soywiz:korlibs-io-fs:6.0.0 | ||
- com.soywiz:korlibs-concurrent:6.0.0 | ||
- com.soywiz:korlibs-platform:6.0.0: exported | ||
- com.soywiz:korlibs-io-stream:6.0.0: exported | ||
- com.soywiz:korlibs-time-core:6.0.0: exported | ||
- com.soywiz:korlibs-string:6.0.0: exported | ||
- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC: exported | ||
|
||
test-dependencies: | ||
- org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0-RC | ||
- com.soywiz:korlibs-time:6.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package korlibs.io.file | ||
|
||
suspend fun VfsFile.getUnderlyingUnscapedFile(): FinalVfsFile = vfs.getUnderlyingUnscapedFile(this.path) | ||
fun VfsFile.toUnscaped() = FinalVfsFile(this) | ||
fun FinalVfsFile.toFile() = this.file | ||
|
||
//inline class FinalVfsFile(val file: VfsFile) { | ||
data class FinalVfsFile(val file: VfsFile) { | ||
constructor(vfs: Vfs, path: String) : this(vfs[path]) | ||
val vfs: Vfs get() = file.vfs | ||
val path: String get() = file.path | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
package korlibs.io.file | ||
|
||
import korlibs.io.core.* | ||
import kotlin.math.* | ||
|
||
val File_pathSeparatorChar: Char get() = SyncSystemFS.pathSeparatorChar | ||
val File_separatorChar: Char get() = SyncSystemFS.fileSeparatorChar | ||
|
||
// @TODO: inline classes. Once done PathInfoExt won't be required to do clean allocation-free stuff. | ||
inline class PathInfo(val fullPath: String) | ||
|
||
fun PathInfo.relativePathTo(relative: PathInfo): String? { | ||
val thisParts = this.parts().toMutableList() | ||
val relativeParts = relative.parts().toMutableList() | ||
val maxNumParts = min(thisParts.size, relativeParts.size) | ||
val outputParts = arrayListOf<String>() | ||
val commonCount = count { it < maxNumParts && thisParts[it] == relativeParts[it] } | ||
while (relativeParts.size > commonCount) { | ||
relativeParts.removeLast() | ||
outputParts += ".." | ||
} | ||
outputParts += thisParts.slice(commonCount until thisParts.size) | ||
return outputParts.joinToString("/") | ||
} | ||
|
||
val String.pathInfo get() = PathInfo(this) | ||
|
||
/** | ||
* /path\to/file.ext -> /path/to/file.ext | ||
*/ | ||
val PathInfo.fullPathNormalized: String get() = fullPath.replace('\\', '/') | ||
|
||
/** | ||
* /path\to/file.ext -> /path\to | ||
*/ | ||
val PathInfo.folder: String get() = fullPath.substring(0, fullPathNormalized.lastIndexOfOrNull('/') ?: 0) | ||
|
||
/** | ||
* /path\to/file.ext -> /path/to/ | ||
*/ | ||
val PathInfo.folderWithSlash: String | ||
get() = fullPath.substring(0, fullPathNormalized.lastIndexOfOrNull('/')?.plus(1) ?: 0) | ||
|
||
/** | ||
* /path\to/file.ext -> file.ext | ||
*/ | ||
val PathInfo.baseName: String get() = fullPathNormalized.substringAfterLast('/') | ||
|
||
/** | ||
* /path\to/file.ext -> /path\to | ||
*/ | ||
val PathInfo.parent: PathInfo get() = PathInfo(folder) | ||
|
||
/** | ||
* /path\to/file.ext -> /path\to/file | ||
*/ | ||
val PathInfo.fullPathWithoutExtension: String | ||
get() { | ||
val startIndex = fullPathNormalized.lastIndexOfOrNull('/')?.plus(1) ?: 0 | ||
return fullPath.substring(0, fullPathNormalized.indexOfOrNull('.', startIndex) ?: fullPathNormalized.length) | ||
} | ||
|
||
/** | ||
* /path\to/file.ext -> /path\to/file.newext | ||
*/ | ||
fun PathInfo.fullPathWithExtension(ext: String): String = | ||
if (ext.isEmpty()) fullPathWithoutExtension else "$fullPathWithoutExtension.$ext" | ||
|
||
/** | ||
* /path\to/file.1.ext -> file.1 | ||
*/ | ||
val PathInfo.baseNameWithoutExtension: String get() = baseName.substringBeforeLast('.', | ||
baseName | ||
) | ||
|
||
/** | ||
* /path\to/file.1.ext -> file | ||
*/ | ||
val PathInfo.baseNameWithoutCompoundExtension: String get() = baseName.substringBefore('.', | ||
baseName | ||
) | ||
|
||
/** | ||
* /path\to/file.1.ext -> /path\to/file.1 | ||
*/ | ||
val PathInfo.fullNameWithoutExtension: String get() = "$folderWithSlash$baseNameWithoutExtension" | ||
|
||
/** | ||
* /path\to/file.1.ext -> file | ||
*/ | ||
val PathInfo.fullNameWithoutCompoundExtension: String get() = "$folderWithSlash$baseNameWithoutCompoundExtension" | ||
|
||
/** | ||
* /path\to/file.1.ext -> file.1.newext | ||
*/ | ||
fun PathInfo.baseNameWithExtension(ext: String): String = | ||
if (ext.isEmpty()) baseNameWithoutExtension else "$baseNameWithoutExtension.$ext" | ||
|
||
/** | ||
* /path\to/file.1.ext -> file.newext | ||
*/ | ||
fun PathInfo.baseNameWithCompoundExtension(ext: String): String = | ||
if (ext.isEmpty()) baseNameWithoutCompoundExtension else "$baseNameWithoutCompoundExtension.$ext" | ||
|
||
/** | ||
* /path\to/file.1.EXT -> EXT | ||
*/ | ||
val PathInfo.extension: String get() = baseName.substringAfterLast('.', "") | ||
|
||
/** | ||
* /path\to/file.1.EXT -> ext | ||
*/ | ||
val PathInfo.extensionLC: String get() = extension.lowercase() | ||
|
||
/** | ||
* /path\to/file.1.EXT -> 1.EXT | ||
*/ | ||
val PathInfo.compoundExtension: String get() = baseName.substringAfter('.', "") | ||
|
||
/** | ||
* /path\to/file.1.EXT -> 1.ext | ||
*/ | ||
val PathInfo.compoundExtensionLC: String get() = compoundExtension.lowercase() | ||
|
||
/** | ||
* /path\to/file.1.ext -> listOf("", "path", "to", "file.1.ext") | ||
*/ | ||
fun PathInfo.getPathComponents(): List<String> = fullPathNormalized.split('/') | ||
|
||
/** | ||
* /path\to/file.1.ext -> listOf("/path", "/path/to", "/path/to/file.1.ext") | ||
*/ | ||
fun PathInfo.getPathFullComponents(): List<String> { | ||
val out = arrayListOf<String>() | ||
for (n in 0 until fullPathNormalized.length) { | ||
when (fullPathNormalized[n]) { | ||
'/', '\\' -> { | ||
out += fullPathNormalized.substring(0, n) | ||
} | ||
} | ||
} | ||
out += fullPathNormalized | ||
return out | ||
} | ||
|
||
/** | ||
* /path\to/file.1.ext -> /path\to/file.1.ext | ||
*/ | ||
val PathInfo.fullName: String get() = fullPath | ||
|
||
interface Path { | ||
val pathInfo: PathInfo | ||
} | ||
|
||
val Path.fullPathNormalized: String get() = pathInfo.fullPathNormalized | ||
val Path.folder: String get() = pathInfo.folder | ||
val Path.folderWithSlash: String get() = pathInfo.folderWithSlash | ||
val Path.baseName: String get() = pathInfo.baseName | ||
val Path.fullPathWithoutExtension: String get() = pathInfo.fullPathWithoutExtension | ||
fun Path.fullPathWithExtension(ext: String): String = pathInfo.fullPathWithExtension(ext) | ||
val Path.fullNameWithoutExtension: String get() = pathInfo.fullNameWithoutExtension | ||
val Path.baseNameWithoutExtension: String get() = pathInfo.baseNameWithoutExtension | ||
val Path.fullNameWithoutCompoundExtension: String get() = pathInfo.fullNameWithoutCompoundExtension | ||
val Path.baseNameWithoutCompoundExtension: String get() = pathInfo.baseNameWithoutCompoundExtension | ||
fun Path.baseNameWithExtension(ext: String): String = pathInfo.baseNameWithExtension(ext) | ||
fun Path.baseNameWithCompoundExtension(ext: String): String = pathInfo.baseNameWithCompoundExtension(ext) | ||
val Path.extension: String get() = pathInfo.extension | ||
val Path.extensionLC: String get() = pathInfo.extensionLC | ||
val Path.compoundExtension: String get() = pathInfo.compoundExtension | ||
val Path.compoundExtensionLC: String get() = pathInfo.compoundExtensionLC | ||
fun Path.getPathComponents(): List<String> = pathInfo.getPathComponents() | ||
fun Path.getPathFullComponents(): List<String> = pathInfo.getPathFullComponents() | ||
val Path.fullName: String get() = pathInfo.fullPath | ||
|
||
open class VfsNamed(override val pathInfo: PathInfo) : Path | ||
|
||
|
||
fun PathInfo.parts(): List<String> = fullPath.split('/') | ||
fun PathInfo.normalize(removeEndSlash: Boolean = true): String { | ||
val path = this.fullPath | ||
val schemeIndex = path.indexOf(":") | ||
return if (schemeIndex >= 0) { | ||
val take = if (path.substring(schemeIndex).startsWith("://")) 3 else 1 | ||
path.substring(0, schemeIndex + take) + path.substring(schemeIndex + take).pathInfo.normalize(removeEndSlash = removeEndSlash) | ||
} else { | ||
val path2 = path.replace('\\', '/') | ||
val out = ArrayList<String>() | ||
val path2PathLength: Int | ||
path2.split("/").also { path2PathLength = it.size }.fastForEachWithIndex { index, part -> | ||
when (part) { | ||
"" -> if (out.isEmpty() || !removeEndSlash) out += "" | ||
"." -> if (index == path2PathLength - 1 && !removeEndSlash) out += "" | ||
".." -> if (out.isNotEmpty() && index != 1) out.removeAt(out.size - 1) | ||
else -> out += part | ||
} | ||
} | ||
out.joinToString("/") | ||
} | ||
} | ||
|
||
fun PathInfo.combine(access: PathInfo): PathInfo { | ||
val base = this.fullPath | ||
val access = access.fullPath | ||
return (if (access.pathInfo.isAbsolute()) access.pathInfo.normalize() else "$base/$access" | ||
.pathInfo.normalize()).pathInfo | ||
} | ||
|
||
fun PathInfo.lightCombine(access: PathInfo): PathInfo { | ||
val base = this.fullPath | ||
val access = access.fullPath | ||
val res = if (base.isNotEmpty()) base.trimEnd('/') + "/" + access.trim('/') else access | ||
return res.pathInfo | ||
} | ||
|
||
fun PathInfo.isAbsolute(): Boolean { | ||
val base = this.fullPath | ||
if (base.isEmpty()) return false | ||
val b = base.replace('\\', '/').substringBefore('/') | ||
if (b.isEmpty()) return true | ||
if (b.contains(':')) return true | ||
return false | ||
} | ||
|
||
fun PathInfo.normalizeAbsolute(): PathInfo { | ||
val path = this.fullPath | ||
//val res = path.replace('/', File.separatorChar).trim(File.separatorChar) | ||
//return if (OS.isUnix) "/$res" else res | ||
return PathInfo(path.replace('/', File_separatorChar)) | ||
} | ||
|
||
private fun String.indexOfOrNull(char: Char, startIndex: Int = 0): Int? = | ||
this.indexOf(char, startIndex).takeIf { it >= 0 } | ||
|
||
private fun String.lastIndexOfOrNull(char: Char, startIndex: Int = lastIndex): Int? = | ||
this.lastIndexOf(char, startIndex).takeIf { it >= 0 } | ||
|
||
private inline fun count(cond: (index: Int) -> Boolean): Int { | ||
var counter = 0 | ||
while (cond(counter)) counter++ | ||
return counter | ||
} | ||
|
||
private inline fun <T> List<T>.fastForEachWithIndex(callback: (index: Int, value: T) -> Unit) { | ||
var n = 0 | ||
while (n < size) { | ||
callback(n, this[n]) | ||
n++ | ||
} | ||
} |
Oops, something went wrong.