diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..d9ce658a
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @aferditamuriqi
diff --git a/Cartfile b/Cartfile
index 0fdf56a1..04c27f7e 100644
--- a/Cartfile
+++ b/Cartfile
@@ -1,4 +1,4 @@
-github "readium/r2-shared-swift" == 1.4.2
+github "readium/r2-shared-swift" == 1.4.3
github "dexman/Minizip" == 1.4.0
github "cezheng/Fuzi" == 3.1.1
github "krzyzanowskim/CryptoSwift" == 1.2.0
diff --git a/Cartfile.resolved b/Cartfile.resolved
index 4c0d5f87..9abe2b96 100644
--- a/Cartfile.resolved
+++ b/Cartfile.resolved
@@ -2,4 +2,4 @@ github "cezheng/Fuzi" "3.1.1"
github "dexman/Minizip" "1.4.0"
github "edrlab/GCDWebServer" "3.6.2"
github "krzyzanowskim/CryptoSwift" "1.2.0"
-github "readium/r2-shared-swift" "1.4.2"
+github "readium/r2-shared-swift" "1.4.3"
diff --git a/R2Streamer.podspec b/R2Streamer.podspec
index e6d74003..1bccd16b 100644
--- a/R2Streamer.podspec
+++ b/R2Streamer.podspec
@@ -1,12 +1,12 @@
Pod::Spec.new do |s|
s.name = "R2Streamer"
- s.version = "1.2.4"
+ s.version = "1.2.5"
s.license = "BSD 3-Clause License"
s.summary = "R2 Streamer"
s.homepage = "http://readium.github.io"
s.author = { "Aferdita Muriqi" => "aferdita.muriqi@gmail.com" }
- s.source = { :git => "https://github.com/readium/r2-streamer-swift.git", :tag => "1.2.4" }
+ s.source = { :git => "https://github.com/readium/r2-streamer-swift.git", :tag => "1.2.5" }
s.exclude_files = ["**/Info*.plist"]
s.requires_arc = true
s.resources = ['r2-streamer-swift/Resources/**']
diff --git a/r2-streamer-swift/Fetcher/ContentFilter.swift b/r2-streamer-swift/Fetcher/ContentFilter.swift
index 5984575e..94f23b04 100644
--- a/r2-streamer-swift/Fetcher/ContentFilter.swift
+++ b/r2-streamer-swift/Fetcher/ContentFilter.swift
@@ -33,10 +33,7 @@ internal extension ContentFilters {
func apply(to input: Data, of publication: Publication, with container: Container, at path: String) throws -> Data {
let inputStream = DataInputStream(data: input)
let decodedInputStream = try apply(to: inputStream, of: publication, with: container, at: path)
- guard let decodedDataStream = decodedInputStream as? DataInputStream else {
- return Data()
- }
- return decodedDataStream.data
+ return try Data.reading(decodedInputStream)
}
}
@@ -126,13 +123,13 @@ final internal class ContentFiltersEpub: ContentFilters {
// Inserting at the start of
.
guard let headStart = resourceHtml.endIndex(of: "") else {
- log(.error, "Invalid resource")
- abort()
+ log(.error, "Invalid HTML resource: missing ")
+ return stream
}
guard let baseUrl = publication.baseURL?.deletingLastPathComponent() else {
log(.error, "Invalid host")
- abort()
+ return stream
}
@@ -146,8 +143,8 @@ final internal class ContentFiltersEpub: ContentFilters {
// Inserting at the end of .
guard let headEnd = resourceHtml.startIndex(of: "") else {
- log(.error, "Invalid resource")
- abort()
+ log(.error, "Invalid HTML resource: missing ")
+ return stream
}
let fontStyle = getHtmlFontStyle(forResource: "\(baseUrl)fonts/OpenDyslexic-Regular.otf", fontFamily: "OpenDyslexic")
resourceHtml = resourceHtml.insert(string: fontStyle, at: headEnd)
diff --git a/r2-streamer-swift/Fetcher/DRM/CBCDRMInputStream.swift b/r2-streamer-swift/Fetcher/DRM/CBCDRMInputStream.swift
index 76662ba9..30fb4c10 100644
--- a/r2-streamer-swift/Fetcher/DRM/CBCDRMInputStream.swift
+++ b/r2-streamer-swift/Fetcher/DRM/CBCDRMInputStream.swift
@@ -20,8 +20,6 @@ final class CBCDRMInputStream: DRMInputStream {
enum Error: Swift.Error {
case invalidStream
case emptyDecryptedData
- case readOutOfRange
- case readEncryptedOutOfRange
case readFailed
case decryptionFailed
}
@@ -63,17 +61,12 @@ final class CBCDRMInputStream: DRMInputStream {
}
override func read(_ buffer: UnsafeMutablePointer, maxLength len: Int) -> Int {
- guard hasBytesAvailable else {
- return 0
- }
-
- let len = Int64(len)
let offset = Int64(self.offset)
- guard offset + len <= length else {
- fail(with: Error.readOutOfRange)
- return -1
+ let len = min(Int64(len), Int64(length) - offset)
+ guard hasBytesAvailable, len > 0 else {
+ return 0 // EOF
}
-
+
// Get offset result offset in the block.
let blockOffset = offset % AESBlockSize
// For beginning of the cipher text, IV used for XOR.
@@ -101,11 +94,6 @@ final class CBCDRMInputStream: DRMInputStream {
do {
let bufferSize = blocksCount * AESBlockSize
var buffer = Array(repeating: 0, count: Int(bufferSize))
- guard readPosition + bufferSize <= stream.length else {
- fail(with: Error.readEncryptedOutOfRange)
- return -1
- }
-
stream.open()
try stream.seek(offset: Int64(readPosition), whence: .startOfFile)
let numberOfBytesRead = stream.read(&buffer, maxLength: Int(bufferSize))
diff --git a/r2-streamer-swift/Fetcher/DRM/DRMInputStream.swift b/r2-streamer-swift/Fetcher/DRM/DRMInputStream.swift
index 59ede650..5242f9d3 100644
--- a/r2-streamer-swift/Fetcher/DRM/DRMInputStream.swift
+++ b/r2-streamer-swift/Fetcher/DRM/DRMInputStream.swift
@@ -42,15 +42,11 @@ class DRMInputStream: SeekableInputStream, Loggable {
let length = Int64(self.length)
switch whence {
case .startOfFile:
- assert(0...length ~= offset)
- _offset = UInt64(offset)
+ _offset = UInt64(min(offset, length))
case .endOfFile:
- assert(-length...0 ~= offset)
- _offset = UInt64(length + offset)
+ _offset = UInt64(min(length + offset, length))
case .currentPosition:
- let newOffset = Int64(_offset) + offset
- assert(0...length ~= newOffset)
- _offset = UInt64(offset)
+ _offset = min(_offset + UInt64(offset), UInt64(length))
}
}
diff --git a/r2-streamer-swift/Fetcher/DRM/FullDRMInputStream.swift b/r2-streamer-swift/Fetcher/DRM/FullDRMInputStream.swift
index c90b455b..7271bc3c 100644
--- a/r2-streamer-swift/Fetcher/DRM/FullDRMInputStream.swift
+++ b/r2-streamer-swift/Fetcher/DRM/FullDRMInputStream.swift
@@ -19,7 +19,6 @@ final class FullDRMInputStream: DRMInputStream {
enum Error: Swift.Error {
case emptyDecryptedData
- case readOutOfRange
case readFailed
case decryptionFailed
case inflateFailed
@@ -82,29 +81,24 @@ final class FullDRMInputStream: DRMInputStream {
}
override func read(_ buffer: UnsafeMutablePointer, maxLength len: Int) -> Int {
- guard hasBytesAvailable else {
- return 0
- }
- guard offset + UInt64(len) <= length else {
- fail(with: Error.readOutOfRange)
- log(.error, "\(link.href): Decryption read out of range")
- return -1
+ let len = min(len, Int(length - offset))
+ guard hasBytesAvailable, len > 0 else {
+ return 0 // EOF
}
guard let data = data else {
return -1
}
- let readSize = (len > Int(length - offset) ? Int(length - offset) : len)
let start = data.index(0, offsetBy: Int(offset))
- let end = data.index(start, offsetBy: readSize)
+ let end = data.index(start, offsetBy: len)
let range = Range(uncheckedBounds: (start, end))
data.copyBytes(to: buffer, from: range)
- _offset += UInt64(readSize)
+ _offset += UInt64(len)
if _offset >= length {
_streamStatus = .atEnd
}
- return readSize
+ return len
}
}
diff --git a/r2-streamer-swift/Parser/EPUB/EPUBParser.swift b/r2-streamer-swift/Parser/EPUB/EPUBParser.swift
index acbc4e0b..c86befd2 100644
--- a/r2-streamer-swift/Parser/EPUB/EPUBParser.swift
+++ b/r2-streamer-swift/Parser/EPUB/EPUBParser.swift
@@ -194,9 +194,8 @@ final public class EpubParser: PublicationParser {
for mediaOverlayLink in mediaOverlays {
let node = MediaOverlayNode()
- guard let smilDataOptional = try? fetcher.data(forLink: mediaOverlayLink),
-// let smilData = smilDataOptional,
- let smilXml = try? XMLDocument(data: smilDataOptional) else
+ guard let smilData = try? fetcher.data(forLink: mediaOverlayLink),
+ let smilXml = try? XMLDocument(data: smilData) else
{
throw OPFParserError.invalidSmilResource
}
@@ -326,7 +325,7 @@ final public class EpubParser: PublicationParser {
?? Int((try? container.dataLength(relativePath: link.href)) ?? 0)
// Arbitrary byte length of a single page in a resource.
- let pageLength = 3500
+ let pageLength = 1024
let pageCount = max(1, Int(ceil((Double(length) / Double(pageLength)))))
let positionList = (1...pageCount).map { position in
diff --git a/r2-streamer-swift/Parser/PDF/PDFFileCGParser.swift b/r2-streamer-swift/Parser/PDF/PDFFileCGParser.swift
index f8986b72..8b83aabb 100644
--- a/r2-streamer-swift/Parser/PDF/PDFFileCGParser.swift
+++ b/r2-streamer-swift/Parser/PDF/PDFFileCGParser.swift
@@ -220,8 +220,8 @@ final class PDFFileCGParser: PDFFileParser, Loggable {
}
let current = stream.offset
- // SeekWhence.currentPosition is not supported at this time
do {
+ // SeekWhence.currentPosition is not supported at this time
try stream.seek(offset: Int64(current) + count, whence: .startOfFile)
} catch {
PDFParser.log(.error, error)
diff --git a/r2-streamer-swift/Parser/PDF/PDFParser.swift b/r2-streamer-swift/Parser/PDF/PDFParser.swift
index 3a3c80b8..a23b217b 100644
--- a/r2-streamer-swift/Parser/PDF/PDFParser.swift
+++ b/r2-streamer-swift/Parser/PDF/PDFParser.swift
@@ -190,9 +190,10 @@ public final class PDFParser: PublicationParser, Loggable {
// Calculates the page count of each resource from the reading order.
let resources = publication.readingOrder.map { link -> (Int, Link) in
- guard let optionalData = try? fetcher.data(forLink: link),
-// let data = optionalData,
- let parser = try? parserType.init(stream: DataInputStream(data: optionalData)),
+ guard let stream = try? fetcher.dataStream(forLink: link),
+ // FIXME: We should be able to use the stream directly here instead of reading it fully into a Data object, but somehow it fails with random access in CBCDRMInputStream.
+ let data = try? Data.reading(stream),
+ let parser = try? parserType.init(stream: DataInputStream(data: data)),
let pageCount = try? parser.parseNumberOfPages() else
{
log(.warning, "Can't get the number of pages from PDF document at \(link)")
diff --git a/r2-streamer-swift/Toolkit/DataExtension.swift b/r2-streamer-swift/Toolkit/DataExtension.swift
index 175c67c0..50a50367 100644
--- a/r2-streamer-swift/Toolkit/DataExtension.swift
+++ b/r2-streamer-swift/Toolkit/DataExtension.swift
@@ -12,18 +12,34 @@
import Foundation
extension Data {
- init(reading input: InputStream) {
- self.init()
- input.open()
+
+ static func reading(_ stream: InputStream) throws -> Data {
+ if let dataStream = stream as? DataInputStream {
+ return dataStream.data
+ }
+
+ var data = Data()
+ stream.open()
+ defer {
+ stream.close()
+ }
let bufferSize = 1024
let buffer = UnsafeMutablePointer.allocate(capacity: bufferSize)
- while input.hasBytesAvailable {
- let read = input.read(buffer, maxLength: bufferSize)
- self.append(buffer, count: read)
+ defer {
+ buffer.deallocate()
+ }
+ while stream.hasBytesAvailable {
+ let read = stream.read(buffer, maxLength: bufferSize)
+ if read < 0 {
+ throw stream.streamError ?? NSError()
+ } else if read == 0 {
+ break // EOF
+ }
+ data.append(buffer, count: read)
}
- buffer.deallocate()
- input.close()
+ return data
}
+
}