Rework FastJarHandler
1. Do not inherit from ZipHandler 2. Previously, the following computations have been happening: - Map<String, ZipEntryDescription> -> Map<String, EntryInfo> (see createEntriesMap) - Map<String, EntryInfo> -> VirtualFile tree But the intermediate computations (Map<String, EntryInfo>) were only used in the constructor, thus they've eliminated in this commit 3. Unclear magic semantic from `getOrCreate` with "/" and "\\" (copy-pasted from CoreJarHandler) has been replaced with `normalizePath`
This commit is contained in:
committed by
teamcityserver
parent
edf9f5e647
commit
979f5e8443
@@ -4,18 +4,17 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.impl.ZipHandler
|
||||
import com.intellij.util.containers.FactoryMap
|
||||
import com.intellij.util.text.ByteArrayCharSequence
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.RandomAccessFile
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandler(path) {
|
||||
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) {
|
||||
private val myRoot: VirtualFile?
|
||||
internal val file = File(path)
|
||||
|
||||
private val ourEntryMap: Map<String, ZipEntryDescription>
|
||||
private val cachedManifest: ByteArray?
|
||||
@@ -33,112 +32,80 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandl
|
||||
}
|
||||
}
|
||||
|
||||
val entries: MutableMap<EntryInfo, FastJarVirtualFile> = HashMap()
|
||||
val entriesMap = entriesMap
|
||||
val childrenMap = FactoryMap.create<FastJarVirtualFile, MutableList<VirtualFile>> { ArrayList() }
|
||||
for (info in entriesMap.values) {
|
||||
val file = getOrCreateFile(info, entries)
|
||||
val parent = file.parent
|
||||
if (parent != null) {
|
||||
childrenMap[parent]?.add(file)
|
||||
}
|
||||
|
||||
myRoot = FastJarVirtualFile(this, "", -1, DEFAULT_TIMESTAMP, null)
|
||||
|
||||
val filesByRelativePath = mutableMapOf<String, FastJarVirtualFile>()
|
||||
filesByRelativePath[""] = myRoot
|
||||
|
||||
for (info in ourEntryMap.values) {
|
||||
getOrCreateFile(info, filesByRelativePath)
|
||||
}
|
||||
|
||||
val rootInfo = getEntryInfo("")
|
||||
myRoot = rootInfo?.let { getOrCreateFile(it, entries) }
|
||||
for (child in filesByRelativePath.values) {
|
||||
child.parent?.let(childrenMap::get)?.add(child)
|
||||
}
|
||||
|
||||
for ((key, childList) in childrenMap) {
|
||||
key.children = childList.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrCreateFile(info: EntryInfo, entries: MutableMap<EntryInfo, FastJarVirtualFile>): FastJarVirtualFile {
|
||||
var file = entries[info]
|
||||
if (file == null) {
|
||||
val parent = info.parent
|
||||
file = FastJarVirtualFile(this, info.shortName,
|
||||
if (info.isDirectory) -1 else info.length,
|
||||
info.timestamp,
|
||||
parent?.let { getOrCreateFile(it, entries) })
|
||||
entries[info] = file
|
||||
private fun getOrCreateFile(entry: ZipEntryDescription, map: MutableMap<String, FastJarVirtualFile>): FastJarVirtualFile {
|
||||
val entryName = entry.relativePath.normalizePath()
|
||||
|
||||
return map.getOrPut(entryName) {
|
||||
val (parentName, shortName) = entryName.splitPath()
|
||||
|
||||
val parentInfo = getOrCreateDirectory(parentName, map)
|
||||
if ("." == shortName) {
|
||||
return parentInfo
|
||||
}
|
||||
|
||||
FastJarVirtualFile(
|
||||
this, shortName,
|
||||
if (entry.isDirectory) -1 else entry.uncompressedSize.toLong(),
|
||||
DEFAULT_TIMESTAMP,
|
||||
parentInfo
|
||||
)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
private fun getOrCreateDirectory(entryName: String, map: MutableMap<String, FastJarVirtualFile>): FastJarVirtualFile {
|
||||
return map.getOrPut(entryName) {
|
||||
val entry = ourEntryMap["$entryName/"]
|
||||
if (entry != null) {
|
||||
return getOrCreateFile(entry, map)
|
||||
}
|
||||
val (parentPath, shortName) = entryName.splitPath()
|
||||
require(entryName != parentPath) {
|
||||
"invalid entry name: '" + entryName + "' in " + this.file.absolutePath + "; after split: " + Pair(parentPath, shortName)
|
||||
}
|
||||
val parentInfo = getOrCreateDirectory(parentPath, map)
|
||||
|
||||
FastJarVirtualFile(this, shortName, -1, DEFAULT_TIMESTAMP, parentInfo)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.normalizePath(): String {
|
||||
if (endsWith('/')) return substring(0, length - 1).normalizePath()
|
||||
if (startsWith('/') || startsWith('\\')) return substring(1, length).normalizePath()
|
||||
if (!contains('\\')) return this
|
||||
return FileUtil.normalize(this)
|
||||
}
|
||||
|
||||
private fun String.splitPath(): Pair<String, String> {
|
||||
val slashIndex = lastIndexOf('/')
|
||||
if (slashIndex == -1) return Pair("", this)
|
||||
return Pair(substring(0, slashIndex), substring(slashIndex + 1))
|
||||
}
|
||||
|
||||
fun findFileByPath(pathInJar: String): VirtualFile? {
|
||||
return myRoot?.findFileByRelativePath(pathInJar)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun createEntriesMap(): Map<String, EntryInfo> {
|
||||
val mapToEntryInfo = mutableMapOf<String, EntryInfo>()
|
||||
mapToEntryInfo[""] = EntryInfo("", true, DEFAULT_LENGTH, DEFAULT_TIMESTAMP, null)
|
||||
for (zipEntry in ourEntryMap.values) {
|
||||
getOrCreate(zipEntry, mapToEntryInfo)
|
||||
}
|
||||
|
||||
return mapToEntryInfo
|
||||
}
|
||||
|
||||
private fun getOrCreate(entry: ZipEntryDescription, map: MutableMap<String, EntryInfo>): EntryInfo {
|
||||
var isDirectory = entry.isDirectory
|
||||
var entryName = entry.relativePath
|
||||
if (StringUtil.endsWithChar(entryName, '/')) {
|
||||
entryName = entryName.substring(0, entryName.length - 1)
|
||||
isDirectory = true
|
||||
}
|
||||
if (StringUtil.startsWithChar(entryName, '/') || StringUtil.startsWithChar(entryName, '\\')) {
|
||||
entryName = entryName.substring(1)
|
||||
}
|
||||
|
||||
var info = map[entryName]
|
||||
if (info != null) return info
|
||||
|
||||
val path = splitPathAndFix(entryName)
|
||||
|
||||
val parentInfo = getOrCreateDirectory(path.first, map)
|
||||
if ("." == path.second) {
|
||||
return parentInfo
|
||||
}
|
||||
info = store(map, parentInfo, path.second, isDirectory, entry.uncompressedSize.toLong(), 0, path.third)
|
||||
return info
|
||||
}
|
||||
|
||||
private fun getOrCreateDirectory(entryName: String, map: MutableMap<String, EntryInfo>): EntryInfo {
|
||||
var info = map[entryName]
|
||||
|
||||
if (info == null) {
|
||||
val entry = ourEntryMap["$entryName/"]
|
||||
if (entry != null) {
|
||||
return getOrCreate(entry, map)
|
||||
}
|
||||
val path = splitPathAndFix(entryName)
|
||||
require(entryName != path.first) {
|
||||
"invalid entry name: '" + entryName + "' in " + this.file.absolutePath + "; after split: " + path
|
||||
}
|
||||
val parentInfo = getOrCreateDirectory(path.first, map)
|
||||
info = store(map, parentInfo, path.second, true, DEFAULT_LENGTH, DEFAULT_TIMESTAMP, path.third)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
private fun store(
|
||||
map: MutableMap<String, EntryInfo>,
|
||||
parentInfo: EntryInfo?,
|
||||
shortName: CharSequence,
|
||||
isDirectory: Boolean,
|
||||
size: Long,
|
||||
time: Long,
|
||||
entryName: String
|
||||
): EntryInfo {
|
||||
val sequence = ByteArrayCharSequence.convertToBytesIfPossible(shortName)
|
||||
val info = EntryInfo(sequence, isDirectory, size, time, parentInfo)
|
||||
map[entryName] = info
|
||||
return info
|
||||
}
|
||||
|
||||
override fun contentsToByteArray(relativePath: String): ByteArray {
|
||||
fun contentsToByteArray(relativePath: String): ByteArray {
|
||||
if (relativePath == MANIFEST_PATH) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath")
|
||||
val zipEntryDescription = ourEntryMap[relativePath] ?: throw FileNotFoundException("$file!/$relativePath")
|
||||
return fileSystem.cachedOpenFileHandles[file].use {
|
||||
@@ -151,4 +118,4 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandl
|
||||
|
||||
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
|
||||
|
||||
|
||||
private const val DEFAULT_TIMESTAMP = 0L
|
||||
|
||||
Reference in New Issue
Block a user