1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
import Foundation
final class FileHandleStream: ByteStream {
private(set) var currentIndex: Int = 0
private let fileHandle: FileHandle
private let bufferLength: Int
private var endOffset: Int = 0
private var startOffset: Int = 0
private var bytes: [UInt8] = []
init(fileHandle: FileHandle, bufferLength: Int = 1024 * 8) throws {
self.fileHandle = fileHandle
self.bufferLength = bufferLength
try readMoreIfNeeded()
}
private func readMoreIfNeeded() throws {
guard Int(endOffset) == currentIndex else { return }
startOffset = currentIndex
let data = try fileHandle.read(upToCount: bufferLength) ?? Foundation.Data()
bytes = [UInt8](data)
endOffset = startOffset + bytes.count
}
@discardableResult
func consumeAny() throws -> UInt8 {
guard let consumed = try peek() else {
throw WasmParserError.unexpectedEnd
}
currentIndex = bytes.index(after: currentIndex)
return consumed
}
@discardableResult
func consume(_ expected: Set<UInt8>) throws -> UInt8 {
guard let consumed = try peek() else {
throw StreamError<UInt8>.unexpectedEnd(expected: Set(expected))
}
guard expected.contains(consumed) else {
throw StreamError<Element>.unexpected(consumed, index: currentIndex, expected: Set(expected))
}
currentIndex = bytes.index(after: currentIndex)
return consumed
}
func consume(count: Int) throws -> ArraySlice<UInt8> {
let bytesToRead = currentIndex + count - endOffset
guard bytesToRead > 0 else {
let bytesIndex = currentIndex - startOffset
let result = bytes[bytesIndex..<bytesIndex + count]
currentIndex = currentIndex + count
return result
}
guard let data = try fileHandle.read(upToCount: bytesToRead), data.count == bytesToRead else {
throw StreamError<UInt8>.unexpectedEnd(expected: nil)
}
bytes.append(contentsOf: [UInt8](data))
endOffset = endOffset + data.count
let bytesIndex = currentIndex - startOffset
let result = bytes[bytesIndex..<bytesIndex + count]
currentIndex = endOffset
return result
}
func peek() throws -> UInt8? {
try readMoreIfNeeded()
let index = currentIndex - startOffset
guard bytes.indices.contains(index) else {
return nil
}
return bytes[index]
}
}
|