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

Reply via email to