NBTContainer.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  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. #ifndef NBT_LOGGING
  12. #define NBT_LOGGING 0
  13. #endif
  14. #if NBT_LOGGING
  15. #define NBTLog(format, ...) NSLog(format, ##__VA_ARGS__)
  16. #else
  17. #define NBTLog(format, ...) while(0)
  18. #endif
  19. @interface NBTContainer ()
  20. - (void)populateWithBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  21. - (uint8_t)byteFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  22. - (uint16_t)shortFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  23. - (uint32_t)intFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  24. - (uint64_t)longFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  25. - (NSString *)stringFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer;
  26. - (void)appendString:(NSString *)str toData:(NSMutableData *)data;
  27. - (void)appendByte:(uint8_t)v toData:(NSMutableData *)data;
  28. - (void)appendShort:(uint16_t)v toData:(NSMutableData *)data;
  29. - (void)appendInt:(uint32_t)v toData:(NSMutableData *)data;
  30. - (void)appendLong:(uint64_t)v toData:(NSMutableData *)data;
  31. - (void)appendFloat:(float)v toData:(NSMutableData *)data;
  32. - (void)appendDouble:(double)v toData:(NSMutableData *)data;
  33. - (NSData *)data;
  34. @end
  35. @implementation NBTContainer
  36. @synthesize name, children, type;
  37. @synthesize stringValue, numberValue, listType;
  38. - (id)init
  39. {
  40. if ((self = [super init]))
  41. {
  42. }
  43. return self;
  44. }
  45. - (void)dealloc
  46. {
  47. [name release];
  48. [children release];
  49. [stringValue release];
  50. [numberValue release];
  51. [super dealloc];
  52. }
  53. + (NBTContainer *)containerWithName:(NSString *)theName type:(NBTType)theType numberValue:(NSNumber *)theNumber
  54. {
  55. NBTContainer *cont = [[[NBTContainer alloc] init] autorelease];
  56. cont.name = theName;
  57. cont.type = theType;
  58. cont.numberValue = theNumber;
  59. return cont;
  60. }
  61. + (id)nbtContainerWithData:(NSData *)data;
  62. {
  63. id obj = [[[self class] alloc] init];
  64. [obj readFromData:data];
  65. return [obj autorelease];
  66. }
  67. - (void)readFromData:(NSData *)data
  68. {
  69. data = [data gzipInflate];
  70. const uint8_t *bytes = (const uint8_t *)[data bytes];
  71. uint32_t offset = 0;
  72. [self populateWithBytes:bytes offset:&offset];
  73. }
  74. - (NSData *)writeData
  75. {
  76. return [[self data] gzipDeflate];
  77. }
  78. - (NBTContainer *)childNamed:(NSString *)theName
  79. {
  80. if (self.type != NBTTypeCompound)
  81. {
  82. NSLog(@"ERROR: Cannot find children inside a non-compound NBTContainer.");
  83. return nil;
  84. }
  85. for (NBTContainer *container in self.children)
  86. {
  87. if ([container.name isEqual:theName])
  88. return container;
  89. }
  90. return nil;
  91. }
  92. #pragma mark -
  93. #pragma mark Private I/O API
  94. - (void)populateWithBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  95. {
  96. uint32_t offset = *offsetPointer;
  97. self.type = [self byteFromBytes:bytes offset:&offset];
  98. self.name = [self stringFromBytes:bytes offset:&offset];
  99. if (self.type == NBTTypeCompound)
  100. {
  101. NBTLog(@">> start compound named %@", self.name);
  102. self.children = [NSMutableArray array];
  103. while (1)
  104. {
  105. NBTType childType = bytes[offset]; // peek
  106. if (childType == NBTTypeEnd)
  107. {
  108. offset += 1;
  109. break;
  110. }
  111. NBTContainer *child = [[NBTContainer alloc] init];
  112. [child populateWithBytes:bytes offset:&offset];
  113. [self.children addObject:child];
  114. [child release];
  115. }
  116. NBTLog(@"<< end compound %@", self.name);
  117. }
  118. else if (self.type == NBTTypeList)
  119. {
  120. listType = [self byteFromBytes:bytes offset:&offset];
  121. uint32_t listLength = [self intFromBytes:bytes offset:&offset];
  122. NBTLog(@">> start list named %@ with type=%d length=%d", self.name, listType, listLength);
  123. self.children = [NSMutableArray array];
  124. while (listLength > 0)
  125. {
  126. if (listType == NBTTypeFloat)
  127. {
  128. uint32_t i = [self intFromBytes:bytes offset:&offset];
  129. float f = *((float*)&i);
  130. NSNumber *num = [NSNumber numberWithFloat:f];
  131. [self.children addObject:num];
  132. }
  133. else if (listType == NBTTypeDouble)
  134. {
  135. uint64_t l = [self longFromBytes:bytes offset:&offset];
  136. double d = *((double*)&l);
  137. NSNumber *num = [NSNumber numberWithDouble:d];
  138. [self.children addObject:num];
  139. }
  140. else if (listType == NBTTypeCompound)
  141. {
  142. NSMutableArray *array = [NSMutableArray array];
  143. while (1)
  144. {
  145. NBTType childType = bytes[offset]; // peek
  146. if (childType == NBTTypeEnd)
  147. {
  148. offset += 1;
  149. break;
  150. }
  151. NBTContainer *child = [[NBTContainer alloc] init];
  152. [child populateWithBytes:bytes offset:&offset];
  153. [array addObject:child];
  154. [child release];
  155. }
  156. [self.children addObject:array];
  157. }
  158. else
  159. {
  160. NSLog(@"Unhandled list type: %d", listType);
  161. }
  162. listLength--;
  163. }
  164. NBTLog(@"<< end list %@", self.name);
  165. }
  166. else if (self.type == NBTTypeString)
  167. {
  168. self.stringValue = [self stringFromBytes:bytes offset:&offset];
  169. NBTLog(@" name=%@ string=%@", self.name, self.stringValue);
  170. }
  171. else if (self.type == NBTTypeLong)
  172. {
  173. self.numberValue = [NSNumber numberWithUnsignedLongLong:[self longFromBytes:bytes offset:&offset]];
  174. NBTLog(@" name=%@ long=%qu", self.name, [self.numberValue unsignedLongLongValue]);
  175. }
  176. else if (self.type == NBTTypeInt)
  177. {
  178. self.numberValue = [NSNumber numberWithUnsignedInt:[self intFromBytes:bytes offset:&offset]];
  179. NBTLog(@" name=%@ int=0x%x", self.name, [self.numberValue unsignedIntValue]);
  180. }
  181. else if (self.type == NBTTypeShort)
  182. {
  183. self.numberValue = [NSNumber numberWithUnsignedShort:[self shortFromBytes:bytes offset:&offset]];
  184. NBTLog(@" name=%@ short=0x%x", self.name, [self.numberValue unsignedShortValue]);
  185. }
  186. else if (self.type == NBTTypeByte)
  187. {
  188. self.numberValue = [NSNumber numberWithUnsignedChar:[self byteFromBytes:bytes offset:&offset]];
  189. NBTLog(@" name=%@ byte=0x%x", self.name, [self.numberValue unsignedCharValue]);
  190. }
  191. else if (self.type == NBTTypeFloat)
  192. {
  193. uint32_t i = [self intFromBytes:bytes offset:&offset];
  194. float f = *((float *)&i);
  195. self.numberValue = [NSNumber numberWithFloat:f];
  196. NBTLog(@" name=%@ float=%f", self.name, [self.numberValue floatValue]);
  197. }
  198. else
  199. {
  200. NSLog(@"Unhandled type: %d", self.type);
  201. }
  202. *offsetPointer = offset;
  203. }
  204. - (NSData *)data
  205. {
  206. NSMutableData *data = [NSMutableData data];
  207. [self appendByte:self.type toData:data];
  208. [self appendString:self.name toData:data];
  209. if (self.type == NBTTypeCompound)
  210. {
  211. for (NBTContainer *child in self.children)
  212. {
  213. [data appendData:[child data]];
  214. }
  215. uint8_t t = NBTTypeEnd;
  216. [data appendBytes:&t length:1];
  217. }
  218. else if (self.type == NBTTypeList)
  219. {
  220. [self appendByte:self.listType toData:data];
  221. [self appendInt:self.children.count toData:data];
  222. for (id item in self.children)
  223. {
  224. if (listType == NBTTypeCompound)
  225. {
  226. for (NBTContainer *i in item)
  227. {
  228. [data appendData:[i data]];
  229. }
  230. uint8_t t = NBTTypeEnd;
  231. [data appendBytes:&t length:1];
  232. }
  233. else if (listType == NBTTypeFloat)
  234. {
  235. [self appendFloat:[item floatValue] toData:data];
  236. }
  237. else if (listType == NBTTypeDouble)
  238. {
  239. [self appendDouble:[item doubleValue] toData:data];
  240. }
  241. else if (listType == NBTTypeByte)
  242. {
  243. [self appendByte:[item unsignedCharValue] toData:data];
  244. }
  245. else
  246. {
  247. NSLog(@"Unhandled list type: %d", listType);
  248. }
  249. }
  250. }
  251. else if (self.type == NBTTypeString)
  252. {
  253. [self appendString:self.stringValue toData:data];
  254. }
  255. else if (self.type == NBTTypeLong)
  256. {
  257. [self appendLong:[self.numberValue unsignedLongLongValue] toData:data];
  258. }
  259. else if (self.type == NBTTypeShort)
  260. {
  261. [self appendShort:[self.numberValue unsignedShortValue] toData:data];
  262. }
  263. else if (self.type == NBTTypeInt)
  264. {
  265. [self appendInt:[self.numberValue unsignedIntValue] toData:data];
  266. }
  267. else if (self.type == NBTTypeByte)
  268. {
  269. [self appendByte:[self.numberValue unsignedCharValue] toData:data];
  270. }
  271. else if (self.type == NBTTypeDouble)
  272. {
  273. [self appendDouble:[self.numberValue doubleValue] toData:data];
  274. }
  275. else if (self.type == NBTTypeFloat)
  276. {
  277. [self appendFloat:[self.numberValue floatValue] toData:data];
  278. }
  279. else
  280. {
  281. NSLog(@"Unhandled type: %d", self.type);
  282. }
  283. return data;
  284. }
  285. #pragma mark -
  286. #pragma mark Data Helpers
  287. - (NSString *)stringFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  288. {
  289. uint32_t offset = *offsetPointer;
  290. uint16_t length = (bytes[offset] << 8) | bytes[offset + 1];
  291. *offsetPointer += 2 + length;
  292. return [[[NSString alloc] initWithBytes:bytes + offset + 2 length:length encoding:NSUTF8StringEncoding] autorelease];
  293. }
  294. - (uint8_t)byteFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  295. {
  296. uint32_t offset = *offsetPointer;
  297. uint8_t n = bytes[offset];
  298. *offsetPointer += 1;
  299. return n;
  300. }
  301. - (uint16_t)shortFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  302. {
  303. uint32_t offset = *offsetPointer;
  304. uint16_t n = (bytes[offset + 0] << 8) | bytes[offset + 1];
  305. *offsetPointer += 2;
  306. return n;
  307. }
  308. - (uint32_t)intFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  309. {
  310. uint32_t offset = *offsetPointer;
  311. uint32_t n = ntohl(*((uint32_t *)(bytes + offset)));
  312. *offsetPointer += 4;
  313. return n;
  314. }
  315. - (uint64_t)longFromBytes:(const uint8_t *)bytes offset:(uint32_t *)offsetPointer
  316. {
  317. uint32_t offset = *offsetPointer;
  318. uint64_t n = ntohl(*((uint32_t *)(bytes + offset)));
  319. n <<= 32;
  320. offset += 4;
  321. n += ntohl(*((uint32_t *)(bytes + offset)));
  322. *offsetPointer += 8;
  323. return n;
  324. }
  325. - (void)appendString:(NSString *)str toData:(NSMutableData *)data
  326. {
  327. [self appendShort:str.length toData:data];
  328. [data appendData:[str dataUsingEncoding:NSUTF8StringEncoding]];
  329. }
  330. - (void)appendByte:(uint8_t)v toData:(NSMutableData *)data
  331. {
  332. [data appendBytes:&v length:1];
  333. }
  334. - (void)appendShort:(uint16_t)v toData:(NSMutableData *)data
  335. {
  336. v = htons(v);
  337. [data appendBytes:&v length:2];
  338. }
  339. - (void)appendInt:(uint32_t)v toData:(NSMutableData *)data
  340. {
  341. v = htonl(v);
  342. [data appendBytes:&v length:4];
  343. }
  344. - (void)appendLong:(uint64_t)v toData:(NSMutableData *)data
  345. {
  346. uint32_t v0 = htonl(v >> 32);
  347. uint32_t v1 = htonl(v);
  348. [data appendBytes:&v0 length:4];
  349. [data appendBytes:&v1 length:4];
  350. }
  351. - (void)appendFloat:(float)v toData:(NSMutableData *)data
  352. {
  353. uint32_t vi = *((uint32_t *)&v);
  354. vi = htonl(vi);
  355. [data appendBytes:&vi length:4];
  356. }
  357. - (void)appendDouble:(double)v toData:(NSMutableData *)data
  358. {
  359. uint64_t vl = *((uint64_t *)&v);
  360. uint32_t v0 = htonl(vl >> 32);
  361. uint32_t v1 = htonl(vl);
  362. [data appendBytes:&v0 length:4];
  363. [data appendBytes:&v1 length:4];
  364. }
  365. @end