//
//  NSData-BytePacking.m
//
//  Created by Philippe Hausler on 9/10/08.
//  Copyright 2008 Philippe Hausler. All rights reserved.
//

#import "NSData-BytePacking.h"
NSByteEndian NSHostEndian()
{
	if(NSHostByteOrder() == NS_LittleEndian)
	{
		return NSLittleEndian;
	}
	else if(NSHostByteOrder() == NS_BigEndian)
	{
		return NSBigEndian;
	}
	return NS_UnknownByteOrder;
}

@implementation NSString (BytePacking)
+ (id)stringWithData:(NSData *)data encoding:(NSStringEncoding)encoding
{
	return [[[NSString alloc] initWithData:data encoding:encoding] autorelease];
}
@end

@implementation NSData (BytePacking)
- (NSString *)stringUsingEncoding:(NSStringEncoding)encoding
{
	return [NSString stringWithData:self encoding:encoding];
}
- (BOOL)hasPrefix:(NSData *)data
{
	return [[self subdataWithRange:NSMakeRange(0, [data length])] isEqualToData:data];
}
- (BOOL)hasSuffix:(NSData *)data
{
	return [[self subdataWithRange:NSMakeRange([self length]-[data length]-1, [data length])] isEqualToData:data];
}
- (BOOL)hasUTF8Prefix:(NSString *)prefix
{
	return [self hasPrefix:[prefix dataUsingEncoding:NSUTF8StringEncoding]];
}
- (BOOL)hasUTF8Suffix:(NSString *)suffix
{
	return [self hasSuffix:[suffix dataUsingEncoding:NSUTF8StringEncoding]];
}
+ (NSData *)dataWithUTF8String:(NSString *)aString
{
	return [aString dataUsingEncoding:NSUTF8StringEncoding];
}
- (unsigned char)byteAtIndex:(NSUInteger)index
{
	unsigned char byte = 0x00;
	[self getBytes:&byte range:NSMakeRange(index, 1)];
	return byte;
}
- (unsigned int)uintAtIndex:(NSUInteger)index
{
	unsigned int number = 0x00;
	[self getBytes:&number range:NSMakeRange(index, sizeof(unsigned int))];
	return number;
}
- (NSData *)dataUntilTermination:(NSData *)terminator
{
	NSUInteger pos = 0;
	while(pos < [self length])
	{
		if([[self subdataWithRange:NSMakeRange(pos, [terminator length])] isEqualToData:terminator])
		{
			return [self subdataWithRange:NSMakeRange(0, pos)];
		}
		pos++;
	}
	return NULL;
}
+ (id)dataWithByte:(unsigned char)byte
{
	return [NSData dataWithBytes:&byte length:1];
}
@end

@implementation NSMutableData (BytePacking)
- (void)pad:(NSData *)pad count:(NSUInteger)count
{
	for(NSUInteger i = 0; i < count; i++)
	{
		[self appendData:pad];
	}
}
- (void)appendString:(NSString *)aString encoding:(NSStringEncoding)encoding
{
	[self appendData:[aString dataUsingEncoding:encoding]];
}
- (void)appendByte:(unsigned char)byte
{
	[self appendBytes:&byte length:1];
}
- (void)appendShort:(short)number
{
	[self appendShort:number ordered:NSSameEndian];
}
- (void)appendUShort:(unsigned short)number
{
	[self appendUShort:number ordered:NSSameEndian];
}
- (void)appendInt:(int)number
{
	[self appendInt:number ordered:NSSameEndian];
}
- (void)appendUInt:(unsigned int)number
{
	[self appendUInt:number ordered:NSSameEndian];
}
- (void)appendLong:(long)number
{
	[self appendLong:number ordered:NSSameEndian];
}
- (void)appendULong:(unsigned long)number
{
	[self appendULong:number ordered:NSSameEndian];
}
- (void)appendDouble:(double)number
{
	[self appendULong:number ordered:NSSameEndian];
}
- (void)appendLongLong:(long long)number
{
	[self appendLongLong:number ordered:NSSameEndian];
}
- (void)appendULongLong:(unsigned long long)number
{
	[self appendLongLong:number ordered:NSSameEndian];
}

