// // HFByteArray.m // HexFiend_2 // // Copyright 2007 ridiculous_fish. All rights reserved. // #import #import @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