Skip to content

Instantly share code, notes, and snippets.

@rnapier
Created November 17, 2015 13:06
Show Gist options
  • Save rnapier/451fcac4a3323b7c37b1 to your computer and use it in GitHub Desktop.
Save rnapier/451fcac4a3323b7c37b1 to your computer and use it in GitHub Desktop.
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