effbe57e创建于 2024年11月25日历史提交
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2024. All rights reserved.
 */
package zip4cj.io.inputstream

abstract class ICipherInputStream <: InputStream & Resource {
    protected open func endOfEntryReached(inputStream: InputStream, numberOfBytesPushedBack: Int64): Unit
    public func getLastReadRawDataCache(): Array<Byte>
}

abstract class CipherInputStream<T> <: ICipherInputStream where T <: Decrypter {
    protected var zipEntryInputStream: ZipEntryInputStream
    protected var lastReadRawDataCache: Array<Byte> = InternalZipConstants.NULL_BYTE_ARRAY
    protected var singleByteBuffer: Array<Byte> = Array<Byte>(1, repeat: 0)
    protected var localFileHeader: LocalFileHeader
    protected var password: ?Array<Rune>
    protected var useUtf8ForPassword: Bool
    protected var decrypter: T = unsafe { zeroValue<T>() }
    var closed = false
    public init(
        zipEntryInputStream: ZipEntryInputStream,
        localFileHeader: LocalFileHeader,
        password: ?Array<Rune>,
        bufferSize: Int64,
        useUtf8ForPassword: Bool
    ) {
        this.useUtf8ForPassword = useUtf8ForPassword
        this.password = password
        this.zipEntryInputStream = zipEntryInputStream
        this.localFileHeader = localFileHeader
        if (Zip4cjUtil.getCompressionMethod(localFileHeader).getCode() == (CompressionMethod.DEFLATE).getCode()) {
            lastReadRawDataCache = Array<Byte>(bufferSize, repeat: 0)
        }
    }

    protected func initializeDecrypter(localFileHeader: LocalFileHeader, password: ?Array<Rune>, useUtf8ForPassword: Bool): T

    public open func read(b: Array<Byte>): Int64 {
        return this.read(b, 0, b.size)
    }

    func read(b: Array<Byte>, off: Int64, len: Int64): Int64 {
        var readLen = Zip4cjUtil.readFully(zipEntryInputStream, b, off, len)
        if (readLen > 0) {
            cacheRawData(b, readLen)
            decrypter.decryptData(b[off..off+readLen])
        }
        return readLen
    }

    public open func isClosed():Bool {
        if(let Some(v) <- (zipEntryInputStream as Resource)) {
            v.isClosed()
        } else {
            this.closed
        }
    }

    public open func close(): Unit {
        zipEntryInputStream.close()
        this.closed = true
    }

    public func getLastReadRawDataCache(): Array<Byte> {
        return lastReadRawDataCache
    }

    protected func readRaw(b: Array<Byte>): Int64 {
        return zipEntryInputStream.readRawFully(b)
    }

    private func cacheRawData(b: Array<Byte>, len: Int64): Unit {
        if (!lastReadRawDataCache.isEmpty()) {
            b.copyTo(lastReadRawDataCache, 0, 0, len)
        }
    }

    public func getDecrypter(): T {
        return decrypter
    }

    protected open func endOfEntryReached(inputStream: InputStream, numberOfBytesPushedBack: Int64): Unit {
        (inputStream,numberOfBytesPushedBack )
        // is optional but useful for AES
        return
    }

    protected func getNumberOfBytesReadForThisEntry(): Int64 {
        return zipEntryInputStream.getNumberOfBytesRead()
    }

    public func getLocalFileHeader(): LocalFileHeader {
        return localFileHeader
    }
}