refactor: rename RDReaderView -> RDEpubReaderView, update pod config and docs

- Rename source module from RDReaderView to RDEpubReaderView
- Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/
- Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec
- Update Podfile, demo project, and CocoaPods config for new pod name
- Delete old RDReaderView pod support files from ReadViewDemo/Pods
- Add new RDEpubReaderView pod support files
- Update documentation (API ref, architecture, UML, conventions, etc.)
- Add FixedLayoutRotationTests
- Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
This commit is contained in:
shenlei
2026-07-10 19:44:53 +09:00
parent d5a7755702
commit d7fcda345d
460 changed files with 38358 additions and 2300 deletions
@@ -0,0 +1,175 @@
import Foundation
public final class RDEPUBResourceResolver {
private let parser: RDEPUBParser
public init(parser: RDEPUBParser) {
self.parser = parser
}
public var opfDirectoryURL: URL? {
parser.opfDirectoryURL
}
public func fileURL(forRelativePath relativePath: String) -> URL? {
parser.fileURL(forRelativePath: relativePath)
}
public func resourceURL(forRelativePath relativePath: String) -> URL? {
parser.resourceURL(forRelativePath: relativePath)
}
public func fileURL(forResourceURL resourceURL: URL) -> URL? {
parser.fileURL(forResourceURL: resourceURL)
}
///
public var hasResourceDataProvider: Bool {
parser.resourceDataProvider != nil
}
/// provider provider provider nil
public func providedResourceData(at fileURL: URL) -> Data? {
parser.providedResourceData(at: fileURL)
}
/// provider
public func resourceData(at fileURL: URL) -> Data? {
parser.resourceData(at: fileURL)
}
public func normalizedHref(_ href: String, relativeToSpineIndex spineIndex: Int? = nil) -> String? {
guard let opfDirectoryURL else {
return href.components(separatedBy: "#").first
}
let pathPart = href.components(separatedBy: "#").first ?? href
if pathPart.isEmpty {
guard let spineIndex, parser.spine.indices.contains(spineIndex) else {
return nil
}
return parser.spine[spineIndex].href.components(separatedBy: "#").first
}
let baseURL: URL
if let spineIndex, parser.spine.indices.contains(spineIndex) {
baseURL = opfDirectoryURL
.appendingPathComponent(parser.spine[spineIndex].href)
.deletingLastPathComponent()
} else {
baseURL = opfDirectoryURL
}
guard let resolvedURL = URL(string: pathPart, relativeTo: baseURL)?.standardizedFileURL else {
return pathPart
}
let opfPath = opfDirectoryURL.standardizedFileURL.path + "/"
let resolvedPath = resolvedURL.path
if resolvedPath.hasPrefix(opfPath) {
return String(resolvedPath.dropFirst(opfPath.count))
}
return pathPart
}
public func normalizedHref(_ href: String, relativeToHref baseHref: String) -> String? {
guard let opfDirectoryURL else {
return href.components(separatedBy: "#").first
}
let pathPart = href.components(separatedBy: "#").first ?? href
let basePath = baseHref.components(separatedBy: "#").first ?? baseHref
let baseURL = opfDirectoryURL
.appendingPathComponent(basePath)
.deletingLastPathComponent()
guard let resolvedURL = URL(string: pathPart, relativeTo: baseURL)?.standardizedFileURL else {
return pathPart
}
let opfPath = opfDirectoryURL.standardizedFileURL.path + "/"
if resolvedURL.path.hasPrefix(opfPath) {
return String(resolvedURL.path.dropFirst(opfPath.count))
}
return pathPart
}
public func fileURL(forReference href: String, relativeToHref baseHref: String) -> URL? {
guard let normalizedHref = normalizedHref(href, relativeToHref: baseHref) else {
return nil
}
return fileURL(forRelativePath: normalizedHref)
}
public func normalizedLocation(
_ location: RDEPUBLocation,
relativeToSpineIndex spineIndex: Int? = nil,
bookIdentifier: String?
) -> RDEPUBLocation? {
let rawHref = location.href
let hrefParts = rawHref.split(separator: "#", maxSplits: 1, omittingEmptySubsequences: false)
let pathPart = hrefParts.first.map(String.init) ?? rawHref
let fragment = location.fragment ?? (hrefParts.count > 1 ? String(hrefParts[1]) : nil)
let normalizedTargetHref: String
if pathPart.isEmpty {
guard let spineIndex, parser.spine.indices.contains(spineIndex) else {
return nil
}
normalizedTargetHref = parser.spine[spineIndex].href.components(separatedBy: "#").first ?? parser.spine[spineIndex].href
} else {
guard let href = normalizedHref(pathPart, relativeToSpineIndex: spineIndex) else {
return nil
}
normalizedTargetHref = href
}
return RDEPUBLocation(
bookIdentifier: bookIdentifier,
href: normalizedTargetHref,
progression: location.progression,
lastProgression: location.lastProgression,
fragment: fragment,
rangeAnchor: location.rangeAnchor,
cfi: location.cfi,
lastCFI: location.lastCFI,
rangeCFI: location.rangeCFI
)
}
public func spineIndex(forNormalizedHref normalizedHref: String) -> Int? {
parser.spine.firstIndex { item in
self.normalizedHref(item.href) == normalizedHref
}
}
public func spineIndex(for location: RDEPUBLocation) -> Int? {
guard let normalizedHref = normalizedHref(location.href) else {
return nil
}
return spineIndex(forNormalizedHref: normalizedHref)
}
public func href(forSpineIndex spineIndex: Int) -> String? {
guard parser.spine.indices.contains(spineIndex) else {
return nil
}
return parser.spine[spineIndex].href
}
public func title(forSpineIndex spineIndex: Int) -> String? {
guard parser.spine.indices.contains(spineIndex) else {
return nil
}
return parser.spine[spineIndex].title
}
public func manifestItem(forHref href: String) -> RDEPUBManifestItem? {
let targetHref = normalizedHref(href) ?? href.components(separatedBy: "#").first ?? href
return parser.manifest.values.first {
normalizedHref($0.href) == targetHref
}
}
}