123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- //
- // NBTFile.m
- // InsideJob
- //
- // Created by Adam Preble on 10/6/10.
- // Copyright 2010 Adam Preble. All rights reserved.
- //
- // Spec for the Named Binary Tag format: http://www.minecraft.net/docs/NBT.txt
- #import "NBTContainer.h"
- #import "NSData+CocoaDevAdditions.h"
- @interface NBTContainer ()
- - (void)populateWithBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
- - (uint8_t)byteFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
- - (uint16_t)shortFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
- - (uint32_t)intFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
- - (uint64_t)longFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
- - (NSString *)stringFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
- @end
- @implementation NBTContainer
- @synthesize name, children, type;
- @synthesize stringValue, numberValue;
- - (id)init
- {
- if ((self = [super init]))
- {
- }
- return self;
- }
- - (void)dealloc
- {
- [name release];
- [children release];
- [stringValue release];
- [numberValue release];
- [super dealloc];
- }
- + (id)nbtContainerWithData:(NSData *)data;
- {
- id obj = [[[self class] alloc] init];
- [obj readFromData:data];
- return obj;
- }
- - (void)readFromData:(NSData *)data
- {
- data = [data gzipInflate];
-
- const uint8_t *bytes = (const uint8_t *)[data bytes];
-
- uint32_t offset = 0;
- [self populateWithBytes:bytes offset:&offset];
- }
- - (void)populateWithBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
- {
- uint32_t offset = *offsetPointer;
- self.type = bytes[offset];
- offset += 1;
-
- self.name = [self stringFromBytes:bytes offset:&offset];
-
- if (self.type == NBTTypeCompound)
- {
- NSLog(@">> start compound named %@", self.name);
- self.children = [NSMutableArray array];
-
- while (1)
- {
- NBTType childType = bytes[offset];
- if (childType == NBTTypeEnd)
- break;
-
- NBTContainer *child = [[NBTContainer alloc] init];
- [child populateWithBytes:bytes offset:&offset];
- [self.children addObject:child];
- [child release];
- }
- NSLog(@"<< end compound %@", self.name);
- }
- else if (self.type == NBTTypeList)
- {
- NBTType listType = bytes[offset];
- offset += 1;
- uint32_t listLength = [self intFromBytes:bytes offset:&offset];
-
- NSLog(@">> start list named %@ with type=%d length=%d", self.name, listType, listLength);
-
- self.children = [NSMutableArray array];
- while (listLength > 0)
- {
- if (listType == NBTTypeDouble)
- {
- NSNumber *num = [NSNumber numberWithDouble:(double)[self longFromBytes:bytes offset:&offset]];
- [self.children addObject:num];
- }
- else
- {
- NSLog(@"Unhandled list type: %d", self.type);
- }
- listLength--;
- }
-
- NSLog(@"<< end list %@", self.name);
- }
- else if (self.type == NBTTypeString)
- {
- self.stringValue = [self stringFromBytes:bytes offset:&offset];
- NSLog(@" name=%@ stringValue=%@", self.name, self.stringValue);
- }
- else if (self.type == NBTTypeLong)
- {
- self.numberValue = [NSNumber numberWithUnsignedLongLong:[self longFromBytes:bytes offset:&offset]];
- NSLog(@" name=%@ long value=%qu", self.name, [self.numberValue unsignedLongLongValue]);
- }
- else if (self.type == NBTTypeShort)
- {
- self.numberValue = [NSNumber numberWithUnsignedShort:[self shortFromBytes:bytes offset:&offset]];
- NSLog(@" name=%@ short value=0x%x", self.name, [self.numberValue unsignedShortValue]);
- }
- else if (self.type == NBTTypeByte)
- {
- self.numberValue = [NSNumber numberWithUnsignedChar:[self byteFromBytes:bytes offset:&offset]];
- NSLog(@" name=%@ byte value=0x%x", self.name, [self.numberValue unsignedCharValue]);
- }
- else
- {
- NSLog(@"Unhandled type: %d", self.type);
- }
-
- *offsetPointer = offset;
- }
- - (NSString *)stringFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
- {
- uint32_t offset = *offsetPointer;
- uint16_t length = (bytes[offset] << 8) | bytes[offset + 1];
- *offsetPointer += 2 + length;
- return [[[NSString alloc] initWithBytes:bytes + offset + 2 length:length encoding:NSUTF8StringEncoding] autorelease];
- }
- - (uint8_t)byteFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
- {
- uint32_t offset = *offsetPointer;
- uint8_t n = bytes[offset];
- *offsetPointer += 1;
- return n;
- }
- - (uint16_t)shortFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
- {
- uint32_t offset = *offsetPointer;
- uint16_t n = (bytes[offset + 0] << 8) | bytes[offset + 1];
- *offsetPointer += 2;
- return n;
- }
- - (uint32_t)intFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
- {
- uint32_t offset = *offsetPointer;
- uint32_t n = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3];
- *offsetPointer += 4;
- return n;
- }
- - (uint64_t)longFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
- {
- uint32_t offset = *offsetPointer;
- uint64_t n = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3];
- *offsetPointer += 4;
- n += (uint64_t)((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) << 32;
- *offsetPointer += 4;
- return n;
- }
- - (NSData *)data
- {
- NSMutableData *data = [NSMutableData data];
- uint8_t t = self.type;
- [data appendBytes:&t length:1];
- uint16_t nameLength = self.name.length;
- [data appendBytes:&nameLength length:2];
- [data appendBytes:[self.name UTF8String] length:self.name.length];
-
- return data;
- }
- @end
|