Skip to content

Instantly share code, notes, and snippets.

@CocoaDebug
Forked from davepeck/BinaryDataScanner.h
Created February 25, 2018 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CocoaDebug/b40c4f646aa5cccd375d72cfcc1f1297 to your computer and use it in GitHub Desktop.
Save CocoaDebug/b40c4f646aa5cccd375d72cfcc1f1297 to your computer and use it in GitHub Desktop.
Two simple Objective-C classes that make it crazy easy to read data from sequential binary files.
//
// BinaryDataScanner.m
//
// Copyright 2009 Dave Peck <davepeck [at] davepeck [dot] org>. All rights reserved.
// http://davepeck.org/
//
// This class makes it quite a bit easier to read sequential binary files in Objective-C.
//
// This code is released under the BSD license. If you use it in your product, please
// let me know and, if possible, please put me in your credits.
//
#import <UIKit/UIKit.h>
@interface BinaryDataScanner : NSObject {
BOOL littleEndian;
NSStringEncoding encoding;
NSData *data;
const uint8_t *current;
NSUInteger scanRemain;
}
+(id)binaryDataScannerWithData:(NSData*)data littleEndian:(BOOL)littleEndian defaultEncoding:(NSStringEncoding)defaultEncoding;
-(NSUInteger) remainingBytes;
-(const uint8_t *) currentPointer;
-(void) skipBytes:(NSUInteger)count;
-(uint8_t) readByte;
-(uint16_t) readWord;
-(uint32_t) readDoubleWord;
-(NSString*) readNullTerminatedString;
-(NSString*) readNullTerminatedStringWithEncoding:(NSStringEncoding)overrideEncoding;
-(NSString*) readStringUntilDelimiter:(uint8_t)delim;
-(NSString*) readStringUntilDelimiter:(uint8_t)delim encoding:(NSStringEncoding)overrideEncoding;
-(NSString*) readStringOfLength:(NSUInteger)count handleNullTerminatorAfter:(BOOL)handleNull;
-(NSString*) readStringOfLength:(NSUInteger)count handleNullTerminatorAfter:(BOOL)handleNull encoding:(NSStringEncoding)overrideEncoding;
-(NSArray*) readArrayOfNullTerminatedStrings:(NSUInteger)count;
-(NSArray*) readArrayOfNullTerminatedStrings:(NSUInteger)count encoding:(NSStringEncoding)overrideEncoding;
@end
//
// BinaryDataScanner.m
//
// Copyright 2009 Dave Peck <davepeck [at] davepeck [dot] org>. All rights reserved.
// http://davepeck.org/
//
// This class makes it quite a bit easier to read sequential binary files in Objective-C.
//
// This code is released under the BSD license. If you use it in your product, please
// let me know and, if possible, please put me in your credits.
//
#import "BinaryDataScanner.h"
// NS byte order stuff is not useful here -- CF byte order ensures we're always dealing
// with the right size on either 32 or 64 bit platforms.
#import <CoreFoundation/CFByteOrder.h>
@interface BinaryDataScanner (Private)
-(id)initWithData:(NSData*)data littleEndian:(BOOL)littleEndian defaultEncoding:(NSStringEncoding)defaultEncoding;
-(void)dealloc;
-(NSException *)buildScanException;
-(void)moveBy:(NSUInteger)count;
@end
@implementation BinaryDataScanner (Private)
-(id)initWithData:(NSData*)initData littleEndian:(BOOL)isLittleEndian defaultEncoding:(NSStringEncoding)theDefaultEncoding
{
self = [super init];
if (self != nil)
{
data = [initData retain];
littleEndian = isLittleEndian;
encoding = theDefaultEncoding;
current = (const uint8_t *) [data bytes];
scanRemain = [data length];
}
return self;
}
-(void)dealloc
{
[data release];
data = nil;
[super dealloc];
}
-(void)moveBy:(NSUInteger)count
{
if (scanRemain < count)
{
@throw [self buildScanException];
}
scanRemain -= count;
current += count;
}
-(NSException *)buildScanException
{
return [NSException exceptionWithName:@"OrangeDataScanException" reason:@"Failure scanning desired information from the bytes." userInfo:nil];
}
@end
@implementation BinaryDataScanner
+(id)binaryDataScannerWithData:(NSData*)data littleEndian:(BOOL)littleEndian defaultEncoding:(NSStringEncoding)defaultEncoding
{
return [[[BinaryDataScanner alloc] initWithData:data littleEndian:littleEndian defaultEncoding:defaultEncoding] autorelease];
}
-(NSUInteger) remainingBytes
{
return scanRemain;
}
-(const uint8_t *) currentPointer
{
return current;
}
-(void) skipBytes:(NSUInteger)count
{
[self moveBy:count];
}
-(uint8_t) readByte
{
const uint8_t *old = current;
[self moveBy:1];
return old[0];
}
-(uint16_t) readWord
{
const uint16_t *word = (const uint16_t *) current;
[self moveBy:sizeof(uint16_t)];
if (littleEndian)
{
return CFSwapInt16LittleToHost(*word);
}
else
{
return CFSwapInt16BigToHost(*word);
}
}
-(uint32_t) readDoubleWord
{
const uint32_t *dword = (const uint32_t *) current;
[self moveBy:sizeof(uint32_t)];
if (littleEndian)
{
return CFSwapInt32LittleToHost(*dword);
}
else
{
return CFSwapInt32BigToHost(*dword);
}
}
-(NSString*) readNullTerminatedString
{
return [self readNullTerminatedStringWithEncoding:encoding];
}
-(NSString*) readNullTerminatedStringWithEncoding:(NSStringEncoding)overrideEncoding
{
return [self readStringUntilDelimiter:0 encoding:overrideEncoding];
}
-(NSString*) readStringUntilDelimiter:(uint8_t)delim
{
return [self readStringUntilDelimiter:delim encoding:encoding];
}
-(NSString*) readStringUntilDelimiter:(uint8_t)delim encoding:(NSStringEncoding)overrideEncoding
{
const uint8_t *start = current;
NSUInteger stringLength = 0;
while (scanRemain > 0 && *current != delim)
{
scanRemain -= 1;
current += 1;
stringLength += 1;
}
if (scanRemain < 1 || *current != delim)
{
@throw [self buildScanException];
}
// move over the delimiter
[self moveBy:1];
NSString *result = [[NSString alloc] initWithBytes:(const void*)start length:stringLength encoding:overrideEncoding];
return [result autorelease];
}
-(NSString*) readStringOfLength:(NSUInteger)count handleNullTerminatorAfter:(BOOL)handleNull
{
return [self readStringOfLength:count handleNullTerminatorAfter:handleNull encoding:encoding];
}
-(NSString*) readStringOfLength:(NSUInteger)count handleNullTerminatorAfter:(BOOL)handleNull encoding:(NSStringEncoding)overrideEncoding
{
const uint8_t *start = current;
[self moveBy:count];
if (handleNull)
{
const uint8_t *nullTerminator = current;
[self moveBy:1];
if (*nullTerminator != 0)
{
@throw [self buildScanException];
}
}
NSString *result = [[NSString alloc] initWithBytes:(const void*)start length:count encoding:overrideEncoding];
return [result autorelease];
}
-(NSArray*) readArrayOfNullTerminatedStrings:(NSUInteger)count
{
return [self readArrayOfNullTerminatedStrings:count encoding:encoding];
}
-(NSArray*) readArrayOfNullTerminatedStrings:(NSUInteger)count encoding:(NSStringEncoding)overrideEncoding
{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
for (NSUInteger i = 0; i < count; i++)
{
[array addObject:[self readNullTerminatedStringWithEncoding:overrideEncoding]];
}
return [array autorelease];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment