diff --git a/Cartfile b/Cartfile index 6ed3b456..357e19c3 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,4 @@ -github "readium/r2-shared-swift" == 1.2.11 +github "readium/r2-shared-swift" == 1.2.12 github "dexman/Minizip" github "edrlab/Fuzi" == 2.2.2 github "krzyzanowskim/CryptoSwift" == 0.15.0 diff --git a/Cartfile.resolved b/Cartfile.resolved index dbb483b6..9dc32c98 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,5 +1,5 @@ github "dexman/Minizip" "1.4.0" github "edrlab/Fuzi" "2.2.2" github "krzyzanowskim/CryptoSwift" "0.15.0" -github "readium/r2-shared-swift" "1.2.11" +github "readium/r2-shared-swift" "1.2.12" github "swisspol/GCDWebServer" "3.5.2" diff --git a/r2-streamer-swift.xcodeproj/project.pbxproj b/r2-streamer-swift.xcodeproj/project.pbxproj index 9a0ed20b..85c40f45 100644 --- a/r2-streamer-swift.xcodeproj/project.pbxproj +++ b/r2-streamer-swift.xcodeproj/project.pbxproj @@ -245,10 +245,10 @@ CA130D25229D4245000A627C /* Parser */ = { isa = PBXGroup; children = ( - CA130D26229D4245000A627C /* CBZ */, - CA130D29229D4245000A627C /* PDF */, CA130D2E229D4245000A627C /* PublicationParser.swift */, + CA130D26229D4245000A627C /* CBZ */, CA130D2F229D4245000A627C /* EPUB */, + CA130D29229D4245000A627C /* PDF */, ); path = Parser; sourceTree = ""; diff --git a/r2-streamer-swift/Fetcher/ContentFilter.swift b/r2-streamer-swift/Fetcher/ContentFilter.swift index 84224eb6..bfa86aa4 100644 --- a/r2-streamer-swift/Fetcher/ContentFilter.swift +++ b/r2-streamer-swift/Fetcher/ContentFilter.swift @@ -15,7 +15,7 @@ import Fuzi /// Protocol defining the content filters. They are implemented below and used /// in the fetcher. They come in different flavors depending of the container /// data mimetype. -internal protocol ContentFilters { +internal protocol ContentFilters: Loggable { init() func apply(to input: SeekableInputStream, @@ -161,12 +161,12 @@ final internal class ContentFiltersEpub: ContentFilters { // Inserting at the start of . guard let headStart = resourceHtml.endIndex(of: "") else { - print("Invalid resource") + log(.error, "Invalid resource") abort() } guard let baseUrl = publication.baseURL?.deletingLastPathComponent() else { - print("Invalid host") + log(.error, "Invalid host") abort() } @@ -184,7 +184,7 @@ final internal class ContentFiltersEpub: ContentFilters { // Inserting at the end of . guard let headEnd = resourceHtml.startIndex(of: "") else { - print("Invalid resource") + log(.error, "Invalid resource") abort() } let cssAfter = getHtmlLink(forResource: "\(baseUrl)styles/\(styleSubFolder)/ReadiumCSS-after.css") @@ -214,7 +214,7 @@ final internal class ContentFiltersEpub: ContentFilters { return stream } guard let endHeadIndex = resourceHtml.startIndex(of: "") else { - print("Invalid resource") + log(.error, "Invalid resource") abort() } diff --git a/r2-streamer-swift/Fetcher/DRMDecoder.swift b/r2-streamer-swift/Fetcher/DRMDecoder.swift index eec9dc8e..b3e074b4 100644 --- a/r2-streamer-swift/Fetcher/DRMDecoder.swift +++ b/r2-streamer-swift/Fetcher/DRMDecoder.swift @@ -13,7 +13,7 @@ import Foundation import R2Shared /// Decrypt DRM encrypted content. -class DrmDecoder { +class DrmDecoder: Loggable { /// Decode the given stream using DRM. If it fails, just return the /// stream unchanged. @@ -47,7 +47,7 @@ class DrmDecoder { data = data.subdata(in: Range.init(uncheckedBounds: (0, data.count - padding))) guard let inflatedBuffer = data.inflate() else { - print("Inflate error") + log(.error, "Inflate error") return input } data = inflatedBuffer diff --git a/r2-streamer-swift/Fetcher/Fetcher.swift b/r2-streamer-swift/Fetcher/Fetcher.swift index cfdb9cd7..4d5f669f 100644 --- a/r2-streamer-swift/Fetcher/Fetcher.swift +++ b/r2-streamer-swift/Fetcher/Fetcher.swift @@ -144,9 +144,9 @@ internal class Fetcher { throw FetcherError.missingContainerMimetype } switch mimeType { - case EpubConstant.mimetype, EpubConstant.mimetypeOEBPS: + case EPUBConstant.mimetype, EPUBConstant.mimetypeOEBPS: return ContentFiltersEpub() - case CbzConstant.mimetype: + case CBZConstant.mimetype: return ContentFiltersCbz() case PDFConstant.pdfMimetype, PDFConstant.lcpdfMimetype: return ContentFiltersPDF() diff --git a/r2-streamer-swift/Model/Container.swift b/r2-streamer-swift/Model/Container.swift index 45540849..d2aec9ac 100644 --- a/r2-streamer-swift/Model/Container.swift +++ b/r2-streamer-swift/Model/Container.swift @@ -21,29 +21,18 @@ import R2Shared /// - xmlParse: An error occured while parsing XML (See underlyingError for more infos). /// - missingLink: The given `Link` ressource couldn't be found in the container. public enum ContainerError: Error { + // Stream initialization failed. case streamInitFailed + // The file couldn't be found. case fileNotFound + // An error occured while accessing the file attributes. case fileError + // The file is missing from the publication. case missingFile(path: String) + // Error while parsing XML case xmlParse(underlyingError: Error) + // The link with given title couldn't be found in the container case missingLink(title: String?) - - public var localizedDescription: String { - switch self { - case .streamInitFailed: - return "Stream initialization failed." - case .fileNotFound: - return "The file couldn't be found." - case .fileError: - return "An error occured while accessing the file attributes." - case .missingFile(let path): - return "The file at \(path) is missing from the archive." - case .xmlParse(let underlyingError): - return "Error while parsing XML: \(underlyingError.localizedDescription)" - case .missingLink(let title): - return "The link, titled \(title ?? "missing"), couldn't be found in the container." - } - } } /// Provide methods for accessing raw data from container's files. @@ -91,7 +80,6 @@ public extension Container { let url = NSURL(fileURLWithPath: rootFile.rootPath) var modificationDate : AnyObject? try? url.getResourceValue(&modificationDate, forKey: .contentModificationDateKey) - print("\(rootFile.rootPath) - \(modificationDate as! Date)") return (modificationDate as? Date) ?? Date() } diff --git a/r2-streamer-swift/Parser/CBZ/CBZContainer.swift b/r2-streamer-swift/Parser/CBZ/CBZContainer.swift index fafd1362..4b6e6b43 100644 --- a/r2-streamer-swift/Parser/CBZ/CBZContainer.swift +++ b/r2-streamer-swift/Parser/CBZ/CBZContainer.swift @@ -24,7 +24,7 @@ protocol CBZContainer: Container { final class CBZArchiveContainer: ArchiveContainer, CBZContainer { init?(path: String) { - super.init(path: path, mimetype: CbzConstant.mimetype) + super.init(path: path, mimetype: CBZConstant.mimetype) do { try archive.buildFilesList() @@ -48,7 +48,7 @@ final class CBZArchiveContainer: ArchiveContainer, CBZContainer { final class CBZDirectoryContainer: DirectoryContainer, CBZContainer { init?(directory: String) { - super.init(directory: directory, mimetype: CbzConstant.mimetype) + super.init(directory: directory, mimetype: CBZConstant.mimetype) } var files: [String] { diff --git a/r2-streamer-swift/Parser/CBZ/CBZParser.swift b/r2-streamer-swift/Parser/CBZ/CBZParser.swift index 51530920..685f3da9 100644 --- a/r2-streamer-swift/Parser/CBZ/CBZParser.swift +++ b/r2-streamer-swift/Parser/CBZ/CBZParser.swift @@ -1,5 +1,5 @@ // -// CbzParser.swift +// CBZParser.swift // r2-streamer-swift // // Created by Alexandre Camilleri on 3/31/17. @@ -15,19 +15,15 @@ import R2Shared /// Errors related to the CBZ publications. /// /// - missingFile: The file at 'path' is missing from the container. -public enum CbzParserError: LocalizedError { +public enum CBZParserError: Error { case missingFile(path: String) - - public var errorDescription: String? { - switch self { - case .missingFile(let path): - return "The file '\(path)' is missing." - } - } } +@available(*, deprecated, renamed: "CBZParserError") +public typealias CbzParserError = CBZParserError + /// CBZ related constants. -public struct CbzConstant { +struct CBZConstant { public static let mimetype = "application/x-cbr" } @@ -65,7 +61,7 @@ public class CbzParser: PublicationParser { /// /// - Parameter path: The path of the file to parse. /// - Returns: The resulting `PubBox` object. - /// - Throws: Throws `CbzParserError.missingFile`. + /// - Throws: Throws `CBZParserError.missingFile`. public static func parse(fileAtPath path: String) throws -> (PubBox, PubParsingCallback) { let container = try generateContainerFrom(fileAtPath: path) let publication = parsePublication(in: container, at: path) @@ -109,13 +105,13 @@ public class CbzParser: PublicationParser { /// /// - Parameter path: The absolute path of the file. /// - Returns: The generated Container. - /// - Throws: `EpubParserError.missingFile`. + /// - Throws: `CBZParserError.missingFile`. private static func generateContainerFrom(fileAtPath path: String) throws -> CBZContainer { var container: CBZContainer? var isDirectory: ObjCBool = false guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) else { - throw CbzParserError.missingFile(path: path) + throw CBZParserError.missingFile(path: path) } if isDirectory.boolValue { container = CBZDirectoryContainer(directory: path) @@ -124,7 +120,7 @@ public class CbzParser: PublicationParser { } guard let containerUnwrapped = container else { - throw CbzParserError.missingFile(path: path) + throw CBZParserError.missingFile(path: path) } return containerUnwrapped } diff --git a/r2-streamer-swift/Parser/EPUB/EPUBContainerParser.swift b/r2-streamer-swift/Parser/EPUB/EPUBContainerParser.swift index 32f68d26..e78fa824 100644 --- a/r2-streamer-swift/Parser/EPUB/EPUBContainerParser.swift +++ b/r2-streamer-swift/Parser/EPUB/EPUBContainerParser.swift @@ -30,7 +30,7 @@ final class EPUBContainerParser: Loggable { let data = try container.data(relativePath: path) try self.init(data: data) } catch { - throw EpubParserError.missingFile(path: path) + throw EPUBParserError.missingFile(path: path) } } @@ -38,7 +38,7 @@ final class EPUBContainerParser: Loggable { func parseRootFilePath() throws -> String { // Get the path of the OPF file, relative to the metadata.rootPath. guard let path = document.firstChild(xpath: "/cn:container/cn:rootfiles/cn:rootfile")?.attr("full-path") else { - throw EpubParserError.missingElement(message: "Missing rootfile in `container.xml`.") + throw EPUBParserError.missingRootfile } return path } diff --git a/r2-streamer-swift/Parser/EPUB/EPUBEncryptionParser.swift b/r2-streamer-swift/Parser/EPUB/EPUBEncryptionParser.swift index 3bf41638..9895cfb2 100644 --- a/r2-streamer-swift/Parser/EPUB/EPUBEncryptionParser.swift +++ b/r2-streamer-swift/Parser/EPUB/EPUBEncryptionParser.swift @@ -31,7 +31,7 @@ final class EPUBEncryptionParser: Loggable { let data = try container.data(relativePath: path) self.init(data: data, drm: drm) } catch { - throw EpubParserError.missingFile(path: path) + throw EPUBParserError.missingFile(path: path) } } diff --git a/r2-streamer-swift/Parser/EPUB/EPUBParser.swift b/r2-streamer-swift/Parser/EPUB/EPUBParser.swift index ce762db5..b864e348 100644 --- a/r2-streamer-swift/Parser/EPUB/EPUBParser.swift +++ b/r2-streamer-swift/Parser/EPUB/EPUBParser.swift @@ -13,7 +13,7 @@ import R2Shared import Fuzi /// Epub related constants. -public struct EpubConstant { +struct EPUBConstant { /// Lcpl file path. public static let lcplFilePath = "META-INF/license.lcpl" /// Epub mime-type. @@ -31,26 +31,18 @@ public struct EpubConstant { /// - missingFile: A file is missing from the container at `path`. /// - xmlParse: An XML parsing error occurred. /// - missingElement: An XML element is missing. -public enum EpubParserError: LocalizedError { +public enum EPUBParserError: Error { + /// The mimetype of the EPUB is not valid. case wrongMimeType case missingFile(path: String) case xmlParse(underlyingError: Error) - case missingElement(message: String) - - public var errorDescription: String? { - switch self { - case .wrongMimeType: - return "The mimetype of the Epub is not valid." - case .missingFile(let path): - return "The file '\(path)' is missing." - case .xmlParse(let underlyingError): - return "Error while parsing XML (\(underlyingError))." - case .missingElement(let message): - return "Missing element: \(message)." - } - } + /// Missing rootfile in `container.xml`. + case missingRootfile } +@available(*, deprecated, renamed: "EPUBParserError") +public typealias EpubParserError = EPUBParserError + extension EpubParser: Loggable {} /// An EPUB container parser that extracts the information from the relevant @@ -66,9 +58,9 @@ final public class EpubParser: PublicationParser { /// The point is to get DRM informations in the DRM object, and /// inform the decypher() function in the DRM object to allow /// the fetcher to decypher encrypted resources. - /// - Throws: `EpubParserError.wrongMimeType`, - /// `EpubParserError.xmlParse`, - /// `EpubParserError.missingFile` + /// - Throws: `EPUBParserError.wrongMimeType`, + /// `EPUBParserError.xmlParse`, + /// `EPUBParserError.missingFile` static public func parse(fileAtPath path: String) throws -> (PubBox, PubParsingCallback) { // Generate the `Container` for `fileAtPath` var container = try generateContainerFrom(fileAtPath: path) @@ -127,7 +119,7 @@ final public class EpubParser: PublicationParser { static internal func scanForDRM(in container: Container) -> DRM? { /// LCP. // Check if a LCP license file is present in the container. - if ((try? container.data(relativePath: EpubConstant.lcplFilePath)) != nil) { + if ((try? container.data(relativePath: EPUBConstant.lcplFilePath)) != nil) { return DRM(brand: .lcp) } return nil @@ -228,7 +220,7 @@ final public class EpubParser: PublicationParser { continue } link.mediaOverlays.append(node) - link.properties.mediaOverlay = EpubConstant.mediaOverlayURL + link.href + link.properties.mediaOverlay = EPUBConstant.mediaOverlayURL + link.href } } @@ -237,21 +229,21 @@ final public class EpubParser: PublicationParser { /// /// - Parameter path: The absolute path of the file. /// - Returns: The generated Container. - /// - Throws: `EpubParserError.missingFile`. + /// - Throws: `EPUBParserError.missingFile`. static fileprivate func generateContainerFrom(fileAtPath path: String) throws -> Container { var isDirectory: ObjCBool = false guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) else { - throw EpubParserError.missingFile(path: path) + throw EPUBParserError.missingFile(path: path) } guard let container: Container = { if isDirectory.boolValue { - return DirectoryContainer(directory: path, mimetype: EpubConstant.mimetype) + return DirectoryContainer(directory: path, mimetype: EPUBConstant.mimetype) } else { - return ArchiveContainer(path: path, mimetype: EpubConstant.mimetype) + return ArchiveContainer(path: path, mimetype: EPUBConstant.mimetype) } }() else { - throw EpubParserError.missingFile(path: path) + throw EPUBParserError.missingFile(path: path) } container.rootFile.rootFilePath = try EPUBContainerParser(container: container).parseRootFilePath() diff --git a/r2-streamer-swift/Parser/EPUB/OPFParser.swift b/r2-streamer-swift/Parser/EPUB/OPFParser.swift index 5737b445..5e0edf5c 100644 --- a/r2-streamer-swift/Parser/EPUB/OPFParser.swift +++ b/r2-streamer-swift/Parser/EPUB/OPFParser.swift @@ -27,16 +27,8 @@ public enum EPUBTitleType: String { public enum OPFParserError: Error { /// The Epub have no title. Title is mandatory. case missingPublicationTitle + /// Smile resource couldn't be parsed. case invalidSmilResource - - var localizedDescription: String { - switch self { - case .missingPublicationTitle: - return "The publication is missing a title." - case .invalidSmilResource: - return "Smile resource couldn't beparsed." - } - } } /// EpubParser support class, able to parse the OPF package document. diff --git a/r2-streamer-swift/Parser/EPUB/SMILParser.swift b/r2-streamer-swift/Parser/EPUB/SMILParser.swift index 7d8cb1d8..adeaffa6 100644 --- a/r2-streamer-swift/Parser/EPUB/SMILParser.swift +++ b/r2-streamer-swift/Parser/EPUB/SMILParser.swift @@ -50,7 +50,7 @@ final class SMILParser { continue } link.mediaOverlays.append(newNode) - link.properties.mediaOverlay = EpubConstant.mediaOverlayURL + link.href + link.properties.mediaOverlay = EPUBConstant.mediaOverlayURL + link.href } } diff --git a/r2-streamer-swift/Parser/PDF/PDFParser.swift b/r2-streamer-swift/Parser/PDF/PDFParser.swift index 87038c43..96df9957 100644 --- a/r2-streamer-swift/Parser/PDF/PDFParser.swift +++ b/r2-streamer-swift/Parser/PDF/PDFParser.swift @@ -31,7 +31,7 @@ public struct PDFConstant { /// Errors thrown during the parsing of the PDF. -public enum PDFParserError: LocalizedError { +public enum PDFParserError: Error { // The file at 'path' is missing from the container. case missingFile(path: String) // Failed to open the PDF @@ -40,20 +40,6 @@ public enum PDFParserError: LocalizedError { case fileEncryptedWithPassword // The LCP for PDF Package is malformed. case invalidLCPDF - - public var errorDescription: String? { - switch self { - case .missingFile(let path): - return "The file '\(path)' is missing." - case .openFailed: - return "Can't open the PDF file." - case .fileEncryptedWithPassword: - return "The PDF is encrypted with a password." - case .invalidLCPDF: - return "The LCP for PDF package is not valid." - } - } - } diff --git a/r2-streamer-swift/Server/WebServerResourceResponse.swift b/r2-streamer-swift/Server/WebServerResourceResponse.swift index e0c1f7da..8e6c7d5b 100644 --- a/r2-streamer-swift/Server/WebServerResourceResponse.swift +++ b/r2-streamer-swift/Server/WebServerResourceResponse.swift @@ -57,7 +57,7 @@ open class WebServerResourceResponse: GCDWebServerFileResponse { self.inputStream = inputStream // If range is non nil - means it's not the first part (?) if let range = range { - print("Request range at \(range.location) remaining: \(range.length).") + WebServerResourceResponse.log(.debug, "Request range at \(range.location) remaining: \(range.length).") /// Return a range of what to read next (nothing, next part, whole data). func getNextRange(after range: NSRange, forStreamOfLength streamLength: UInt64) -> Range { diff --git a/r2-streamer-swift/Toolkit/Streams/ZIPInputStream.swift b/r2-streamer-swift/Toolkit/Streams/ZIPInputStream.swift index 84005120..17ae81db 100644 --- a/r2-streamer-swift/Toolkit/Streams/ZIPInputStream.swift +++ b/r2-streamer-swift/Toolkit/Streams/ZIPInputStream.swift @@ -89,7 +89,7 @@ internal class ZipInputStream: SeekableInputStream { try zipArchive.openCurrentFile() _streamStatus = .open } catch { - print("ERROR: could not ZipArchive.openCurrentFile()") + log(.error, "Could not ZipArchive.openCurrentFile()") _streamStatus = .error _streamError = error } diff --git a/r2-streamer-swift/Toolkit/ZIPArchive/ZIPArchive.swift b/r2-streamer-swift/Toolkit/ZIPArchive/ZIPArchive.swift index 6c5602ff..580ab1a6 100644 --- a/r2-streamer-swift/Toolkit/ZIPArchive/ZIPArchive.swift +++ b/r2-streamer-swift/Toolkit/ZIPArchive/ZIPArchive.swift @@ -8,6 +8,7 @@ import Foundation import Minizip +import R2Shared public struct ZipFileInfo { let path: String @@ -35,7 +36,7 @@ internal enum ZipArchiveError: Error { } /// Wrapper around Minizip C lib. (Minizip uses Zlib) -internal class ZipArchive { +internal class ZipArchive: Loggable { /// The minizip memory representation of the Archive. internal var unzFile: unzFile /// The informations about the Archive. @@ -148,7 +149,7 @@ internal class ZipArchive { let bytesRead = unzReadCurrentFile(unzFile, buffer, UInt32(maxLength)) if bytesRead < 0 { - print("ERROR READ NOTHING") + log(.error, "Nothing to read") } // if bytesRead >= 0 { // currentFileOffset += UInt64(bytesRead)