Created
November 17, 2015 13:06
-
-
Save rnapier/451fcac4a3323b7c37b1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
let bufferSize = 1024*1024 | |
enum Error: ErrorType { | |
case UnknownArgument(String) | |
case MissingValue(String) | |
case MissingPassword | |
case ShortWrite | |
case ReadError(NSError?) | |
} | |
func printUsage() { | |
print("Usage") | |
} | |
struct Config { | |
var encrypt = true | |
var password = "" | |
var input = NSInputStream(fileAtPath: "/dev/stdin")! | |
var output = NSOutputStream(toFileAtPath: "/dev/stdout", append: true)! | |
var rest = [String]() | |
} | |
func parseArgsOrExit() -> Config { | |
do { | |
return try parseArgs() | |
} | |
catch Error.UnknownArgument(let arg) { | |
print("Unknown Argument: \(arg)") | |
} | |
catch Error.MissingValue(let arg) { | |
print("Argument \(arg) requires a value") | |
} | |
catch { | |
print("Unknown Error: \(error)") | |
} | |
printUsage() | |
exit(1) | |
} | |
func parseArgs() throws -> Config { | |
return try parseArgs(Process.arguments.dropFirst()) | |
} | |
func parseArgs<Seq: SequenceType where Seq.Generator.Element == String>(args: Seq) throws -> Config { | |
var config = Config() | |
var argGen = args.generate() | |
while let arg = argGen.next() { | |
guard arg.hasPrefix("-") else { | |
config.rest.append(arg) | |
break | |
} | |
switch arg { | |
case "-h", "--help": | |
printUsage() | |
exit(0) | |
case "-e", "--encrypt": | |
config.encrypt = true | |
case "-d", "--decrypt": | |
config.encrypt = false | |
case "-p", "--password": | |
guard let password = argGen.next() else { throw Error.MissingValue(arg) } | |
config.password = password | |
case "--": | |
break | |
default: | |
throw Error.UnknownArgument(arg) | |
} | |
} | |
config.rest += GeneratorSequence(argGen) | |
return config | |
} | |
func validateConfig(config: Config) throws { | |
guard config.password != "" else { | |
throw Error.MissingPassword | |
} | |
} | |
func validateConfigOrExit(config: Config) { | |
do { | |
try validateConfig(config) | |
return | |
} | |
catch Error.MissingPassword { | |
print("Password is required") | |
} | |
catch { | |
print("Unknown Error: \(error)") | |
} | |
exit(1) | |
} | |
let config = parseArgsOrExit() | |
validateConfigOrExit(config) | |
config.input.open() | |
config.output.open() | |
var buffer = [UInt8](count: bufferSize, repeatedValue: 0) | |
let cryptor: RNCryptorType = config.encrypt ? | |
RNCryptor.Encryptor(password: config.password) : RNCryptor.Encryptor(password: config.password) | |
var length = 0 | |
do { | |
var inLength = 0 | |
while true { | |
let inLength = config.input.read(&buffer, maxLength: buffer.count) | |
guard inLength >= 0 else { | |
throw Error.ReadError(config.input.streamError) | |
} | |
guard inLength > 0 else { | |
break | |
} | |
let inputData = NSData(bytesNoCopy: &buffer, length: inLength) | |
let result = try cryptor.updateWithData(inputData) | |
let outLength = config.output.write(UnsafePointer(result.bytes), maxLength: result.length) | |
guard inLength != outLength else { throw Error.ShortWrite } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment