feat: load images from cbz files instead
This commit is contained in:
@@ -3,9 +3,10 @@
|
||||
// TODO: Convert between state for normal and scrolling page turn
|
||||
// TODO: Support reading with scrolling and landscape mode
|
||||
|
||||
import Foundation
|
||||
import FlatBuffers
|
||||
import Foundation
|
||||
import UIKit
|
||||
import ZIPFoundation
|
||||
|
||||
let preloadCount = 2
|
||||
// With a whopping 2 cores, and 2 threads because no hyperthreading, it makes sense to only have a queue as an extra thread to do work with to allow the main thread for ui.
|
||||
@@ -182,7 +183,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
for dir in directories {
|
||||
if !fileManager.fileExists(atPath: dir.appendingPathComponent(metadataFilename).path) {
|
||||
getMetadataFromFileName(path: dir)
|
||||
getMetadataFromFilename(path: dir)
|
||||
}
|
||||
|
||||
currentPath = dir
|
||||
@@ -192,15 +193,20 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
metadata = try! getCheckedRoot(byteBuffer: &byteBuffer)
|
||||
metadataList[dir] = metadata
|
||||
loadLocalState()
|
||||
|
||||
let volCovP = ProgressIndices(v: progress.v, c: 0, i: 0)
|
||||
let volumeDir = currentPath.appendingPathComponent("volumes")
|
||||
let archive = try! Archive(url: volumeDir.appendingPathComponent(metadata.volumes[progress.v].archive), accessMode: .read)
|
||||
let targetEntry = archive[metadata.volumes[volCovP.v].chapters[volCovP.c].images[volCovP.i].filename]!
|
||||
var extractedData = Data()
|
||||
_ = try archive.extract(targetEntry) { data in
|
||||
extractedData.append(data)
|
||||
}
|
||||
comics.append(
|
||||
Comic(
|
||||
cover: UIImage(contentsOfFile:
|
||||
getImagePath(progress: ProgressIndices(v: progress.v, c: 0, i: 0)).path
|
||||
)!,
|
||||
cover: UIImage(data: extractedData)!,
|
||||
metadata: metadata,
|
||||
path: dir
|
||||
))
|
||||
))
|
||||
}
|
||||
} catch {
|
||||
print("Failed to read directories")
|
||||
@@ -256,7 +262,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
func getMetadataFromFileName(path: URL) {
|
||||
func getMetadataFromFilename(path: URL) {
|
||||
// Beautiful, is it not?
|
||||
let patterns: [(NSRegularExpression, NSRegularExpression, Int, Int, Int)] = [
|
||||
(try! NSRegularExpression(pattern: #"c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-[0-9]+)?)"#), try! NSRegularExpression(pattern: #"^(.*) - c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-[0-9]+)?)"#), 3, 1, 2),
|
||||
@@ -287,28 +293,45 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
var titleValue: String = ""
|
||||
|
||||
let volumeDir = path.appendingPathComponent("volumes")
|
||||
|
||||
var isDir: ObjCBool = false
|
||||
if !fileManager.fileExists(atPath: volumeDir.path, isDirectory: &isDir) || !isDir.boolValue {
|
||||
print("Subdirectory volumes not found in \"\(path)\", returning")
|
||||
return
|
||||
}
|
||||
let volumeURLs = try! fileManager.contentsOfDirectory(
|
||||
at: volumeDir,
|
||||
includingPropertiesForKeys: [.isRegularFileKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
).filter { $0.pathExtension == "cbz" }
|
||||
|
||||
if volumeURLs.isEmpty {
|
||||
print("found no volumes in volume dir: \(volumeDir)")
|
||||
return
|
||||
}
|
||||
|
||||
var filenames: [(String, String)] = []
|
||||
for volumeURL in volumeURLs {
|
||||
do {
|
||||
let volumeArchive = try Archive(url: volumeURL, accessMode: .read)
|
||||
volumeArchive.map { URL(string: $0.path)!.lastPathComponent }.sorted().forEach{ filenames.append((volumeURL.lastPathComponent, $0)) }
|
||||
} catch {
|
||||
print("Failed to read archive \(volumeURL)")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if filenames.isEmpty {
|
||||
print("Found no files in archives")
|
||||
return
|
||||
}
|
||||
|
||||
print("example filename in archive: \(filenames[0].1), \(filenames[1].1)")
|
||||
|
||||
do {
|
||||
let dir = path.appendingPathComponent("images")
|
||||
|
||||
var isDir: ObjCBool = false
|
||||
if !fileManager.fileExists(atPath: dir.path, isDirectory: &isDir) || !isDir.boolValue {
|
||||
print("Subdirectory images not found in \"\(path)\", returning")
|
||||
return
|
||||
}
|
||||
|
||||
let testFilename = try fileManager.contentsOfDirectory(
|
||||
at: dir,
|
||||
includingPropertiesForKeys: [.isRegularFileKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
).first
|
||||
if testFilename == nil {
|
||||
print("Empty images dir, returning")
|
||||
return
|
||||
}
|
||||
|
||||
for (currentPattern, currentTitlePattern, currentPageRegexPosition, currentChapterRegexPosition, currentVolumeRegexPosition) in patterns {
|
||||
let filename = testFilename!.lastPathComponent
|
||||
let filename = filenames[0].1
|
||||
let range = NSRange(filename.startIndex..., in: filename)
|
||||
if let match = currentTitlePattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: 1)) == "" {
|
||||
@@ -356,13 +379,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
let regex = pattern!
|
||||
let titleRegex = titlePattern!
|
||||
|
||||
let fileURLs = try fileManager.contentsOfDirectory(
|
||||
at: dir,
|
||||
includingPropertiesForKeys: [.isRegularFileKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
)
|
||||
let filenames = fileURLs.map { $0.lastPathComponent }.sorted()
|
||||
for (i, filename) in filenames.enumerated() {
|
||||
for (i, (volumeURL, filename)) in filenames.enumerated() {
|
||||
let range = NSRange(filename.startIndex..., in: filename)
|
||||
if i == 0 {
|
||||
if let match = titleRegex.firstMatch(in: filename, range: range) {
|
||||
@@ -387,7 +404,15 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
UInt32(pageParts[0])!, pageParts.count > 1
|
||||
)
|
||||
|
||||
let size = imageSize(at: dir.appendingPathComponent(filename))!
|
||||
let archive = try Archive(url: volumeDir.appendingPathComponent(volumeURL), accessMode: .read)
|
||||
let entry = archive[filename]!
|
||||
var size = ImageDimensions(width: 0, height: 0)
|
||||
do {
|
||||
size = try imageDimensions(of: entry, in: archive)
|
||||
} catch {
|
||||
print("Failed to get image dimensions of filename: \(filename)")
|
||||
return
|
||||
}
|
||||
let m_filename = builder.create(string: filename)
|
||||
let imageMetadata = ImageMetadata.createImageMetadata(&builder,
|
||||
doublePage: doublePage,
|
||||
@@ -413,12 +438,14 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
let volumeTitle = builder.create(string: "")
|
||||
let volumeURLOffset = builder.create(string: volumeURL)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: MetaValue(main: currentVolume, bonus: 0),
|
||||
titleOffset: volumeTitle,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset,
|
||||
)
|
||||
|
||||
volumes.append(volumeMetadata)
|
||||
@@ -466,11 +493,13 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
let volumeTitle = builder.create(string: "")
|
||||
let volumeURLOffset = builder.create(string: volumeURL)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: MetaValue(main: volume, bonus: 0),
|
||||
titleOffset: volumeTitle,
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
)
|
||||
|
||||
@@ -662,6 +691,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
var offset = scrollingCollectionView.contentOffset
|
||||
offset.y *= (screenSize.width / screenSize.height)
|
||||
scrollingCollectionView.setContentOffset(offset, animated: false)
|
||||
// FIXME: This is a caching issue, needs a different cache for scrolling since it Fill instead of Fit.
|
||||
scrollingCollectionView.reloadData()
|
||||
}
|
||||
}
|
||||
@@ -1017,8 +1047,10 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
if mode == .scroll {
|
||||
setupScrolling()
|
||||
} else {
|
||||
let archiveURL = currentPath.appendingPathComponent("volumes").appendingPathComponent(metadata.volumes[progress.v].archive)
|
||||
imageLoader.loadImage(
|
||||
at: getImagePath(progress: progress),
|
||||
archiveURL: archiveURL,
|
||||
filename: getImagePath(progress: progress),
|
||||
scaling: .scaleAspectFit,
|
||||
screenSize: UIScreen.main.bounds.size
|
||||
) { [weak self] image in
|
||||
@@ -1158,22 +1190,21 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
}
|
||||
progress = newProgress
|
||||
updateInfo()
|
||||
var preloadPaths: [URL] = []
|
||||
let path = getImagePath(progress: progress)
|
||||
|
||||
for _ in 0 ..< preloadCount {
|
||||
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
|
||||
preloadPaths.append(getImagePath(progress: newProgress))
|
||||
}
|
||||
|
||||
imageLoader.setActiveWindow([path])
|
||||
|
||||
imageLoader.loadImage(at: path, scaling: scaling, screenSize: UIScreen.main.bounds.size) { [weak self] image in
|
||||
let archiveURL = currentPath.appendingPathComponent("volumes").appendingPathComponent(metadata.volumes[progress.v].archive)
|
||||
imageLoader.loadImage(archiveURL: archiveURL, filename: getImagePath(progress: progress), scaling: scaling, screenSize: UIScreen.main.bounds.size) { [weak self] image in
|
||||
self?.imageView.image = image
|
||||
}
|
||||
|
||||
for path in preloadPaths {
|
||||
imageLoader.preloadImage(at: path, scaling: scaling, screenSize: UIScreen.main.bounds.size)
|
||||
for _ in 0 ..< preloadCount {
|
||||
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
|
||||
let archive = metadata.volumes[newProgress.v].archive!
|
||||
let filename = getImagePath(progress: newProgress)
|
||||
let archiveURL = currentPath.appendingPathComponent("volumes").appendingPathComponent(archive)
|
||||
imageLoader.preloadImage(archiveURL: archiveURL, filename: filename, scaling: scaling, screenSize: UIScreen.main.bounds.size)
|
||||
}
|
||||
|
||||
saveLocalState()
|
||||
@@ -1242,10 +1273,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
info.text = text
|
||||
}
|
||||
|
||||
func getImagePath(progress: ProgressIndices) -> URL {
|
||||
func getImagePath(progress: ProgressIndices) -> String {
|
||||
let (v, c, i) = (progress.v, progress.c, progress.i)
|
||||
let modernPath = currentPath!.appendingPathComponent("images").appendingPathComponent(metadata.volumes[v].chapters[c].images[i].filename)
|
||||
// print("trying to get path \(modernPath)")
|
||||
let modernPath = metadata.volumes[v].chapters[c].images[i].filename!
|
||||
// if fileManager.fileExists(atPath: modernPath.path) {
|
||||
return modernPath
|
||||
// }
|
||||
@@ -1299,8 +1329,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
scaling = UIView.ContentMode.scaleAspectFill
|
||||
} else { scaling = UIView.ContentMode.scaleAspectFit }
|
||||
imageLoader.loadImage(
|
||||
at:
|
||||
getImagePath(progress: progress),
|
||||
archiveURL: currentPath.appendingPathComponent("volumes").appendingPathComponent(metadata.volumes[progress.v].archive),
|
||||
filename: getImagePath(progress: progress),
|
||||
scaling: scaling,
|
||||
screenSize: UIScreen.main.bounds.size
|
||||
) { [weak self] image in
|
||||
@@ -1311,7 +1341,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
var newProgress = progress
|
||||
for _ in 0 ..< preloadCount {
|
||||
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
|
||||
imageLoader.preloadImage(at: getImagePath(progress: newProgress), scaling: scaling, screenSize: UIScreen.main.bounds.size)
|
||||
imageLoader.preloadImage(archiveURL: currentPath.appendingPathComponent("volumes").appendingPathComponent(metadata.volumes[progress.v].archive), filename: getImagePath(progress: newProgress), scaling: scaling, screenSize: UIScreen.main.bounds.size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1330,7 +1360,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
if mode != .scroll {
|
||||
imageLoader.loadImage(
|
||||
at: getImagePath(progress: progress),
|
||||
archiveURL: currentPath.appendingPathComponent("volumes").appendingPathComponent(metadata.volumes[progress.v].archive),
|
||||
filename: getImagePath(progress: progress),
|
||||
scaling: .scaleAspectFit,
|
||||
screenSize: size
|
||||
) { image in
|
||||
@@ -1424,7 +1455,10 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl
|
||||
newProgress = getProgressIndicesFromTurn(turn: .next, progress: newProgress)
|
||||
}
|
||||
}
|
||||
imageLoader.loadImage(at: getImagePath(progress: newProgress), scaling: scaling, screenSize: UIScreen.main.bounds.size) { image in
|
||||
imageLoader.loadImage(
|
||||
archiveURL: currentPath.appendingPathComponent("volumes").appendingPathComponent(metadata.volumes[progress.v].archive),
|
||||
filename: getImagePath(progress: newProgress),
|
||||
scaling: scaling, screenSize: UIScreen.main.bounds.size) { image in
|
||||
cell.imageView.image = image
|
||||
}
|
||||
return cell
|
||||
@@ -1541,23 +1575,29 @@ class ImageLoader {
|
||||
private let horCache = NSCache<NSString, UIImage>()
|
||||
private var loadingTasks: [String: (UIImage?) -> Void] = [:]
|
||||
private var activeTokens: [String: CancellationToken] = [:]
|
||||
private var archives = NSCache<NSString, Archive>()
|
||||
|
||||
init() {
|
||||
// 128 MiB
|
||||
cache.totalCostLimit = 128 * 1024 * 1024
|
||||
horCache.totalCostLimit = 128 * 1024 * 1024
|
||||
// The reason archives are cached and have a strict limit of four, is because Archive supposedly opens a posix file pointer and keeps it until the object is destroyed.
|
||||
archives.countLimit = 4
|
||||
}
|
||||
|
||||
func preloadImage(at path: URL, scaling: UIView.ContentMode, screenSize: CGSize) {
|
||||
loadImage(at: path, scaling: scaling, screenSize: screenSize, completion: nil)
|
||||
func preloadImage(archiveURL: URL, filename: String, scaling: UIView.ContentMode, screenSize: CGSize) {
|
||||
loadImage(archiveURL: archiveURL, filename: filename, scaling: scaling, screenSize: screenSize, completion: nil)
|
||||
}
|
||||
|
||||
// FIXME: So scrolling is not really handled well in terms of caching. This is because it should have a separate cache since it uses a different scaling (Fill instead of Fit).
|
||||
func loadImage(
|
||||
at path: URL, scaling: UIView.ContentMode,
|
||||
archiveURL: URL, filename: String,
|
||||
scaling: UIView.ContentMode,
|
||||
screenSize: CGSize,
|
||||
completion: ((UIImage?) -> Void)?
|
||||
) {
|
||||
let rotation: Rotation = screenSize.width > screenSize.height ? .horizontal : .vertical
|
||||
let key = path.path
|
||||
let key = filename
|
||||
|
||||
if rotation == .vertical, let cached = cache.object(forKey: key as NSString) {
|
||||
completion?(cached); return
|
||||
@@ -1597,7 +1637,19 @@ class ImageLoader {
|
||||
|
||||
if token.isCancelled { finish(nil); return }
|
||||
|
||||
guard var image = UIImage(contentsOfFile: key) else {
|
||||
var extractedData = Data()
|
||||
if self.archives.object(forKey: archiveURL.lastPathComponent as NSString) == nil {
|
||||
let archive = try! Archive(url: archiveURL, accessMode: .read)
|
||||
self.archives.setObject(archive, forKey: archiveURL.lastPathComponent as NSString)
|
||||
}
|
||||
let archive = self.archives.object(forKey: archiveURL.lastPathComponent as NSString)!
|
||||
_ = try! archive.extract(archive[filename]!) { data in
|
||||
extractedData.append(data)
|
||||
}
|
||||
|
||||
if token.isCancelled { finish(nil); return }
|
||||
|
||||
guard var image = UIImage(data: extractedData) else {
|
||||
finish(nil)
|
||||
return
|
||||
}
|
||||
@@ -1613,7 +1665,7 @@ class ImageLoader {
|
||||
let vScaledSize = aspectSize(for: image.size, in: vertical, scaling: scaling)
|
||||
let vScaleImage = resizeImage(image, to: vScaledSize)
|
||||
if let cost = imageByteSize(vScaleImage) {
|
||||
self.cache.setObject(vScaleImage, forKey: path.path as NSString, cost: cost)
|
||||
self.cache.setObject(vScaleImage, forKey: filename as NSString, cost: cost)
|
||||
}
|
||||
if rotation == .vertical { image = vScaleImage }
|
||||
}
|
||||
@@ -1628,7 +1680,7 @@ class ImageLoader {
|
||||
let hScaledSize = aspectSize(for: image.size, in: horizontal, scaling: scaling)
|
||||
let hScaleImage = resizeImage(image, to: hScaledSize)
|
||||
if let cost = imageByteSize(hScaleImage) {
|
||||
self.horCache.setObject(hScaleImage, forKey: path.path as NSString, cost: cost)
|
||||
self.horCache.setObject(hScaleImage, forKey: filename as NSString, cost: cost)
|
||||
}
|
||||
if rotation == .horizontal { image = hScaleImage }
|
||||
}
|
||||
@@ -1637,8 +1689,8 @@ class ImageLoader {
|
||||
}
|
||||
}
|
||||
|
||||
func setActiveWindow(_ paths: [URL]) {
|
||||
let desired = Set(paths.map { $0.path })
|
||||
func setActiveWindow(_ paths: [String]) {
|
||||
let desired = Set(paths)
|
||||
for (key, token) in activeTokens where !desired.contains(key) {
|
||||
token.cancel()
|
||||
loadingTasks[key] = nil
|
||||
@@ -1695,3 +1747,49 @@ final class CancellationToken {
|
||||
_isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageDimensions {
|
||||
let width: Int
|
||||
let height: Int
|
||||
}
|
||||
|
||||
enum ImageSizeResult: Error {
|
||||
case found(ImageDimensions)
|
||||
}
|
||||
|
||||
enum ImageSizeError: Error {
|
||||
case couldNotDetermineSize
|
||||
}
|
||||
|
||||
func imageDimensions(of entry: Entry, in archive: Archive) throws -> ImageDimensions {
|
||||
let imageSource = CGImageSourceCreateIncremental(nil)
|
||||
var accumulatedData = Data()
|
||||
|
||||
do {
|
||||
// This runs until the closure throws, or the entry is fully consumed
|
||||
_ = try archive.extract(entry) { chunk in
|
||||
accumulatedData.append(chunk)
|
||||
CGImageSourceUpdateData(imageSource, accumulatedData as CFData, false)
|
||||
|
||||
if let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any],
|
||||
let width = properties[kCGImagePropertyPixelWidth as String] as? Int,
|
||||
let height = properties[kCGImagePropertyPixelHeight as String] as? Int {
|
||||
// We have what we need — abort the rest of the decompression
|
||||
throw ImageSizeResult.found(ImageDimensions(width: width, height: height))
|
||||
}
|
||||
}
|
||||
} catch ImageSizeResult.found(let dimensions) {
|
||||
return dimensions
|
||||
}
|
||||
|
||||
// Fallback: some formats only report size once fully loaded (rare, but be safe)
|
||||
CGImageSourceUpdateData(imageSource, accumulatedData as CFData, true)
|
||||
if let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any],
|
||||
let width = properties[kCGImagePropertyPixelWidth as String] as? Int,
|
||||
let height = properties[kCGImagePropertyPixelHeight as String] as? Int {
|
||||
print("This fell back to loading the complete image for size metadata")
|
||||
return ImageDimensions(width: width, height: height)
|
||||
}
|
||||
|
||||
throw ImageSizeError.couldNotDetermineSize
|
||||
}
|
||||
|
||||
@@ -31,18 +31,19 @@ table ImageMetadata {
|
||||
double_page:bool;
|
||||
filename:string (required);
|
||||
first_page:uint;
|
||||
size:Size;
|
||||
size:Size (required);
|
||||
}
|
||||
|
||||
table ChapterMetadata {
|
||||
chapter:MetaValue;
|
||||
chapter:MetaValue (required);
|
||||
name:string;
|
||||
images:[ImageMetadata];
|
||||
}
|
||||
|
||||
table VolumeMetadata {
|
||||
volume:MetaValue;
|
||||
volume:MetaValue (required);
|
||||
title:string;
|
||||
archive:string (required);
|
||||
chapters:[ChapterMetadata];
|
||||
}
|
||||
|
||||
|
||||
@@ -291,21 +291,21 @@ public struct ImageMetadata: FlatBufferTable, FlatbuffersVectorInitializable, Ve
|
||||
public var filename: String! { let o = _accessor.offset(VT.filename); return _accessor.string(at: o) }
|
||||
public var filenameSegmentArray: [UInt8]! { return _accessor.getVector(at: VT.filename) }
|
||||
public var firstPage: UInt32 { let o = _accessor.offset(VT.firstPage); return o == 0 ? 0 : _accessor.readBuffer(of: UInt32.self, at: o) }
|
||||
public var size: Size? { let o = _accessor.offset(VT.size); return o == 0 ? nil : _accessor.readBuffer(of: Size.self, at: o) }
|
||||
public var mutableSize: Size_Mutable? { let o = _accessor.offset(VT.size); return o == 0 ? nil : Size_Mutable(_accessor.bb, o: o + _accessor.position) }
|
||||
public var size: Size! { let o = _accessor.offset(VT.size); return _accessor.readBuffer(of: Size.self, at: o) }
|
||||
public var mutableSize: Size_Mutable! { let o = _accessor.offset(VT.size); return Size_Mutable(_accessor.bb, o: o + _accessor.position) }
|
||||
public static func startImageMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 4) }
|
||||
public static func add(doublePage: Bool, _ fbb: inout FlatBufferBuilder) { fbb.add(element: doublePage, def: false,
|
||||
at: VT.doublePage) }
|
||||
public static func add(filename: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: filename, at: VT.filename) }
|
||||
public static func add(firstPage: UInt32, _ fbb: inout FlatBufferBuilder) { fbb.add(element: firstPage, def: 0, at: VT.firstPage) }
|
||||
public static func add(size: Size?, _ fbb: inout FlatBufferBuilder) { guard let size = size else { return }; fbb.create(struct: size, position: VT.size) }
|
||||
public static func endImageMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [6]); return end }
|
||||
public static func endImageMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [6, 10]); return end }
|
||||
public static func createImageMetadata(
|
||||
_ fbb: inout FlatBufferBuilder,
|
||||
doublePage: Bool = false,
|
||||
filenameOffset filename: Offset,
|
||||
firstPage: UInt32 = 0,
|
||||
size: Size? = nil
|
||||
size: Size
|
||||
) -> Offset {
|
||||
let __start = ImageMetadata.startImageMetadata(&fbb)
|
||||
ImageMetadata.add(doublePage: doublePage, &fbb)
|
||||
@@ -320,7 +320,7 @@ public struct ImageMetadata: FlatBufferTable, FlatbuffersVectorInitializable, Ve
|
||||
try _v.visit(field: VT.doublePage, fieldName: "doublePage", required: false, type: Bool.self)
|
||||
try _v.visit(field: VT.filename, fieldName: "filename", required: true, type: ForwardOffset<String>.self)
|
||||
try _v.visit(field: VT.firstPage, fieldName: "firstPage", required: false, type: UInt32.self)
|
||||
try _v.visit(field: VT.size, fieldName: "size", required: false, type: Size.self)
|
||||
try _v.visit(field: VT.size, fieldName: "size", required: true, type: Size.self)
|
||||
_v.finish()
|
||||
}
|
||||
}
|
||||
@@ -340,8 +340,8 @@ public struct ChapterMetadata: FlatBufferTable, FlatbuffersVectorInitializable,
|
||||
static let images: VOffset = 8
|
||||
}
|
||||
|
||||
public var chapter: MetaValue? { let o = _accessor.offset(VT.chapter); return o == 0 ? nil : _accessor.readBuffer(of: MetaValue.self, at: o) }
|
||||
public var mutableChapter: MetaValue_Mutable? { let o = _accessor.offset(VT.chapter); return o == 0 ? nil : MetaValue_Mutable(_accessor.bb, o: o + _accessor.position) }
|
||||
public var chapter: MetaValue! { let o = _accessor.offset(VT.chapter); return _accessor.readBuffer(of: MetaValue.self, at: o) }
|
||||
public var mutableChapter: MetaValue_Mutable! { let o = _accessor.offset(VT.chapter); return MetaValue_Mutable(_accessor.bb, o: o + _accessor.position) }
|
||||
public var name: String? { let o = _accessor.offset(VT.name); return o == 0 ? nil : _accessor.string(at: o) }
|
||||
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.name) }
|
||||
public var images: FlatbufferVector<ImageMetadata> { return _accessor.vector(at: VT.images, byteSize: 4) }
|
||||
@@ -349,10 +349,10 @@ public struct ChapterMetadata: FlatBufferTable, FlatbuffersVectorInitializable,
|
||||
public static func add(chapter: MetaValue?, _ fbb: inout FlatBufferBuilder) { guard let chapter = chapter else { return }; fbb.create(struct: chapter, position: VT.chapter) }
|
||||
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VT.name) }
|
||||
public static func addVectorOf(images: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: images, at: VT.images) }
|
||||
public static func endChapterMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
|
||||
public static func endChapterMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [4]); return end }
|
||||
public static func createChapterMetadata(
|
||||
_ fbb: inout FlatBufferBuilder,
|
||||
chapter: MetaValue? = nil,
|
||||
chapter: MetaValue,
|
||||
nameOffset name: Offset = Offset(),
|
||||
imagesVectorOffset images: Offset = Offset()
|
||||
) -> Offset {
|
||||
@@ -365,7 +365,7 @@ public struct ChapterMetadata: FlatBufferTable, FlatbuffersVectorInitializable,
|
||||
|
||||
public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
|
||||
var _v = try verifier.visitTable(at: position)
|
||||
try _v.visit(field: VT.chapter, fieldName: "chapter", required: false, type: MetaValue.self)
|
||||
try _v.visit(field: VT.chapter, fieldName: "chapter", required: true, type: MetaValue.self)
|
||||
try _v.visit(field: VT.name, fieldName: "name", required: false, type: ForwardOffset<String>.self)
|
||||
try _v.visit(field: VT.images, fieldName: "images", required: false, type: ForwardOffset<Vector<ForwardOffset<ImageMetadata>, ImageMetadata>>.self)
|
||||
_v.finish()
|
||||
@@ -384,36 +384,43 @@ public struct VolumeMetadata: FlatBufferTable, FlatbuffersVectorInitializable, V
|
||||
private struct VT {
|
||||
static let volume: VOffset = 4
|
||||
static let title: VOffset = 6
|
||||
static let chapters: VOffset = 8
|
||||
static let archive: VOffset = 8
|
||||
static let chapters: VOffset = 10
|
||||
}
|
||||
|
||||
public var volume: MetaValue? { let o = _accessor.offset(VT.volume); return o == 0 ? nil : _accessor.readBuffer(of: MetaValue.self, at: o) }
|
||||
public var mutableVolume: MetaValue_Mutable? { let o = _accessor.offset(VT.volume); return o == 0 ? nil : MetaValue_Mutable(_accessor.bb, o: o + _accessor.position) }
|
||||
public var volume: MetaValue! { let o = _accessor.offset(VT.volume); return _accessor.readBuffer(of: MetaValue.self, at: o) }
|
||||
public var mutableVolume: MetaValue_Mutable! { let o = _accessor.offset(VT.volume); return MetaValue_Mutable(_accessor.bb, o: o + _accessor.position) }
|
||||
public var title: String? { let o = _accessor.offset(VT.title); return o == 0 ? nil : _accessor.string(at: o) }
|
||||
public var titleSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.title) }
|
||||
public var archive: String! { let o = _accessor.offset(VT.archive); return _accessor.string(at: o) }
|
||||
public var archiveSegmentArray: [UInt8]! { return _accessor.getVector(at: VT.archive) }
|
||||
public var chapters: FlatbufferVector<ChapterMetadata> { return _accessor.vector(at: VT.chapters, byteSize: 4) }
|
||||
public static func startVolumeMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 3) }
|
||||
public static func startVolumeMetadata(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 4) }
|
||||
public static func add(volume: MetaValue?, _ fbb: inout FlatBufferBuilder) { guard let volume = volume else { return }; fbb.create(struct: volume, position: VT.volume) }
|
||||
public static func add(title: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: title, at: VT.title) }
|
||||
public static func add(archive: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: archive, at: VT.archive) }
|
||||
public static func addVectorOf(chapters: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: chapters, at: VT.chapters) }
|
||||
public static func endVolumeMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
|
||||
public static func endVolumeMetadata(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [4, 8]); return end }
|
||||
public static func createVolumeMetadata(
|
||||
_ fbb: inout FlatBufferBuilder,
|
||||
volume: MetaValue? = nil,
|
||||
volume: MetaValue,
|
||||
titleOffset title: Offset = Offset(),
|
||||
archiveOffset archive: Offset,
|
||||
chaptersVectorOffset chapters: Offset = Offset()
|
||||
) -> Offset {
|
||||
let __start = VolumeMetadata.startVolumeMetadata(&fbb)
|
||||
VolumeMetadata.add(volume: volume, &fbb)
|
||||
VolumeMetadata.add(title: title, &fbb)
|
||||
VolumeMetadata.add(archive: archive, &fbb)
|
||||
VolumeMetadata.addVectorOf(chapters: chapters, &fbb)
|
||||
return VolumeMetadata.endVolumeMetadata(&fbb, start: __start)
|
||||
}
|
||||
|
||||
public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
|
||||
var _v = try verifier.visitTable(at: position)
|
||||
try _v.visit(field: VT.volume, fieldName: "volume", required: false, type: MetaValue.self)
|
||||
try _v.visit(field: VT.volume, fieldName: "volume", required: true, type: MetaValue.self)
|
||||
try _v.visit(field: VT.title, fieldName: "title", required: false, type: ForwardOffset<String>.self)
|
||||
try _v.visit(field: VT.archive, fieldName: "archive", required: true, type: ForwardOffset<String>.self)
|
||||
try _v.visit(field: VT.chapters, fieldName: "chapters", required: false, type: ForwardOffset<Vector<ForwardOffset<ChapterMetadata>, ChapterMetadata>>.self)
|
||||
_v.finish()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user