Skip to content
This repository has been archived by the owner on Aug 12, 2022. It is now read-only.

Use the new Format API #159

Merged
merged 7 commits into from
May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions r2-streamer-swift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
CA6F97D222A5161A007D2049 /* EPUBContainerParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6F97D122A5161A007D2049 /* EPUBContainerParserTests.swift */; };
CA6F97D422A52810007D2049 /* OPFParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6F97D322A52810007D2049 /* OPFParserTests.swift */; };
CA6F97DA22A6A0B7007D2049 /* OPFMeta.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6F97D922A6A0B6007D2049 /* OPFMeta.swift */; };
CA7116EC24547E0A00C029FD /* Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA7116EB24547E0A00C029FD /* Link.swift */; };
CA8672B2244868B50035FDF4 /* DataCompression.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA130D20229D4245000A627C /* DataCompression.swift */; };
CA94291822BCE42500305CDB /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA94291722BCE42500305CDB /* CoreServices.framework */; };
CABAC16622CDD6A200360595 /* DRMInputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = CABAC16522CDD6A200360595 /* DRMInputStream.swift */; };
Expand Down Expand Up @@ -138,6 +139,7 @@
CA6F97D122A5161A007D2049 /* EPUBContainerParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPUBContainerParserTests.swift; sourceTree = "<group>"; };
CA6F97D322A52810007D2049 /* OPFParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPFParserTests.swift; sourceTree = "<group>"; };
CA6F97D922A6A0B6007D2049 /* OPFMeta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPFMeta.swift; sourceTree = "<group>"; };
CA7116EB24547E0A00C029FD /* Link.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Link.swift; sourceTree = "<group>"; };
CA94291722BCE42500305CDB /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
CABAC16522CDD6A200360595 /* DRMInputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DRMInputStream.swift; sourceTree = "<group>"; };
CABAC16722CDD7A500360595 /* FullDRMInputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullDRMInputStream.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -327,6 +329,7 @@
CA130D3F229D4245000A627C /* Toolkit */ = {
isa = PBXGroup;
children = (
CA7116EA24547DFE00C029FD /* Extensions */,
CA130D37229D4245000A627C /* ZIPArchive */,
CA130CFF229D4245000A627C /* Streams */,
CA130D40229D4245000A627C /* Logger.swift */,
Expand Down Expand Up @@ -388,6 +391,14 @@
path = EPUB;
sourceTree = "<group>";
};
CA7116EA24547DFE00C029FD /* Extensions */ = {
isa = PBXGroup;
children = (
CA7116EB24547E0A00C029FD /* Link.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
CABAC16422CDD67A00360595 /* DRM */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -539,6 +550,7 @@
CA6F97DA22A6A0B7007D2049 /* OPFMeta.swift in Sources */,
CA130D74229D4245000A627C /* DataExtension.swift in Sources */,
CABAC16622CDD6A200360595 /* DRMInputStream.swift in Sources */,
CA7116EC24547E0A00C029FD /* Link.swift in Sources */,
CA130D75229D4245000A627C /* StringExtension.swift in Sources */,
CABAC16A22CDD83C00360595 /* CBCDRMInputStream.swift in Sources */,
CA130D68229D4245000A627C /* NCXParser.swift in Sources */,
Expand Down
4 changes: 1 addition & 3 deletions r2-streamer-swift/Fetcher/ContentFilter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,7 @@ final internal class ContentFiltersEpub: ContentFilters {
// if (publication layout is 'reflow' && resource is `not specified`)
// || resource is 'reflow'
// - inject pagination
if let link = publication.link(withHref: path),
["application/xhtml+xml", "text/html"].contains(link.type)
{
if let link = publication.link(withHref: path), link.mediaType?.isHTML == true {
if publication.metadata.presentation.layout(of: link) == .reflowable {
decodedInputStream = injectReflowableHtml(in: decodedInputStream, for: publication)
}
Expand Down
2 changes: 1 addition & 1 deletion r2-streamer-swift/Fetcher/DRM/CBCDRMInputStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ final class CBCDRMInputStream: DRMInputStream {
}

// TODO: Double check if there is a different way to remove padding from HTML resources only.
if (link.type == "application/xhtml+xml") {
if link.mediaType?.isHTML == true {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also match text/html now.

let padding = Int(data[data.count - 1])
data = data.subdata(in: Range(uncheckedBounds: (0, data.count - padding)))
}
Expand Down
12 changes: 6 additions & 6 deletions r2-streamer-swift/Fetcher/Fetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,16 @@ internal class Fetcher {
/// - Returns: The corresponding ContentFilters subclass.
/// - Throws: In case the mimetype is nil or invalid, throws a
/// `FetcherError.missingContainerMimetype`
static func getContentFilters(forMimeType mimeType: String?) throws -> ContentFilters {
guard let mimeType = mimeType else {
static func getContentFilters(forMimeType mediaType: String?) throws -> ContentFilters {
guard let format = Format.of(mediaType: mediaType) else {
throw FetcherError.missingContainerMimetype
}
switch mimeType {
case EPUBConstant.mimetype, EPUBConstant.mimetypeOEBPS:
switch format {
case .epub:
return ContentFiltersEpub()
case CBZConstant.mimetype:
case .cbz:
return ContentFiltersCbz()
case PDFConstant.pdfMimetype, PDFConstant.lcpdfMimetype:
case .pdf, .lcpProtectedPDF:
return ContentFiltersPDF()
default:
throw FetcherError.missingContainerMimetype
Expand Down
5 changes: 3 additions & 2 deletions r2-streamer-swift/Parser/CBZ/CBZContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//

import Foundation
import R2Shared


/// Specializing the `Container` for CBZ publications.
Expand All @@ -24,7 +25,7 @@ protocol CBZContainer: Container {
final class CBZArchiveContainer: ArchiveContainer, CBZContainer {

init?(path: String) {
super.init(path: path, mimetype: CBZConstant.mimetype)
super.init(path: path, mimetype: MediaType.cbz.string)

do {
try archive.buildFilesList()
Expand All @@ -48,7 +49,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: MediaType.cbz.string)
}

var files: [String] {
Expand Down
28 changes: 4 additions & 24 deletions r2-streamer-swift/Parser/CBZ/CBZParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,6 @@ public enum CBZParserError: Error {
@available(*, deprecated, renamed: "CBZParserError")
public typealias CbzParserError = CBZParserError

/// CBZ related constants.
struct CBZConstant {
public static let mimetype = "application/vnd.comicbook+zip"
}

public enum MediaType: String {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By replacing this with Format.of() and checking format.mediaType.isBitmap, we are supporting much more formats in a CBZ.

case jpeg = "image/jpeg"
case png = "image/png"

init?(filename: String) {
switch filename.pathExtension.lowercased() {
case "jpg", "jpeg":
self = .jpeg
case "png":
self = .png
default:
return nil
}
}

}

/// CBZ publication parsing class.
public class CbzParser: PublicationParser {

Expand Down Expand Up @@ -84,12 +62,14 @@ public class CbzParser: PublicationParser {
),
readingOrder: container.files
.compactMap { filename in
guard let mediaType = MediaType(filename: filename) else {
guard let format = Format.of(fileExtension: filename.pathExtension),
format.mediaType.isBitmap else
{
return nil
}
return Link(
href: normalize(base: container.rootFile.rootFilePath, href: filename),
type: mediaType.rawValue
type: format.mediaType.string
)
}
)
Expand Down
2 changes: 1 addition & 1 deletion r2-streamer-swift/Parser/EPUB/EPUBContainerParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import R2Shared
/// A parser for the META-INF/container.xml file.
final class EPUBContainerParser: Loggable {

private let document: XMLDocument
private let document: Fuzi.XMLDocument

init(data: Data) throws {
self.document = try XMLDocument(data: data)
Expand Down
6 changes: 3 additions & 3 deletions r2-streamer-swift/Parser/EPUB/EPUBEncryptionParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ final class EPUBEncryptionParser: Loggable {
}
}

private lazy var document: XMLDocument? = {
let document = try? XMLDocument(data: data)
private lazy var document: Fuzi.XMLDocument? = {
let document = try? Fuzi.XMLDocument(data: data)
document?.definePrefix("enc", forNamespace: "http://www.w3.org/2001/04/xmlenc#")
document?.definePrefix("ds", forNamespace: "http://www.w3.org/2000/09/xmldsig#")
document?.definePrefix("comp", forNamespace: "http://www.idpf.org/2016/encryption#compression")
Expand Down Expand Up @@ -87,7 +87,7 @@ final class EPUBEncryptionParser: Loggable {
/// - Parameters:
/// - encryptionProperty: The EncryptionProperty element, parent of <Compression>.
/// - encryption: The Encryption structure to fill.
private func parseCompressionElement(from encryptionProperty: XMLElement, to encryption: inout Encryption) {
private func parseCompressionElement(from encryptionProperty: Fuzi.XMLElement, to encryption: inout Encryption) {
// Check that we have a compression element, with originalLength, not empty.
guard let compressionElement = encryptionProperty.firstChild(xpath:"comp:Compression"),
let method = compressionElement.attr("Method"),
Expand Down
22 changes: 11 additions & 11 deletions r2-streamer-swift/Parser/EPUB/EPUBMetadataParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import Fuzi
/// Reference: https://github.com/readium/architecture/blob/master/streamer/parser/metadata.md
final class EPUBMetadataParser: Loggable {

private let document: XMLDocument
private let displayOptions: XMLDocument?
private let document: Fuzi.XMLDocument
private let displayOptions: Fuzi.XMLDocument?
private let metas: OPFMetaList

init(document: XMLDocument, displayOptions: XMLDocument?, metas: OPFMetaList) {
init(document: Fuzi.XMLDocument, displayOptions: Fuzi.XMLDocument?, metas: OPFMetaList) {
self.document = document
self.displayOptions = displayOptions
self.metas = metas
Expand All @@ -31,7 +31,7 @@ final class EPUBMetadataParser: Loggable {
document.definePrefix("rendition", forNamespace: "http://www.idpf.org/2013/rendition")
}

private lazy var metadataElement: XMLElement? = {
private lazy var metadataElement: Fuzi.XMLElement? = {
return document.firstChild(xpath: "/opf:package/opf:metadata")
}()

Expand Down Expand Up @@ -71,7 +71,7 @@ final class EPUBMetadataParser: Loggable {
/// 1. its xml:lang attribute
/// 2. the package's xml:lang attribute
/// 3. the primary language for the publication
private func language(for element: XMLElement) -> String? {
private func language(for element: Fuzi.XMLElement) -> String? {
return element.attr("lang") ?? packageLanguage ?? languages.first
}

Expand Down Expand Up @@ -140,7 +140,7 @@ final class EPUBMetadataParser: Loggable {

/// Finds all the `<dc:title> element matching the given `title-type`.
/// The elements are then sorted by the `display-seq` refines, when available.
private func titleElements(ofType titleType: EPUBTitleType) -> [XMLElement] {
private func titleElements(ofType titleType: EPUBTitleType) -> [Fuzi.XMLElement] {
// Finds the XML element corresponding to the specific title type
// `<meta refines="#.." property="title-type" id="title-type">titleType</meta>`
return metas["title-type"]
Expand Down Expand Up @@ -171,7 +171,7 @@ final class EPUBMetadataParser: Loggable {
}
}()

private lazy var mainTitleElement: XMLElement? = titleElements(ofType: .main).first
private lazy var mainTitleElement: Fuzi.XMLElement? = titleElements(ofType: .main).first
?? metas["title", in: .dcterms].first?.element

private lazy var mainTitle: LocalizedString? = localizedString(for: mainTitleElement)
Expand Down Expand Up @@ -261,7 +261,7 @@ final class EPUBMetadataParser: Loggable {
///
/// - Parameter metadata: The XML metadata element.
/// - Returns: The array of XML element representing the contributors.
private func findContributorElements() -> [XMLElement] {
private func findContributorElements() -> [Fuzi.XMLElement] {
let contributors = metas["creator", in: .dcterms]
+ metas["publisher", in: .dcterms]
+ metas["contributor", in: .dcterms]
Expand All @@ -275,7 +275,7 @@ final class EPUBMetadataParser: Loggable {
/// - Parameters:
/// - element: The XML element to parse.
/// - metadata: The Metadata object.
private func parseContributor(from element: XMLElement, to metadata: inout Metadata) {
private func parseContributor(from element: Fuzi.XMLElement, to metadata: inout Metadata) {
guard var contributor = createContributor(from: element) else {
return
}
Expand Down Expand Up @@ -331,7 +331,7 @@ final class EPUBMetadataParser: Loggable {
/// - Parameters:
/// - element: The XML element reprensenting the contributor.
/// - Returns: The newly created Contributor instance.
private func createContributor(from element: XMLElement) -> Contributor? {
private func createContributor(from element: Fuzi.XMLElement) -> Contributor? {
guard let name = localizedString(for: element) else {
return nil
}
Expand Down Expand Up @@ -411,7 +411,7 @@ final class EPUBMetadataParser: Loggable {
///
/// - Parameters:
/// - element: The element to parse (can be a title or a contributor).
private func localizedString(for element: XMLElement?) -> LocalizedString? {
private func localizedString(for element: Fuzi.XMLElement?) -> LocalizedString? {
guard let element = element else {
return nil
}
Expand Down
20 changes: 8 additions & 12 deletions r2-streamer-swift/Parser/EPUB/EPUBParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,11 @@ import R2Shared
import Fuzi

/// Epub related constants.
struct EPUBConstant {
private struct EPUBConstant {
/// Lcpl file path.
public static let lcplFilePath = "META-INF/license.lcpl"
/// Epub mime-type.
public static let mimetype = "application/epub+zip"
/// http://www.idpf.org/oebps/ (Legacy).
public static let mimetypeOEBPS = "application/oebps-package+xml"
static let lcplFilePath = "META-INF/license.lcpl"
/// Media Overlays URL.
public static let mediaOverlayURL = "media-overlay?resource="
static let mediaOverlayURL = "media-overlay?resource="
}

/// Errors thrown during the parsing of the EPUB
Expand Down Expand Up @@ -156,7 +152,7 @@ final public class EpubParser: PublicationParser {
/// - publication: The Epub publication.
private static func parseNCXDocument(from container: Container, to publication: inout Publication) {
// Get the link in the readingOrder pointing to the NCX document.
guard let ncxLink = publication.resources.first(where: { $0.type == "application/x-dtbncx+xml" }),
guard let ncxLink = publication.resources.first(withType: .ncx),
let ncxDocumentData = try? container.data(relativePath: ncxLink.href) else
{
return
Expand All @@ -180,7 +176,7 @@ final public class EpubParser: PublicationParser {
/// - container: The Epub Container.
/// - publication: The Publication object representing the Epub data.
private static func parseMediaOverlay(from fetcher: Fetcher, to publication: inout Publication) throws {
let mediaOverlays = publication.resources.filter({ $0.type == "application/smil+xml"})
let mediaOverlays = publication.resources.filter(byType: .smil)

guard !mediaOverlays.isEmpty else {
log(.info, "No media-overlays found in the Publication.")
Expand Down Expand Up @@ -236,9 +232,9 @@ final public class EpubParser: PublicationParser {

guard let container: Container = {
if isDirectory.boolValue {
return DirectoryContainer(directory: path, mimetype: EPUBConstant.mimetype)
return DirectoryContainer(directory: path, mimetype: MediaType.epub.string)
} else {
return ArchiveContainer(path: path, mimetype: EPUBConstant.mimetype)
return ArchiveContainer(path: path, mimetype: MediaType.epub.string)
}
}() else {
throw EPUBParserError.missingFile(path: path)
Expand Down Expand Up @@ -337,7 +333,7 @@ final public class EpubParser: PublicationParser {
private static func makeLocator(from link: Link, progression: Double, position: Int) -> Locator {
return Locator(
href: link.href,
type: link.type ?? "text/html",
type: link.type ?? MediaType.html.string,
title: link.title,
locations: .init(
progression: progression,
Expand Down
6 changes: 3 additions & 3 deletions r2-streamer-swift/Parser/EPUB/NCXParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class NCXParser {
self.path = path
}

private lazy var document: XMLDocument? = {
private lazy var document: Fuzi.XMLDocument? = {
let document = try? XMLDocument(data: data)
document?.definePrefix("ncx", forNamespace: "http://www.daisy.org/z3986/2005/ncx/")
return document
Expand All @@ -60,13 +60,13 @@ final class NCXParser {
}

/// Parses recursively a list of nodes as a list of `Link`.
private func links(in element: XMLElement, nodeTagName: String) -> [Link] {
private func links(in element: Fuzi.XMLElement, nodeTagName: String) -> [Link] {
return element.xpath("ncx:\(nodeTagName)")
.compactMap { self.link(for: $0, nodeTagName: nodeTagName) }
}

/// Parses a node element as a `Link`.
private func link(for element: XMLElement, nodeTagName: String) -> Link? {
private func link(for element: Fuzi.XMLElement, nodeTagName: String) -> Link? {
return NavigationDocumentParser.makeLink(
title: element.firstChild(xpath: "ncx:navLabel/ncx:text")?.stringValue,
href: element.firstChild(xpath: "ncx:content")?.attr("src"),
Expand Down
8 changes: 4 additions & 4 deletions r2-streamer-swift/Parser/EPUB/NavigationDocumentParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ final class NavigationDocumentParser {
self.path = path
}

private lazy var document: XMLDocument? = {
private lazy var document: Fuzi.XMLDocument? = {
// Warning: Somehow if we use HTMLDocument instead of XMLDocument, then the `epub` prefix doesn't work.
let document = try? XMLDocument(data: data)
let document = try? Fuzi.XMLDocument(data: data)
document?.definePrefix("html", forNamespace: "http://www.w3.org/1999/xhtml")
document?.definePrefix("epub", forNamespace: "http://www.idpf.org/2007/ops")
return document
Expand All @@ -57,13 +57,13 @@ final class NavigationDocumentParser {
}

/// Parses recursively an <ol> as a list of `Link`.
private func links(in element: XMLElement) -> [Link] {
private func links(in element: Fuzi.XMLElement) -> [Link] {
return element.xpath("html:ol[1]/html:li")
.compactMap { self.link(for: $0) }
}

/// Parses a <li> element as a `Link`.
private func link(for li: XMLElement) -> Link? {
private func link(for li: Fuzi.XMLElement) -> Link? {
guard let label = li.firstChild(xpath: "html:a|html:span") else {
return nil
}
Expand Down
Loading