Skip to content

Instantly share code, notes, and snippets.

@PsychoH13
Created August 3, 2010 23:00
Show Gist options
  • Save PsychoH13/507321 to your computer and use it in GitHub Desktop.
Save PsychoH13/507321 to your computer and use it in GitHub Desktop.
A class enabling NSData object scanning and a category enabling NSMutableData writing.
/*
NSMutableData+PSYDataWriter.h
Created by Remy "Psy" Demarest on 22/01/2012.
Copyright (c) 2012. Remy "Psy" Demarest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#import <Foundation/Foundation.h>
@interface NSMutableData (PSYDataWriter)
- (void)appendInt8:(uint8_t)value;
- (void)appendLittleEndianInt16:(uint16_t)value;
- (void)appendLittleEndianInt32:(uint32_t)value;
- (void)appendLittleEndianInt64:(uint64_t)value;
- (void)appendBigEndianInt16:(uint16_t)value;
- (void)appendBigEndianInt32:(uint32_t)value;
- (void)appendBigEndianInt64:(uint64_t)value;
// These methods append floating point values depending on the architecture of your processor
// they're usually not appropriate for network transmission
- (void)appendFloat:(float)value;
- (void)appendDouble:(double)value;
- (void)appendSwappedFloat:(float)value;
- (void)appendSwappedDouble:(double)value;
- (void)appendString:(NSString *)value usingEncoding:(NSStringEncoding)encoding;
- (void)replaceBytesInRange:(NSRange)range withData:(NSData *)value;
- (void)replaceBytesInRange:(NSRange)range withInt8:(uint8_t)value;
- (void)replaceBytesInRange:(NSRange)range withLittleEndianInt16:(uint16_t)value;
- (void)replaceBytesInRange:(NSRange)range withLittleEndianInt32:(uint32_t)value;
- (void)replaceBytesInRange:(NSRange)range withLittleEndianInt64:(uint64_t)value;
- (void)replaceBytesInRange:(NSRange)range withBigEndianInt16:(uint16_t)value;
- (void)replaceBytesInRange:(NSRange)range withBigEndianInt32:(uint32_t)value;
- (void)replaceBytesInRange:(NSRange)range withBigEndianInt64:(uint64_t)value;
// These methods append floating point values depending on the architecture of your processor
// they're usually not appropriate for network transmission
- (void)replaceBytesInRange:(NSRange)range withFloat:(float)value;
- (void)replaceBytesInRange:(NSRange)range withDouble:(double)value;
- (void)replaceBytesInRange:(NSRange)range withSwappedFloat:(float)value;
- (void)replaceBytesInRange:(NSRange)range withSwappedDouble:(double)value;
- (void)replaceBytesInRange:(NSRange)range withString:(NSString *)value usingEncoding:(NSStringEncoding)encoding;
@end
/*
NSMutableData+PSYDataWriter.m
Created by Remy "Psy" Demarest on 22/01/2012.
Copyright (c) 2012. Remy "Psy" Demarest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#import "NSMutableData+PSYDataWriter.h"
#define APPEND_METHOD(endian, size) \
- (void)append ## endian ## EndianInt ## size:(uint ## size ## _t)value \
{ \
value = CFSwapInt ## size ## HostTo ## endian(value); \
[self appendBytes:&value length:sizeof(value)]; \
}
#define REPLACE_METHOD(endian, size) \
- (void)replaceBytesInRange:(NSRange)range with ## endian ## EndianInt ## size:(uint ## size ## _t)value; \
{ \
value = CFSwapInt ## size ## HostTo ## endian(value); \
[self replaceBytesInRange:range withBytes:&value length:sizeof(value)]; \
}
@implementation NSMutableData (PSYDataWriter)
- (void)appendInt8:(uint8_t)value;
{
[self appendBytes:&value length:sizeof(value)];
}
APPEND_METHOD(Little, 16)
APPEND_METHOD(Little, 32)
APPEND_METHOD(Little, 64)
APPEND_METHOD(Big, 16)
APPEND_METHOD(Big, 32)
APPEND_METHOD(Big, 64)
- (void)appendFloat:(float)value;
{
[self appendBytes:&value length:sizeof(value)];
}
- (void)appendDouble:(double)value;
{
[self appendBytes:&value length:sizeof(value)];
}
- (void)appendSwappedFloat:(float)value;
{
CFSwappedFloat32 v = CFConvertFloatHostToSwapped(value);
[self appendBytes:&v length:sizeof(value)];
}
- (void)appendSwappedDouble:(double)value;
{
CFSwappedFloat64 v = CFConvertDoubleHostToSwapped(value);
[self appendBytes:&v length:sizeof(value)];
}
- (void)appendString:(NSString *)value usingEncoding:(NSStringEncoding)encoding;
{
[self appendData:[value dataUsingEncoding:encoding]];
}
- (void)replaceBytesInRange:(NSRange)range withData:(NSData *)value;
{
[self replaceBytesInRange:range withBytes:[value bytes] length:[value length]];
}
- (void)replaceBytesInRange:(NSRange)range withInt8:(uint8_t)value;
{
[self replaceBytesInRange:range withBytes:&value length:sizeof(value)];
}
REPLACE_METHOD(Little, 16)
REPLACE_METHOD(Little, 32)
REPLACE_METHOD(Little, 64)
REPLACE_METHOD(Big, 16)
REPLACE_METHOD(Big, 32)
REPLACE_METHOD(Big, 64)
- (void)replaceBytesInRange:(NSRange)range withFloat:(float)value;
{
[self replaceBytesInRange:range withBytes:&value length:sizeof(value)];
}
- (void)replaceBytesInRange:(NSRange)range withDouble:(double)value;
{
[self replaceBytesInRange:range withBytes:&value length:sizeof(value)];
}
- (void)replaceBytesInRange:(NSRange)range withSwappedFloat:(float)value;
{
CFSwappedFloat32 v = CFConvertFloatHostToSwapped(value);
[self replaceBytesInRange:range withBytes:&v length:sizeof(value)];
}
- (void)replaceBytesInRange:(NSRange)range withSwappedDouble:(double)value;
{
CFSwappedFloat64 v = CFConvertDoubleHostToSwapped(value);
[self replaceBytesInRange:range withBytes:&v length:sizeof(value)];
}
- (void)replaceBytesInRange:(NSRange)range withString:(NSString *)value usingEncoding:(NSStringEncoding)encoding;
{
[self replaceBytesInRange:range withData:[value dataUsingEncoding:encoding]];
}
@end
/*
PSYDataScanner.h
Created by Remy "Psy" Demarest on 20/07/2010.
Copyright (c) 2010 Remy "Psy" Demarest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#import <Foundation/Foundation.h>
typedef enum _PSYDataScannerLocation
{
PSYDataScannerLocationBegin,
PSYDataScannerLocationCurrent,
PSYDataScannerLocationEnd,
} PSYDataScannerLocation;
@interface PSYDataScanner : NSObject
{
@private
NSData *_scannedData;
NSUInteger _dataLength;
NSUInteger _scanLocation;
}
+ (id)scannerWithData:(NSData *)dataToScan;
- (id)initWithData:(NSData *)dataToScan;
@property(readonly, copy, nonatomic) NSData *data;
@property(nonatomic) NSUInteger scanLocation;
- (BOOL)isAtEnd;
// Returns NO if the computed range is outside of the range of the data
- (BOOL)setScanLocation:(NSInteger)relativeLocation relativeTo:(PSYDataScannerLocation)startPoint;
- (BOOL)scanInt8:(uint8_t *)value;
- (BOOL)scanLittleEndianInt16:(uint16_t *)value;
- (BOOL)scanLittleEndianInt32:(uint32_t *)value;
- (BOOL)scanLittleEndianInt64:(uint64_t *)value;
- (BOOL)scanBigEndianInt16:(uint16_t *)value;
- (BOOL)scanBigEndianInt32:(uint32_t *)value;
- (BOOL)scanBigEndianInt64:(uint64_t *)value;
// These methods scan floating point values depending on the architecture of your processor
// they're usually not appropriate for network transmission
- (BOOL)scanFloat:(float *)value;
- (BOOL)scanDouble:(double *)value;
- (BOOL)scanSwappedFloat:(float *)value;
- (BOOL)scanSwappedDouble:(double *)value;
- (BOOL)scanData:(NSData **)data ofLength:(NSUInteger)length;
- (BOOL)scanData:(NSData *)data intoData:(NSData **)dataValue;
- (BOOL)scanUpToData:(NSData *)stopData intoData:(NSData **)dataValue;
- (BOOL)scanString:(NSString **)value ofLength:(NSUInteger)length usingEncoding:(NSStringEncoding)encoding;
@end
/*
PSYDataScanner.m
Created by Remy "Psy" Demarest on 20/07/2010.
Copyright (c) 2010 Remy "Psy" Demarest
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#import "PSYDataScanner.h"
@implementation PSYDataScanner
@synthesize data = _scannedData, scanLocation = _scanLocation;
+ (id)scannerWithData:(NSData *)dataToScan
{
return [[[self alloc] initWithData:dataToScan] autorelease];
}
- (id)init
{
[self release];
return nil;
}
- (id)initWithData:(NSData *)dataToScan
{
if((self = [super init]))
{
_scannedData = [dataToScan copy];
_dataLength = [_scannedData length];
}
return self;
}
- (void)dealloc
{
[_scannedData release];
[super dealloc];
}
- (BOOL)setScanLocation:(NSInteger)relativeLocation relativeTo:(PSYDataScannerLocation)startPoint;
{
NSInteger computed = NSNotFound;
switch(startPoint)
{
case PSYDataScannerLocationCurrent : computed = relativeLocation + [self scanLocation]; break;
case PSYDataScannerLocationEnd : computed = _dataLength - relativeLocation; break;
case PSYDataScannerLocationBegin :
default : computed = relativeLocation; break;
}
if(computed >= 0 && computed <= _dataLength)
{
[self setScanLocation:computed];
return YES;
}
return NO;
}
- (BOOL)isAtEnd;
{
return _dataLength == _scanLocation;
}
- (BOOL)scanInt8:(uint8_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL) [_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
_scanLocation += length;
return YES;
}
- (BOOL)scanLittleEndianInt16:(uint16_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
[_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
*value = CFSwapInt16LittleToHost(*value);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanLittleEndianInt32:(uint32_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
[_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
*value = CFSwapInt32LittleToHost(*value);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanLittleEndianInt64:(uint64_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
[_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
*value = CFSwapInt64LittleToHost(*value);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanBigEndianInt16:(uint16_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
[_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
*value = CFSwapInt16BigToHost(*value);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanBigEndianInt32:(uint32_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
[_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
*value = CFSwapInt32BigToHost(*value);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanBigEndianInt64:(uint64_t *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
[_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
*value = CFSwapInt64BigToHost(*value);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanFloat:(float *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL) [_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
_scanLocation += length;
return YES;
}
- (BOOL)scanDouble:(double *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL) [_scannedData getBytes:value range:NSMakeRange(_scanLocation, length)];
_scanLocation += length;
return YES;
}
- (BOOL)scanSwappedFloat:(float *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
CFSwappedFloat32 scan;
[_scannedData getBytes:&scan range:NSMakeRange(_scanLocation, length)];
*value = CFConvertFloatSwappedToHost(scan);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanSwappedDouble:(double *)value
{
NSUInteger length = sizeof(*value);
if(_scanLocation + length > _dataLength) return NO;
if(value != NULL)
{
CFSwappedFloat64 scan;
[_scannedData getBytes:&scan range:NSMakeRange(_scanLocation, length)];
*value = CFConvertDoubleSwappedToHost(scan);
}
_scanLocation += length;
return YES;
}
- (BOOL)scanData:(NSData **)data ofLength:(NSUInteger)length
{
if(_scanLocation + length > _dataLength) return NO;
if(data != NULL) *data = [_scannedData subdataWithRange:NSMakeRange(_scanLocation, length)];
_scanLocation += length;
return YES;
}
- (BOOL)scanData:(NSData *)data intoData:(NSData **)dataValue
{
NSUInteger length = [data length];
if(_scanLocation + length > _dataLength) return NO;
if(length > 0)
{
NSData *subdata = [_scannedData subdataWithRange:NSMakeRange(_scanLocation, length)];
if([subdata isEqualToData:data])
{
if(dataValue != NULL) *dataValue = subdata;
_scanLocation += length;
return YES;
}
}
return NO;
}
- (BOOL)scanUpToData:(NSData *)stopData intoData:(NSData **)dataValue
{
NSUInteger length = [stopData length];
NSRange scannedRange = NSMakeRange(_scanLocation, 0);
if(length == 0 || _scanLocation + length > _dataLength)
scannedRange.length = _dataLength - _scanLocation;
else
{
const unsigned char *scannedBuffer = [_scannedData bytes];
const unsigned char *stopBuffer = [stopData bytes];
BOOL hasFoundData = NO;
for(NSUInteger scannedLoc = _scanLocation; scannedLoc + length <= _dataLength; scannedLoc++)
{
hasFoundData = YES;
for(NSUInteger stopLoc = 0; stopLoc < length; stopLoc++)
if(scannedBuffer[scannedLoc + stopLoc] != stopBuffer[stopLoc])
{
hasFoundData = NO;
break;
}
if(hasFoundData)
{
scannedRange.length = scannedLoc - _scanLocation;
break;
}
}
if(!hasFoundData) scannedRange.length = _dataLength - _scanLocation;
}
if(scannedRange.length == 0) return NO;
if(dataValue != NULL) *dataValue = [_scannedData subdataWithRange:scannedRange];
_scanLocation = NSMaxRange(scannedRange);
return YES;
}
- (BOOL)scanString:(NSString **)value ofLength:(NSUInteger)length usingEncoding:(NSStringEncoding)encoding
{
if(_scanLocation + length > _dataLength) return NO;
if(length > 0 && value != NULL)
{
NSData *subdata = [_scannedData subdataWithRange:NSMakeRange(_scanLocation, length)];
*value = [[[NSString alloc] initWithData:subdata encoding:encoding] autorelease];
}
_scanLocation += length;
return YES;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment