NBTContainer.m 10.0 KB

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