NBTContainer.m 9.4 KB

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