NBTContainer.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. //
  2. // NBTFile.m
  3. // InsideJob
  4. //
  5. // Created by Adam Preble on 10/6/10.
  6. // Copyright 2010 Adam Preble. All rights reserved.
  7. //
  8. // Spec for the Named Binary Tag format: http://www.minecraft.net/docs/NBT.txt
  9. #import "NBTContainer.h"
  10. #import "NSData+CocoaDevAdditions.h"
  11. @interface NBTContainer ()
  12. - (void)populateWithBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  13. - (uint8_t)byteFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  14. - (uint16_t)shortFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  15. - (uint32_t)intFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  16. - (uint64_t)longFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  17. - (NSString *)stringFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  18. @end
  19. @implementation NBTContainer
  20. @synthesize name, children, type;
  21. @synthesize stringValue, numberValue;
  22. - (id)init
  23. {
  24. if ((self = [super init]))
  25. {
  26. }
  27. return self;
  28. }
  29. - (void)dealloc
  30. {
  31. [name release];
  32. [children release];
  33. [stringValue release];
  34. [numberValue release];
  35. [super dealloc];
  36. }
  37. + (id)nbtContainerWithData:(NSData *)data;
  38. {
  39. id obj = [[[self class] alloc] init];
  40. [obj readFromData:data];
  41. return obj;
  42. }
  43. - (void)readFromData:(NSData *)data
  44. {
  45. data = [data gzipInflate];
  46. const uint8_t *bytes = (const uint8_t *)[data bytes];
  47. uint32_t offset = 0;
  48. [self populateWithBytes:bytes offset:&offset];
  49. }
  50. - (void)populateWithBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  51. {
  52. uint32_t offset = *offsetPointer;
  53. self.type = bytes[offset];
  54. offset += 1;
  55. self.name = [self stringFromBytes:bytes offset:&offset];
  56. if (self.type == NBTTypeCompound)
  57. {
  58. NSLog(@">> start compound named %@", self.name);
  59. self.children = [NSMutableArray array];
  60. while (1)
  61. {
  62. NBTType childType = bytes[offset];
  63. if (childType == NBTTypeEnd)
  64. break;
  65. NBTContainer *child = [[NBTContainer alloc] init];
  66. [child populateWithBytes:bytes offset:&offset];
  67. [self.children addObject:child];
  68. [child release];
  69. }
  70. NSLog(@"<< end compound %@", self.name);
  71. }
  72. else if (self.type == NBTTypeList)
  73. {
  74. NBTType listType = bytes[offset];
  75. offset += 1;
  76. uint32_t listLength = [self intFromBytes:bytes offset:&offset];
  77. NSLog(@">> start list named %@ with type=%d length=%d", self.name, listType, listLength);
  78. self.children = [NSMutableArray array];
  79. while (listLength > 0)
  80. {
  81. if (listType == NBTTypeDouble)
  82. {
  83. NSNumber *num = [NSNumber numberWithDouble:(double)[self longFromBytes:bytes offset:&offset]];
  84. [self.children addObject:num];
  85. }
  86. else
  87. {
  88. NSLog(@"Unhandled list type: %d", self.type);
  89. }
  90. listLength--;
  91. }
  92. NSLog(@"<< end list %@", self.name);
  93. }
  94. else if (self.type == NBTTypeString)
  95. {
  96. self.stringValue = [self stringFromBytes:bytes offset:&offset];
  97. NSLog(@" name=%@ stringValue=%@", self.name, self.stringValue);
  98. }
  99. else if (self.type == NBTTypeLong)
  100. {
  101. self.numberValue = [NSNumber numberWithUnsignedLongLong:[self longFromBytes:bytes offset:&offset]];
  102. NSLog(@" name=%@ long value=%qu", self.name, [self.numberValue unsignedLongLongValue]);
  103. }
  104. else if (self.type == NBTTypeShort)
  105. {
  106. self.numberValue = [NSNumber numberWithUnsignedShort:[self shortFromBytes:bytes offset:&offset]];
  107. NSLog(@" name=%@ short value=0x%x", self.name, [self.numberValue unsignedShortValue]);
  108. }
  109. else if (self.type == NBTTypeByte)
  110. {
  111. self.numberValue = [NSNumber numberWithUnsignedChar:[self byteFromBytes:bytes offset:&offset]];
  112. NSLog(@" name=%@ byte value=0x%x", self.name, [self.numberValue unsignedCharValue]);
  113. }
  114. else
  115. {
  116. NSLog(@"Unhandled type: %d", self.type);
  117. }
  118. *offsetPointer = offset;
  119. }
  120. - (NSString *)stringFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  121. {
  122. uint32_t offset = *offsetPointer;
  123. uint16_t length = (bytes[offset] << 8) | bytes[offset + 1];
  124. *offsetPointer += 2 + length;
  125. return [[[NSString alloc] initWithBytes:bytes + offset + 2 length:length encoding:NSUTF8StringEncoding] autorelease];
  126. }
  127. - (uint8_t)byteFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  128. {
  129. uint32_t offset = *offsetPointer;
  130. uint8_t n = bytes[offset];
  131. *offsetPointer += 1;
  132. return n;
  133. }
  134. - (uint16_t)shortFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  135. {
  136. uint32_t offset = *offsetPointer;
  137. uint16_t n = (bytes[offset + 0] << 8) | bytes[offset + 1];
  138. *offsetPointer += 2;
  139. return n;
  140. }
  141. - (uint32_t)intFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  142. {
  143. uint32_t offset = *offsetPointer;
  144. uint32_t n = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3];
  145. *offsetPointer += 4;
  146. return n;
  147. }
  148. - (uint64_t)longFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  149. {
  150. uint32_t offset = *offsetPointer;
  151. uint64_t n = (bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3];
  152. *offsetPointer += 4;
  153. n += (uint64_t)((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) << 32;
  154. *offsetPointer += 4;
  155. return n;
  156. }
  157. - (NSData *)data
  158. {
  159. NSMutableData *data = [NSMutableData data];
  160. uint8_t t = self.type;
  161. [data appendBytes:&t length:1];
  162. uint16_t nameLength = self.name.length;
  163. [data appendBytes:&nameLength length:2];
  164. [data appendBytes:[self.name UTF8String] length:self.name.length];
  165. return data;
  166. }
  167. @end