/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 * Jonathan Schleifer <js@webkeks.org> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFApplication.h" #import "OFArray.h" #import "OFFile.h" #import "OFMD5Hash.h" #import "OFRIPEMD160Hash.h" #import "OFSHA1Hash.h" #import "OFSHA224Hash.h" #import "OFSHA256Hash.h" #import "OFSHA384Hash.h" #import "OFSHA512Hash.h" #import "OFStdIOStream.h" #import "OFOpenItemFailedException.h" #import "OFReadFailedException.h" @interface OFHash: OFObject @end OF_APPLICATION_DELEGATE(OFHash) static void help(void) { [of_stderr writeFormat: @"Usage: %@ [md5|rmd160|sha1|sha224|sha256|sha384|sha512] " @"file1 [file2 ...]\n", [OFApplication programName]]; [OFApplication terminateWithStatus: 1]; } static id <OFHash> hashForName(OFString *name) { if ([name isEqual: @"md5"]) return [OFMD5Hash hash]; else if ([name isEqual: @"rmd160"] || [name isEqual: @"ripemd160"]) return [OFRIPEMD160Hash hash]; else if ([name isEqual: @"sha1"]) return [OFSHA1Hash hash]; else if ([name isEqual: @"sha224"]) return [OFSHA224Hash hash]; else if ([name isEqual: @"sha256"]) return [OFSHA256Hash hash]; else if ([name isEqual: @"sha384"]) return [OFSHA384Hash hash]; else if ([name isEqual: @"sha512"]) return [OFSHA512Hash hash]; return nil; } @implementation OFHash - (void)applicationDidFinishLaunching { OFArray OF_GENERIC(OFString*) *arguments = [OFApplication arguments]; id <OFHash> hash; OFEnumerator *enumerator; OFString *path; int exitStatus = 0; if ([arguments count] < 2) help(); if ((hash = hashForName([arguments firstObject])) == nil) help(); enumerator = [[arguments objectsInRange: of_range(1, [arguments count] - 1)] objectEnumerator]; while ((path = [enumerator nextObject]) != nil) { void *pool = objc_autoreleasePoolPush(); OFStream *file; const uint8_t *digest; size_t i, digestSize; if ([path isEqual: @"-"]) file = of_stdin; else { @try { file = [OFFile fileWithPath: path mode: @"rb"]; } @catch (OFOpenItemFailedException *e) { [of_stderr writeFormat: @"Failed to open file %@: %s\n", [e path], strerror([e errNo])]; exitStatus = 1; goto outer_loop_end; } } [hash reset]; while (![file isAtEndOfStream]) { uint8_t buffer[1024]; size_t length; @try { length = [file readIntoBuffer: buffer length: 1024]; } @catch (OFReadFailedException *e) { [of_stderr writeFormat: @"Failed to read %@: %s\n", path, strerror([e errNo])]; exitStatus = 1; goto outer_loop_end; } [hash updateWithBuffer: buffer length: length]; } [file close]; digest = [hash digest]; digestSize = [[hash class] digestSize]; for (i = 0; i < digestSize; i++) [of_stdout writeFormat: @"%02x", digest[i]]; [of_stdout writeFormat: @" %@\n", path]; outer_loop_end: objc_autoreleasePoolPop(pool); } [OFApplication terminateWithStatus: exitStatus]; } @end