Updates delta cores + replaces ZipZap with ZIPFoundation
Replaces ZipZap with ZIPFoundation due to DeltaCore now using ZIPFoundation
This commit is contained in:
parent
f293a2843f
commit
15b23c13e7
@ -1 +1 @@
|
||||
Subproject commit 4947d10713ba31017e40df275f40a315cf0da897
|
||||
Subproject commit ec24fdbd721a8a21636916797f65c2a97f1b0ac5
|
||||
@ -1 +1 @@
|
||||
Subproject commit 54d064d34a4d856fd34a49308f42f1aefac8eaad
|
||||
Subproject commit f958a29481557135ffaf3d7f4c50b43edacffb7e
|
||||
@ -1 +1 @@
|
||||
Subproject commit 9c295a2a287821544fec4b29d2b3f1205f965275
|
||||
Subproject commit 1a45f455c2fb89a81fad1eea4abb198084a4e41a
|
||||
@ -1 +1 @@
|
||||
Subproject commit a3f0547bc57c14b548105020136a9ead56f73470
|
||||
Subproject commit 4641bfc256383817cbded045eaf214aacea6ac6d
|
||||
@ -85,8 +85,6 @@
|
||||
BF6BF3271EB87EB8008E83CD /* PhotoLibraryImportOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6BF3261EB87EB8008E83CD /* PhotoLibraryImportOption.swift */; };
|
||||
BF6EE5E91F7C5F860051AD6C /* _GameControllerInputMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6EE5E81F7C5F860051AD6C /* _GameControllerInputMapping.swift */; };
|
||||
BF6EE5EB1F7C5F8F0051AD6C /* GameControllerInputMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6EE5EA1F7C5F8F0051AD6C /* GameControllerInputMapping.swift */; };
|
||||
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; };
|
||||
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF70798B1B6B464B0019077C /* ZipZap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BF71CF871FE90006001F1613 /* AppIconShortcutsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF71CF861FE90006001F1613 /* AppIconShortcutsViewController.swift */; };
|
||||
BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF71CF891FE904B1001F1613 /* GameTableViewCell.xib */; };
|
||||
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */; };
|
||||
@ -118,7 +116,6 @@
|
||||
BFF0742C1E9DC17500ACDF4A /* GBCDeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; };
|
||||
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */; };
|
||||
BFF93AA01E0FB036005EC865 /* InputStreamOutputWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */; };
|
||||
BFFA4C091E8A24D600D87934 /* GameTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */; };
|
||||
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */; };
|
||||
BFFA71E21AAC406100EE9DD1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFFA71E01AAC406100EE9DD1 /* Main.storyboard */; };
|
||||
@ -140,7 +137,6 @@
|
||||
BF9F4FD01AAD7B87004C9500 /* DeltaCore.framework in Embed Frameworks */,
|
||||
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */,
|
||||
BFEC732E1AAECC4A00650035 /* Roxas.framework in Embed Frameworks */,
|
||||
BF70798D1B6B464B0019077C /* ZipZap.framework in Embed Frameworks */,
|
||||
BF0418151D01E93400E85BCF /* GBADeltaCore.framework in Embed Frameworks */,
|
||||
BF99C6951D0A9AA600BA92BC /* SNESDeltaCore.framework in Embed Frameworks */,
|
||||
);
|
||||
@ -250,7 +246,6 @@
|
||||
BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveStateMigrationPolicy.swift; sourceTree = "<group>"; };
|
||||
BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBCDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputStreamOutputWriter.swift; sourceTree = "<group>"; };
|
||||
BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameTableViewCell.swift; sourceTree = "<group>"; };
|
||||
BFFA71D71AAC406100EE9DD1 /* Delta.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Delta.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BFFA71DB1AAC406100EE9DD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@ -273,7 +268,6 @@
|
||||
BF9F4FCF1AAD7B87004C9500 /* DeltaCore.framework in Frameworks */,
|
||||
BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */,
|
||||
BF99C6941D0A9AA600BA92BC /* SNESDeltaCore.framework in Frameworks */,
|
||||
BF70798C1B6B464B0019077C /* ZipZap.framework in Frameworks */,
|
||||
BF0418141D01E93400E85BCF /* GBADeltaCore.framework in Frameworks */,
|
||||
BFF0742C1E9DC17500ACDF4A /* GBCDeltaCore.framework in Frameworks */,
|
||||
4FE8465FD28810191C3E5212 /* Pods_Delta.framework in Frameworks */,
|
||||
@ -394,7 +388,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF59426D1E09BC5D0051894B /* DatabaseManager.swift */,
|
||||
BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */,
|
||||
BF5942711E09BC690051894B /* Model */,
|
||||
BF95E2751E49763D0030E7AD /* OpenVGDB */,
|
||||
);
|
||||
@ -968,7 +961,6 @@
|
||||
BF696B801D9B2B02009639E0 /* Theme.swift in Sources */,
|
||||
BF7AE8081C2E858400B1B5BC /* GridMenuViewController.swift in Sources */,
|
||||
BF6BF31A1EB82146008E83CD /* ClipboardImportOption.swift in Sources */,
|
||||
BFF93AA01E0FB036005EC865 /* InputStreamOutputWriter.swift in Sources */,
|
||||
BF59427F1E09BC830051894B /* GameCollection.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@ -11,7 +11,7 @@ import CoreData
|
||||
|
||||
// Workspace
|
||||
import DeltaCore
|
||||
import ZipZap
|
||||
import ZIPFoundation
|
||||
|
||||
// Pods
|
||||
import FileMD5Hash
|
||||
@ -346,7 +346,6 @@ extension DatabaseManager
|
||||
{
|
||||
DispatchQueue.global().async {
|
||||
|
||||
var semaphores = Set<DispatchSemaphore>()
|
||||
var outputURLs = Set<URL>()
|
||||
var errors = Set<ImportError>()
|
||||
|
||||
@ -354,17 +353,20 @@ extension DatabaseManager
|
||||
{
|
||||
var archiveContainsValidGameFile = false
|
||||
|
||||
do
|
||||
guard let archive = Archive(url: url, accessMode: .read) else {
|
||||
errors.insert(.invalid(url))
|
||||
continue
|
||||
}
|
||||
|
||||
for entry in archive
|
||||
{
|
||||
let archive = try ZZArchive(url: url)
|
||||
|
||||
for entry in archive.entries
|
||||
do
|
||||
{
|
||||
// Ensure entry is not in a subdirectory
|
||||
guard !entry.fileName.contains("/") else { continue }
|
||||
guard !entry.path.contains("/") else { continue }
|
||||
|
||||
let fileExtension = (entry.path as NSString).pathExtension
|
||||
|
||||
let fileExtension = (entry.fileName as NSString).pathExtension
|
||||
|
||||
guard GameType(fileExtension: fileExtension) != nil else { continue }
|
||||
|
||||
// At least one entry is a valid game file, so we set archiveContainsValidGameFile to true
|
||||
@ -372,54 +374,22 @@ extension DatabaseManager
|
||||
// However, if this game file does turn out to be invalid when extracting, we'll return an ImportError.invalid error specific to this game file
|
||||
archiveContainsValidGameFile = true
|
||||
|
||||
// ROMs may potentially be very large, so we extract using file streams and not raw Data
|
||||
let inputStream = try entry.newStream()
|
||||
|
||||
// Must use temporary directory, and not the directory containing zip file, since the latter might be read-only (such as when importing from Safari)
|
||||
let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent(entry.fileName)
|
||||
let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent(entry.path)
|
||||
|
||||
if FileManager.default.fileExists(atPath: outputURL.path)
|
||||
{
|
||||
try FileManager.default.removeItem(at: outputURL)
|
||||
}
|
||||
|
||||
guard let outputStream = OutputStream(url: outputURL, append: false) else { continue }
|
||||
_ = try archive.extract(entry, to: outputURL)
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
semaphores.insert(semaphore)
|
||||
|
||||
let outputWriter = InputStreamOutputWriter(inputStream: inputStream, outputStream: outputStream)
|
||||
outputWriter.start { (error) in
|
||||
if let error = error
|
||||
{
|
||||
if FileManager.default.fileExists(atPath: outputURL.path)
|
||||
{
|
||||
do
|
||||
{
|
||||
try FileManager.default.removeItem(at: outputURL)
|
||||
}
|
||||
catch
|
||||
{
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
print(error)
|
||||
|
||||
errors.insert(.invalid(outputURL))
|
||||
}
|
||||
else
|
||||
{
|
||||
outputURLs.insert(outputURL)
|
||||
}
|
||||
|
||||
semaphore.signal()
|
||||
}
|
||||
outputURLs.insert(outputURL)
|
||||
}
|
||||
catch
|
||||
{
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
print(error)
|
||||
}
|
||||
|
||||
if !archiveContainsValidGameFile
|
||||
@ -428,11 +398,6 @@ extension DatabaseManager
|
||||
}
|
||||
}
|
||||
|
||||
for semaphore in semaphores
|
||||
{
|
||||
semaphore.wait()
|
||||
}
|
||||
|
||||
for url in urls
|
||||
{
|
||||
if FileManager.default.fileExists(atPath: url.path)
|
||||
|
||||
@ -1,148 +0,0 @@
|
||||
//
|
||||
// InputStreamOutputWriter.swift
|
||||
// Delta
|
||||
//
|
||||
// Created by Riley Testut on 12/25/16.
|
||||
// Copyright © 2016 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private let MaximumBufferLength = 4 * 1024 // 4 KB
|
||||
|
||||
class InputStreamOutputWriter: NSObject
|
||||
{
|
||||
let inputStream: InputStream
|
||||
let outputStream: OutputStream
|
||||
|
||||
private var completion: ((Error?) -> Void)?
|
||||
|
||||
private var dataBuffer = Data(capacity: MaximumBufferLength * 2)
|
||||
|
||||
init(inputStream: InputStream, outputStream: OutputStream)
|
||||
{
|
||||
self.inputStream = inputStream
|
||||
self.outputStream = outputStream
|
||||
|
||||
super.init()
|
||||
|
||||
self.inputStream.delegate = self
|
||||
self.outputStream.delegate = self
|
||||
}
|
||||
|
||||
func start(with completion: @escaping ((Error?) -> Void))
|
||||
{
|
||||
guard self.completion == nil else { return }
|
||||
|
||||
self.completion = completion
|
||||
|
||||
let writingQueue = DispatchQueue(label: "com.rileytestut.InputStreamOutputWriter.writingQueue", qos: .userInitiated)
|
||||
writingQueue.async {
|
||||
self.inputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
|
||||
self.outputStream.schedule(in: .current, forMode: .defaultRunLoopMode)
|
||||
|
||||
self.outputStream.open()
|
||||
self.inputStream.open()
|
||||
|
||||
RunLoop.current.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension InputStreamOutputWriter
|
||||
{
|
||||
func writeDataBuffer()
|
||||
{
|
||||
while self.outputStream.hasSpaceAvailable && self.dataBuffer.count > 0
|
||||
{
|
||||
self.dataBuffer.withUnsafeMutableBytes { (buffer: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
let writtenBytesCount = self.outputStream.write(buffer, maxLength: self.dataBuffer.count)
|
||||
if writtenBytesCount >= 0
|
||||
{
|
||||
self.dataBuffer.removeSubrange(0 ..< writtenBytesCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func finishWriting()
|
||||
{
|
||||
self.inputStream.close()
|
||||
self.outputStream.close()
|
||||
|
||||
self.inputStream.remove(from: .current, forMode: .commonModes)
|
||||
self.outputStream.remove(from: .current, forMode: .commonModes)
|
||||
|
||||
self.completion?(self.inputStream.streamError ?? self.outputStream.streamError)
|
||||
|
||||
CFRunLoopStop(CFRunLoopGetCurrent())
|
||||
}
|
||||
}
|
||||
|
||||
extension InputStreamOutputWriter: StreamDelegate
|
||||
{
|
||||
func stream(_ aStream: Stream, handle eventCode: Stream.Event)
|
||||
{
|
||||
if let inputStream = aStream as? InputStream
|
||||
{
|
||||
self.inputStream(inputStream, handle: eventCode)
|
||||
}
|
||||
else if let outputStream = aStream as? OutputStream
|
||||
{
|
||||
self.outputStream(outputStream, handle: eventCode)
|
||||
}
|
||||
}
|
||||
|
||||
private func inputStream(_ inputStream: InputStream, handle eventCode: Stream.Event)
|
||||
{
|
||||
switch eventCode
|
||||
{
|
||||
case Stream.Event.hasBytesAvailable:
|
||||
|
||||
guard inputStream.streamError == nil else { return }
|
||||
|
||||
while inputStream.hasBytesAvailable
|
||||
{
|
||||
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: MaximumBufferLength)
|
||||
|
||||
let readBytesCount = inputStream.read(buffer, maxLength: MaximumBufferLength)
|
||||
|
||||
guard readBytesCount >= 0 else { break }
|
||||
|
||||
self.dataBuffer.append(buffer, count: readBytesCount)
|
||||
|
||||
buffer.deallocate(capacity: MaximumBufferLength)
|
||||
|
||||
self.writeDataBuffer()
|
||||
}
|
||||
|
||||
case Stream.Event.endEncountered:
|
||||
if self.dataBuffer.count == 0
|
||||
{
|
||||
self.finishWriting()
|
||||
}
|
||||
|
||||
case Stream.Event.errorOccurred: self.finishWriting()
|
||||
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
private func outputStream(_ outputStream: OutputStream, handle eventCode: Stream.Event)
|
||||
{
|
||||
switch eventCode
|
||||
{
|
||||
case Stream.Event.hasSpaceAvailable:
|
||||
self.writeDataBuffer()
|
||||
|
||||
if self.inputStream.streamStatus == .atEnd
|
||||
{
|
||||
self.finishWriting()
|
||||
}
|
||||
|
||||
case Stream.Event.errorOccurred: self.finishWriting()
|
||||
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user