Skip to content

Instantly share code, notes, and snippets.

@swillits
Created April 26, 2017 00:42
Show Gist options
  • Save swillits/c3ed14f95878085e909677db7dc09980 to your computer and use it in GitHub Desktop.
Save swillits/c3ed14f95878085e909677db7dc09980 to your computer and use it in GitHub Desktop.
AGBinaryStream Obj-C
//
// AGBinaryDataStream.h
// AraeliumFoundation
//
// Created by Seth Willits on 11/15/09.
// Copyright 2009 Araelium Group. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "AGBinaryStream.h"
@interface AGBinaryDataStream : AGBinaryStream {
NSData * mData;
uint64_t mPosition;
}
@end
//
// AGBinaryDataStream.m
// AraeliumFoundation
//
// Created by Seth Willits on 11/15/09.
// Copyright 2009 Araelium Group. All rights reserved.
//
#import "AGBinaryDataStream.h"
#define AGBinaryStreamRaiseIfNoData \
if (!mData) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryDataStream has no data"];
#define AGBinaryDataStreamReadBytes(arg_data, arg_length) \
if ((NSUInteger)(mPosition) + (NSUInteger)(arg_length) <= [mData length]) { \
[mData getBytes:(arg_data) range:NSMakeRange((NSUInteger)mPosition, (NSUInteger)(arg_length))]; \
mPosition += (arg_length); \
} else { \
mPosition = (uint64_t)[self length]; \
[NSException raise:AGBinaryStreamEndOfStreamException format:@"AGBinaryStream reached EOF"]; \
}
#define AGBinaryDataStreamWriteBytes(arg_data, arg_length) \
if ((NSUInteger)(mPosition + (arg_length)) > [mData length]) { \
[(NSMutableData *)mData increaseLengthBy:(NSUInteger)((NSUInteger)(mPosition + (arg_length)) - [mData length])]; \
} \
[(NSMutableData *)mData replaceBytesInRange:NSMakeRange((NSUInteger)mPosition, (NSUInteger)(arg_length)) withBytes:(arg_data) length:(NSUInteger)(arg_length)]; \
mPosition += (arg_length);
@implementation AGBinaryDataStream
- (id)initWithData:(NSData *)data;
{
if (!(self = [super init])) {
[self release];
return nil;
}
if (data) {
mData = [data retain];
} else {
mData = [[NSMutableData alloc] init];
}
mLittleEndian = NO;
return self;
}
- (void)dealloc;
{
[self close];
[mData release];
[super dealloc];
}
- (BOOL)open:(NSInteger)options error:(NSError **)error;
{
[self close];
// Endianness
if (options & AGBSOptionsLittleEndian) {
mLittleEndian = YES;
} else if (options & AGBSOptionsBigEndian) {
mLittleEndian = NO;
} else {
#if BS_Byte_Order == BS_LITTLE_ENDIAN
mLittleEndian = YES;
#else
mLittleEndian = NO;
#endif
}
if (options & AGBSOptionsWrite) {
if (![mData isKindOfClass:[NSMutableData class]]) {
[mData autorelease];
mData = [[NSMutableData alloc] initWithData:mData];
}
}
return YES;
}
- (void)close;
{
}
- (void)flush;
{
}
//////////////////////////////////////////////////////////////////////////////////
//
// Options and Such
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Accessors
- (FILE *)file;
{
return NULL;
}
- (NSData *)data;
{
return mData;
}
- (BOOL)isEndOfFile;
{
return ([self position] == [self length]);
}
- (NSInteger)lastErrorCode;
{
return 0;
}
- (uint64_t)length;
{
return [mData length];
}
- (void)setLength:(uint64_t)length;
{
[(NSMutableData *)mData setLength:(NSUInteger)length];
}
- (BOOL)isLittleEndian;
{
return mLittleEndian;
}
- (void)setLittleEndian:(BOOL)set;
{
mLittleEndian = set;
}
- (off_t)position;
{
return (off_t)mPosition;
}
- (void)setPosition:(off_t)pos;
{
mPosition = pos;
if (mPosition > [self length]) {
[(NSMutableData *)mData increaseLengthBy:(NSUInteger)(mPosition - [mData length])];
}
}
//////////////////////////////////////////////////////////////////////////////////
//
// File Writing
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Writing
- (size_t)writeData:(const void *)data length:(unsigned long)length;
{
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamWriteBytes(data, length)
return length;
}
- (void)writeDouble:(double)data;
{
AGBinaryStreamRaiseIfNoData
double value = data;
uint64_t intValue = *(uint64_t*)&value;
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap64(intValue);
}
AGBinaryDataStreamWriteBytes(&intValue, sizeof(intValue))
}
- (void)writeFloat:(float)data;
{
AGBinaryStreamRaiseIfNoData
float value = data;
uint32_t intValue = *(uint32_t*)&value;
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap32(intValue);
}
AGBinaryDataStreamWriteBytes(&intValue, sizeof(intValue))
}
- (void)writeBool:(BOOL)data;
{
AGBinaryStreamRaiseIfNoData
char value = 0;
if (data) value = 1;
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeInt8:(int8_t)data;
{
AGBinaryStreamRaiseIfNoData
int8_t value = data;
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeInt16:(int16_t)data;
{
AGBinaryStreamRaiseIfNoData
int16_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap16(data);
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeInt32:(int32_t)data;
{
AGBinaryStreamRaiseIfNoData
int32_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap32(data);
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeInt64:(int64_t)data;
{
AGBinaryStreamRaiseIfNoData
int64_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap64(data);
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeUInt8:(uint8_t)data;
{
AGBinaryStreamRaiseIfNoData
uint8_t value = data;
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeUInt16:(uint16_t)data;
{
AGBinaryStreamRaiseIfNoData
uint16_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap16(data);
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeUInt32:(uint32_t)data;
{
AGBinaryStreamRaiseIfNoData
uint32_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap32(data);
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
- (void)writeUInt64:(uint64_t)data;
{
AGBinaryStreamRaiseIfNoData
uint64_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap64(data);
AGBinaryDataStreamWriteBytes(&value, sizeof(value))
}
//////////////////////////////////////////////////////////////////////////////////
//
// File Reading
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Reading
- (size_t)readData:(void *)data length:(unsigned long)length;
{
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(data, length)
return length;
}
- (double)readDouble;
{
double value;
uint64_t intValue = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&intValue, sizeof(uint64_t));
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap64(intValue);
}
value = *(double*)(&intValue);
return value;
}
- (float)readFloat;
{
float value;
uint32_t intValue = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&intValue, sizeof(uint32_t));
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap32(intValue);
}
value = *(float*)(&intValue);
return value;
}
- (BOOL)readBool;
{
char value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
return (value != '\0');
}
- (int8_t)readInt8;
{
int8_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
return value;
}
- (int16_t)readInt16;
{
int16_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
if (mLittleEndian != BS_Byte_Order) value = BS_Swap16(value);
return value;
}
- (int32_t)readInt32;
{
int32_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
if (mLittleEndian != BS_Byte_Order) value = BS_Swap32(value);
return value;
}
- (int64_t)readInt64;
{
int64_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
if (mLittleEndian != BS_Byte_Order) value = BS_Swap64(value);
return value;
}
- (uint8_t)readUInt8;
{
uint8_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
return value;
}
- (uint16_t)readUInt16;
{
uint16_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
if (mLittleEndian != BS_Byte_Order) value = BS_Swap16(value);
return value;
}
- (uint32_t)readUInt32;
{
uint32_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value));
if (mLittleEndian != BS_Byte_Order) value = BS_Swap32(value);
return value;
}
- (uint64_t)readUInt64;
{
uint64_t value = 0;
AGBinaryStreamRaiseIfNoData
AGBinaryDataStreamReadBytes(&value, sizeof(value))
if (mLittleEndian != BS_Byte_Order) value = BS_Swap64(value);
return value;
}
@end
//
// AGBinaryFileStream.h
// AraeliumFoundation
//
// Created by Seth Willits on 11/15/09.
// Copyright 2009 Araelium Group. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "AGBinaryStream.h"
@interface AGBinaryFileStream : AGBinaryStream {
NSString * mFilePath;
FILE * mFile;
NSInteger mLastErrorCode;
}
@end
//
// AGBinaryFileStream.m
// AraeliumFoundation
//
// Created by Seth Willits on 11/15/09.
// Copyright 2009 Araelium Group. All rights reserved.
//
#import "AGBinaryFileStream.h"
@implementation AGBinaryFileStream
- (id)initWithFilePath:(NSString *)filePath;
{
if (!(self = [super init])) {
[self release];
return nil;
}
assert(filePath != nil);
mFilePath = [filePath copy];
mLittleEndian = NO;
mLastErrorCode = 0;
return self;
}
- (void)dealloc;
{
[self close];
[mFilePath release];
[super dealloc];
}
- (BOOL)open:(NSInteger)options error:(NSError **)error;
{
[self close];
// Endianness
if (options & AGBSOptionsLittleEndian) {
mLittleEndian = YES;
} else if (options & AGBSOptionsBigEndian) {
mLittleEndian = NO;
} else {
#if BS_Byte_Order == BS_LITTLE_ENDIAN
mLittleEndian = YES;
#else
mLittleEndian = NO;
#endif
}
// Make Options String
char flags[4] = {'\0'}; NSInteger flag = 0;
if ((options & AGBSOptionsRead) && (options & AGBSOptionsWrite)) {
flags[flag++] = 'w';
flags[flag++] = '+';
} else if (options & AGBSOptionsRead) {
flags[flag++] = 'r';
} else if (options & AGBSOptionsWrite) {
flags[flag++] = 'w';
}
// Always binary
flags[flag] = 'b';
// Open the File
mFile = fopen([mFilePath fileSystemRepresentation], flags);
if (!mFile) {
mLastErrorCode = errno;
if (error) *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:mLastErrorCode userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"Could not open file %@", mFilePath], NSLocalizedDescriptionKey,
[NSString stringWithFormat:@"AGBinaryStream: failed to open %@. Error (%d) %s", mFilePath, (int)mLastErrorCode, strerror(errno)], NSLocalizedFailureReasonErrorKey,
nil]];
return NO;
}
return YES;
}
- (void)close;
{
if (mFile) {
if (fclose(mFile)) {
mLastErrorCode = errno;
} else {
mLastErrorCode = 0;
}
mFile = NULL;
}
}
- (void)flush;
{
if (mFile) {
if (fflush(mFile)) {
mLastErrorCode = errno;
} else {
mLastErrorCode = 0;
}
}
}
//////////////////////////////////////////////////////////////////////////////////
//
// Options and Such
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Accessors
- (FILE *)file;
{
return mFile;
}
- (NSData *)data;
{
return nil;
}
- (BOOL)isEndOfFile;
{
if (mFile) {
if (self.position == self.length) {
return YES;
}
return (feof(mFile) == 1);
}
return YES;
}
- (NSInteger)lastErrorCode;
{
if (mFile) {
return mLastErrorCode; //ferror(mFile);
}
return -1;
}
- (uint64_t)length;
{
off_t currentPosition = [self position];
uint64_t length = 0;
if (mFile) {
if (fseeko(mFile, 0, SEEK_END)) {
mLastErrorCode = errno;
} else {
length = [self position];
[self setPosition:currentPosition];
}
}
return length;
}
- (void)setLength:(uint64_t)length;
{
[self doesNotRecognizeSelector:_cmd];
}
- (BOOL)isLittleEndian;
{
return mLittleEndian;
}
- (void)setLittleEndian:(BOOL)set;
{
mLittleEndian = set;
}
- (off_t)position;
{
off_t position = 0;
if (mFile) {
position = ftello(mFile);
if (position == -1) {
mLastErrorCode = errno;
} else {
mLastErrorCode = 0;
}
}
return position;
}
- (void)setPosition:(off_t)pos;
{
if (mFile) {
if (fseeko(mFile, pos, SEEK_SET)) {
mLastErrorCode = errno;
} else {
mLastErrorCode = 0;
}
}
}
//////////////////////////////////////////////////////////////////////////////////
//
// File Writing
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Writing
- (size_t)writeData:(const void *)data length:(unsigned long)length;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
size_t written = fwrite(data, 1, length, mFile);
mLastErrorCode = (written == length ? 0 : errno);
return written;
}
- (void)writeDouble:(double)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
double value = data;
uint64_t intValue = *(uint64_t*)&value;
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap64(intValue);
}
size_t written = fwrite(&intValue, sizeof(uint64_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeFloat:(float)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
float value = data;
uint32_t intValue = *(uint32_t*)&value;
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap32(intValue);
}
size_t written = fwrite(&intValue, sizeof(uint32_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeBool:(BOOL)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
char value = 0;
if (data) value = 1;
size_t written = fwrite(&value, sizeof(char), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeInt8:(int8_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int8_t value = data;
size_t written = fwrite(&value, sizeof(int8_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeInt16:(int16_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int16_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap16(data);
size_t written = fwrite(&value, sizeof(int16_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeInt32:(int32_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int32_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap32(data);
size_t written = fwrite(&value, sizeof(int32_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeInt64:(int64_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int64_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap64(data);
size_t written = fwrite(&value, sizeof(int64_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeUInt8:(uint8_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint8_t value = data;
size_t written = fwrite(&value, sizeof(uint8_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeUInt16:(uint16_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint16_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap16(data);
size_t written = fwrite(&value, sizeof(uint16_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeUInt32:(uint32_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint32_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap32(data);
size_t written = fwrite(&value, sizeof(uint32_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
- (void)writeUInt64:(uint64_t)data;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint64_t value = (mLittleEndian == BS_Byte_Order) ? data : BS_Swap64(data);
size_t written = fwrite(&value, sizeof(uint64_t), 1, mFile);
mLastErrorCode = (written == 1 ? 0 : errno);
}
//////////////////////////////////////////////////////////////////////////////////
//
// File Reading
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Reading
- (size_t)readData:(void *)data length:(unsigned long)length;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
size_t result = fread(data, 1, length, mFile);
AGBinaryStreamRaiseReadEOF(result, length);
return result;
}
- (double)readDouble;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
double value;
uint64_t intValue = 0;
size_t result = fread(&intValue, sizeof(uint64_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap64(intValue);
}
value = *(double*)(&intValue);
return value;
}
- (float)readFloat;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
float value;
uint32_t intValue = 0;
size_t result = fread(&intValue, sizeof(uint32_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) {
intValue = BS_Swap32(intValue);
}
value = *(float*)(&intValue);
return value;
}
- (BOOL)readBool;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
char value = 0;
size_t result = fread(&value, sizeof(char), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (value != '\0')
return YES;
return NO;
}
- (int8_t)readInt8;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int8_t value = 0;
size_t result = fread(&value, sizeof(int8_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
return value;
}
- (int16_t)readInt16;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int16_t value = 0;
size_t result = fread(&value, sizeof(int16_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) value = BS_Swap16(value);
return value;
}
- (int32_t)readInt32;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int32_t value = 0;
size_t result = fread(&value, sizeof(int32_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) value = BS_Swap32(value);
return value;
}
- (int64_t)readInt64;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
int64_t value = 0;
size_t result = fread(&value, sizeof(int64_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) value = BS_Swap64(value);
return value;
}
- (uint8_t)readUInt8;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint8_t value = 0;
size_t result = fread(&value, sizeof(uint8_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
return value;
}
- (uint16_t)readUInt16;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint16_t value = 0;
size_t result = fread(&value, sizeof(uint16_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) value = BS_Swap16(value);
return value;
}
- (uint32_t)readUInt32;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint32_t value = 0;
size_t result = fread(&value, sizeof(uint32_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) value = BS_Swap32(value);
return value;
}
- (uint64_t)readUInt64;
{
if (!mFile) [NSException raise:NSInternalInconsistencyException format:@"AGBinaryStream has no FILE"];
uint64_t value = 0;
size_t result = fread(&value, sizeof(uint64_t), 1, mFile);
AGBinaryStreamRaiseReadEOF(result, 1);
if (mLittleEndian != BS_Byte_Order) value = BS_Swap64(value);
return value;
}
@end
//
// AGBinaryStream.h
// Araelium Foundation
//
// Created by Seth Willits on 1/31/07.
// Copyright 2007 Araelium Group. All rights reserved.
//
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
typedef enum {
AGBSOptionsRead = 1 << 1,
AGBSOptionsWrite = 1 << 2,
AGBSOptionsLittleEndian = 1 << 3,
AGBSOptionsBigEndian = 1 << 4,
AGBSOptionsDefault = AGBSOptionsRead,
AGBSOptionsDefaultL = AGBSOptionsRead | AGBSOptionsLittleEndian,
AGBSOptionsDefaultB = AGBSOptionsRead | AGBSOptionsBigEndian
} AGBinaryStreamOptions;
extern NSString * AGBinaryStreamEndOfStreamException;
extern NSString * AGBinaryStreamReadErrorException;
@interface AGBinaryStream : NSObject {
BOOL mLittleEndian;
}
@end
@interface AGBinaryStream (Methods)
- (instancetype)initWithFilePath:(NSString *)filePath;
- (instancetype)initWithData:(NSData * _Nullable)data;
- (BOOL)open:(NSInteger)options error:(NSError **)error;
- (void)close;
- (void)flush;
/// Returns nil if the stream was initialized with data and not a file path.
- (FILE * _Nullable)file;
/// Returns nil if the stream was initialized with a file path and not data.
- (NSData * _Nullable)data;
- (BOOL)isEndOfFile;
- (NSInteger)lastErrorCode;
- (uint64_t)length;
- (void)setLength:(uint64_t)length;
- (BOOL)isLittleEndian;
- (void)setLittleEndian:(BOOL)set;
- (off_t)position;
- (void)setPosition:(off_t)pos;
- (void)offsetPosition:(off_t)pos;
- (size_t)writeData:(const void *)data length:(unsigned long)length;
- (void)writeDouble:(double)data;
- (void)writeFloat:(float)data;
- (void)writeBool:(BOOL)data;
- (void)writeInt8:(int8_t)data;
- (void)writeInt16:(int16_t)data;
- (void)writeInt32:(int32_t)data;
- (void)writeInt64:(int64_t)data;
- (void)writeUInt8:(uint8_t)data;
- (void)writeUInt16:(uint16_t)data;
- (void)writeUInt32:(uint32_t)data;
- (void)writeUInt64:(uint64_t)data;
- (size_t)readData:(void *)data length:(unsigned long)length;
- (double)readDouble;
- (float)readFloat;
- (BOOL)readBool;
- (int8_t)readInt8;
- (int16_t)readInt16;
- (int32_t)readInt32;
- (int64_t)readInt64;
- (uint8_t)readUInt8;
- (uint16_t)readUInt16;
- (uint32_t)readUInt32;
- (uint64_t)readUInt64;
@end
@interface AGBinaryStream (Additions)
- (void)writeString:(NSString *)string; // always utf8 encoding
- (NSString * _Nullable)readString; // always utf8 encoding
- (NSData *)readDataOfLength:(unsigned long)length;
@end
// --------- Intended for internal use ------------ //
// Determines the Endianness of the Processor
#define BS_LITTLE_ENDIAN 1
#define BS_BIG_ENDIAN 0
#if defined(__LITTLE_ENDIAN__)
#define BS_Byte_Order BS_LITTLE_ENDIAN
#else
#define BS_Byte_Order BS_BIG_ENDIAN
#endif
// Byte swapping
#define BS_Swap16(arg) CFSwapInt16(arg)
#define BS_Swap32(arg) CFSwapInt32(arg)
#define BS_Swap64(arg) CFSwapInt64(arg)
#define AGBinaryStreamRaiseReadEOF(result, size) \
if (result != size) {\
mLastErrorCode = errno;\
if (feof(mFile)) {\
[NSException raise:AGBinaryStreamEndOfStreamException format:@"AGBinaryStream reached EOF"];\
} else {\
NSException * exception = [NSException exceptionWithName:AGBinaryStreamReadErrorException reason:NSSTRF(@"Error %d when reading", (int)mLastErrorCode) userInfo:@{@"errno" : @(mLastErrorCode)}];\
[exception raise];\
}\
} else {\
mLastErrorCode = 0;\
}
NS_ASSUME_NONNULL_END
//
// AGBinaryStream.m
// Screenflick
//
// Created by Seth Willits on 1/31/07.
// Copyright 2007 Araelium Group. All rights reserved.
//
#import "AGBinaryStream.h"
//#import "AGBinaryFileStream.h"
//#import "AGBinaryDataStream.h"
NSString * AGBinaryStreamEndOfStreamException = @"AGBinaryStreamEndOfStreamException";
NSString * AGBinaryStreamReadErrorException = @"AGBinaryStreamReadErrorException";
@implementation AGBinaryStream
- (id)initWithFilePath:(NSString *)filePath;
{
[self release];
return [[NSClassFromString(@"AGBinaryFileStream") alloc] initWithFilePath:filePath];
}
- (id)initWithData:(NSData *)data;
{
[self release];
return [[NSClassFromString(@"AGBinaryDataStream") alloc] initWithData:data];
}
- (void)offsetPosition:(off_t)pos;
{
[self setPosition:([self position] + pos)];
}
@end
//////////////////////////////////////////////////////////////////////////////////
//
// Additions
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark
#pragma mark
@implementation AGBinaryStream (Additions)
- (void)writeString:(NSString *)string; // always utf8 encoding
{
[self writeBool:(string != nil)];
NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
uint32_t length = (uint32_t)[data length];
[self writeUInt32:length];
if (length > 0) {
[self writeData:[data bytes] length:length];
}
}
- (NSString *)readString;
{
BOOL isValid = [self readBool];
if (!isValid) {
return nil;
}
uint32_t length = [self readUInt32];
if (length == 0) {
return @"";
}
NSMutableData * data = [NSMutableData dataWithLength:length];
[self readData:[data mutableBytes] length:length];
return [[[NSString alloc] initWithBytes:[data bytes] length:length encoding:NSUTF8StringEncoding] autorelease];
}
- (NSData *)readDataOfLength:(unsigned long)length;
{
NSMutableData * data = [NSMutableData dataWithLength:length];
[self readData:[data mutableBytes] length:length];
return data;
}
@end
//////////////////////////////////////////////////////////////////////////////////
//
// Byte Swapping
//
//////////////////////////////////////////////////////////////////////////////////
#pragma mark
#pragma mark
#pragma mark Byte Swapping
#ifndef BS_Swap16
static __inline__ uint16_t BS_Swap16(uint16_t D) {
return((D<<8)|(D>>8));
}
#endif
#ifndef BS_Swap32
static __inline__ uint32_t BS_Swap32(uint32_t D) {
return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
}
#endif
#ifndef BS_Swap64
static __inline__ uint64_t BS_Swap64(uint64_t val) {
uint32_t hi, lo;
/* Separate into high and low 32-bit values and swap them */
lo = (uint32_t)(val&0xFFFFFFFF);
val >>= 32;
hi = (uint32_t)(val&0xFFFFFFFF);
val = BS_Swap32(lo);
val <<= 32;
val |= BS_Swap32(hi);
return(val);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment