Skip to content

Instantly share code, notes, and snippets.

@geoffgarside
Created December 12, 2010 12:51
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geoffgarside/738017 to your computer and use it in GitHub Desktop.
Save geoffgarside/738017 to your computer and use it in GitHub Desktop.
NSOutputStream subclass which updates a SHA1 checksum for all data written
//
// GGChecksummingOutputStream.h
//
// Created by Geoff Garside on 12/12/2010.
// Copyright 2010 Geoff Garside. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
enum { // error codes
GGChecksummingOutputStreamErrorChecksumFinalized
};
@interface GGChecksummingOutputStream : NSOutputStream {
CC_SHA1_CTX ctx;
unsigned char digest[CC_SHA1_DIGEST_LENGTH];
}
- (id)initToMemory;
- (id)initToBuffer:(uint8_t *)buffer capacity:(NSUInteger)capacity;
- (id)initToFileAtPath:(NSString *)path append:(BOOL)shouldAppend;
- (id)initWithURL:(NSURL *)url append:(BOOL)shouldAppend;
- (BOOL)hasSpaceAvailable;
- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length;
- (NSInteger)writeChecksum;
- (NSData *)checksumData;
@end
//
// GGChecksummingOutputStream.m
//
// Created by Geoff Garside on 12/12/2010.
// Copyright 2010 Geoff Garside. All rights reserved.
//
#import "GGChecksummingOutputStream.h"
@implementation GGChecksummingOutputStream
- (id)initToMemory {
if ( self = [super initToMemory] )
CC_SHA1_Init(&ctx);
return self;
}
- (id)initToBuffer:(uint8_t *)buffer capacity:(NSUInteger)capacity {
if ( self = [super initToBuffer:buffer capacity:capacity] )
CC_SHA1_Init(&ctx);
return self;
}
- (id)initToFileAtPath:(NSString *)path append:(BOOL)shouldAppend {
if ( self = [super initToFileAtPath:path append:shouldAppend] )
CC_SHA1_Init(&ctx);
return self;
}
- (id)initWithURL:(NSURL *)url append:(BOOL)shouldAppend {
if ( self = [super initWithURL:url append:shouldAppend] )
CC_SHA1_Init(&ctx);
return self;
}
- (BOOL)hasSpaceAvailable {
if ( digest )
return NO;
return [super hasSpaceAvailable];
}
- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length {
if ( digest ) return -1;
CC_SHA1_Update(&ctx, buffer, length);
return [super write:buffer maxLength:length];
}
- (NSError *)streamError {
if ( !digest )
return [super streamError];
NSError *error = [NSError errorWithDomain:@"com.github.gist.geoffgarside"
code:GGChecksummingOutputStreamErrorChecksumFinalized
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedString(@"Checksum digest has already been calculated",
@"GGChecksummingOutputStreamErrorChecksumFinalized"),
NSLocalizedDescriptionKey, nil]];
return error;
}
- (NSData *)checksumData {
if ( !digest )
CC_SHA1_Final(digest, &ctx);
return [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
}
- (NSInteger)writeChecksum {
if ( !digest )
CC_SHA1_Final(digest, &ctx);
return [super write:digest maxLength:CC_SHA1_DIGEST_LENGTH];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment