219 lines
7.4 KiB
Objective-C
219 lines
7.4 KiB
Objective-C
//
|
|
// HFByteArray.m
|
|
// HexFiend_2
|
|
//
|
|
// Copyright 2007 ridiculous_fish. All rights reserved.
|
|
//
|
|
|
|
#import <HexFiend/HFByteArray_Internal.h>
|
|
#import <HexFiend/HFFullMemoryByteSlice.h>
|
|
|
|
|
|
@implementation HFByteArray
|
|
|
|
- (instancetype)init {
|
|
if ([self class] == [HFByteArray class]) {
|
|
[NSException raise:NSInvalidArgumentException format:@"init sent to HFByteArray, but HFByteArray is an abstract class. Instantiate one of its subclasses instead, like HFBTreeByteArray."];
|
|
}
|
|
return [super init];
|
|
}
|
|
|
|
- (instancetype)initWithByteSlice:(HFByteSlice *)slice {
|
|
if(!(self = [self init])) return nil;
|
|
self = [self init];
|
|
[self insertByteSlice:slice inRange:HFRangeMake(0, 0)];
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithByteArray:(HFByteArray *)array {
|
|
if(!(self = [self init])) return nil;
|
|
NSEnumerator *e = [array byteSliceEnumerator];
|
|
HFByteSlice *slice;
|
|
while((slice = [e nextObject])) {
|
|
[self insertByteSlice:slice inRange:HFRangeMake([self length], 0)];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (NSArray *)byteSlices { UNIMPLEMENTED(); }
|
|
- (unsigned long long)length { UNIMPLEMENTED(); }
|
|
- (void)copyBytes:(unsigned char *)dst range:(HFRange)range { USE(dst); USE(range); UNIMPLEMENTED_VOID(); }
|
|
- (void)insertByteSlice:(HFByteSlice *)slice inRange:(HFRange)lrange { USE(slice); USE(lrange); UNIMPLEMENTED_VOID(); }
|
|
|
|
- (NSEnumerator *)byteSliceEnumerator {
|
|
return [[self byteSlices] objectEnumerator];
|
|
}
|
|
|
|
- (HFByteSlice *)sliceContainingByteAtIndex:(unsigned long long)offset beginningOffset:(unsigned long long *)actualOffset {
|
|
HFByteSlice *slice;
|
|
unsigned long long current = 0;
|
|
NSEnumerator *enumer = [self byteSliceEnumerator];
|
|
while ((slice = [enumer nextObject])) {
|
|
unsigned long long sum = HFSum([slice length], current);
|
|
if (sum > offset) break;
|
|
current = sum;
|
|
}
|
|
if (actualOffset) *actualOffset = current;
|
|
return slice;
|
|
}
|
|
|
|
- (void)insertByteArray:(HFByteArray*)array inRange:(HFRange)lrange {
|
|
REQUIRE_NOT_NULL(array);
|
|
HFASSERT(HFRangeIsSubrangeOfRange(lrange, HFRangeMake(0, [self length])));
|
|
#ifndef NDEBUG
|
|
unsigned long long expectedLength = [self length] - lrange.length + [array length];
|
|
#endif
|
|
[self incrementGenerationOrRaiseIfLockedForSelector:_cmd];
|
|
NSEnumerator *sliceEnumerator;
|
|
HFByteSlice *byteSlice;
|
|
if (array == self) {
|
|
/* Guard against self insertion */
|
|
sliceEnumerator = [[array byteSlices] objectEnumerator];
|
|
}
|
|
else {
|
|
sliceEnumerator = [array byteSliceEnumerator];
|
|
}
|
|
while ((byteSlice = [sliceEnumerator nextObject])) {
|
|
[self insertByteSlice:byteSlice inRange:lrange];
|
|
lrange.location += [byteSlice length];
|
|
lrange.length = 0;
|
|
}
|
|
/* If there were no slices, delete the lrange */
|
|
if (lrange.length > 0) {
|
|
[self deleteBytesInRange:lrange];
|
|
}
|
|
#ifndef NDEBUG
|
|
HFASSERT(expectedLength == [self length]);
|
|
#endif
|
|
}
|
|
|
|
- (HFByteArray *)subarrayWithRange:(HFRange)range { USE(range); UNIMPLEMENTED(); }
|
|
|
|
- (id)mutableCopyWithZone:(NSZone *)zone {
|
|
USE(zone);
|
|
return [[self subarrayWithRange:HFRangeMake(0, [self length])] retain];
|
|
}
|
|
|
|
- (id)copyWithZone:(NSZone *)zone {
|
|
USE(zone);
|
|
return [[self subarrayWithRange:HFRangeMake(0, [self length])] retain];
|
|
}
|
|
|
|
- (void)deleteBytesInRange:(HFRange)lrange {
|
|
[self incrementGenerationOrRaiseIfLockedForSelector:_cmd];
|
|
HFByteSlice* slice = [[HFFullMemoryByteSlice alloc] initWithData:[NSData data]];
|
|
[self insertByteSlice:slice inRange:lrange];
|
|
[slice release];
|
|
}
|
|
|
|
- (BOOL)isEqual:v {
|
|
REQUIRE_NOT_NULL(v);
|
|
if (self == v) return YES;
|
|
else if (! [v isKindOfClass:[HFByteArray class]]) return NO;
|
|
else {
|
|
HFByteArray* obj = v;
|
|
unsigned long long length = [self length];
|
|
if (length != [obj length]) return NO;
|
|
unsigned long long offset;
|
|
unsigned char buffer1[1024];
|
|
unsigned char buffer2[sizeof buffer1 / sizeof *buffer1];
|
|
for (offset = 0; offset < length; offset += sizeof buffer1) {
|
|
size_t amountToGrab = sizeof buffer1;
|
|
if (amountToGrab > length - offset) amountToGrab = ll2l(length - offset);
|
|
[self copyBytes:buffer1 range:HFRangeMake(offset, amountToGrab)];
|
|
[obj copyBytes:buffer2 range:HFRangeMake(offset, amountToGrab)];
|
|
if (memcmp(buffer1, buffer2, amountToGrab)) return NO;
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (unsigned long long)indexOfBytesEqualToBytes:(HFByteArray *)findBytes inRange:(HFRange)range searchingForwards:(BOOL)forwards trackingProgress:(id)progressTracker {
|
|
UNIMPLEMENTED();
|
|
}
|
|
|
|
- (BOOL)_debugIsEqual:(HFByteArray *)v {
|
|
REQUIRE_NOT_NULL(v);
|
|
if (! [v isKindOfClass:[HFByteArray class]]) return NO;
|
|
HFByteArray* obj = v;
|
|
unsigned long long length = [self length];
|
|
if (length != [obj length]) {
|
|
printf("Lengths differ: %llu versus %llu\n", length, [obj length]);
|
|
abort();
|
|
return NO;
|
|
}
|
|
|
|
unsigned long long offset;
|
|
unsigned char buffer1[1024];
|
|
unsigned char buffer2[sizeof buffer1 / sizeof *buffer1];
|
|
for (offset = 0; offset < length; offset += sizeof buffer1) {
|
|
memset(buffer1, 0, sizeof buffer1);
|
|
memset(buffer2, 0, sizeof buffer2);
|
|
size_t amountToGrab = sizeof buffer1;
|
|
if (amountToGrab > length - offset) amountToGrab = ll2l(length - offset);
|
|
[self copyBytes:buffer1 range:HFRangeMake(offset, amountToGrab)];
|
|
[obj copyBytes:buffer2 range:HFRangeMake(offset, amountToGrab)];
|
|
size_t i;
|
|
for (i=0; i < amountToGrab; i++) {
|
|
if (buffer1[i] != buffer2[i]) {
|
|
printf("Inconsistency found at %llu (%02x versus %02x)\n", i + offset, buffer1[i], buffer2[i]);
|
|
abort();
|
|
return NO;
|
|
}
|
|
}
|
|
}
|
|
return YES;
|
|
}
|
|
|
|
- (NSData *)_debugData {
|
|
NSMutableData *data = [NSMutableData dataWithLength:(NSUInteger)[self length]];
|
|
[self copyBytes:[data mutableBytes] range:HFRangeMake(0, [self length])];
|
|
return data;
|
|
}
|
|
|
|
- (BOOL)_debugIsEqualToData:(NSData *)val {
|
|
REQUIRE_NOT_NULL(val);
|
|
HFByteArray *byteArray = [[NSClassFromString(@"HFFullMemoryByteArray") alloc] init];
|
|
HFByteSlice *byteSlice = [[HFFullMemoryByteSlice alloc] initWithData:val];
|
|
[byteArray insertByteSlice:byteSlice inRange:HFRangeMake(0, 0)];
|
|
[byteSlice release];
|
|
BOOL result = [self _debugIsEqual:byteArray];
|
|
[byteArray release];
|
|
return result;
|
|
}
|
|
|
|
- (void)incrementChangeLockCounter {
|
|
[self willChangeValueForKey:@"changesAreLocked"];
|
|
if (HFAtomicIncrement(&changeLockCounter, NO) == 0) {
|
|
[NSException raise:NSInvalidArgumentException format:@"change lock counter overflow for %@", self];
|
|
}
|
|
[self didChangeValueForKey:@"changesAreLocked"];
|
|
}
|
|
|
|
- (void)decrementChangeLockCounter {
|
|
[self willChangeValueForKey:@"changesAreLocked"];
|
|
if (HFAtomicDecrement(&changeLockCounter, NO) == NSUIntegerMax) {
|
|
[NSException raise:NSInvalidArgumentException format:@"change lock counter underflow for %@", self];
|
|
}
|
|
[self didChangeValueForKey:@"changesAreLocked"];
|
|
}
|
|
|
|
- (BOOL)changesAreLocked {
|
|
return !! changeLockCounter;
|
|
}
|
|
|
|
- (NSUInteger)changeGenerationCount {
|
|
return changeGenerationCount;
|
|
}
|
|
|
|
- (void)incrementGenerationOrRaiseIfLockedForSelector:(SEL)sel {
|
|
if (changeLockCounter) {
|
|
[NSException raise:NSInvalidArgumentException format:@"Selector %@ sent to a locked byte array %@", NSStringFromSelector(sel), self];
|
|
}
|
|
else {
|
|
HFAtomicIncrement(&changeGenerationCount, YES);
|
|
}
|
|
}
|
|
|
|
@end
|