From 9c45b4185ba615e58708c975571dc02da8b03483 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 22 Sep 2008 23:53:22 -0700 Subject: [PATCH] added writing unpacked objects to disk, sha calculations, sha packing and unpacking --- Git.h | 8 +++- Git.m | 94 +++++++++++++++++++++++++++++++++++++++++++++- GitServerHandler.h | 1 + GitServerHandler.m | 14 ++++++- 4 files changed, 112 insertions(+), 5 deletions(-) diff --git a/Git.h b/Git.h index 520986f..aa1108e 100644 --- a/Git.h +++ b/Git.h @@ -19,9 +19,13 @@ - (BOOL) ensureGitPath; - (void) initGitRepo; -- (void) writeObject:(NSData *)objectData withType:(int)type withSize:(int)size; +- (NSString *) writeObject:(NSData *)objectData withType:(NSString *)type withSize:(int)size; - (NSMutableArray *) getCommitsFromSha:(NSString *)shaValue withLimit:(int)commitSize; - (NSString *) getLooseObjectPathBySha:(NSString *)shaValue; -@end ++ (int) isAlpha:(unsigned char)n ; ++ (int) gitUnpackHex:(const unsigned char *)rawsha fillSha:(char *)sha1; ++ (int) gitPackHex:(const char *)sha1 fillRawSha:(unsigned char *)rawsha; + +@end \ No newline at end of file diff --git a/Git.m b/Git.m index 005eb51..7d88cfa 100644 --- a/Git.m +++ b/Git.m @@ -8,6 +8,8 @@ #import "GitCommit.h" #import "GitServerHandler.h" +#include + @implementation Git @synthesize gitDirectory; @@ -55,12 +57,33 @@ - (void) initGitRepo { [fm createDirectoryAtPath:[gitDirectory stringByAppendingPathComponent:@"info"] attributes:nil]; } -- (void) writeObject:(NSData *)objectData withType:(int)type withSize:(int)size +- (NSString *) writeObject:(NSData *)objectData withType:(NSString *)type withSize:(int)size { NSLog(@"WRITE OBJECT"); + NSMutableData *object; + NSString *header, *path, *shaStr; + unsigned char rawsha[20]; + char sha1[41]; + + header = [NSString stringWithFormat:@"%@ %d", type, size]; + NSLog(@"header: %@", header); + + const char *headerBytes = [header cStringUsingEncoding:NSASCIIStringEncoding]; + + object = [NSMutableData dataWithBytes:headerBytes length:([header length] + 1)]; + [object appendData:objectData]; + + CC_SHA1([object bytes], [object length], rawsha); + [Git gitUnpackHex:rawsha fillSha:sha1]; + NSLog(@"SHAR: %s", sha1); + + // write object to file + shaStr = [NSString stringWithCString:sha1 encoding:NSASCIIStringEncoding]; + path = [self getLooseObjectPathBySha:shaStr]; + [object writeToFile:path atomically:YES]; + return shaStr; } - - (BOOL) openRepo:(NSString *)dirPath { gitDirectory = dirPath; @@ -99,8 +122,75 @@ - (NSString *) getLooseObjectPathBySha: (NSString *)shaValue NSString *looseSubDir = [shaValue substringWithRange:NSMakeRange(0, 2)]; NSString *looseFileName = [shaValue substringWithRange:NSMakeRange(2, 38)]; + NSString *dir = [NSString stringWithFormat: @"%@/objects/%@", gitDirectory, looseSubDir]; + + BOOL isDir; + NSFileManager *fm = [NSFileManager defaultManager]; + if (!([fm fileExistsAtPath:dir isDirectory:&isDir] && isDir)) { + [fm createDirectoryAtPath:dir attributes:nil]; + } + return [NSString stringWithFormat: @"%@/objects/%@/%@", \ gitDirectory, looseSubDir, looseFileName]; } + +/* + * returns 1 if the char is alphanumeric, 0 if not + */ ++ (int) isAlpha:(unsigned char)n +{ + if(n <= 102 && n >= 97) { + return 1; + } + return 0; +} + +/* + * fills a 40-char string with a readable hex version of 20-char sha binary + */ ++ (int) gitUnpackHex:(const unsigned char *)rawsha fillSha:(char *)sha1 +{ + static const char hex[] = "0123456789abcdef"; + int i; + + for (i = 0; i < 20; i++) { + unsigned char n = rawsha[i]; + sha1[i * 2] = hex[((n >> 4) & 15)]; + n <<= 4; + sha1[(i * 2) + 1] = hex[((n >> 4) & 15)]; + } + sha1[40] = 0; + + return 1; +} + +/* + * fills 20-char sha from 40-char hex version + */ ++ (int) gitPackHex:(const char *)sha1 fillRawSha:(unsigned char *)rawsha +{ + unsigned char byte = 0; + int i, j = 0; + + for (i = 1; i <= 40; i++) { + unsigned char n = sha1[i - 1]; + + if([Git isAlpha:n]) { + byte |= ((n & 15) + 9) & 15; + } else { + byte |= (n & 15); + } + if(i & 1) { + byte <<= 4; + } else { + rawsha[j] = (byte & 0xff); + j++; + byte = 0; + } + } + return 1; +} + @end + diff --git a/GitServerHandler.h b/GitServerHandler.h index f85ad4a..b8516d8 100644 --- a/GitServerHandler.h +++ b/GitServerHandler.h @@ -33,6 +33,7 @@ - (void) readPack; - (void) writeRefs; - (NSData *) readData:(int)size; +- (NSString *) typeString:(int)type; - (int) readPackHeader; - (void) unpackObject; diff --git a/GitServerHandler.m b/GitServerHandler.m index 6621078..5e935c1 100644 --- a/GitServerHandler.m +++ b/GitServerHandler.m @@ -171,7 +171,7 @@ - (void) unpackObject { if((type == OBJ_COMMIT) || (type == OBJ_TREE) || (type == OBJ_BLOB) || (type == OBJ_TAG)) { NSData *objectData; objectData = [self readData:size]; - [gitRepo writeObject:objectData withType:type withSize:size]; + [gitRepo writeObject:objectData withType:[self typeString:type] withSize:size]; // TODO : check saved delta objects } else if ((type == OBJ_REF_DELTA) || (type == OBJ_OFS_DELTA)) { NSLog(@"NO SUPPORT FOR DELTAS YET"); @@ -180,6 +180,18 @@ - (void) unpackObject { } } +- (NSString *) typeString:(int)type { + if (type == OBJ_COMMIT) + return @"commit"; + if (type == OBJ_TREE) + return @"tree"; + if (type == OBJ_BLOB) + return @"blob"; + if (type == OBJ_TAG) + return @"tag"; + return @""; +} + - (NSData *) readData:(int)size { // read in the data NSMutableData *decompressed = [NSMutableData dataWithLength: size];