From 8243cf58b374cda0a9653e4e3fb982793f21cb2b Mon Sep 17 00:00:00 2001 From: Johannes Gilger Date: Fri, 28 Aug 2009 18:05:29 +0200 Subject: [PATCH] PBGitTree: Don't try to print binary-file contents This patch prevents the plaintext display of files with binary content in tree-view by connecting the content to the textContents attribute. PBGitTree is extended with the method textContents, which returns the textual representation of a PBGitTree-object. The methods first checks the output of "git check-attr binary " 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, the file-content is loaded and Unix "file" is run on the first 100 bytes of the file to make a decision. It also adds the -[PBGitTree fileSize] method to check the size of the file before actually loading its contents. Signed-off-by: Johannes Gilger Edited-by: Pieter de Bie --- PBGitHistoryView.xib | 69 +++++++++++++++++--------------- PBGitTree.h | 5 ++- PBGitTree.m | 95 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 124 insertions(+), 45 deletions(-) diff --git a/PBGitHistoryView.xib b/PBGitHistoryView.xib index 10b884e..741ed2c 100644 --- a/PBGitHistoryView.xib +++ b/PBGitHistoryView.xib @@ -43,6 +43,7 @@ path contents selectedTab + textContents PBGitTree @@ -2047,35 +2048,6 @@ 264 - - - value: selection.contents - - - - - - value: selection.contents - value - selection.contents - - YES - - YES - NSAllowsEditingMultipleValuesSelection - NSConditionallySetsEditable - - - YES - - - - - 2 - - - 266 - branchPopUp @@ -2146,6 +2118,35 @@ 290 + + + value: selection.textContents + + + + + + value: selection.textContents + value + selection.textContents + + YES + + YES + NSAllowsEditingMultipleValuesSelection + NSConditionallySetsEditable + + + YES + + + + + 2 + + + 291 + @@ -2858,6 +2859,8 @@ 273.IBPluginDependency 28.IBPluginDependency 28.IBShouldRemoveOnLegacySave + 287.IBPluginDependency + 288.IBPluginDependency 29.IBPluginDependency 29.IBShouldRemoveOnLegacySave 3.IBPluginDependency @@ -2950,7 +2953,7 @@ com.apple.InterfaceBuilder.CocoaPlugin {{504, 612}, {346, 102}} {{504, 612}, {346, 102}} - + {1000, 102} @@ -2990,6 +2993,8 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3021,7 +3026,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{59, 67}, {852, 432}} + {{321, 67}, {852, 432}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -3056,7 +3061,7 @@ - 290 + 291 diff --git a/PBGitTree.h b/PBGitTree.h index 9f4334b..d48ab6e 100644 --- a/PBGitTree.h +++ b/PBGitTree.h @@ -10,13 +10,15 @@ #import "PBGitRepository.h" @interface PBGitTree : NSObject { + long long _fileSize; + NSString* sha; NSString* path; PBGitRepository* repository; __weak PBGitTree* parent; NSArray* children; BOOL leaf; - + NSString* localFileName; NSDate* localMtime; } @@ -26,6 +28,7 @@ - (void) saveToFolder: (NSString *) directory; - (NSString*) tmpFileNameForContents; +- (long long)fileSize; @property(copy) NSString* sha; @property(copy) NSString* path; diff --git a/PBGitTree.m b/PBGitTree.m index 51fadd2..21c91f8 100644 --- a/PBGitTree.m +++ b/PBGitTree.m @@ -63,25 +63,96 @@ return NO; } +- (BOOL)hasBinaryHeader:(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]; + + return [filetype rangeOfString:@"text"].location == NSNotFound; +} + +- (BOOL)hasBinaryAttributes +{ + // First ask git check-attr if the file has a binary attribute custom set + 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) + return NO; + string = [string stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + if ([string hasSuffix:@"binary: set"]) + return YES; + + if ([string hasSuffix:@"binary: unset"]) + return NO; + + // Binary state unknown, do a check on 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]]; - NSData* data = nil; - - if ([self isLocallyCached]) - data = [NSData dataWithContentsOfFile: localFileName]; - else { - NSFileHandle* handle = [repository handleForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]]; - data = [handle readDataToEndOfFile]; + if ([self isLocallyCached]) { + NSData *data = [NSData dataWithContentsOfFile:localFileName]; + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (!string) + string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; + return string; } - NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - if (!string) { - string = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; - } - return string; + return [repository outputForArguments:[NSArray arrayWithObjects:@"show", [self refSpec], nil]]; +} + +- (long long)fileSize +{ + if (_fileSize) + return _fileSize; + + NSFileHandle *handle = [repository handleForArguments:[NSArray arrayWithObjects:@"cat-file", @"-s", [self refSpec], nil]]; + NSString *sizeString = [[NSString alloc] initWithData:[handle readDataToEndOfFile] encoding:NSISOLatin1StringEncoding]; + + if (!sizeString) + _fileSize = -1; + else + _fileSize = [sizeString longLongValue]; + + return _fileSize; +} + +- (NSString *)textContents +{ + if (!leaf) + return [NSString stringWithFormat:@"This is a tree with path %@", [self fullPath]]; + + if ([self hasBinaryAttributes]) + return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], [self fileSize]]; + + long long fileSize = [self fileSize]; + if (fileSize > 52428800) // ~50MB + return [NSString stringWithFormat:@"%@ is too big to be displayed (%d bytes)", [self fullPath], fileSize]; + + NSString *contents = [self contents]; + + if ([self hasBinaryHeader:([contents length] >= 100) ? [contents substringToIndex:99] : contents]) + return [NSString stringWithFormat:@"%@ appears to be a binary file of %d bytes", [self fullPath], fileSize]; + + return contents; } - (void) saveToFolder: (NSString *) dir