Skip to content

Instantly share code, notes, and snippets.

@watmough
Created September 24, 2011 02:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save watmough/1238869 to your computer and use it in GitHub Desktop.
Save watmough/1238869 to your computer and use it in GitHub Desktop.
Provide a rangeOfData:options:range: method for pre-4.0 iOS.
//--------------------------------------------------------------------------------
// NSData+JWUtil
// Provide a rangeOfData:options:range: method for pre-4.0 iOS.
//--------------------------------------------------------------------------------
@interface NSData (JWUtil)
- (NSRange)rangeOfDataX:(NSData *)dataToFind options:(NSDataSearchOptions)mask range:(NSRange)searchRange;
@end
//--------------------------------------------------------------------------------
// NSData+JWUtil
// Provide a rangeOfData:options:range: method for pre-4.0 iOS.
//
// Notes:
// 1) [strike]Uses strnstr() to fake it.[/strike]
// Now uses a hand-written piece of code to string search
// 2) Tested uploading a 1MB png file & various text files.
//
// Contraindications:
// 1) does not support NSDataSearchBackwards
//--------------------------------------------------------------------------------
@implementation NSData (JWUtil)
- (NSRange)rangeOfDataX:(NSData *)dataToFind options:(NSDataSearchOptions)mask range:(NSRange)searchRange
{
NSRange notFound = {NSNotFound,0};
// use native call if available
if ([self respondsToSelector:@selector(rangeOfData:options:range:)]) {
return [self rangeOfData:dataToFind options:mask range:searchRange];
}
// assert if called with backwards flag
NSAssert((mask&/*NSDataSearchBackwards*/1)==0,
@"NSDataSearchBackwards is not supported");
// assert if a >0 location is specified for an anchored search
NSAssert(searchRange.location==0||(mask&/*NSDataSearchAnchored*/2)==0,
@"NSDataAnchoredSearch means searchRange must start at 0.");
// assert on bad search range
NSAssert(searchRange.location+searchRange.length<=[self length],
@"searchRange must be within receiver");
// short circuit if data to find + start of range is longer than data to search
if (searchRange.location + [dataToFind length]>[self length]) {
return notFound;
}
// get a zero-terminated string to search
NSInteger s2size = [dataToFind length];
char * s2 = malloc(s2size+1);
NSAssert(s2!=NULL,@"Copying search string failed to allocate memory.");
*(s2+s2size) = 0;
strncpy(s2,[dataToFind bytes],s2size);
// get position and length to search
NSInteger p = searchRange.location;
NSInteger n = [self length] - p;
const char * s1 = [self bytes] + p;
// // do the search - this doesn't work for zeroes in the string to be searched
// const char * found = strnstr(s1, s2, n);
// implement a sort of memnmem()
const char * s = s1;
const char * found = NULL;
while (1) {
// find first character of search string
while (*s++!=*s2 && s-s1<n)
{};
// check if we have the whole string
const char * u = s-1;
const char * v = s2;
while (*u++==*v++ && u-s1<n && v-s2<s2size )
{};
// did we get it?
if (v-s2==s2size) {
found = s-1;
break;
}
// done?
if (u-s1>n)
break;
}
// free our zero-terminated copy
free(s2);
// not found?
if (found==NULL) {
return notFound;
}
// build appropriate range, relative to receiver
NSRange foundRange;
foundRange.location = found-s1+p;
foundRange.length = s2size;
return foundRange;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment