Skip to content

Commit

Permalink
Generally works, though it could use quite a bit of improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
rickosborne committed Mar 18, 2012
1 parent c1aa947 commit d9113fa
Show file tree
Hide file tree
Showing 13 changed files with 1,779 additions and 4,227 deletions.
26 changes: 26 additions & 0 deletions wow/WoWLogSplit/WoWLogSplit.xcodeproj/project.pbxproj
Expand Up @@ -17,6 +17,10 @@
B973D76E151505A600401595 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B973D74E151505A400401595 /* Cocoa.framework */; };
B973D776151505A600401595 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B973D774151505A600401595 /* InfoPlist.strings */; };
B973D779151505A600401595 /* WoWLogSplitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B973D778151505A600401595 /* WoWLogSplitTests.m */; };
B9CEA124151599E500F5E675 /* FileReader.m in Sources */ = {isa = PBXBuildFile; fileRef = B9CEA123151599E500F5E675 /* FileReader.m */; };
B9CEA12815159B4800F5E675 /* NSDataExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = B9CEA12715159B4800F5E675 /* NSDataExtensions.m */; };
B9CEA12B15159FC300F5E675 /* WoWLogLine.m in Sources */ = {isa = PBXBuildFile; fileRef = B9CEA12A15159FC300F5E675 /* WoWLogLine.m */; };
B9CEA12E1515BDE400F5E675 /* WoWLogTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = B9CEA12D1515BDE400F5E675 /* WoWLogTableView.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -49,6 +53,14 @@
B973D775151505A600401595 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
B973D777151505A600401595 /* WoWLogSplitTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WoWLogSplitTests.h; sourceTree = "<group>"; };
B973D778151505A600401595 /* WoWLogSplitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WoWLogSplitTests.m; sourceTree = "<group>"; };
B9CEA122151599E500F5E675 /* FileReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileReader.h; sourceTree = "<group>"; };
B9CEA123151599E500F5E675 /* FileReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileReader.m; sourceTree = "<group>"; };
B9CEA12615159B4800F5E675 /* NSDataExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDataExtensions.h; sourceTree = "<group>"; };
B9CEA12715159B4800F5E675 /* NSDataExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDataExtensions.m; sourceTree = "<group>"; };
B9CEA12915159FC300F5E675 /* WoWLogLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WoWLogLine.h; sourceTree = "<group>"; };
B9CEA12A15159FC300F5E675 /* WoWLogLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WoWLogLine.m; sourceTree = "<group>"; };
B9CEA12C1515BDE400F5E675 /* WoWLogTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WoWLogTableView.h; sourceTree = "<group>"; };
B9CEA12D1515BDE400F5E675 /* WoWLogTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WoWLogTableView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -116,6 +128,14 @@
children = (
B973D760151505A400401595 /* WLSAppDelegate.h */,
B973D761151505A400401595 /* WLSAppDelegate.m */,
B9CEA12C1515BDE400F5E675 /* WoWLogTableView.h */,
B9CEA12D1515BDE400F5E675 /* WoWLogTableView.m */,
B9CEA12615159B4800F5E675 /* NSDataExtensions.h */,
B9CEA12715159B4800F5E675 /* NSDataExtensions.m */,
B9CEA122151599E500F5E675 /* FileReader.h */,
B9CEA123151599E500F5E675 /* FileReader.m */,
B9CEA12915159FC300F5E675 /* WoWLogLine.h */,
B9CEA12A15159FC300F5E675 /* WoWLogLine.m */,
B973D763151505A500401595 /* MainMenu.xib */,
B973D755151505A400401595 /* Supporting Files */,
);
Expand Down Expand Up @@ -262,6 +282,10 @@
files = (
B973D75B151505A400401595 /* main.m in Sources */,
B973D762151505A400401595 /* WLSAppDelegate.m in Sources */,
B9CEA124151599E500F5E675 /* FileReader.m in Sources */,
B9CEA12815159B4800F5E675 /* NSDataExtensions.m in Sources */,
B9CEA12B15159FC300F5E675 /* WoWLogLine.m in Sources */,
B9CEA12E1515BDE400F5E675 /* WoWLogTableView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -433,6 +457,7 @@
B973D77E151505A600401595 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
B973D77F151505A600401595 /* Build configuration list for PBXNativeTarget "WoWLogSplitTests" */ = {
isa = XCConfigurationList;
Expand All @@ -441,6 +466,7 @@
B973D781151505A600401595 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
Expand Down
34 changes: 34 additions & 0 deletions wow/WoWLogSplit/WoWLogSplit/FileReader.h
@@ -0,0 +1,34 @@
//
// FileReader.h
// LineReader
//
// Created by Tobias Preuss on 05.10.10.
// Copyright 2010 Tobias Preuss. All rights reserved.
//
// Originally written by Dave DeLong,
// Source: http://stackoverflow.com/questions/3707427#3711079


@interface FileReader : NSObject {

NSString* m_filePath; /**< File path. */
NSFileHandle* m_fileHandle; /**< File handle. */
unsigned long long m_currentOffset; /**< Current offset is needed for forwards reading. */
unsigned long long m_currentInset; /**< Current inset is needed for backwards reading. */
NSRange m_prevDelimiterRange; /**< Position and length of the last delimiter. */
unsigned long long m_totalFileLength; /**< Total number of bytes in file. */
NSString* m_lineDelimiter; /**< Character for line break or page break. */
NSUInteger m_chunkSize; /**< Standard block size. */
}

- (id)initWithFilePath:(NSString*)filePath;
- (NSString*)readLine;
- (NSString*)readLineBackwards;
- (NSString*)readTrimmedLine;

#if NS_BLOCKS_AVAILABLE
- (void)enumerateLinesUsingBlock:(void(^)(NSString*, BOOL*))block;
#endif

@end

222 changes: 222 additions & 0 deletions wow/WoWLogSplit/WoWLogSplit/FileReader.m
@@ -0,0 +1,222 @@
//
// FileReader.m
// LineReader
//
// Created by Tobias Preuss on 05.10.10.
// Copyright 2010 Tobias Preuss. All rights reserved.
//
// Originally written by Dave DeLong,
// Source: http://stackoverflow.com/questions/3707427#3711079


#import "FileReader.h"
#import "NSDataExtensions.h"


/**
A file reader.
Files can be read forwards or backwards by calling the
corresponding function multiple times.
*/
@implementation FileReader

- (void)dealloc{
[m_fileHandle release], m_fileHandle = nil;
[super dealloc];
}

/**
Initialized a file reader object.
@param filePath A file path.
@returns An initialized FileReader object or nil if the object could not be created.
*/
- (id)initWithFilePath:(NSString*)filePath {

self = [super init];
if (self != nil) {
if (!filePath || [filePath length] <= 0) {
return nil;
}
m_fileHandle = [[NSFileHandle fileHandleForReadingAtPath:filePath] retain];
if (m_fileHandle == nil) {
return nil;
}
// TODO: How can I use NSLineSeparatorCharacter instead of \n here?
m_lineDelimiter = [[NSString alloc] initWithString:@"\n"];
m_filePath = filePath;
m_currentOffset = 0ULL;
m_chunkSize = 10;
[m_fileHandle seekToEndOfFile];
m_totalFileLength = [m_fileHandle offsetInFile];
m_currentInset = m_totalFileLength;
m_prevDelimiterRange = NSMakeRange(m_currentInset, 1);

NSLog(@"%qu characters in %@", m_totalFileLength, [filePath lastPathComponent]); /* DEBUG LOG */
}
return self;
}



/**
Reads the file forwards.
Empty lines are not returned.
@returns Another single line on each call or nil if the file end has been reached.
*/
- (NSString*)readLine {

if (m_totalFileLength == 0 || m_currentOffset >= m_totalFileLength) {
return nil;
}

NSData* newLineData = [m_lineDelimiter dataUsingEncoding:NSUTF8StringEncoding];
[m_fileHandle seekToFileOffset:m_currentOffset];
NSMutableData* currentData = [[NSMutableData alloc] init];
BOOL shouldReadMore = YES;

while (shouldReadMore) {
if (m_currentOffset >= m_totalFileLength) {
break;
}
NSData* chunk = [m_fileHandle readDataOfLength:m_chunkSize]; // always length = 10
// Find the location and length of the next line delimiter.
NSRange newLineRange = [chunk rangeOfData:newLineData];
if (newLineRange.location != NSNotFound) {
// Include the length so we can include the delimiter in the string.
NSRange subDataRange = NSMakeRange(0, newLineRange.location + [newLineData length]);
chunk = [chunk subdataWithRange:subDataRange];
shouldReadMore = NO;
}
[currentData appendData:chunk];
m_currentOffset += [chunk length];
}

NSString* line = [currentData stringValueWithEncoding:NSUTF8StringEncoding];
// finished with data
[currentData release], currentData = nil;
return line;
}




/**
Reads the file backwards.
Empty lines are returned as well.
@returns Another single line on each call or nil if the file end has been reached.
*/
- (NSString*)readLineBackwards {

if (m_totalFileLength == 0 || (m_currentInset == 0 && m_chunkSize == 0)) {
return nil;
}

NSData* newLineData = [m_lineDelimiter dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger currentChunkSize = m_chunkSize;


// Process block smaller than standard chunk size.
// Shrink current chunk size.
// Shift inset to zero.
if (m_currentInset < m_chunkSize) {
currentChunkSize = m_currentInset;
m_currentInset -= currentChunkSize;
}
// Process blocks of chunk size.
// Shift inset by standard chunk size.
if (m_currentInset >= m_chunkSize && m_currentInset <= m_totalFileLength) {
m_currentInset -= m_chunkSize;
}
[m_fileHandle seekToFileOffset:m_currentInset];


NSMutableData* currentData = [[NSMutableData alloc] init];
BOOL shouldReadMore = YES;

while (shouldReadMore) {

if (m_currentInset == NSNotFound) {
break;
}

NSData* chunk = [m_fileHandle readDataOfLength:currentChunkSize];
NSRange newLineRange = [chunk rangeOfDataBackwardsSearch:newLineData];
m_prevDelimiterRange = NSMakeRange(m_currentInset + newLineRange.location, newLineRange.length);
if (newLineRange.location == NSNotFound) {
m_prevDelimiterRange = NSMakeRange(NSNotFound, 0);
}
if (newLineRange.location != NSNotFound) {
NSUInteger subDataLoc = newLineRange.location + [newLineData length];
NSUInteger subDataLen = currentChunkSize - subDataLoc;
chunk = [chunk subdataWithRange:NSMakeRange(subDataLoc, subDataLen)];
shouldReadMore = NO;
}
[currentData prepend:chunk];



if (m_prevDelimiterRange.location == NSNotFound) {
// Process block smaller than standard chunk size.
// Shrink current chunk size.
// Shift inset to zero.
// Break while loop if front has been reached.
if (m_currentInset < currentChunkSize) {
currentChunkSize = m_currentInset;
m_currentInset -= currentChunkSize;
if (currentChunkSize == 0 && m_currentInset == 0) {
m_chunkSize = 0;
break;
}
}
// Process blocks of chunk size.
// Shift inset by standard chunk size.
else {
currentChunkSize = m_chunkSize;
m_currentInset -= currentChunkSize;
}
[m_fileHandle seekToFileOffset:m_currentInset];
}
// Shift inset to last found position.
else {
m_currentInset = m_prevDelimiterRange.location;
}

} // End if while.

NSString* line = [[NSString alloc] initWithData:currentData encoding:NSUTF8StringEncoding];
// finished with data
[currentData release], currentData = nil;
return line;
}




/**
Reads the file forwards while trimming white spaces.
@returns Another single line on each call or nil if the file end has been reached.
*/
- (NSString*)readTrimmedLine {

return [[self readLine] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}



#if NS_BLOCKS_AVAILABLE
/**
Reads the file forwards using a block object.
@param block
*/
- (void)enumerateLinesUsingBlock:(void(^)(NSString*, BOOL*))block {
NSString* line = nil;
BOOL stop = NO;
while (stop == NO && (line = [self readLine])) {
block(line, &stop);
}
}
#endif



@end
32 changes: 32 additions & 0 deletions wow/WoWLogSplit/WoWLogSplit/NSDataExtensions.h
@@ -0,0 +1,32 @@
//
// NSDataExtensions.h
// LineReader
//
// Created by Tobias Preuss on 08.10.10.
// Copyright 2010 Tobias Preuss. All rights reserved.
//



// -----------------------------------------------------------------------------
// NSData additions.
// -----------------------------------------------------------------------------

@interface NSData (Additions)

- (NSRange)rangeOfData:(NSData*)dataToFind;
- (NSRange)rangeOfDataBackwardsSearch:(NSData*)dataToFind;
- (NSString*)stringValueWithEncoding:(NSStringEncoding)encoding;

@end


// -----------------------------------------------------------------------------
// NSMutableData additions.
// -----------------------------------------------------------------------------

@interface NSMutableData (Additions)

- (void)prepend:(NSData*)data;

@end

0 comments on commit d9113fa

Please sign in to comment.