This tries to determine whether a file is binary or not, i.e. whether it can be displayed in a sensible way. PBGitTree is extended with the method isBinary, which first checks the output of "git check-attr binary <file>" to see if the user set/unset the binary attribute manually. Then it checks for common binary file-extensions. If this method can't determine whether the file is binary, and the file is < 50MB, its content is loaded and Unix "file" is run on the first 100 bytes of the file to make a decision.
Signed-off-by: Johannes Gilger <[email protected]> --- OK, third try and quite a rewrite. Now things happen in this order: 1. git check-attr binary <file> is checked and common filename extensions if this doesn't yield a result then 2. <file> is checked for execessive size (> ~50MB) if it's smaller than that 3. <file> content is loaded and the first 100 bytes go to "file" This might seem quite complicated, but so far I couldn't think of a better way to do it. I know some folks will cry because they'll have 51MB files in use, but at least our program remains usable and doesn't just stall because you clicked the wrong file. (Which QuickLook does btw ;) Comments? ;) PBGitTree.m | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 55 insertions(+), 5 deletions(-) diff --git a/PBGitTree.m b/PBGitTree.m index 51fadd2..6abf38a 100644 --- a/PBGitTree.m +++ b/PBGitTree.m @@ -63,24 +63,74 @@ - (BOOL) isLocallyCached return NO; } +- (BOOL)isBinary:(NSString *)fileHeader +{ + if(!fileHeader) + return NO; + + NSString* filetype = [PBEasyPipe outputForCommand:@"/usr/bin/file" withArgs:[NSArray arrayWithObjects:@"-b", @"-N", @"-", nil] inDir:[repository workingDirectory] inputString:fileHeader retValue:nil]; + if([filetype rangeOfString:@"text"].location == NSNotFound) + return YES; + else + return NO; +} + +- (BOOL)isBinary +{ + NSFileHandle* handle = [repository handleInWorkDirForArguments:[NSArray arrayWithObjects:@"check-attr", @"binary", [self fullPath], nil]]; + NSData* data = [handle readDataToEndOfFile]; + NSString* string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; + + if(string) { + string = [string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + if([string hasSuffix:@"binary: set"]) { + return YES; + } else if([string hasSuffix:@"binary: unset"]) { + return NO; + } else if([string hasSuffix:@"binary: unspecified"]) { + // first try common filename-extensions + for (NSString* extension in [NSArray arrayWithObjects:@".pdf", @".jpg", @".jpeg", @".png", @".bmp", @".gif", @".o", nil]) { + if([[self fullPath] hasSuffix:extension]) + return YES; + } + } + } + + return NO; +} + - (NSString*) contents { if (!leaf) return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]]; + NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"cat-file", @"-s", [self refSpec], nil]]; + NSString* fileSize = [[NSString alloc] initWithData:[handle readDataToEndOfFile] encoding:NSISOLatin1StringEncoding]; + + if([self isBinary]) + return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [fileSize longLongValue]]; + + if([fileSize longLongValue] > 52428800) // ~50MB + return [NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], [fileSize longLongValue]]; + + // we couldnt decide yet, we'll have to examine the whole file-content NSData* data = nil; - + if ([self isLocallyCached]) data = [NSData dataWithContentsOfFile: localFileName]; else { - NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]]; + [handle closeFile]; + handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]]; data = [handle readDataToEndOfFile]; } - + NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (!string) { + if (!string) string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; - } + + if([self isBinary:([string length] >= 100) ? [string substringToIndex:99] : string]) + return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [fileSize longLongValue]]; + return string; } -- 1.6.4.2.236.gf324c
