Permalink
Browse files

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 <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, 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 <heipei@hackvalue.de>
Edited-by: Pieter de Bie <pdebie@ai.rug.nl>
  • Loading branch information...
1 parent 8750060 commit 8243cf58b374cda0a9653e4e3fb982793f21cb2b @heipei heipei committed with Aug 28, 2009
Showing with 124 additions and 45 deletions.
  1. +37 −32 PBGitHistoryView.xib
  2. +4 −1 PBGitTree.h
  3. +83 −12 PBGitTree.m
View
@@ -43,6 +43,7 @@
<string>path</string>
<string>contents</string>
<string>selectedTab</string>
+ <string>textContents</string>
</object>
<string key="NSObjectClassName">PBGitTree</string>
<object class="_NSManagedProxy" key="_NSManagedProxy"/>
@@ -2048,35 +2049,6 @@
<int key="connectionID">264</int>
</object>
<object class="IBConnectionRecord">
- <object class="IBBindingConnection" key="connection">
- <string key="label">value: selection.contents</string>
- <reference key="source" ref="75600241"/>
- <reference key="destination" ref="69733037"/>
- <object class="NSNibBindingConnector" key="connector">
- <reference key="NSSource" ref="75600241"/>
- <reference key="NSDestination" ref="69733037"/>
- <string key="NSLabel">value: selection.contents</string>
- <string key="NSBinding">value</string>
- <string key="NSKeyPath">selection.contents</string>
- <object class="NSDictionary" key="NSOptions">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <object class="NSMutableArray" key="dict.sortedKeys">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <string>NSAllowsEditingMultipleValuesSelection</string>
- <string>NSConditionallySetsEditable</string>
- </object>
- <object class="NSMutableArray" key="dict.values">
- <bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="0" id="8"/>
- <reference ref="8"/>
- </object>
- </object>
- <int key="NSNibBindingConnectorVersion">2</int>
- </object>
- </object>
- <int key="connectionID">266</int>
- </object>
- <object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">branchPopUp</string>
<reference key="source" ref="892732705"/>
@@ -2146,6 +2118,35 @@
</object>
<int key="connectionID">290</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">value: selection.textContents</string>
+ <reference key="source" ref="75600241"/>
+ <reference key="destination" ref="69733037"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="75600241"/>
+ <reference key="NSDestination" ref="69733037"/>
+ <string key="NSLabel">value: selection.textContents</string>
+ <string key="NSBinding">value</string>
+ <string key="NSKeyPath">selection.textContents</string>
+ <object class="NSDictionary" key="NSOptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSAllowsEditingMultipleValuesSelection</string>
+ <string>NSConditionallySetsEditable</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <boolean value="NO" id="6"/>
+ <reference ref="6"/>
+ </object>
+ </object>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">291</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -2858,6 +2859,8 @@
<string>273.IBPluginDependency</string>
<string>28.IBPluginDependency</string>
<string>28.IBShouldRemoveOnLegacySave</string>
+ <string>287.IBPluginDependency</string>
+ <string>288.IBPluginDependency</string>
<string>29.IBPluginDependency</string>
<string>29.IBShouldRemoveOnLegacySave</string>
<string>3.IBPluginDependency</string>
@@ -2950,7 +2953,7 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{504, 612}, {346, 102}}</string>
<string>{{504, 612}, {346, 102}}</string>
- <reference ref="8"/>
+ <integer value="0" id="8"/>
<boolean value="YES" id="5"/>
<reference ref="5"/>
<string>{1000, 102}</string>
@@ -2990,6 +2993,8 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="9"/>
@@ -3021,7 +3026,7 @@
</object>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{59, 67}, {852, 432}}</string>
+ <string>{{321, 67}, {852, 432}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -3056,7 +3061,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">290</int>
+ <int key="maxID">291</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
View
@@ -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;
View
@@ -63,25 +63,96 @@ - (BOOL) isLocallyCached
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

0 comments on commit 8243cf5

Please sign in to comment.