Skip to content

Instantly share code, notes, and snippets.

@steipete
Last active March 21, 2017 16:00
Show Gist options
  • Save steipete/b22babbf3014e29c19f0 to your computer and use it in GitHub Desktop.
Save steipete/b22babbf3014e29c19f0 to your computer and use it in GitHub Desktop.
Haven't done much with dispatch_io yet so I'd appreciate a few more eyeballs on this. Am I closing things correctly in all error conditions? Are there other knobs I could change to make things even faster? (I know I've been lazy on the NSError's)
static NSData *PSPDFCalculateSHA256FromFileURL(NSURL *fileURL, CC_LONG dataLength, NSError **error) {
NSCParameterAssert(fileURL);
dispatch_queue_t shaQueue = dispatch_queue_create("com.pspdfkit.sha256-queue", DISPATCH_QUEUE_SERIAL);
__block dispatch_io_t readChannel;
void (^processIntError)(int intError) = ^(int intError) {
if (intError != 0) {
PSPDFLogWarning(@"Stream error: %d", intError);
if (error) *error = [NSError errorWithDomain:@"SHA256Error" code:100 userInfo:@{NSLocalizedDescriptionKey: @"failed to open file for calculating SHA256."}];
}
dispatch_async(shaQueue, ^{
dispatch_io_close(readChannel, DISPATCH_IO_STOP);
});
};
// Open the IO channel
readChannel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, fileURL.path.UTF8String, O_RDONLY, 0, shaQueue, processIntError);
if (!readChannel) {
if (error) *error = [NSError errorWithDomain:@"SHA256Error" code:100 userInfo:@{NSLocalizedDescriptionKey: @"failed to open file for calculating SHA256."}];
return nil;
}
// Prepare SHA hash
__block CC_SHA256_CTX ctx;
CC_SHA256_Init(&ctx);
// Start read and block until we are done.
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block int lastIntError = 0;
dispatch_io_set_high_water(readChannel, 512*1024);
dispatch_io_read(readChannel, 0, SIZE_MAX, shaQueue, ^(bool done, dispatch_data_t data, int intError) {
if (intError != 0) {
lastIntError = intError;
processIntError(intError);
dispatch_semaphore_signal(semaphore);
return;
}
dispatch_data_apply(data, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
CC_SHA256_Update(&ctx, (const void *)buffer, (CC_LONG)size);
return true;
});
if (done) {
dispatch_semaphore_signal(semaphore);
}
});
// Wait for the signal, then wake up.
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_io_close(readChannel, DISPATCH_IO_STOP);
// Finalize SHA256 calculation unless there's an error.
if (lastIntError == 0) {
unsigned char sha256[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(sha256, &ctx);
NSData *shaData = [NSData dataWithBytes:sha256 length:CC_SHA256_DIGEST_LENGTH];
return shaData;
}
return nil;
}
@steipete
Copy link
Author

@Vyazovoy I fixed the error handling part (note: also I'm not actually shipping that code, ended up with a simpler/faster way)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment