mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Implementation of [NSData rangeOfData:options:range], adapted from [NSString rangeOfString:options:range].
This commit is contained in:
parent
79f738ceb1
commit
0b69d88ee2
4 changed files with 212 additions and 0 deletions
|
@ -1,3 +1,7 @@
|
|||
2020-10-11 Adam Fox <adam.fox@eggplantsoftware.com>
|
||||
|
||||
* Source/NSData.m: Implement rangeOfData:options:range.
|
||||
|
||||
2020-08-30 Fred Kiefer <fredkiefer@gmx.de>
|
||||
|
||||
* Source/NSDateComponentsFormatter.m: Fix use of wrong operator.
|
||||
|
|
|
@ -40,6 +40,14 @@ extern "C" {
|
|||
@class NSURL;
|
||||
#endif
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6,GS_API_LATEST)
|
||||
enum {
|
||||
NSDataSearchBackwards = (1UL << 0),
|
||||
NSDataSearchAnchored = (1UL << 1),
|
||||
};
|
||||
typedef NSUInteger NSDataSearchOptions;
|
||||
#endif
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
enum {
|
||||
NSDataBase64DecodingIgnoreUnknownCharacters = (1UL << 0)
|
||||
|
@ -136,6 +144,12 @@ DEFINE_BLOCK_TYPE(GSDataDeallocatorBlock, void, void*, NSUInteger);
|
|||
range: (NSRange)aRange;
|
||||
- (NSData*) subdataWithRange: (NSRange)aRange;
|
||||
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6,GS_API_LATEST)
|
||||
- (NSRange) rangeOfData: (NSData *)dataToFind
|
||||
options: (NSDataSearchOptions)mask
|
||||
range: (NSRange)searchRange;
|
||||
#endif
|
||||
|
||||
// base64
|
||||
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9,GS_API_LATEST)
|
||||
- (NSData *) base64EncodedDataWithOptions: (NSDataBase64EncodingOptions)options;
|
||||
|
|
113
Source/NSData.m
113
Source/NSData.m
|
@ -1082,6 +1082,119 @@ failure:
|
|||
return [NSData dataWithBytesNoCopy: buffer length: aRange.length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns the range of the first occurrence of the given data, within the given range, subject to given options.
|
||||
*/
|
||||
- (NSRange) rangeOfData: (NSData *)dataToFind
|
||||
options: (NSDataSearchOptions)mask
|
||||
range: (NSRange)searchRange
|
||||
{
|
||||
NSUInteger length = [self length];
|
||||
NSUInteger countOther = [dataToFind length];
|
||||
const void* bytesSelf = [self bytes];
|
||||
const void* bytesOther = [dataToFind bytes];
|
||||
NSRange result;
|
||||
|
||||
GS_RANGE_CHECK(searchRange, length);
|
||||
if (dataToFind == nil)
|
||||
[NSException raise: NSInvalidArgumentException format: @"range of nil"];
|
||||
|
||||
/* Zero length data is always found at the start of the given range.
|
||||
*/
|
||||
if (0 == countOther)
|
||||
{
|
||||
if ((mask & NSDataSearchBackwards) == NSDataSearchBackwards)
|
||||
{
|
||||
searchRange.location += searchRange.length;
|
||||
}
|
||||
searchRange.length = 0;
|
||||
return searchRange;
|
||||
}
|
||||
|
||||
if (searchRange.length < countOther)
|
||||
{
|
||||
/* Range to search is smaller than data to look for.
|
||||
*/
|
||||
result = NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((mask & NSDataSearchAnchored) == NSDataSearchAnchored
|
||||
|| searchRange.length == countOther)
|
||||
{
|
||||
/* Range to search is same size as data to look for.
|
||||
*/
|
||||
if ((mask & NSDataSearchBackwards) == NSDataSearchBackwards)
|
||||
{
|
||||
searchRange.location = NSMaxRange(searchRange) - countOther;
|
||||
searchRange.length = countOther;
|
||||
}
|
||||
else
|
||||
{
|
||||
searchRange.length = countOther;
|
||||
}
|
||||
if (memcmp(&bytesSelf[0], &bytesOther[0], countOther) == 0)
|
||||
{
|
||||
result = searchRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Range to search is bigger than data to look for.
|
||||
*/
|
||||
|
||||
NSUInteger pos;
|
||||
NSUInteger end;
|
||||
|
||||
end = searchRange.length - countOther + 1;
|
||||
if ((mask & NSDataSearchBackwards) == NSDataSearchBackwards)
|
||||
{
|
||||
pos = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if ((mask & NSDataSearchBackwards) == NSDataSearchBackwards)
|
||||
{
|
||||
while (pos-- > 0)
|
||||
{
|
||||
if (memcmp(&bytesSelf[searchRange.location + pos], bytesOther, countOther) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pos < end)
|
||||
{
|
||||
if (memcmp(&bytesSelf[searchRange.location + pos], bytesOther, countOther) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos >= end)
|
||||
{
|
||||
result = NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NSMakeRange(searchRange.location + pos, countOther);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSData *) base64EncodedDataWithOptions: (NSDataBase64EncodingOptions)options
|
||||
{
|
||||
void *srcBytes = (void*)[self bytes];
|
||||
|
|
81
Tests/base/NSData/search.m
Normal file
81
Tests/base/NSData/search.m
Normal file
|
@ -0,0 +1,81 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "Testing.h"
|
||||
|
||||
static BOOL rangesEqual(NSRange r1, NSRange r2)
|
||||
{
|
||||
if (&r1 == &r2)
|
||||
return YES;
|
||||
|
||||
if (r1.length == 0 && r2.length == 0)
|
||||
return YES;
|
||||
|
||||
return (r1.length == r2.length && r1.location == r2.location);
|
||||
}
|
||||
|
||||
static void dataRange(char *s0, char *s1, NSDataSearchOptions opts,
|
||||
NSRange range, NSRange want)
|
||||
{
|
||||
NSData *d0 = [NSData dataWithBytes:s0 length:strlen(s0)];
|
||||
NSData *d1 = [NSData dataWithBytes:s1 length:strlen(s1)];
|
||||
|
||||
NSRange res = [d0 rangeOfData:d1 options:opts range:range];
|
||||
PASS(rangesEqual(res,want), "NSData range for '%s' and '%s' is ok",s0,s1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||
|
||||
/* Borrowed from NSString/test00.m
|
||||
*/
|
||||
dataRange("hello", "hello", NSDataSearchAnchored,
|
||||
NSMakeRange(0,5), NSMakeRange(0,5));
|
||||
dataRange("hello", "hello", NSDataSearchAnchored | NSDataSearchBackwards,
|
||||
NSMakeRange(0,5), NSMakeRange(0,5));
|
||||
dataRange("hello", "hElLo", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(NSNotFound,0));
|
||||
dataRange("hello", "hell", NSDataSearchAnchored,
|
||||
NSMakeRange(0,5), NSMakeRange(0,4));
|
||||
dataRange("hello", "hell", NSDataSearchAnchored | NSDataSearchBackwards,
|
||||
NSMakeRange(0,4), NSMakeRange(0,4));
|
||||
dataRange("hello", "ello", NSDataSearchAnchored,
|
||||
NSMakeRange(0,5), NSMakeRange(NSNotFound,0));
|
||||
dataRange("hello", "hel", NSDataSearchBackwards,
|
||||
NSMakeRange(0,5), NSMakeRange(0,3));
|
||||
dataRange("hello", "he", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(0,2));
|
||||
dataRange("hello", "h", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(0,1));
|
||||
dataRange("hello", "l", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(2,1));
|
||||
dataRange("hello", "l", NSDataSearchBackwards,
|
||||
NSMakeRange(0,5), NSMakeRange(3,1));
|
||||
dataRange("hello", "", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(0,0));
|
||||
dataRange("hello", "el", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(1,2));
|
||||
dataRange("hello", "el", 0,
|
||||
NSMakeRange(0,2), NSMakeRange(0,0));
|
||||
dataRange("hello", "el", 0,
|
||||
NSMakeRange(2,3), NSMakeRange(0,0));
|
||||
dataRange("hello", "ell", 0,
|
||||
NSMakeRange(0,5), NSMakeRange(1,3));
|
||||
dataRange("hello", "lo", 0,
|
||||
NSMakeRange(2,3), NSMakeRange(3,2));
|
||||
dataRange("boaboaboa", "abo", 0,
|
||||
NSMakeRange(0,9), NSMakeRange(2,3));
|
||||
dataRange("boaboaboa", "abo", NSDataSearchBackwards,
|
||||
NSMakeRange(0,9), NSMakeRange(5,3));
|
||||
dataRange("", "", 0,
|
||||
NSMakeRange(0,0), NSMakeRange(0,0));
|
||||
dataRange("x", "", 0,
|
||||
NSMakeRange(0,1), NSMakeRange(0,0));
|
||||
dataRange("x", "", NSDataSearchBackwards,
|
||||
NSMakeRange(0,1), NSMakeRange(1,0));
|
||||
|
||||
[arp release];
|
||||
arp = nil;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue