Skip to content

Instantly share code, notes, and snippets.

@swankjesse
Created February 7, 2021 16:27

Revisions

  1. swankjesse created this gist Feb 7, 2021.
    71 changes: 71 additions & 0 deletions ZipFileSystemSketch.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    /*
    * Copyright (C) 2021 Square, Inc.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package okio

    import java.util.zip.InflaterInputStream
    import okio.Path.Companion.toPath

    @ExperimentalFileSystem
    class ZipFileSystemSketch private constructor(
    private val fileSystem: FileSystem,
    private val zipPath: Path,
    private val entries: List<Entry>
    ) : FileSystem() {

    override fun canonicalize(path: Path): Path {
    return "/".toPath() / path
    }

    override fun metadataOrNull(path: Path): FileMetadata? {
    val canonicalPath = canonicalize(path)
    return entries.firstOrNull { it.path == canonicalPath }?.metadata
    }

    override fun list(dir: Path): List<Path> {
    val canonicalDir = canonicalize(dir)
    return entries.mapNotNull { if (it.path.parent == canonicalDir) it.path else null }
    }

    override fun source(file: Path): Source {
    val canonicalPath = canonicalize(file)
    val entry = entries.firstOrNull { it.path == canonicalPath }
    ?: throw FileNotFoundException("no such file: $file")
    val zipSource = fileSystem.source(zipPath)
    val cursor = zipSource.cursor ?: throw IOException("zip file not random access")
    cursor.seek(entry.offset)
    // TODO(jwilson): there's some framing needed here.
    return InflaterInputStream(zipSource.buffer().inputStream()).source()
    }

    override fun sink(file: Path): Sink = throw IOException("zip file systems are read-only")

    override fun appendingSink(file: Path): Sink =
    throw IOException("zip file systems are read-only")

    override fun createDirectory(dir: Path): Unit =
    throw IOException("zip file systems are read-only")

    override fun atomicMove(source: Path, target: Path): Unit =
    throw IOException("zip file systems are read-only")

    override fun delete(path: Path): Unit = throw IOException("zip file systems are read-only")

    private class Entry(
    val path: Path,
    val metadata: FileMetadata,
    val offset: Long
    )
    }