- (void)appendShort:(short)number ordered:(NSByteEndian)endian
{
	switch (endian) {
		case NSLittleEndian: {
			short bytes = NSSwapHostShortToLittle((unsigned short)number);
			[self appendBytes:&bytes length:sizeof(short)];
			break;
		}
		case NSBigEndian: {
			short bytes = NSSwapHostShortToBig((unsigned short)number);
			[self appendBytes:&bytes length:sizeof(short)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(short)];
			break;
		}
	}
}
- (void)appendUShort:(unsigned short)number ordered:(NSByteEndian)endian
{
	switch (endian) {
		case NSLittleEndian: {
			unsigned short bytes = NSSwapHostShortToLittle(number);
			[self appendBytes:&bytes length:sizeof(unsigned short)];
			break;
		}
		case NSBigEndian: {
			unsigned short bytes = NSSwapHostShortToBig(number);
			[self appendBytes:&bytes length:sizeof(unsigned short)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(unsigned short)];
			break;
		}
	}
}

- (void)appendInt:(int)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			int bytes = NSSwapHostIntToLittle((unsigned int)number);
			[self appendBytes:&bytes length:sizeof(int)];
			break;
		}
		case NSBigEndian: {
			int bytes = NSSwapHostIntToBig((unsigned int)number);
			[self appendBytes:&bytes length:sizeof(int)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(int)];
			break;
		}
	}
}
- (void)appendUInt:(unsigned int)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			unsigned int bytes = NSSwapHostIntToLittle(number);
			[self appendBytes:&bytes length:sizeof(unsigned int)];
			break;
		}
		case NSBigEndian: {
			unsigned int bytes = NSSwapHostIntToBig(number);
			[self appendBytes:&bytes length:sizeof(unsigned int)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(unsigned int)];
			break;
		}
	}
}
- (void)appendLong:(long)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			long bytes = NSSwapHostLongToLittle((unsigned long)number);
			[self appendBytes:&bytes length:sizeof(long)];
			break;
		}
		case NSBigEndian: {
			long bytes = NSSwapHostLongToBig((unsigned long)number);
			[self appendBytes:&bytes length:sizeof(long)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(long)];
			break;
		}
	}
}
- (void)appendULong:(unsigned long)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			unsigned long bytes = NSSwapHostLongToLittle(number);
			[self appendBytes:&bytes length:sizeof(unsigned long)];
			break;
		}
		case NSBigEndian: {
			unsigned long bytes = NSSwapHostLongToBig(number);
			[self appendBytes:&bytes length:sizeof(unsigned long)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(unsigned long)];
			break;
		}
	}
}
- (void)appendDouble:(double)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			NSSwappedDouble bytes = NSSwapHostDoubleToLittle(number);
			[self appendBytes:&bytes length:sizeof(NSSwappedDouble)];
			break;
		}
		case NSBigEndian: {
			NSSwappedDouble bytes = NSSwapHostDoubleToBig(number);
			[self appendBytes:&bytes length:sizeof(NSSwappedDouble)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(double)];
			break;
		}
	}
}
- (void)appendLongLong:(long long)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			long long bytes = NSSwapHostLongLongToLittle((unsigned long long)number);
			[self appendBytes:&bytes length:sizeof(long long)];
			break;
		}
		case NSBigEndian: {
			long long bytes = NSSwapHostLongToBig((unsigned long long)number);
			[self appendBytes:&bytes length:sizeof(long long)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(long long)];
			break;
		}
	}
}
- (void)appendULongLong:(unsigned long long)number ordered:(NSByteEndian)endian
{
	switch(endian)
	{
		case NSLittleEndian: {
			unsigned long long bytes = NSSwapHostLongToLittle(number);
			[self appendBytes:&bytes length:sizeof(unsigned long long)];
			break;
		}
		case NSBigEndian: {
			unsigned long long bytes = NSSwapHostLongToBig(number);
			[self appendBytes:&bytes length:sizeof(unsigned long long)];
			break;
		}
		case NSSameEndian: {
			[self appendBytes:&number length:sizeof(unsigned long long)];
			break;
		}
	}
}
@end
