93 lines
3.0 KiB
Swift
93 lines
3.0 KiB
Swift
//
|
|
// Copyright 2025 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public class NonceHeaderInputStreamTransform: StreamTransform, BufferedStreamTransform {
|
|
|
|
private var buffer = Data()
|
|
private var headerLength: Int?
|
|
private var hasFinishedReadingHeader: Bool
|
|
private var needMoreData: Bool = true
|
|
|
|
public var hasPendingBytes: Bool { return !needMoreData && (headerLength == nil || buffer.count > headerLength!) }
|
|
public func readBufferedData() throws -> Data {
|
|
let returnedData = try skipPastMetadataHeader()
|
|
buffer = Data()
|
|
return returnedData
|
|
}
|
|
|
|
init(source: BackupImportSource) {
|
|
switch source {
|
|
case .remote:
|
|
// Remote backups have the header,
|
|
// we have to finish reading it first
|
|
self.hasFinishedReadingHeader = false
|
|
case .linkNsync:
|
|
// Link'N'Sync backups have no header; finish immediately.
|
|
self.hasFinishedReadingHeader = true
|
|
}
|
|
}
|
|
|
|
public func transform(data: Data) throws -> Data {
|
|
if hasFinishedReadingHeader {
|
|
return data
|
|
}
|
|
|
|
if data.count > 0 {
|
|
needMoreData = false
|
|
buffer.append(data)
|
|
}
|
|
return try skipPastMetadataHeader()
|
|
}
|
|
|
|
/// Decode the next chunk of data, if enough data is present in the buffer.
|
|
private func skipPastMetadataHeader() throws -> Data {
|
|
guard buffer.count > BackupNonce.magicFileSignature.count else {
|
|
// We dont have enough data to decode the signature, return for now.
|
|
needMoreData = true
|
|
return Data()
|
|
}
|
|
|
|
// decode the next variable length int
|
|
let (dataSize, intLength) = ChunkedInputStreamTransform.decodeVariableLengthInteger(
|
|
buffer: buffer,
|
|
start: BackupNonce.magicFileSignature.count
|
|
)
|
|
|
|
guard dataSize > 0 else {
|
|
needMoreData = true
|
|
// Don't have enough data to decode an int, so return for now
|
|
return Data()
|
|
}
|
|
|
|
guard let intDataSize = Int(exactly: dataSize) else {
|
|
// The decoded integer is to large to fit into an Int
|
|
// The Data operations all require Int Ranges, so
|
|
owsFailDebug("Decoded data size too large")
|
|
return Data()
|
|
}
|
|
|
|
// Only advance if there is enough data present to both
|
|
// decode the variable length integer and skip past the specified
|
|
// number of bytes.
|
|
let endOfHeader = BackupNonce.magicFileSignature.count + intDataSize + intLength
|
|
guard buffer.count >= endOfHeader else {
|
|
needMoreData = true
|
|
return Data()
|
|
}
|
|
|
|
// Return any data past the header, skipping the header portion.
|
|
let returnBuffer = buffer.dropFirst(endOfHeader)
|
|
|
|
headerLength = endOfHeader
|
|
hasFinishedReadingHeader = true
|
|
needMoreData = false
|
|
buffer = Data()
|
|
|
|
return returnBuffer
|
|
}
|
|
}
|