mirror of
https://github.com/GayPizzaSpecifications/darwin-apk.git
synced 2025-08-04 05:51:31 +00:00
Flatten TextInputStream wrapper and allow lines to be used directly on InputStream
This commit is contained in:
@ -104,7 +104,7 @@ public struct ApkIndexUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return try ApkIndex(raw:
|
return try ApkIndex(raw:
|
||||||
try ApkRawIndex(lines: TextInputStream(binaryStream: MemoryInputStream(buffer: apkIndexFile)).lines))
|
try ApkRawIndex(lines: MemoryInputStream(buffer: apkIndexFile).lines))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* darwin-apk © 2024 Gay Pizza Specifications
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import System
|
|
||||||
|
|
||||||
struct TextInputStream<InStream: InputStream> where InStream.Element == UInt8 {
|
|
||||||
private var _stream: InStream
|
|
||||||
|
|
||||||
public init(binaryStream: InStream) {
|
|
||||||
_stream = binaryStream
|
|
||||||
}
|
|
||||||
|
|
||||||
public var lines: LineSequence {
|
|
||||||
LineSequence(_stream: self._stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct LineSequence: Sequence {
|
|
||||||
public typealias Element = String
|
|
||||||
|
|
||||||
fileprivate var _stream: InStream
|
|
||||||
|
|
||||||
public struct Iterator: IteratorProtocol {
|
|
||||||
public typealias Element = String
|
|
||||||
|
|
||||||
fileprivate init(stream: InStream) {
|
|
||||||
self._stream = stream
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _stream: InStream
|
|
||||||
private var _bytes = [UInt8]()
|
|
||||||
private var _lastChar: UInt8? = nil
|
|
||||||
private var _eof = false
|
|
||||||
|
|
||||||
@inline(__always) private mutating func readRawLine() {
|
|
||||||
if let first = self._lastChar {
|
|
||||||
// Add any holdovers from reading the previous line to the start of this one
|
|
||||||
self._bytes.append(first)
|
|
||||||
self._lastChar = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
while true {
|
|
||||||
guard let nextChar = self._stream.next() else {
|
|
||||||
self._eof = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nextChar == 0x0A { // "\n"
|
|
||||||
break
|
|
||||||
} else if nextChar == 0x0D { // "\r"
|
|
||||||
// Match CRLF to avoid double newlines when dealing with DOS-based text
|
|
||||||
let lookAhead = self._stream.next()
|
|
||||||
if _slowPath(lookAhead != 0x0A) {
|
|
||||||
// If it wasn't an LF then queue it for the next line
|
|
||||||
self._lastChar = nextChar
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
self._bytes.append(nextChar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public mutating func next() -> String? {
|
|
||||||
// Return early if we already hit the end of the stream
|
|
||||||
guard !self._eof else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read raw bytes until newline
|
|
||||||
self.readRawLine()
|
|
||||||
defer {
|
|
||||||
self._bytes.removeAll(keepingCapacity: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _fastPath(!self._bytes.isEmpty) {
|
|
||||||
// Convert and return line
|
|
||||||
return String(decoding: self._bytes, as: UTF8.self)
|
|
||||||
} else {
|
|
||||||
if _fastPath(!self._eof) {
|
|
||||||
// Don't bother decoding empty lines and just return an empty string
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// Ignore the final empty newline
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func makeIterator() -> Iterator {
|
|
||||||
Iterator(stream: self._stream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
91
Sources/apk/Utility/TextLineSequence.swift
Normal file
91
Sources/apk/Utility/TextLineSequence.swift
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* darwin-apk © 2024 Gay Pizza Specifications
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import System
|
||||||
|
|
||||||
|
internal struct TextLineSequence<Base: InputStream>: Sequence where Base.Element == UInt8 {
|
||||||
|
public typealias Element = String
|
||||||
|
|
||||||
|
private var _stream: Base
|
||||||
|
|
||||||
|
fileprivate init(_ stream: Base) {
|
||||||
|
self._stream = stream
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Iterator: IteratorProtocol {
|
||||||
|
public typealias Element = String
|
||||||
|
|
||||||
|
fileprivate init(base stream: Base) {
|
||||||
|
self._stream = stream
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _stream: Base
|
||||||
|
private var _bytes = [UInt8]()
|
||||||
|
private var _lastChar: UInt8? = nil
|
||||||
|
private var _eof = false
|
||||||
|
|
||||||
|
@inline(__always) private mutating func readRawLine() {
|
||||||
|
if let first = self._lastChar {
|
||||||
|
// Add any holdovers from reading the previous line to the start of this one
|
||||||
|
self._bytes.append(first)
|
||||||
|
self._lastChar = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
while true {
|
||||||
|
guard let nextChar = self._stream.next() else {
|
||||||
|
self._eof = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nextChar == 0x0A { // "\n"
|
||||||
|
break
|
||||||
|
} else if nextChar == 0x0D { // "\r"
|
||||||
|
// Match CRLF to avoid double newlines when dealing with DOS-based text
|
||||||
|
let lookAhead = self._stream.next()
|
||||||
|
if _slowPath(lookAhead != 0x0A) {
|
||||||
|
// If it wasn't an LF then queue it for the next line
|
||||||
|
self._lastChar = nextChar
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
self._bytes.append(nextChar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func next() -> String? {
|
||||||
|
// Return early if we already hit the end of the stream
|
||||||
|
guard !self._eof else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read raw bytes until newline
|
||||||
|
self.readRawLine()
|
||||||
|
defer {
|
||||||
|
self._bytes.removeAll(keepingCapacity: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _fastPath(!self._bytes.isEmpty) {
|
||||||
|
// Convert and return line
|
||||||
|
return String(decoding: self._bytes, as: UTF8.self)
|
||||||
|
} else {
|
||||||
|
if _fastPath(!self._eof) {
|
||||||
|
// Don't bother decoding empty lines and just return an empty string
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// Ignore the final empty newline
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeIterator() -> Iterator {
|
||||||
|
Iterator(base: self._stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal extension InputStream {
|
||||||
|
var lines: TextLineSequence<InputStream> {
|
||||||
|
.init(self)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user