Created
September 24, 2011 02:21
-
-
Save watmough/1238869 to your computer and use it in GitHub Desktop.
Provide a rangeOfData:options:range: method for pre-4.0 iOS.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//-------------------------------------------------------------------------------- | |
// 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