// // SoulSeekMessage.m // TesteStream // // Created by Marcelo Alves on 14/02/06 (only if it works ;) ). // // TODO : remove the "magic number" +4 (message size) #import "SoulSeekMessage.h" @implementation SoulSeekMessage -(NSData*) data { return data; } -(id) init { return [self initWithData:nil andMessageType:0]; } -(id) initWithData:(NSData *)theData { return [self initWithData:theData andMessageType:0]; } -(id) initWithData:(NSData *)theData andMessageType:(uint32_t) messageType { if (self = [super init]) { data = [[NSMutableData alloc] init]; [self appendUInt32:0]; // the length :) pos = 4; // the first 4 bytes are the length if (messageType != 0) { [self appendUInt32:messageType]; pos += sizeof(uint32_t); } if (theData) [data appendData:theData]; } return self; } -(id) dealloc { [data release]; [super dealloc]; return self; } -(SoulSeekMessage *) appendUInt32: (uint32_t) value { NSAssert(data, @"Data is NULL. Did you forgot to call init?"); uint32_t flippedValue = CFSwapInt32HostToLittle(value); [data appendBytes:&flippedValue length:sizeof(uint32_t)]; return self; } -(SoulSeekMessage *) appendString: (NSString *) value { NSAssert(data, @"Data is NULL. Did you call init first?"); const uint8_t * charArray = (const uint8_t*)[value UTF8String]; uint32_t stringLength = strlen((const char*)charArray); [self appendUInt32:stringLength]; [data appendBytes:charArray length:stringLength]; return self; } -(void *) bytes { NSAssert(data, @"Data is NULL. Did you call init first?"); // updating the first 4 bytes - Message size NSRange r = NSMakeRange(0, sizeof(uint32_t)); // remember, the message length DOES NOT count in total length uint32_t structSize = CFSwapInt32HostToLittle([data length] - sizeof(uint32_t)); [data replaceBytesInRange:r withBytes:&structSize]; return (void *)[data bytes]; } -(long) length { if (!data) return 0; return [data length]; } -(uint32_t) readUInt32 { NSAssert (pos <= [data length], @"Trying to read beyond the data..."); NSRange r = NSMakeRange(pos, sizeof(uint32_t)); uint32_t value = 0; [data getBytes:&value range:r]; pos += sizeof(uint32_t); return CFSwapInt32LittleToHost(value); } -(uint8_t) readByte { NSAssert (pos <= [data length], @"Trying to read beyond the data..."); NSRange r = NSMakeRange(pos, sizeof(uint8_t)); uint8_t value = 0; [data getBytes:&value range:r]; pos += sizeof(uint8_t); return value; } -(NSString *) readString { NSAssert (pos <= [data length], @"Trying to read beyond the data..."); uint32_t size = [self readUInt32]; if (size + pos > [data length]) { NSLog(@"Weird string, longer than the Message... truncating"); size = [data length] - pos; } NSRange r = NSMakeRange(pos, size); char *c = malloc(size + 1); // just for sure ;) c[size] = 0; [data getBytes:c range:r]; NSString *result = [[[NSString alloc] initWithUTF8String:c] autorelease]; pos += size; free(c); return result; } -(void) setPos:(long) newPos { pos = newPos + 4; NSAssert (pos <= [data length], @"Trying set cursor beyond the data..."); } -(long) pos { return pos - 4; } -(SoulSeekMessage *)compress { if (data == NULL) return self; void* dataPtr = [data mutableBytes] + 8; // starting pos to compress. Don't compress the first 8 bytes, as they are the message size and message payload long size = [data length] - 8; long maximumSize = compressBound(size); unsigned long compressedSize = maximumSize; NSMutableData * newData = [[NSMutableData alloc] initWithLength:maximumSize]; void* buffer = [newData mutableBytes]; if (compress(buffer, &compressedSize, dataPtr, size) != Z_OK) { NSLog(@"Compression failed."); } else { // copying the compressed data NSRange range = NSMakeRange(8, compressedSize); [newData setLength: compressedSize]; [data setLength: compressedSize + 8]; [data replaceBytesInRange:range withBytes: buffer]; } [newData release]; return self; } -(SoulSeekMessage *)uncompress { if (data == NULL) return self; void* dataPtr = [data mutableBytes] + 8; // starting pos to compress. Don't compress the first 8 bytes, as they are the message size and message payload unsigned long size = [data length] - 8; unsigned long maximumSize = size * 10; // some people will ask me about the "10" magic number. It's the average compression ratio :) unsigned long uncompressedSize = maximumSize; NSMutableData * newData = [[NSMutableData alloc] initWithLength:maximumSize]; void* buffer = [newData mutableBytes]; if (uncompress(buffer, &uncompressedSize, dataPtr, size) != Z_OK) { NSLog(@"Decompression failed..."); } else { // copying the compressed data NSRange range = NSMakeRange(8, uncompressedSize); [newData setLength: uncompressedSize]; [data setLength: uncompressedSize + 8]; [data replaceBytesInRange:range withBytes: buffer]; } [newData release]; return self; } @end