mirror of
https://github.com/ItsElaineTime/SwresTools.git
synced 2025-01-18 19:31:53 +00:00
Initial commit from private projects repository.
This commit is contained in:
parent
a5d55c35df
commit
d96267259c
2
.gitignore
vendored
2
.gitignore
vendored
@ -63,3 +63,5 @@ fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
|
||||
.DS_Store
|
||||
|
4
Configurations/Debug.xcconfig
Normal file
4
Configurations/Debug.xcconfig
Normal file
@ -0,0 +1,4 @@
|
||||
#include "Project.xcconfig"
|
||||
|
||||
ONLY_ACTIVE_ARCH = YES
|
||||
SWIFT_OPTIMIZATION_LEVEL = -Onone
|
5
Configurations/Project.xcconfig
Normal file
5
Configurations/Project.xcconfig
Normal file
@ -0,0 +1,5 @@
|
||||
SDKROOT = macosx
|
||||
WARNING_CFLAGS = -Wall -Wextra
|
||||
|
||||
SWIFT_VERSION = 3.0
|
||||
SWIFT_INCLUDE_PATHS = "${PROJECT_DIR}/Modules"
|
5
Configurations/Release.xcconfig
Normal file
5
Configurations/Release.xcconfig
Normal file
@ -0,0 +1,5 @@
|
||||
#include "Project.xcconfig"
|
||||
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) NDEBUG=1
|
||||
|
||||
SWIFT_OPTIMIZATION_LEVEL = -O
|
18
Extras/DictionaryExtras.swift
Normal file
18
Extras/DictionaryExtras.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// DictionaryExtras.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
extension Dictionary {
|
||||
init(_ elements: Array<Element>){
|
||||
self.init()
|
||||
for (key, value) in elements {
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
func flatMap(transform: (Key, Value) -> (Key, Value)?) -> Dictionary<Key, Value> {
|
||||
return Dictionary(self.flatMap(transform))
|
||||
}
|
||||
}
|
||||
|
28
Extras/ErrorExtras.swift
Normal file
28
Extras/ErrorExtras.swift
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// ErrorExtras.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
protocol SwresError: Error, CustomStringConvertible {
|
||||
}
|
||||
|
||||
protocol NestingSwresError: SwresError {
|
||||
var underlyingError: Error? { get }
|
||||
}
|
||||
|
||||
extension Error {
|
||||
func shortDescription(withUnderlyingError: Bool = false) -> String {
|
||||
switch self {
|
||||
case let error as NestingSwresError:
|
||||
var string = error.description
|
||||
if let underlyingError = error.underlyingError, withUnderlyingError == true {
|
||||
string += "\n" + underlyingError.shortDescription(withUnderlyingError: true)
|
||||
}
|
||||
return string
|
||||
case let error as SwresError:
|
||||
return error.description
|
||||
default:
|
||||
return localizedDescription
|
||||
}
|
||||
}
|
||||
}
|
36
Extras/PointerExtras.swift
Normal file
36
Extras/PointerExtras.swift
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// PointerExtras.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
import Darwin
|
||||
|
||||
// For performance, there are a few places strings are passed around as a base pointer
|
||||
// and a count of bytes. The Swift standard library includes `UnsafeBufferPointer` and
|
||||
// `UnsafeMutableBufferPointer` which could wrap that pointer and length, but it's
|
||||
// surprisingly slow. Replacing that with this tiny `Buffer` struct sped up string
|
||||
// formatting hotpaths considerably.
|
||||
struct Buffer<T> {
|
||||
let pointer: UnsafePointer<T>
|
||||
let count: Int
|
||||
}
|
||||
|
||||
class ManagedUnsafeMutablePointer<T>: Hashable {
|
||||
let pointer: UnsafeMutablePointer<T>
|
||||
|
||||
init(adoptPointer: UnsafeMutablePointer<T>) {
|
||||
pointer = adoptPointer
|
||||
}
|
||||
|
||||
deinit {
|
||||
free(pointer)
|
||||
}
|
||||
|
||||
var hashValue: Int {
|
||||
return pointer.hashValue
|
||||
}
|
||||
|
||||
static func ==(lhs: ManagedUnsafeMutablePointer, rhs: ManagedUnsafeMutablePointer) -> Bool {
|
||||
return lhs.pointer == rhs.pointer
|
||||
}
|
||||
}
|
22
Extras/SequenceExtras.swift
Normal file
22
Extras/SequenceExtras.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// SequenceExtras.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
extension Sequence {
|
||||
func firstSome<ElementOfResult>(_ transform: @escaping (Iterator.Element) -> ElementOfResult?) -> ElementOfResult? {
|
||||
return self.lazy.flatMap(transform).first
|
||||
}
|
||||
|
||||
func groupBy<ElementOfResult: Hashable>(_ transform: (Iterator.Element) -> ElementOfResult) -> Dictionary<ElementOfResult, Array<Iterator.Element>> {
|
||||
var groupedBy: Dictionary<ElementOfResult, Array<Iterator.Element>> = Dictionary()
|
||||
for item in self {
|
||||
let transformed = transform(item)
|
||||
if groupedBy[transformed] == nil {
|
||||
groupedBy[transformed] = Array<Iterator.Element>()
|
||||
}
|
||||
groupedBy[transformed]!.append(item)
|
||||
}
|
||||
return groupedBy
|
||||
}
|
||||
}
|
10
Extras/StrideExtras.swift
Normal file
10
Extras/StrideExtras.swift
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// StrideExtras.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
func offsetAndLengthStride(from: Int, to: Int, by: Int, _ block: (Int, Int) -> Void) {
|
||||
for offset in stride(from: from, to: to, by: by) {
|
||||
block(offset, min(by, to - offset))
|
||||
}
|
||||
}
|
100
Extras/StringExtras.swift
Normal file
100
Extras/StringExtras.swift
Normal file
@ -0,0 +1,100 @@
|
||||
//
|
||||
// StringFunctions.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private let MinimumDisplayableByteValue: UInt8 = 32
|
||||
|
||||
let MacOSRomanByteFullStop: UInt8 = 0x2E
|
||||
let MacOSRomanByteQuestionMark: UInt8 = 0x3F
|
||||
|
||||
struct MacOSRomanConversionOptions {
|
||||
let filterControlCharacters: Bool
|
||||
let filterFilesystemUnsafeCharacters: Bool
|
||||
let filterNonASCIICharacters: Bool
|
||||
let replacementMacOSRomanByte: UInt8?
|
||||
}
|
||||
|
||||
func stringFromMacOSRomanBytes(_ buffer: Buffer<UInt8>, options: MacOSRomanConversionOptions) -> String {
|
||||
let filterControlCharacters = options.filterControlCharacters || options.filterFilesystemUnsafeCharacters
|
||||
|
||||
let filteredBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: buffer.count + 1)
|
||||
defer {
|
||||
filteredBytes.deallocate(capacity: buffer.count + 1)
|
||||
}
|
||||
|
||||
var filteredByteIterator = filteredBytes
|
||||
|
||||
@inline(__always) func writeFilteredByte(_ byte: UInt8) {
|
||||
filteredByteIterator.pointee = byte
|
||||
filteredByteIterator += 1
|
||||
}
|
||||
|
||||
var bufferPointer = buffer.pointer
|
||||
let endPointer = buffer.pointer + buffer.count
|
||||
|
||||
while bufferPointer < endPointer {
|
||||
var replaceCharacter = false
|
||||
let byte = bufferPointer.pointee
|
||||
|
||||
// SPACE, DELETE
|
||||
if filterControlCharacters, byte < 0x20 || byte == 0x7F {
|
||||
replaceCharacter = true
|
||||
}
|
||||
// DELETE
|
||||
else if options.filterNonASCIICharacters, byte > 0x7F {
|
||||
replaceCharacter = true
|
||||
}
|
||||
// ASTERISK, FULL STOP, SOLIDUS, COLON, REVERSE SOLIDUS, TILDE
|
||||
// Some of these aren't technically unsafe, but they can cause issues in the
|
||||
// shell or Finder, such as a period at the start of a file or a tilde.
|
||||
else if options.filterFilesystemUnsafeCharacters, byte == 0x2A || byte == 0x2E || byte == 0x2F || byte == 0x3A || byte == 0x5C || byte == 0x7E {
|
||||
replaceCharacter = true
|
||||
}
|
||||
|
||||
if replaceCharacter, let unwrappedReplacementByte = options.replacementMacOSRomanByte {
|
||||
writeFilteredByte(unwrappedReplacementByte)
|
||||
} else if !replaceCharacter {
|
||||
writeFilteredByte(byte)
|
||||
}
|
||||
|
||||
bufferPointer += 1
|
||||
}
|
||||
|
||||
filteredByteIterator.pointee = 0
|
||||
|
||||
let cStringPointer = UnsafeRawPointer(filteredBytes).assumingMemoryBound(to: CChar.self)
|
||||
return String(cString: cStringPointer, encoding: String.Encoding.macOSRoman)!
|
||||
}
|
||||
|
||||
func stringFromMacOSRomanBytes(_ data: Data, options: MacOSRomanConversionOptions) -> String {
|
||||
return data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
|
||||
let buffer = Buffer(pointer: bytes, count: data.count)
|
||||
return stringFromMacOSRomanBytes(buffer, options: options)
|
||||
}
|
||||
}
|
||||
|
||||
func filesystemSafeString(_ data: Data) -> String {
|
||||
let options = MacOSRomanConversionOptions(filterControlCharacters: true, filterFilesystemUnsafeCharacters: true, filterNonASCIICharacters: false, replacementMacOSRomanByte: nil)
|
||||
return stringFromMacOSRomanBytes(data, options: options)
|
||||
}
|
||||
|
||||
extension String {
|
||||
func copyCString() -> ManagedUnsafeMutablePointer<Int8> {
|
||||
return self.withCString({ (cString: UnsafePointer<Int8>) -> ManagedUnsafeMutablePointer<Int8> in
|
||||
return ManagedUnsafeMutablePointer(adoptPointer: strdup(cString))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct StringAndCString {
|
||||
let string: String
|
||||
let cString: ManagedUnsafeMutablePointer<CChar>
|
||||
|
||||
init(_ string: String) {
|
||||
self.string = string
|
||||
cString = string.copyCString()
|
||||
}
|
||||
}
|
5
Modules/FUSE/module.modulemap
Normal file
5
Modules/FUSE/module.modulemap
Normal file
@ -0,0 +1,5 @@
|
||||
module Fuse [system] {
|
||||
header "/usr/local/include/osxfuse/fuse.h"
|
||||
link "osxfuse"
|
||||
export *
|
||||
}
|
49
README
Normal file
49
README
Normal file
@ -0,0 +1,49 @@
|
||||
SwresTools is a set of two tools for exploring and dumping classic Macintosh resource forks, written in Swift.
|
||||
|
||||
SwresTools can convert some resources to modern types. For example, it can translate some <code>snd </code> resources to WAV files.
|
||||
|
||||
To be honest, this was just a fun side project and shouldn't be used for anything important.
|
||||
|
||||
### SwresExplode
|
||||
|
||||
`SwresExplode` dumps the resources of a classic Macintosh resource fork to individual files.
|
||||
|
||||
For example, list all of the resource types in a resource fork:
|
||||
|
||||
SwresExplode resourcefile
|
||||
|
||||
Dump all `snd ` resources to individual files:
|
||||
|
||||
SwresExplode -d -t 'snd '
|
||||
|
||||
### SwresFUSE
|
||||
|
||||
`SwresFUSE` mounts a resource fork as a filesystem. It requires [FUSE for macOS][fuse].
|
||||
|
||||
Example usage:
|
||||
|
||||
SwresFUSE resourcefile mountpoint
|
||||
|
||||
![A screenshot of SwresFUSE exploring a resource fork.](SwresFUSE.png)
|
||||
|
||||
[fuse]: https://osxfuse.github.io
|
||||
|
||||
### Why?
|
||||
|
||||
¯\\_(ツ)_/¯
|
||||
|
||||
### No, Really, Why?
|
||||
|
||||
I wanted to rip the music out of the old Mac game [Troubled Souls][troubledsouls], and this seemed like such a bad way to go about it I had to give it a go. I was playing around with Swift and thought this would be a fun way to write a project that interfaced with a C library.
|
||||
|
||||
[troubledsouls]: https://en.wikipedia.org/wiki/Troubled_Souls
|
||||
|
||||
### Buiding
|
||||
|
||||
You may need to point the header parameter of Modules/FUSE/module.modulemap to your FUSE header directory. For some reason module maps don't seem to respect header search paths and need absolute paths.
|
||||
|
||||
### Limitations
|
||||
|
||||
* The translators are very limited. Only Pascal style prefix strings and an extremely limited subset of `SND` resources are supported.
|
||||
* ResEdit features like `RMAP` and `TMPL` resources are not supported.
|
||||
* Editing or creating new resources is not supported.
|
367
SwresExplode/SwresExplode.swift
Normal file
367
SwresExplode/SwresExplode.swift
Normal file
@ -0,0 +1,367 @@
|
||||
//
|
||||
// SwresExplode.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct ExplodeTask {
|
||||
var printResources: Bool = false
|
||||
var dumpResources: Bool = false
|
||||
var overwriteExistingFiles: Bool = false
|
||||
var translatorFilter: TranslatorFilter = TranslatorFilter.noTranslators
|
||||
var identifierFilter: Int16?
|
||||
var typeFilter: FourCharCode?
|
||||
var inputURL: URL?
|
||||
var outputFolder: URL = URL(fileURLWithPath: "SwresExplode")
|
||||
}
|
||||
|
||||
func printUsageAndExit(status: Int32 = EXIT_SUCCESS) -> Never {
|
||||
let processName = ProcessInfo.processInfo.processName
|
||||
|
||||
print("Extract Macintosh Toolbox resources.")
|
||||
print("Usage: \(processName) [options] resourcefile")
|
||||
print("Options:")
|
||||
print(" -h Show this help message")
|
||||
print("Filtering Options:")
|
||||
print(" -i [id] Filter by resource identifier.")
|
||||
print(" -t [xxxx] Filter by resource type.")
|
||||
print("Dumping Options:")
|
||||
print(" -p Print resources to standard output.")
|
||||
print(" -d Dump resources to files.")
|
||||
print(" -o Output directory for the dumped resource.")
|
||||
print(" -f Overwrite existing files when dumping.")
|
||||
print(" -c Attempt to convert resources into more modern or portable formats.")
|
||||
print(" -C Also use best guess conversions.")
|
||||
print("Examples:")
|
||||
print(" \(processName) resourcefile List all of the types.")
|
||||
print(" \(processName) -d -t 'snd ' Dump all `snd ' resources.")
|
||||
print(" \(processName) -d -t 'snd ' -i 1000 Dump the `snd ' resource with id 1000.")
|
||||
print(" \(processName) -d -o /tmp/foo Dump all resources to the directory /tmp/foo.")
|
||||
|
||||
exit(status)
|
||||
}
|
||||
|
||||
func taskForArguments() -> ExplodeTask {
|
||||
var task = ExplodeTask()
|
||||
let argc = CommandLine.argc
|
||||
opterr = 0
|
||||
|
||||
while true {
|
||||
let option = getopt(argc, CommandLine.unsafeArgv, "hi:t:pdfcCo:")
|
||||
if option == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
let optionScalar = UnicodeScalar(Int(option))!
|
||||
switch optionScalar {
|
||||
case UnicodeScalar("h"):
|
||||
printUsageAndExit()
|
||||
case UnicodeScalar("i"):
|
||||
let identifierNumber = String(cString: optarg)
|
||||
task.identifierFilter = Int16(identifierNumber)
|
||||
case UnicodeScalar("t"):
|
||||
do {
|
||||
task.typeFilter = try FourCharCode(optarg)
|
||||
} catch FourCharCodeError.invalidSequence {
|
||||
print("Invalid type filter.");
|
||||
printUsageAndExit(status: EXIT_FAILURE)
|
||||
} catch {
|
||||
print("Unexpected error parsing type filter.")
|
||||
printUsageAndExit(status: EXIT_FAILURE)
|
||||
}
|
||||
case UnicodeScalar("p"):
|
||||
task.printResources = true
|
||||
case UnicodeScalar("d"):
|
||||
task.dumpResources = true
|
||||
case UnicodeScalar("o"):
|
||||
task.outputFolder = URL(fileURLWithPath: String(cString: optarg))
|
||||
case UnicodeScalar("f"):
|
||||
task.overwriteExistingFiles = true
|
||||
case UnicodeScalar("c"):
|
||||
task.translatorFilter = max(task.translatorFilter, TranslatorFilter.onlyLikelyTranslators)
|
||||
case UnicodeScalar("C"):
|
||||
task.translatorFilter = max(task.translatorFilter, TranslatorFilter.likelyAndPossibleTranslators)
|
||||
case UnicodeScalar("?"):
|
||||
let unknownOption = UnicodeScalar(Int(optopt))!
|
||||
if unknownOption == UnicodeScalar("i") || unknownOption == UnicodeScalar("t") {
|
||||
print("Option -\(unknownOption) requires an argument.")
|
||||
} else {
|
||||
print("Unknown option -\(unknownOption.escaped(asASCII: true)).")
|
||||
}
|
||||
printUsageAndExit(status: EXIT_FAILURE)
|
||||
default:
|
||||
printUsageAndExit(status: EXIT_FAILURE)
|
||||
}
|
||||
}
|
||||
|
||||
guard optind < argc else {
|
||||
print("No input file specified.")
|
||||
printUsageAndExit(status: EXIT_FAILURE)
|
||||
}
|
||||
|
||||
let inputPathBytes = CommandLine.unsafeArgv[Int(optind)]!
|
||||
let inputPath = String(cString:inputPathBytes)
|
||||
task.inputURL = URL(fileURLWithPath: inputPath)
|
||||
|
||||
return task
|
||||
}
|
||||
|
||||
func run(_ task: ExplodeTask) -> Int32 {
|
||||
let resourcesByType = read(task)
|
||||
process(task: task, resourcesByType: resourcesByType)
|
||||
return EXIT_SUCCESS
|
||||
}
|
||||
|
||||
func read(_ task: ExplodeTask) -> ResourcesByType {
|
||||
do {
|
||||
return try readResourceFork(task.inputURL!)
|
||||
} catch let error {
|
||||
print(error.shortDescription(withUnderlyingError: true))
|
||||
exit(EXIT_FAILURE)
|
||||
}
|
||||
}
|
||||
|
||||
func process(task: ExplodeTask, resourcesByType: ResourcesByType) {
|
||||
if task.dumpResources {
|
||||
do {
|
||||
try createOutputDirectory(task: task)
|
||||
} catch let error {
|
||||
print(error.shortDescription(withUnderlyingError: true))
|
||||
exit(EXIT_FAILURE)
|
||||
}
|
||||
}
|
||||
|
||||
let filteredResourcesByType = filter(resources: resourcesByType, task: task)
|
||||
for (_, resources) in filteredResourcesByType {
|
||||
for resource in resources {
|
||||
print(format(resource))
|
||||
|
||||
if task.printResources {
|
||||
print(format(resource.data))
|
||||
}
|
||||
|
||||
if task.dumpResources {
|
||||
dump(task: task, resource: resource)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum OutputDirectoryError: NestingSwresError {
|
||||
case directoryIsNotAFolder
|
||||
case directoryExists
|
||||
case couldntCreateDirectory(underlyingError: Error)
|
||||
|
||||
var underlyingError: Error? {
|
||||
switch self {
|
||||
case .couldntCreateDirectory(let underlyingError):
|
||||
return underlyingError
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .directoryIsNotAFolder:
|
||||
return "Output directory is not a folder."
|
||||
case .directoryExists:
|
||||
return "Output directory already exists. Use -f to overwrite existing files."
|
||||
case .couldntCreateDirectory:
|
||||
return "Couldn't create output directory."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createOutputDirectory(task: ExplodeTask) throws {
|
||||
let fileManager = FileManager.default
|
||||
let outputDirectoryPath = task.outputFolder.path
|
||||
|
||||
var isDirectory: ObjCBool = false
|
||||
if fileManager.fileExists(atPath: outputDirectoryPath, isDirectory: &isDirectory) {
|
||||
guard isDirectory.boolValue else {
|
||||
throw OutputDirectoryError.directoryIsNotAFolder
|
||||
}
|
||||
|
||||
guard task.overwriteExistingFiles else {
|
||||
throw OutputDirectoryError.directoryExists
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
try fileManager.createDirectory(at: task.outputFolder, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch let error {
|
||||
throw OutputDirectoryError.couldntCreateDirectory(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
func dump(task: ExplodeTask, resource: Resource) {
|
||||
let (folderURL, fileURL) = explodedLocation(task: task, resource: resource)
|
||||
|
||||
let fileManager = FileManager.default
|
||||
do {
|
||||
try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
|
||||
try resource.data.write(to: fileURL)
|
||||
} catch let error {
|
||||
print("Couldn't dump resource \(resource.type) \(resource.identifier).")
|
||||
print(error.shortDescription)
|
||||
}
|
||||
|
||||
if task.translatorFilter >= TranslatorFilter.onlyLikelyTranslators {
|
||||
let translatorManager = TranslatorManager.sharedInstance
|
||||
let translationResults = translatorManager.translate(resource, includeTranslators: task.translatorFilter)
|
||||
|
||||
for translationResult in translationResults {
|
||||
switch translationResult {
|
||||
case .translated(let translation):
|
||||
let outputURL = fileURL.appendingPathExtension(translation.suggestedFileExtension)
|
||||
let data = translation.data
|
||||
do {
|
||||
try data.write(to: outputURL)
|
||||
} catch let error {
|
||||
let resourceDescription = format(resource, short: true)
|
||||
print("Couldn't write translation for resource \(resourceDescription).")
|
||||
print(error.shortDescription(withUnderlyingError: true))
|
||||
}
|
||||
case .error(let error):
|
||||
let resourceDescription = format(resource, short: true)
|
||||
print("Failed to translate resource \(resourceDescription).")
|
||||
print(error.shortDescription(withUnderlyingError: true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func filter(resources: ResourcesByType, task: ExplodeTask) -> ResourcesByType {
|
||||
return resources.flatMap { (type: FourCharCode, resources: Array<Resource>) -> (FourCharCode, Array<Resource>)? in
|
||||
if let typeFilter = task.typeFilter, type != typeFilter {
|
||||
return nil
|
||||
}
|
||||
|
||||
let filteredResources = resources.flatMap { (resource: Resource) -> Resource? in
|
||||
if let identifierFilter = task.identifierFilter, resource.identifier != identifierFilter {
|
||||
return nil
|
||||
}
|
||||
return resource
|
||||
}
|
||||
|
||||
return (type, filteredResources)
|
||||
}
|
||||
}
|
||||
|
||||
func format(_ resource: Resource, short: Bool = false) -> String {
|
||||
if short {
|
||||
return "'\(resource.type.description)' \(resource.identifier)"
|
||||
}
|
||||
|
||||
var string = String(format: "'%@' %7d %8d bytes", resource.type.description, resource.identifier, resource.data.count)
|
||||
if let name = resource.stringName {
|
||||
string += " \"\(name)\""
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
func format(_ data: Data) -> String {
|
||||
let options = MacOSRomanConversionOptions(filterControlCharacters: true, filterFilesystemUnsafeCharacters: false, filterNonASCIICharacters: true, replacementMacOSRomanByte: MacOSRomanByteFullStop)
|
||||
|
||||
var lines = Array<String>()
|
||||
data.withUnsafeBytes { (unsafeBytes: UnsafePointer<UInt8>) in
|
||||
offsetAndLengthStride(from: 0, to: data.count, by: 16, { (offset: Int, length: Int) in
|
||||
let formattedOffset = format(asHex: offset, length: 8)
|
||||
|
||||
let lineBuffer = Buffer(pointer: unsafeBytes + offset, count: length)
|
||||
let formattedLine = format(line: lineBuffer, lineLength: 16)
|
||||
let asciiFormattedBytes = stringFromMacOSRomanBytes(lineBuffer, options: options)
|
||||
|
||||
let rowString = "\(formattedOffset): \(formattedLine) \(asciiFormattedBytes)"
|
||||
lines.append(rowString)
|
||||
})
|
||||
}
|
||||
|
||||
return lines.joined(separator: "\n")
|
||||
}
|
||||
|
||||
// 0-9, A-F
|
||||
let asciiHexCharacters: Array<CChar> = [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66]
|
||||
let asciiSpace: CChar = 0x20
|
||||
|
||||
func format(asHex number: Int, length: Int) -> String {
|
||||
assert(length >= 0)
|
||||
|
||||
var number = number
|
||||
let stringBufferCapacity = length + 1
|
||||
let stringBuffer = UnsafeMutablePointer<CChar>.allocate(capacity: stringBufferCapacity)
|
||||
defer {
|
||||
stringBuffer.deallocate(capacity: stringBufferCapacity)
|
||||
}
|
||||
|
||||
var stringBufferIterator = stringBuffer + length
|
||||
stringBufferIterator.pointee = 0
|
||||
stringBufferIterator -= 1
|
||||
|
||||
while stringBufferIterator >= stringBuffer {
|
||||
stringBufferIterator.pointee = asciiHexCharacters[number % 16]
|
||||
number = number / 16
|
||||
stringBufferIterator -= 1
|
||||
}
|
||||
|
||||
return String(cString: stringBuffer, encoding: String.Encoding.ascii)!
|
||||
}
|
||||
|
||||
func format(line lineBuffer: Buffer<UInt8>, lineLength: Int) -> String {
|
||||
assert(lineBuffer.count <= lineLength)
|
||||
|
||||
let lineBytes = lineBuffer.pointer
|
||||
let lineBytesCount = lineBuffer.count
|
||||
|
||||
let spacerCount = max(0, (lineLength - 1) / 2)
|
||||
let stringBufferSize = lineLength * 2 + spacerCount + 1
|
||||
let stringBuffer = UnsafeMutablePointer<CChar>.allocate(capacity: stringBufferSize)
|
||||
defer {
|
||||
stringBuffer.deallocate(capacity: stringBufferSize)
|
||||
}
|
||||
|
||||
var stringBufferIterator = stringBuffer
|
||||
|
||||
@inline(__always) func writeCChar(_ char: CChar) {
|
||||
stringBufferIterator.pointee = char
|
||||
stringBufferIterator += 1
|
||||
}
|
||||
|
||||
for byteIndex in 0..<lineLength {
|
||||
if byteIndex % 2 == 0 && byteIndex > 0 {
|
||||
writeCChar(asciiSpace)
|
||||
}
|
||||
|
||||
if byteIndex < lineBytesCount {
|
||||
let byte = lineBytes[byteIndex]
|
||||
writeCChar(asciiHexCharacters[Int(byte / 16)])
|
||||
writeCChar(asciiHexCharacters[Int(byte % 16)])
|
||||
} else {
|
||||
writeCChar(asciiSpace)
|
||||
writeCChar(asciiSpace)
|
||||
}
|
||||
}
|
||||
|
||||
writeCChar(0)
|
||||
|
||||
return String(cString: stringBuffer, encoding: String.Encoding.ascii)!
|
||||
}
|
||||
|
||||
func explodedLocation(task: ExplodeTask, resource: Resource) -> (URL, URL) {
|
||||
let outputFolder = task.outputFolder
|
||||
let typeFolder = outputFolder.appendingPathComponent(filesystemSafeString(resource.type.bytes))
|
||||
var filename = "\(resource.identifier)"
|
||||
if let name = resource.name {
|
||||
let sanitizedName = filesystemSafeString(name)
|
||||
filename += " \(sanitizedName)"
|
||||
}
|
||||
let url = typeFolder.appendingPathComponent(filename)
|
||||
return (typeFolder, url)
|
||||
}
|
||||
|
||||
func swresExplodeMain() -> Int32 {
|
||||
let task = taskForArguments()
|
||||
return run(task)
|
||||
}
|
1
SwresExplode/SwresExplode.xcconfig
Normal file
1
SwresExplode/SwresExplode.xcconfig
Normal file
@ -0,0 +1 @@
|
||||
PRODUCT_NAME = SwresExplode
|
8
SwresExplode/main.swift
Normal file
8
SwresExplode/main.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// main.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
import Darwin
|
||||
|
||||
exit(swresExplodeMain())
|
BIN
SwresFUSE.png
Normal file
BIN
SwresFUSE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 189 KiB |
113
SwresFUSE/FilesystemNode.swift
Normal file
113
SwresFUSE/FilesystemNode.swift
Normal file
@ -0,0 +1,113 @@
|
||||
//
|
||||
// FilesystemNode.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum FilesystemNode {
|
||||
case folder(name: StringAndCString, children: Dictionary<String, FilesystemNode>)
|
||||
case file(name: StringAndCString, data: Data)
|
||||
|
||||
var cStringName: ManagedUnsafeMutablePointer<Int8> {
|
||||
switch self {
|
||||
case .folder(let name, _):
|
||||
return name.cString
|
||||
case .file(let name, _):
|
||||
return name.cString
|
||||
}
|
||||
}
|
||||
|
||||
var name: String {
|
||||
switch self {
|
||||
case .folder(let name, _):
|
||||
return name.string
|
||||
case .file(let name, _):
|
||||
return name.string
|
||||
}
|
||||
}
|
||||
|
||||
init(name: String, data: Data) {
|
||||
self = .file(name: StringAndCString(name), data: data)
|
||||
}
|
||||
|
||||
init(name: String, children: Array<FilesystemNode>) {
|
||||
let nameAndChildTuples = children.map { (child: FilesystemNode) -> (String, FilesystemNode) in
|
||||
return (child.name, child)
|
||||
}
|
||||
self = .folder(name: StringAndCString(name), children: Dictionary(nameAndChildTuples))
|
||||
}
|
||||
|
||||
func nodeAtPath(_ path: UnsafePointer<Int8>) -> FilesystemNode? {
|
||||
guard let pathString = String(cString: path, encoding: String.Encoding.utf8) else {
|
||||
return nil
|
||||
}
|
||||
return nodeAtPath(pathString)
|
||||
}
|
||||
|
||||
func nodeAtPath(_ path: String) -> FilesystemNode? {
|
||||
let pathComponents = path.components(separatedBy: "/").filter { (pathComponent: String) -> Bool in
|
||||
pathComponent.characters.count > 0
|
||||
}
|
||||
|
||||
return _nodeAtPath(pathComponents[0 ..< pathComponents.endIndex])
|
||||
}
|
||||
|
||||
private func _nodeAtPath(_ pathComponents: ArraySlice<String>) -> FilesystemNode? {
|
||||
guard let nextComponent = pathComponents.first else {
|
||||
return self
|
||||
}
|
||||
|
||||
switch self {
|
||||
case .file:
|
||||
guard pathComponents.count == 1 && nextComponent == self.name else {
|
||||
return nil
|
||||
}
|
||||
return self
|
||||
case .folder(_, let children):
|
||||
guard let child = children[nextComponent] else {
|
||||
return nil
|
||||
}
|
||||
return child._nodeAtPath(pathComponents[1 ..< pathComponents.endIndex])
|
||||
}
|
||||
}
|
||||
|
||||
func isFolder() -> Bool {
|
||||
switch self {
|
||||
case .folder:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func stLinkCount() -> nlink_t {
|
||||
switch self {
|
||||
case .file:
|
||||
return 1
|
||||
case .folder(_, let children):
|
||||
let childFolders = children.filter { (_, child: FilesystemNode) in
|
||||
return child.isFolder()
|
||||
}
|
||||
return nlink_t(childFolders.count + 2)
|
||||
}
|
||||
}
|
||||
|
||||
func stMode() -> mode_t {
|
||||
switch self {
|
||||
case .file:
|
||||
return S_IFREG | 0o0444
|
||||
case .folder:
|
||||
return S_IFDIR | 0o0555
|
||||
}
|
||||
}
|
||||
|
||||
func stSize() -> off_t {
|
||||
switch self {
|
||||
case .file(_, let data):
|
||||
return off_t(data.count)
|
||||
case .folder:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
6
SwresFUSE/SwresFUSE.xcconfig
Normal file
6
SwresFUSE/SwresFUSE.xcconfig
Normal file
@ -0,0 +1,6 @@
|
||||
PRODUCT_NAME = SwresFUSE
|
||||
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) FUSE_USE_VERSION=26 _FILE_OFFSET_BITS=64
|
||||
|
||||
HEADER_SEARCH_PATHS = $(inherited) /usr/local/include/osxfuse
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) /usr/local/lib
|
324
SwresFUSE/SwresFuse.swift
Normal file
324
SwresFUSE/SwresFuse.swift
Normal file
@ -0,0 +1,324 @@
|
||||
//
|
||||
// SwresFuse.swift
|
||||
// SwresTools
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Fuse
|
||||
|
||||
struct FuseTask {
|
||||
var inputURL: URL?
|
||||
var includeTranslations: Bool = false
|
||||
var allowPossibleTranslations: Bool = false
|
||||
var fuseArgs: ManagedUnsafeMutablePointer<fuse_args>?
|
||||
}
|
||||
|
||||
struct CommandLineOption {
|
||||
let template: String
|
||||
let key: CommandLineKey
|
||||
}
|
||||
|
||||
enum CommandLineKey: Int32 {
|
||||
case fuse_opt_key_keep = -3
|
||||
case fuse_opt_key_nonopt = -2
|
||||
case fuse_opt_key_opt = -1
|
||||
case help = 1
|
||||
case includeTranslations
|
||||
case allowPossibleTranslations
|
||||
}
|
||||
|
||||
var rootNode: FilesystemNode?
|
||||
let currentDirectoryCString = ".".copyCString()
|
||||
let parentDirectoryCString = "..".copyCString()
|
||||
|
||||
func printUsageAndExit(status: Int32 = EXIT_SUCCESS) -> Never {
|
||||
let processName = ProcessInfo.processInfo.processName
|
||||
|
||||
print("Mount a resource fork with FUSE.")
|
||||
print("Usage: \(processName) [options] resourcefile mountpoint")
|
||||
print("Options:")
|
||||
print(" -h Show this help message")
|
||||
print(" -c Attempt to convert resources into more modern or portable formats.")
|
||||
print(" -C Also use best guess conversions.")
|
||||
|
||||
exit(status)
|
||||
}
|
||||
|
||||
func dieWithMessage(_ message: String) -> Never {
|
||||
print(message)
|
||||
exit(EXIT_FAILURE)
|
||||
}
|
||||
|
||||
func withFuseOptions(_ options: Array<CommandLineOption>, _ block: (UnsafePointer<fuse_opt>) -> Void) {
|
||||
var cStringPool = Array<ManagedUnsafeMutablePointer<Int8>>()
|
||||
|
||||
var fuseOptions = ContiguousArray<fuse_opt>()
|
||||
fuseOptions.reserveCapacity(options.count)
|
||||
|
||||
for option in options {
|
||||
let cString = option.template.copyCString()
|
||||
cStringPool.append(cString)
|
||||
|
||||
let fuseOption = fuse_opt(templ: UnsafePointer(cString.pointer), offset: UInt(UInt32(bitPattern: -1)), value: option.key.rawValue)
|
||||
fuseOptions.append(fuseOption)
|
||||
}
|
||||
|
||||
let nullOption = fuse_opt(templ: nil, offset: 0, value: 0)
|
||||
fuseOptions.append(nullOption)
|
||||
|
||||
fuseOptions.withUnsafeBufferPointer { (fuseOptionsBufferPointer: UnsafeBufferPointer<fuse_opt>) in
|
||||
guard let fuseOptionsPointer = fuseOptionsBufferPointer.baseAddress else {
|
||||
dieWithMessage("Error setting up option parsing.")
|
||||
}
|
||||
block(fuseOptionsPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func taskForArguments() -> FuseTask {
|
||||
var task = FuseTask()
|
||||
|
||||
let options = [
|
||||
CommandLineOption(template: "-h", key: CommandLineKey.help),
|
||||
CommandLineOption(template: "-c", key: CommandLineKey.includeTranslations),
|
||||
CommandLineOption(template: "-C", key: CommandLineKey.allowPossibleTranslations),
|
||||
CommandLineOption(template: "-d", key: CommandLineKey.fuse_opt_key_keep),
|
||||
]
|
||||
|
||||
let args = malloc(MemoryLayout<fuse_args>.size).assumingMemoryBound(to: fuse_args.self)
|
||||
args.pointee.argc = CommandLine.argc
|
||||
args.pointee.argv = CommandLine.unsafeArgv
|
||||
args.pointee.allocated = 0
|
||||
|
||||
withFuseOptions(options, { (fuseOptions: UnsafePointer<fuse_opt>) in
|
||||
let parseResult = fuse_opt_parse(args, &task, fuseOptions, { (context: UnsafeMutableRawPointer?, arg: UnsafePointer<Int8>?, key: Int32, args: UnsafeMutablePointer<fuse_args>?) -> Int32 in
|
||||
guard let taskRawPointer = UnsafeMutableRawPointer(context) else {
|
||||
dieWithMessage("Error parsing arguments. Received a NULL context pointer from FUSE.")
|
||||
}
|
||||
let taskPointer = taskRawPointer.bindMemory(to: FuseTask.self, capacity: 1)
|
||||
|
||||
guard let arg = arg else {
|
||||
dieWithMessage("Error parsing arguments. Received a NULL argument from FUSE.")
|
||||
}
|
||||
guard let option = String(cString: arg, encoding: String.Encoding.ascii) else {
|
||||
dieWithMessage("Error parsing arguments. Argument encoding unrecognized.")
|
||||
}
|
||||
|
||||
guard let key = CommandLineKey(rawValue: key) else {
|
||||
dieWithMessage("Unexpected key from FUSE.")
|
||||
}
|
||||
|
||||
switch key {
|
||||
case .fuse_opt_key_nonopt:
|
||||
if taskPointer.pointee.inputURL == nil {
|
||||
taskPointer.pointee.inputURL = URL(fileURLWithPath: option)
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
case .fuse_opt_key_opt:
|
||||
print("Unrecognized option \(option).")
|
||||
printUsageAndExit(status: EXIT_FAILURE)
|
||||
case .help:
|
||||
printUsageAndExit()
|
||||
case .includeTranslations:
|
||||
taskPointer.pointee.includeTranslations = true
|
||||
return 0
|
||||
case .allowPossibleTranslations:
|
||||
taskPointer.pointee.includeTranslations = true
|
||||
taskPointer.pointee.allowPossibleTranslations = true
|
||||
return 0
|
||||
default:
|
||||
dieWithMessage("Unexpected key from FUSE.")
|
||||
}
|
||||
return 1
|
||||
})
|
||||
|
||||
if parseResult != 0 {
|
||||
print("Failed to parse optinos.")
|
||||
exit(EXIT_FAILURE)
|
||||
}
|
||||
})
|
||||
|
||||
fuse_opt_add_arg(args, "-s")
|
||||
fuse_opt_add_arg(args, "-f")
|
||||
|
||||
task.fuseArgs = ManagedUnsafeMutablePointer(adoptPointer: args)
|
||||
return task
|
||||
}
|
||||
|
||||
func getAttr(path: UnsafePointer<Int8>?, stbuf: UnsafeMutablePointer<stat>?) -> Int32 {
|
||||
guard let rootNode = rootNode else {
|
||||
dieWithMessage("No filesystem root note was created.")
|
||||
}
|
||||
guard let path = path, let stbuf = stbuf else {
|
||||
dieWithMessage("Received null parameter from FUSE.")
|
||||
}
|
||||
|
||||
guard let node = rootNode.nodeAtPath(path) else {
|
||||
return -ENOENT
|
||||
}
|
||||
|
||||
stbuf.pointee.st_mode = node.stMode()
|
||||
stbuf.pointee.st_nlink = node.stLinkCount()
|
||||
stbuf.pointee.st_size = node.stSize()
|
||||
stbuf.pointee.st_uid = getuid()
|
||||
stbuf.pointee.st_gid = getgid()
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func readDir(path: UnsafePointer<Int8>?, buf: UnsafeMutableRawPointer?, filler: fuse_fill_dir_t?, offset: off_t, fi: UnsafeMutablePointer<fuse_file_info>?) -> Int32 {
|
||||
guard let rootNode = rootNode else {
|
||||
dieWithMessage("No filesystem root note was created.")
|
||||
}
|
||||
guard let path = path, let buf = buf, let filler = filler else {
|
||||
dieWithMessage("Received null parameter from FUSE.")
|
||||
}
|
||||
|
||||
guard let node = rootNode.nodeAtPath(path) else {
|
||||
return -ENOENT
|
||||
}
|
||||
|
||||
@inline(__always) func appendEntry(filename: ManagedUnsafeMutablePointer<Int8>) {
|
||||
guard filler(buf, filename.pointer, nil, 0) == 0 else {
|
||||
// TODO: Figure out how to correctly support large directories.
|
||||
dieWithMessage("readDir buffer is full.")
|
||||
}
|
||||
}
|
||||
|
||||
switch node {
|
||||
case .file:
|
||||
return -ENOENT
|
||||
case .folder(_, let children):
|
||||
appendEntry(filename: parentDirectoryCString)
|
||||
appendEntry(filename: currentDirectoryCString)
|
||||
for (_, child) in children {
|
||||
appendEntry(filename: child.cStringName)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func openFile(path: UnsafePointer<Int8>?, fi: UnsafeMutablePointer<fuse_file_info>?) -> Int32 {
|
||||
guard let rootNode = rootNode else {
|
||||
dieWithMessage("No filesystem root note was created.")
|
||||
}
|
||||
guard let path = path, let fi = fi else {
|
||||
dieWithMessage("Received null parameter from FUSE.")
|
||||
}
|
||||
|
||||
guard let _ = rootNode.nodeAtPath(path) else {
|
||||
return -ENOENT
|
||||
}
|
||||
|
||||
guard fi.pointee.flags & 3 == O_RDONLY else {
|
||||
return -EACCES
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func readFile(path: UnsafePointer<Int8>?, buf: UnsafeMutablePointer<Int8>?, size: size_t, offset: off_t, fi: UnsafeMutablePointer<fuse_file_info>?) -> Int32 {
|
||||
guard let rootNode = rootNode else {
|
||||
dieWithMessage("No filesystem root note was created.")
|
||||
}
|
||||
guard let path = path else {
|
||||
dieWithMessage("Received null parameter from FUSE.")
|
||||
}
|
||||
|
||||
guard let node = rootNode.nodeAtPath(path) else {
|
||||
return -ENOENT
|
||||
}
|
||||
|
||||
switch node {
|
||||
case .folder:
|
||||
return -ENOENT
|
||||
case .file(_, let data):
|
||||
let length = data.count
|
||||
let offset = Int(offset)
|
||||
guard length > offset else {
|
||||
return 0
|
||||
}
|
||||
let bytesCopied = min(length - offset, size)
|
||||
data.withUnsafeBytes { (dataBytes: UnsafePointer<Int8>) -> Void in
|
||||
memcpy(buf, dataBytes + offset, bytesCopied)
|
||||
}
|
||||
return Int32(bytesCopied)
|
||||
}
|
||||
}
|
||||
|
||||
func run(_ task: FuseTask) -> Int32 {
|
||||
guard let inputURL = task.inputURL else {
|
||||
dieWithMessage("Missing inputURL in task.")
|
||||
}
|
||||
|
||||
do {
|
||||
let resourcesByType = try readResourceFork(inputURL)
|
||||
rootNode = filesystemNode(resourcesByType, includeTranslations: task.includeTranslations)
|
||||
|
||||
var operations = fuse_operations()
|
||||
operations.getattr = getAttr
|
||||
operations.readdir = readDir
|
||||
operations.open = openFile
|
||||
operations.read = readFile
|
||||
|
||||
guard let args = task.fuseArgs?.pointer else {
|
||||
dieWithMessage("Failed to construct arguments to pass to FUSE.")
|
||||
}
|
||||
|
||||
let result = fuse_main_real(args.pointee.argc, args.pointee.argv, &operations, MemoryLayout.size(ofValue: operations), nil)
|
||||
print("hi")
|
||||
return result
|
||||
} catch {
|
||||
dieWithMessage(error.shortDescription(withUnderlyingError: true))
|
||||
}
|
||||
}
|
||||
|
||||
func filesystemNode(_ resourcesByType: ResourcesByType, includeTranslations: Bool) -> FilesystemNode {
|
||||
let folders = resourcesByType.map { (type: FourCharCode, resources: Array<Resource>) -> FilesystemNode in
|
||||
let folderName = filesystemSafeString(type.bytes)
|
||||
let children = resources.flatMap { (resource: Resource) -> Array<FilesystemNode> in
|
||||
return filesystemNodes(resource, includeTranslations: includeTranslations)
|
||||
}
|
||||
|
||||
return FilesystemNode(name: folderName, children: children)
|
||||
}
|
||||
|
||||
return FilesystemNode(name: "ROOT", children: folders)
|
||||
}
|
||||
|
||||
func filesystemNodes(_ resource: Resource, includeTranslations: Bool) -> Array<FilesystemNode> {
|
||||
var nodes = Array<FilesystemNode>()
|
||||
|
||||
var filename = "\(resource.identifier)"
|
||||
if let name = resource.name {
|
||||
let sanitizedName = filesystemSafeString(name)
|
||||
filename += " \(sanitizedName)"
|
||||
}
|
||||
nodes.append(FilesystemNode(name: filename, data: resource.data))
|
||||
|
||||
if (includeTranslations) {
|
||||
let translatorManager = TranslatorManager.sharedInstance
|
||||
let translationResults = translatorManager.translate(resource, includeTranslators: TranslatorFilter.likelyAndPossibleTranslators)
|
||||
|
||||
let translationNodes = translationResults.flatMap { (translationResult: TranslationResult) -> FilesystemNode? in
|
||||
switch translationResult {
|
||||
case .translated(let translation):
|
||||
let translatedFilename = filename + ".\(translation.suggestedFileExtension)"
|
||||
return FilesystemNode(name: translatedFilename, data: translation.data)
|
||||
case .error(let error):
|
||||
print(error.shortDescription(withUnderlyingError: true))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
nodes.append(contentsOf: translationNodes)
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
func swresFuseMain() -> Int32 {
|
||||
let task = taskForArguments()
|
||||
return run(task)
|
||||
}
|
8
SwresFUSE/main.swift
Normal file
8
SwresFUSE/main.swift
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// main.swift
|
||||
// SwresFUSE
|
||||
//
|
||||
|
||||
import Darwin
|
||||
|
||||
exit(swresFuseMain())
|
535
SwresTools.xcodeproj/project.pbxproj
Normal file
535
SwresTools.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,535 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
CA9567C41DC132620031E5F5 /* Everything */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = CA9567C51DC132620031E5F5 /* Build configuration list for PBXAggregateTarget "Everything" */;
|
||||
buildPhases = (
|
||||
);
|
||||
dependencies = (
|
||||
CA9567C91DC1326A0031E5F5 /* PBXTargetDependency */,
|
||||
CA9567CB1DC1326C0031E5F5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Everything;
|
||||
productName = Everything;
|
||||
};
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
CA2B20FF1DA57DAB00A14B92 /* TranslatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2B20FE1DA57DAB00A14B92 /* TranslatorManager.swift */; };
|
||||
CA4150EA1DAF4401005F689D /* SequenceExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E41DAF4401005F689D /* SequenceExtras.swift */; };
|
||||
CA4150EB1DAF4401005F689D /* DictionaryExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E51DAF4401005F689D /* DictionaryExtras.swift */; };
|
||||
CA4150EC1DAF4401005F689D /* ErrorExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E61DAF4401005F689D /* ErrorExtras.swift */; };
|
||||
CA4150ED1DAF4401005F689D /* PointerExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E71DAF4401005F689D /* PointerExtras.swift */; };
|
||||
CA4150EE1DAF4401005F689D /* StrideExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E81DAF4401005F689D /* StrideExtras.swift */; };
|
||||
CA4150EF1DAF4401005F689D /* StringExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E91DAF4401005F689D /* StringExtras.swift */; };
|
||||
CA4150F21DAF4407005F689D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150F01DAF4407005F689D /* main.swift */; };
|
||||
CA4150F31DAF4407005F689D /* SwresExplode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150F11DAF4407005F689D /* SwresExplode.swift */; };
|
||||
CA4150F61DAF440F005F689D /* PascalStringTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150F41DAF440F005F689D /* PascalStringTranslator.swift */; };
|
||||
CA4150F71DAF440F005F689D /* SndTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150F51DAF440F005F689D /* SndTranslator.swift */; };
|
||||
CA4EB2CE1DB8057100A775DF /* SequenceExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E41DAF4401005F689D /* SequenceExtras.swift */; };
|
||||
CA4EB2CF1DB8057100A775DF /* DictionaryExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E51DAF4401005F689D /* DictionaryExtras.swift */; };
|
||||
CA4EB2D01DB8057100A775DF /* ErrorExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E61DAF4401005F689D /* ErrorExtras.swift */; };
|
||||
CA4EB2D11DB8057100A775DF /* PointerExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E71DAF4401005F689D /* PointerExtras.swift */; };
|
||||
CA4EB2D21DB8057100A775DF /* StrideExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E81DAF4401005F689D /* StrideExtras.swift */; };
|
||||
CA4EB2D31DB8057100A775DF /* StringExtras.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150E91DAF4401005F689D /* StringExtras.swift */; };
|
||||
CA4EB2D41DB8057700A775DF /* FourCharCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007D01D8DBD1900B7D2BD /* FourCharCode.swift */; };
|
||||
CA4EB2D51DB8057700A775DF /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007D41D8DF9C400B7D2BD /* Resource.swift */; };
|
||||
CA4EB2D61DB8057700A775DF /* ResourceForkReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007CE1D8DBCAF00B7D2BD /* ResourceForkReader.swift */; };
|
||||
CA4EB2D71DB8057700A775DF /* SeekableReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007CC1D8DB31400B7D2BD /* SeekableReader.swift */; };
|
||||
CA4EB2D81DB8057700A775DF /* Writer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA572C501DB2058E00A2AF8F /* Writer.swift */; };
|
||||
CA4EB2D91DB8057700A775DF /* TranslatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2B20FE1DA57DAB00A14B92 /* TranslatorManager.swift */; };
|
||||
CA4EB2DA1DB8057700A775DF /* PascalStringTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150F41DAF440F005F689D /* PascalStringTranslator.swift */; };
|
||||
CA4EB2DB1DB8057700A775DF /* SndTranslator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4150F51DAF440F005F689D /* SndTranslator.swift */; };
|
||||
CA4EB2DC1DB8057700A775DF /* Translator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6136641DA4ADD0001F81DA /* Translator.swift */; };
|
||||
CA4EB2E11DB9ECCB00A775DF /* FilesystemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4EB2DF1DB9E44300A775DF /* FilesystemNode.swift */; };
|
||||
CA572C511DB2058E00A2AF8F /* Writer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA572C501DB2058E00A2AF8F /* Writer.swift */; };
|
||||
CA584C971DB491DF00E36C26 /* SwresFuse.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA584C961DB491DF00E36C26 /* SwresFuse.swift */; };
|
||||
CA5AA8EC1DB44814001866EB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA5AA8EB1DB44814001866EB /* main.swift */; };
|
||||
CA6136651DA4ADD0001F81DA /* Translator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6136641DA4ADD0001F81DA /* Translator.swift */; };
|
||||
CA9007CD1D8DB31400B7D2BD /* SeekableReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007CC1D8DB31400B7D2BD /* SeekableReader.swift */; };
|
||||
CA9007CF1D8DBCAF00B7D2BD /* ResourceForkReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007CE1D8DBCAF00B7D2BD /* ResourceForkReader.swift */; };
|
||||
CA9007D11D8DBD1900B7D2BD /* FourCharCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007D01D8DBD1900B7D2BD /* FourCharCode.swift */; };
|
||||
CA9007D51D8DF9C400B7D2BD /* Resource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA9007D41D8DF9C400B7D2BD /* Resource.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
CA9567C81DC1326A0031E5F5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = CA9007BA1D8DAFB500B7D2BD /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = CA9007C11D8DAFB500B7D2BD;
|
||||
remoteInfo = SwresExplode;
|
||||
};
|
||||
CA9567CA1DC1326C0031E5F5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = CA9007BA1D8DAFB500B7D2BD /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = CA5AA8E81DB44814001866EB;
|
||||
remoteInfo = SwresFUSE;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
CA5AA8E71DB44814001866EB /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
CA9007C01D8DAFB500B7D2BD /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
CA2B20FE1DA57DAB00A14B92 /* TranslatorManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TranslatorManager.swift; path = Translators/TranslatorManager.swift; sourceTree = "<group>"; };
|
||||
CA4150E41DAF4401005F689D /* SequenceExtras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SequenceExtras.swift; path = Extras/SequenceExtras.swift; sourceTree = "<group>"; };
|
||||
CA4150E51DAF4401005F689D /* DictionaryExtras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DictionaryExtras.swift; path = Extras/DictionaryExtras.swift; sourceTree = "<group>"; };
|
||||
CA4150E61DAF4401005F689D /* ErrorExtras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ErrorExtras.swift; path = Extras/ErrorExtras.swift; sourceTree = "<group>"; };
|
||||
CA4150E71DAF4401005F689D /* PointerExtras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PointerExtras.swift; path = Extras/PointerExtras.swift; sourceTree = "<group>"; };
|
||||
CA4150E81DAF4401005F689D /* StrideExtras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StrideExtras.swift; path = Extras/StrideExtras.swift; sourceTree = "<group>"; };
|
||||
CA4150E91DAF4401005F689D /* StringExtras.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringExtras.swift; path = Extras/StringExtras.swift; sourceTree = "<group>"; };
|
||||
CA4150F01DAF4407005F689D /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = SwresExplode/main.swift; sourceTree = "<group>"; };
|
||||
CA4150F11DAF4407005F689D /* SwresExplode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwresExplode.swift; path = SwresExplode/SwresExplode.swift; sourceTree = "<group>"; };
|
||||
CA4150F41DAF440F005F689D /* PascalStringTranslator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PascalStringTranslator.swift; path = Translators/PascalStringTranslator.swift; sourceTree = "<group>"; };
|
||||
CA4150F51DAF440F005F689D /* SndTranslator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SndTranslator.swift; path = Translators/SndTranslator.swift; sourceTree = "<group>"; };
|
||||
CA4EB2DF1DB9E44300A775DF /* FilesystemNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilesystemNode.swift; sourceTree = "<group>"; };
|
||||
CA572C501DB2058E00A2AF8F /* Writer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Writer.swift; sourceTree = "<group>"; };
|
||||
CA584C8C1DB47C9300E36C26 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = Modules/FUSE/module.modulemap; sourceTree = "<group>"; };
|
||||
CA584C8F1DB4894500E36C26 /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Configurations/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
CA584C901DB4894500E36C26 /* Project.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Project.xcconfig; path = Configurations/Project.xcconfig; sourceTree = "<group>"; };
|
||||
CA584C911DB4894500E36C26 /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Configurations/Release.xcconfig; sourceTree = "<group>"; };
|
||||
CA584C941DB4897800E36C26 /* SwresExplode.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = SwresExplode.xcconfig; path = SwresExplode/SwresExplode.xcconfig; sourceTree = "<group>"; };
|
||||
CA584C951DB4897F00E36C26 /* SwresFUSE.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SwresFUSE.xcconfig; sourceTree = "<group>"; };
|
||||
CA584C961DB491DF00E36C26 /* SwresFuse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwresFuse.swift; sourceTree = "<group>"; };
|
||||
CA5AA8E91DB44814001866EB /* SwresFUSE */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SwresFUSE; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CA5AA8EB1DB44814001866EB /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||
CA6136641DA4ADD0001F81DA /* Translator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Translator.swift; path = Translators/Translator.swift; sourceTree = "<group>"; };
|
||||
CA9007C21D8DAFB500B7D2BD /* SwresExplode */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SwresExplode; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CA9007CC1D8DB31400B7D2BD /* SeekableReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeekableReader.swift; sourceTree = "<group>"; };
|
||||
CA9007CE1D8DBCAF00B7D2BD /* ResourceForkReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResourceForkReader.swift; sourceTree = "<group>"; };
|
||||
CA9007D01D8DBD1900B7D2BD /* FourCharCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FourCharCode.swift; sourceTree = "<group>"; };
|
||||
CA9007D41D8DF9C400B7D2BD /* Resource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Resource.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
CA5AA8E61DB44814001866EB /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
CA9007BF1D8DAFB500B7D2BD /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
CA4150E31DAF439C005F689D /* SwresExpolode */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA4150F01DAF4407005F689D /* main.swift */,
|
||||
CA4150F11DAF4407005F689D /* SwresExplode.swift */,
|
||||
CA584C941DB4897800E36C26 /* SwresExplode.xcconfig */,
|
||||
);
|
||||
name = SwresExpolode;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA584C8D1DB47C9F00E36C26 /* Modules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA5AA8F01DB44E40001866EB /* FUSE */,
|
||||
);
|
||||
name = Modules;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA584C8E1DB4893300E36C26 /* Configurations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA584C8F1DB4894500E36C26 /* Debug.xcconfig */,
|
||||
CA584C901DB4894500E36C26 /* Project.xcconfig */,
|
||||
CA584C911DB4894500E36C26 /* Release.xcconfig */,
|
||||
);
|
||||
name = Configurations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA5AA8EA1DB44814001866EB /* SwresFUSE */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA5AA8EB1DB44814001866EB /* main.swift */,
|
||||
CA4EB2DF1DB9E44300A775DF /* FilesystemNode.swift */,
|
||||
CA584C961DB491DF00E36C26 /* SwresFuse.swift */,
|
||||
CA584C951DB4897F00E36C26 /* SwresFUSE.xcconfig */,
|
||||
);
|
||||
path = SwresFUSE;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA5AA8F01DB44E40001866EB /* FUSE */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA584C8C1DB47C9300E36C26 /* module.modulemap */,
|
||||
);
|
||||
name = FUSE;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA6136601DA49D48001F81DA /* Extras */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA4150E51DAF4401005F689D /* DictionaryExtras.swift */,
|
||||
CA4150E61DAF4401005F689D /* ErrorExtras.swift */,
|
||||
CA4150E71DAF4401005F689D /* PointerExtras.swift */,
|
||||
CA4150E41DAF4401005F689D /* SequenceExtras.swift */,
|
||||
CA4150E81DAF4401005F689D /* StrideExtras.swift */,
|
||||
CA4150E91DAF4401005F689D /* StringExtras.swift */,
|
||||
);
|
||||
name = Extras;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA6136611DA4ADA2001F81DA /* Translators */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA4150F41DAF440F005F689D /* PascalStringTranslator.swift */,
|
||||
CA4150F51DAF440F005F689D /* SndTranslator.swift */,
|
||||
CA6136641DA4ADD0001F81DA /* Translator.swift */,
|
||||
CA2B20FE1DA57DAB00A14B92 /* TranslatorManager.swift */,
|
||||
);
|
||||
name = Translators;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA9007B91D8DAFB500B7D2BD = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA6136601DA49D48001F81DA /* Extras */,
|
||||
CA9007C41D8DAFB500B7D2BD /* SwresTools */,
|
||||
CA6136611DA4ADA2001F81DA /* Translators */,
|
||||
CA4150E31DAF439C005F689D /* SwresExpolode */,
|
||||
CA5AA8EA1DB44814001866EB /* SwresFUSE */,
|
||||
CA584C8D1DB47C9F00E36C26 /* Modules */,
|
||||
CA584C8E1DB4893300E36C26 /* Configurations */,
|
||||
CA9007C31D8DAFB500B7D2BD /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA9007C31D8DAFB500B7D2BD /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA9007C21D8DAFB500B7D2BD /* SwresExplode */,
|
||||
CA5AA8E91DB44814001866EB /* SwresFUSE */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CA9007C41D8DAFB500B7D2BD /* SwresTools */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CA9007D01D8DBD1900B7D2BD /* FourCharCode.swift */,
|
||||
CA9007D41D8DF9C400B7D2BD /* Resource.swift */,
|
||||
CA9007CE1D8DBCAF00B7D2BD /* ResourceForkReader.swift */,
|
||||
CA9007CC1D8DB31400B7D2BD /* SeekableReader.swift */,
|
||||
CA572C501DB2058E00A2AF8F /* Writer.swift */,
|
||||
);
|
||||
path = SwresTools;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
CA5AA8E81DB44814001866EB /* SwresFUSE */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = CA5AA8EF1DB44814001866EB /* Build configuration list for PBXNativeTarget "SwresFUSE" */;
|
||||
buildPhases = (
|
||||
CA5AA8E51DB44814001866EB /* Sources */,
|
||||
CA5AA8E61DB44814001866EB /* Frameworks */,
|
||||
CA5AA8E71DB44814001866EB /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = SwresFUSE;
|
||||
productName = SwresFUSE;
|
||||
productReference = CA5AA8E91DB44814001866EB /* SwresFUSE */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
CA9007C11D8DAFB500B7D2BD /* SwresExplode */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = CA9007C91D8DAFB500B7D2BD /* Build configuration list for PBXNativeTarget "SwresExplode" */;
|
||||
buildPhases = (
|
||||
CA9007BE1D8DAFB500B7D2BD /* Sources */,
|
||||
CA9007BF1D8DAFB500B7D2BD /* Frameworks */,
|
||||
CA9007C01D8DAFB500B7D2BD /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = SwresExplode;
|
||||
productName = SwresTools;
|
||||
productReference = CA9007C21D8DAFB500B7D2BD /* SwresExplode */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
CA9007BA1D8DAFB500B7D2BD /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0810;
|
||||
LastUpgradeCheck = 0810;
|
||||
ORGANIZATIONNAME = "Paul Knight";
|
||||
TargetAttributes = {
|
||||