iPodArtworkDB.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. /*
  2. *
  3. *
  4. * Copyright (c) 2007 Will Fisher ([email protected])
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. The name of the author may not be used to endorse or promote products
  16. * derived from this software without specific prior permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. *
  30. *
  31. */
  32. #include "iPodArtworkDB.h"
  33. #include <algorithm>
  34. #include <strsafe.h>
  35. //utilities
  36. #define SAFEDELETE(x) {if(x) delete (x); (x)=0;}
  37. #define SAFEFREE(x) {if(x) free(x); (x)=0;}
  38. static __forceinline unsigned short rev1(const BYTE *data)
  39. {
  40. return ((unsigned short) data[0]);
  41. }
  42. static __forceinline unsigned short rev1i(const BYTE *data, int &ptr)
  43. {
  44. unsigned short ret = rev1(data+ptr);
  45. ptr+=1;
  46. return ret;
  47. }
  48. static __forceinline unsigned short rev2(const BYTE *data)
  49. {
  50. unsigned short ret;
  51. ret = ((unsigned short) data[1]) << 8;
  52. ret += ((unsigned short) data[0]);
  53. return ret;
  54. }
  55. static __forceinline unsigned short rev2i(const BYTE *data, int &ptr)
  56. {
  57. unsigned short ret = rev2(data+ptr);
  58. ptr+=2;
  59. return ret;
  60. }
  61. // get 4 bytes from data, reversed
  62. static __forceinline unsigned int rev4(const BYTE * data)
  63. {
  64. unsigned int ret;
  65. ret = ((unsigned long) data[3]) << 24;
  66. ret += ((unsigned long) data[2]) << 16;
  67. ret += ((unsigned long) data[1]) << 8;
  68. ret += ((unsigned long) data[0]);
  69. return ret;
  70. }
  71. static __forceinline unsigned int rev4i(const BYTE * data, int &ptr)
  72. {
  73. unsigned int ret = rev4(data+ptr);
  74. ptr+=4;
  75. return ret;
  76. }
  77. // get 4 bytes from data
  78. static __forceinline unsigned long get4(const unsigned char * data)
  79. {
  80. unsigned long ret;
  81. ret = ((unsigned long) data[0]) << 24;
  82. ret += ((unsigned long) data[1]) << 16;
  83. ret += ((unsigned long) data[2]) << 8;
  84. ret += ((unsigned long) data[3]);
  85. return ret;
  86. }
  87. static __forceinline unsigned long get4i(const unsigned char * data, int &ptr)
  88. {
  89. unsigned long ret = get4(data+ptr);
  90. ptr+=4;
  91. return ret;
  92. }
  93. // get 8 bytes from data
  94. static __forceinline unsigned __int64 get8(const unsigned char * data)
  95. {
  96. unsigned __int64 ret;
  97. ret = get4(data);
  98. ret = ret << 32;
  99. ret+= get4(data+4);
  100. return ret;
  101. }
  102. // get 8 bytes from data
  103. static __forceinline unsigned __int64 get8i(const unsigned char * data, int &ptr)
  104. {
  105. unsigned __int64 ret = get8(data+ptr);
  106. ptr+=8;
  107. return ret;
  108. }
  109. // reverse 8 bytes in place
  110. static __forceinline unsigned __int64 rev8(unsigned __int64 number)
  111. {
  112. unsigned __int64 ret;
  113. ret = (number&0x00000000000000FF) << 56;
  114. ret+= (number&0x000000000000FF00) << 40;
  115. ret+= (number&0x0000000000FF0000) << 24;
  116. ret+= (number&0x00000000FF000000) << 8;
  117. ret+= (number&0x000000FF00000000) >> 8;
  118. ret+= (number&0x0000FF0000000000) >> 24;
  119. ret+= (number&0x00FF000000000000) >> 40;
  120. ret+= (number&0xFF00000000000000) >> 56;
  121. return ret;
  122. }
  123. static __forceinline void putmh(const char* x, BYTE *data, int &ptr) {
  124. data[0+ptr]=x[0];
  125. data[1+ptr]=x[1];
  126. data[2+ptr]=x[2];
  127. data[3+ptr]=x[3];
  128. ptr+=4;
  129. }
  130. //write 4 bytes reversed
  131. static __forceinline void rev4(const unsigned long number, unsigned char * data)
  132. {
  133. data[3] = (unsigned char)(number >> 24) & 0xff;
  134. data[2] = (unsigned char)(number >> 16) & 0xff;
  135. data[1] = (unsigned char)(number >> 8) & 0xff;
  136. data[0] = (unsigned char)number & 0xff;
  137. }
  138. static __forceinline void rev4i(const unsigned int number, BYTE* data, int &ptr)
  139. {
  140. rev4(number,data+ptr);
  141. ptr+=4;
  142. }
  143. static __forceinline void rev2(const unsigned short number, unsigned char * data)
  144. {
  145. data[1] = (unsigned char)(number >> 8) & 0xff;
  146. data[0] = (unsigned char)number & 0xff;
  147. }
  148. static __forceinline void rev2i(const unsigned short number, BYTE* data, int &ptr)
  149. {
  150. rev2(number,data+ptr);
  151. ptr+=2;
  152. }
  153. static __forceinline void rev1(const unsigned char number, unsigned char * data)
  154. {
  155. data[0] = number;
  156. }
  157. static __forceinline void rev1i(const unsigned char number, BYTE* data, int &ptr)
  158. {
  159. rev1(number,data+ptr);
  160. ptr+=1;
  161. }
  162. // write 8 bytes normal
  163. static __forceinline void put8(unsigned __int64 number, unsigned char * data)
  164. {
  165. data[0] = (unsigned char)(number >> 56) & 0xff;
  166. data[1] = (unsigned char)(number >> 48) & 0xff;
  167. data[2] = (unsigned char)(number >> 40) & 0xff;
  168. data[3] = (unsigned char)(number >> 32) & 0xff;
  169. data[4] = (unsigned char)(number >> 24) & 0xff;
  170. data[5] = (unsigned char)(number >> 16) & 0xff;
  171. data[6] = (unsigned char)(number >> 8) & 0xff;
  172. data[7] = (unsigned char)number & 0xff;
  173. }
  174. static __forceinline void put8i(unsigned __int64 number, unsigned char * data, int &ptr) {
  175. put8(number,data+ptr);
  176. ptr+=8;
  177. }
  178. static __forceinline void pad(BYTE * data, int endpoint, int& startpoint) {
  179. if(endpoint == startpoint) return;
  180. ZeroMemory(data+startpoint, endpoint - startpoint);
  181. startpoint = endpoint;
  182. }
  183. ///////////////////////////////////////////////////////////////////////////////
  184. // ArtDB
  185. ArtDB::ArtDB() :
  186. headerlen(0x84),
  187. totallen(0),
  188. unk1(0),
  189. unk2(2),
  190. unk3(0),
  191. nextid(0x40),
  192. unk5(0),
  193. unk6(0),
  194. unk7(0),
  195. unk8(0),
  196. unk9(0),
  197. unk10(0),
  198. unk11(0),
  199. imageListDS(0),
  200. albumListDS(0),
  201. fileListDS(0)
  202. {
  203. }
  204. ArtDB::~ArtDB() {
  205. SAFEDELETE(imageListDS);
  206. SAFEDELETE(albumListDS);
  207. SAFEDELETE(fileListDS);
  208. }
  209. int ArtDB::parse(BYTE * data, int len, wchar_t drive) {
  210. int ptr=4;
  211. if(len < headerlen) return -1;
  212. if (_strnicmp((char *)data,"mhfd",4)) return -1;
  213. headerlen = rev4i(data,ptr);
  214. if(headerlen < 0x84) return -1;
  215. totallen = rev4i(data,ptr);
  216. unk1 = rev4i(data,ptr);
  217. unk2 = rev4i(data,ptr);
  218. int numchildren = rev4i(data,ptr);
  219. unk3 = rev4i(data,ptr);
  220. nextid = rev4i(data,ptr);
  221. unk5 = rev8(get8i(data,ptr));
  222. unk6 = rev8(get8i(data,ptr));
  223. unk7 = rev4i(data,ptr);
  224. unk8 = rev4i(data,ptr);
  225. unk9 = rev4i(data,ptr);
  226. unk10 = rev4i(data,ptr);
  227. unk11 = rev4i(data,ptr);
  228. ptr=headerlen;
  229. for(int i=0; i<numchildren; i++) {
  230. ArtDataSet * d = new ArtDataSet;
  231. int p = d->parse(data+ptr,len-ptr);
  232. if(p == -1) return -1;
  233. switch(d->index) {
  234. case 1: imageListDS = d; break;
  235. case 2: albumListDS = d; break;
  236. case 3: fileListDS = d; break;
  237. default: delete d;
  238. }
  239. ptr+=p;
  240. }
  241. if(!imageListDS) imageListDS = new ArtDataSet(1);
  242. if(!albumListDS) albumListDS = new ArtDataSet(2);
  243. if(!fileListDS) fileListDS = new ArtDataSet(3);
  244. for(ArtImageList::ArtImageMapIterator i = imageListDS->imageList->images.begin(); i!=imageListDS->imageList->images.end(); i++) {
  245. if(i->second) {
  246. for(auto j = i->second->dataobjs.begin(); j != i->second->dataobjs.end(); j++) {
  247. if((*j)->image) {
  248. ArtFile *f = fileListDS->fileList->getFile((*j)->image->corrid);
  249. if(!f) {
  250. f = new ArtFile();
  251. f->corrid = (*j)->image->corrid;
  252. fileListDS->fileList->files.push_back(f);
  253. }
  254. f->images.push_back(new ArtFileImage((*j)->image->ithmboffset,(*j)->image->imagesize,1));
  255. }
  256. }
  257. }
  258. }
  259. for(auto i = fileListDS->fileList->files.begin(); i!=fileListDS->fileList->files.end(); i++) {
  260. wchar_t file[MAX_PATH] = {0};
  261. StringCchPrintfW(file, MAX_PATH, L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,(*i)->corrid);
  262. (*i)->file = _wcsdup(file);
  263. (*i)->sortImages();
  264. }
  265. return totallen;
  266. }
  267. int ArtDB::write(BYTE *data, int len) {
  268. int ptr=0;
  269. if(headerlen > len) return -1;
  270. putmh("mhfd",data,ptr);
  271. rev4i(headerlen,data,ptr);
  272. rev4i(0,data,ptr); // fill total len here later
  273. rev4i(unk1,data,ptr);
  274. rev4i(unk2,data,ptr); // always seems to be "2" when iTunes writes it
  275. rev4i(3,data,ptr); // num children
  276. rev4i(unk3,data,ptr);
  277. rev4i(nextid,data,ptr);
  278. put8i(rev8(unk5),data,ptr);
  279. put8i(rev8(unk6),data,ptr);
  280. rev4i(unk7,data,ptr);
  281. rev4i(unk8,data,ptr);
  282. rev4i(unk9,data,ptr);
  283. rev4i(unk10,data,ptr);
  284. rev4i(unk11,data,ptr);
  285. pad(data,headerlen,ptr);
  286. // write out children
  287. int p;
  288. p = imageListDS->write(data+ptr,len-ptr);
  289. if(p<0) return -1;
  290. ptr+=p;
  291. p = albumListDS->write(data+ptr,len-ptr);
  292. if(p<0) return -1;
  293. ptr+=p;
  294. p = fileListDS->write(data+ptr,len-ptr);
  295. if(p<0) return -1;
  296. ptr+=p;
  297. rev4(ptr,&data[8]); // fill in total length
  298. return ptr;
  299. }
  300. void ArtDB::makeEmptyDB(wchar_t drive) {
  301. imageListDS = new ArtDataSet(1);
  302. albumListDS = new ArtDataSet(2);
  303. fileListDS = new ArtDataSet(3);
  304. for(auto i = fileListDS->fileList->files.begin(); i!=fileListDS->fileList->files.end(); i++) {
  305. wchar_t file[MAX_PATH] = {0};
  306. StringCchPrintfW(file, MAX_PATH, L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,(*i)->corrid);
  307. (*i)->file = _wcsdup(file);
  308. }
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. // ArtDatSet
  312. ArtDataSet::ArtDataSet() :
  313. headerlen(0x60),
  314. totallen(0),
  315. index(0),
  316. imageList(0),
  317. albumList(0),
  318. fileList(0)
  319. {
  320. }
  321. ArtDataSet::ArtDataSet(int idx) :
  322. headerlen(0x60),
  323. totallen(0),
  324. index(idx),
  325. imageList(0),
  326. albumList(0),
  327. fileList(0)
  328. {
  329. switch(idx) {
  330. case 1: imageList = new ArtImageList; break;
  331. case 2: albumList = new ArtAlbumList; break;
  332. case 3: fileList = new ArtFileList; break;
  333. default: index=0;
  334. }
  335. }
  336. ArtDataSet::~ArtDataSet() {
  337. SAFEDELETE(imageList);
  338. SAFEDELETE(albumList);
  339. SAFEDELETE(fileList);
  340. }
  341. int ArtDataSet::parse(BYTE *data, int len) {
  342. int ptr=4;
  343. if(len < headerlen) return -1;
  344. if (_strnicmp((char *)data,"mhsd",4)) return -1;
  345. headerlen = rev4i(data,ptr);
  346. if(headerlen < 0x60) return -1;
  347. totallen = rev4i(data,ptr);
  348. index = rev4i(data,ptr);
  349. ptr=headerlen;
  350. int p=0;
  351. switch(index) {
  352. case 1: imageList = new ArtImageList; p = imageList->parse(data+ptr, len-ptr); break;
  353. case 2: albumList = new ArtAlbumList; p = albumList->parse(data+ptr, len-ptr); break;
  354. case 3: fileList = new ArtFileList; p = fileList->parse(data+ptr, len-ptr); break;
  355. }
  356. if(p < 0) return -1;
  357. return totallen;
  358. }
  359. int ArtDataSet::write(BYTE *data, int len) {
  360. int ptr=0;
  361. if(headerlen > len) return -1;
  362. putmh("mhsd",data,ptr);
  363. rev4i(headerlen,data,ptr);
  364. rev4i(0,data,ptr); // fill total len here later
  365. rev4i(index,data,ptr);
  366. pad(data,headerlen,ptr);
  367. int p=0;
  368. switch(index) {
  369. case 1: p=imageList->write(data+ptr, len-ptr); break;
  370. case 2: p=albumList->write(data+ptr, len-ptr); break;
  371. case 3: p=fileList->write(data+ptr, len-ptr); break;
  372. }
  373. if(p<0) return -1;
  374. ptr+=p;
  375. rev4(ptr,&data[8]); // fill in total length
  376. return ptr;
  377. }
  378. ///////////////////////////////////////////////////////////////////////////////
  379. // ArtImageList
  380. ArtImageList::ArtImageList() :
  381. headerlen(0x5c)
  382. {
  383. }
  384. ArtImageList::~ArtImageList() {
  385. for(ArtImageMapIterator f = images.begin(); f != images.end(); f++)
  386. delete f->second;
  387. images.clear();
  388. }
  389. int ArtImageList::parse(BYTE *data, int len) {
  390. int ptr=4;
  391. if(len < headerlen) return -1;
  392. if (_strnicmp((char *)data,"mhli",4)) return -1;
  393. headerlen = rev4i(data,ptr);
  394. if(headerlen < 0x5c) return -1;
  395. int children = rev4i(data,ptr);
  396. ptr=headerlen;
  397. for(int i=0; i<children; i++) {
  398. ArtImage * f = new ArtImage;
  399. int p = f->parse(data+ptr,len-ptr);
  400. if(p<0) {delete f; return -1;}
  401. ptr+=p;
  402. images.insert(ArtImageMapPair(f->songid,f));
  403. }
  404. return ptr;
  405. }
  406. int ArtImageList::write(BYTE *data, int len) {
  407. int ptr=0;
  408. if(headerlen > len) return -1;
  409. putmh("mhli",data,ptr);
  410. rev4i(headerlen,data,ptr);
  411. rev4i(images.size(),data,ptr);
  412. pad(data,headerlen,ptr);
  413. for(ArtImageMapIterator f = images.begin(); f != images.end(); f++) {
  414. int p = f->second->write(data+ptr,len-ptr);
  415. if(p<0) return -1;
  416. ptr+=p;
  417. }
  418. return ptr;
  419. }
  420. ///////////////////////////////////////////////////////////////////////////////
  421. // ArtImage
  422. ArtImage::ArtImage() :
  423. headerlen(0x98),
  424. totallen(0),
  425. id(0),
  426. songid(0),
  427. unk4(0),
  428. rating(0),
  429. unk6(0),
  430. originalDate(0),
  431. digitizedDate(0),
  432. srcImageSize(0)
  433. {
  434. }
  435. ArtImage::~ArtImage()
  436. {
  437. for (auto obj : dataobjs)
  438. {
  439. delete obj;
  440. }
  441. dataobjs.clear();
  442. }
  443. int ArtImage::parse(BYTE *data, int len) {
  444. int ptr=4;
  445. if(len < headerlen) return -1;
  446. if (_strnicmp((char *)data,"mhii",4)) return -1;
  447. headerlen = rev4i(data,ptr);
  448. if(headerlen < 0x98) return -1;
  449. totallen = rev4i(data,ptr);
  450. int numchildren = rev4i(data,ptr);
  451. id = rev4i(data,ptr);
  452. songid = rev8(get8i(data,ptr));
  453. unk4 = rev4i(data,ptr);
  454. rating = rev4i(data,ptr);
  455. unk6 = rev4i(data,ptr);
  456. originalDate = rev4i(data,ptr);
  457. digitizedDate = rev4i(data,ptr);
  458. srcImageSize = rev4i(data,ptr);
  459. ptr = headerlen;
  460. for(int i=0; i<numchildren; i++) {
  461. ArtDataObject *d = new ArtDataObject;
  462. int p = d->parse(data+ptr,len-ptr);
  463. if(p<0) { delete d; return -1; }
  464. ptr+=p;
  465. // fuck with d. ugh.
  466. if((d->type == 2 || d->type == 5) && d->data) { // this is a container mhod
  467. d->image = new ArtImageName;
  468. int p2 = d->image->parse(d->data,d->datalen);
  469. if(p2>0) {
  470. SAFEFREE(d->data);
  471. d->datalen=0;
  472. } else SAFEDELETE(d->image);
  473. }
  474. dataobjs.push_back(d);
  475. }
  476. return totallen;
  477. }
  478. template<class T>
  479. BYTE *expandMemWrite(T * x, int &len, int maxsize=1024000) {
  480. int s = 1024;
  481. for(;;) {
  482. BYTE *r = (BYTE*)malloc(s);
  483. int p = x->write(r,s);
  484. if(p>0) {
  485. len=p;
  486. return r;
  487. }
  488. free(r);
  489. s = s+s;
  490. if(s > maxsize) break;
  491. }
  492. return NULL;
  493. }
  494. int ArtImage::write(BYTE *data, int len) {
  495. int ptr=0;
  496. if(headerlen > len) return -1;
  497. putmh("mhii",data,ptr);
  498. rev4i(headerlen,data,ptr);
  499. rev4i(0,data,ptr); // fill in total length later
  500. rev4i(dataobjs.size(),data,ptr);
  501. rev4i(id,data,ptr);
  502. put8i(rev8(songid),data,ptr);
  503. rev4i(unk4,data,ptr);
  504. rev4i(rating,data,ptr);
  505. rev4i(unk6,data,ptr);
  506. rev4i(originalDate,data,ptr);
  507. rev4i(digitizedDate,data,ptr);
  508. rev4i(srcImageSize,data,ptr);
  509. pad(data,headerlen,ptr);
  510. for(auto f = dataobjs.begin(); f != dataobjs.end(); f++) {
  511. if((*f)->image) {
  512. int len=0;
  513. BYTE *b = expandMemWrite((*f)->image,len);
  514. if(!b) return -1;
  515. (*f)->data = b;
  516. (*f)->datalen = len;
  517. }
  518. int p = (*f)->write(data+ptr,len-ptr);
  519. if((*f)->image) {
  520. SAFEFREE((*f)->data);
  521. (*f)->datalen=0;
  522. }
  523. if(p<0) return -1;
  524. ptr+=p;
  525. }
  526. rev4(ptr,&data[8]); // fill in total length
  527. return ptr;
  528. }
  529. ///////////////////////////////////////////////////////////////////////////////
  530. // ArtDataObj
  531. ArtDataObject::ArtDataObject() :
  532. headerlen(0x18),
  533. type(0),
  534. data(0),
  535. datalen(0),
  536. image(0),
  537. unk1(0)
  538. {
  539. }
  540. ArtDataObject::~ArtDataObject() {
  541. SAFEDELETE(image);
  542. SAFEFREE(data);
  543. }
  544. int ArtDataObject::parse(BYTE *data, int len) {
  545. int ptr=4;
  546. if(len < headerlen) return -1;
  547. if (_strnicmp((char *)data,"mhod",4)) return -1;
  548. headerlen = rev4i(data,ptr);
  549. if(headerlen < 0x18) return -1;
  550. int totallen = rev4i(data,ptr);
  551. if(len < totallen) return -1;
  552. type = rev2i(data,ptr);
  553. unk1 = (unsigned char)rev1i(data,ptr);
  554. short padding = rev1i(data,ptr);
  555. ptr = headerlen;
  556. if(type == 3 && rev2(&data[totallen-2]) == 0)
  557. datalen = wcslen((wchar_t*)(data+ptr+12))*sizeof(wchar_t) + 12;
  558. else
  559. datalen = totallen - headerlen - padding;
  560. if(datalen > 0x400 || datalen < 0) return -1;
  561. this->data = (BYTE*)malloc(datalen);
  562. memcpy(this->data,data+ptr,datalen);
  563. return totallen;
  564. }
  565. int ArtDataObject::write(BYTE *data, int len) {
  566. int ptr=0;
  567. if(headerlen > len) return -1;
  568. putmh("mhod",data,ptr);
  569. rev4i(headerlen,data,ptr);
  570. short padding = (4 - ((headerlen + datalen) % 4));// % 4;
  571. if(padding == 4) padding = 0;
  572. rev4i(headerlen+datalen+padding,data,ptr);
  573. rev2i(type,data,ptr);
  574. rev1i(unk1,data,ptr);
  575. rev1i((unsigned char)padding,data,ptr);
  576. pad(data,headerlen,ptr);
  577. //write data
  578. memcpy(data+ptr,this->data,datalen);
  579. ptr+=datalen;
  580. //add padding...
  581. pad(data,ptr+padding,ptr);
  582. return ptr;
  583. }
  584. void ArtDataObject::GetString(wchar_t * str, int len) {
  585. if(rev4(data+4) != 2) { str[0]=0; return; }//not utf-16!
  586. int l = (rev4(data)/sizeof(wchar_t));
  587. StringCchCopyN(str, len, (wchar_t*)&data[12], l);
  588. //lstrcpyn(str,(wchar_t*)&data[12],min(l,len));
  589. }
  590. void ArtDataObject::SetString(wchar_t * str) {
  591. SAFEFREE(data);
  592. datalen = wcslen(str)*sizeof(wchar_t) + 12;
  593. data = (BYTE*)malloc(datalen);
  594. rev4(wcslen(str)*sizeof(wchar_t),data);
  595. rev4(2,data+4); //type 2 means utf-16
  596. rev4(0,data+8); //unk
  597. memcpy(data+12,str,wcslen(str)*sizeof(wchar_t));
  598. }
  599. ///////////////////////////////////////////////////////////////////////////////
  600. // ArtImageName
  601. ArtImageName::ArtImageName() :
  602. headerlen(0x4c),
  603. totallen(0),
  604. corrid(0),
  605. ithmboffset(0),
  606. imagesize(0),
  607. vpad(0),
  608. hpad(0),
  609. imgh(0),
  610. imgw(0),
  611. filename(0)
  612. {
  613. }
  614. ArtImageName::~ArtImageName() {
  615. SAFEDELETE(filename);
  616. }
  617. int ArtImageName::parse(BYTE *data, int len) {
  618. int ptr=4;
  619. if(len < headerlen) return -1;
  620. if (_strnicmp((char *)data,"mhni",4)) return -1;
  621. headerlen = rev4i(data,ptr);
  622. if(headerlen < 0x4c) return -1;
  623. totallen = rev4i(data,ptr);
  624. int children = rev4i(data,ptr);
  625. corrid = rev4i(data,ptr);
  626. ithmboffset = rev4i(data,ptr);
  627. imagesize = rev4i(data,ptr);
  628. vpad = (short)rev2i(data,ptr);
  629. hpad = (short)rev2i(data,ptr);
  630. imgw = rev2i(data,ptr);
  631. imgh = rev2i(data,ptr);
  632. ptr = headerlen;
  633. if(children) {
  634. filename = new ArtDataObject();
  635. int p = filename->parse(data+ptr,len-ptr);
  636. if(p<0) SAFEDELETE(filename);
  637. }
  638. return totallen;
  639. }
  640. int ArtImageName::write(BYTE *data, int len) {
  641. int ptr=0;
  642. if(headerlen > len) return -1;
  643. putmh("mhni",data,ptr);
  644. rev4i(headerlen,data,ptr);
  645. rev4i(0,data,ptr); // fill in totallen later
  646. rev4i(filename?1:0,data,ptr); //num children
  647. rev4i(corrid,data,ptr);
  648. rev4i(ithmboffset,data,ptr);
  649. rev4i(imagesize,data,ptr);
  650. rev2i(vpad,data,ptr);
  651. rev2i(hpad,data,ptr);
  652. rev2i(imgw,data,ptr);
  653. rev2i(imgh,data,ptr);
  654. pad(data,headerlen,ptr);
  655. if(filename) {
  656. int p = filename->write(data+ptr,len-ptr);
  657. if(p<0) return -1;
  658. ptr+=p;
  659. }
  660. rev4(ptr,&data[8]); // fill in totallen
  661. return ptr;
  662. }
  663. ///////////////////////////////////////////////////////////////////////////////
  664. // ArtAlbumList
  665. ArtAlbumList::ArtAlbumList() :
  666. headerlen(0x5c)
  667. {
  668. }
  669. ArtAlbumList::~ArtAlbumList() {}
  670. int ArtAlbumList::parse(BYTE *data, int len) {
  671. int ptr=4;
  672. if(len < headerlen) return -1;
  673. if (_strnicmp((char *)data,"mhla",4)) return -1;
  674. headerlen = rev4i(data,ptr);
  675. if(headerlen < 0x5c) return -1;
  676. int children = rev4i(data,ptr);
  677. if(children != 0) return -1;
  678. return headerlen;
  679. }
  680. int ArtAlbumList::write(BYTE *data, int len) {
  681. int ptr=0;
  682. if(headerlen > len) return -1;
  683. putmh("mhla",data,ptr);
  684. rev4i(headerlen,data,ptr);
  685. rev4i(0,data,ptr); // num children
  686. pad(data,headerlen,ptr);
  687. return ptr;
  688. }
  689. ///////////////////////////////////////////////////////////////////////////////
  690. // ArtFileList
  691. ArtFileList::ArtFileList() :
  692. headerlen(0x5c)
  693. {
  694. }
  695. ArtFileList::~ArtFileList()
  696. {
  697. for (auto file : files)
  698. {
  699. delete file;
  700. }
  701. files.clear();
  702. }
  703. int ArtFileList::parse(BYTE *data, int len) {
  704. int ptr=4;
  705. if(len < headerlen) return -1;
  706. if (_strnicmp((char *)data,"mhlf",4)) return -1;
  707. headerlen = rev4i(data,ptr);
  708. if(headerlen < 0x5c) return -1;
  709. int children = rev4i(data,ptr);
  710. ptr = headerlen;
  711. for(int i=0; i<children; i++) {
  712. ArtFile * f = new ArtFile;
  713. int p = f->parse(data+ptr,len-ptr);
  714. if(p<0) { delete f; return -1; }
  715. ptr+=p;
  716. files.push_back(f);
  717. }
  718. return ptr;
  719. }
  720. int ArtFileList::write(BYTE *data, int len) {
  721. int ptr=0;
  722. if(headerlen > len) return -1;
  723. putmh("mhlf",data,ptr);
  724. rev4i(headerlen,data,ptr);
  725. rev4i(files.size(),data,ptr); // num children
  726. pad(data,headerlen,ptr);
  727. for(auto f = files.begin(); f != files.end(); f++) {
  728. int p = (*f)->write(data+ptr,len-ptr);
  729. if(p<0) return -1;
  730. ptr+=p;
  731. }
  732. return ptr;
  733. }
  734. ArtFile * ArtFileList::getFile(int corrid) {
  735. for(auto i = files.begin(); i!=files.end(); i++) {
  736. if((*i)->corrid == corrid) return *i;
  737. }
  738. return NULL;
  739. }
  740. ///////////////////////////////////////////////////////////////////////////////
  741. // ArtFile
  742. ArtFile::ArtFile() :
  743. headerlen(0x7c),
  744. corrid(0),
  745. imagesize(0),
  746. file(0)
  747. {
  748. }
  749. ArtFile::~ArtFile() {
  750. SAFEFREE(file);
  751. }
  752. int ArtFile::parse(BYTE *data, int len) {
  753. int ptr=4;
  754. if(len < headerlen) return -1;
  755. if (_strnicmp((char *)data,"mhif",4)) return -1;
  756. headerlen = rev4i(data,ptr);
  757. if(headerlen < 0x7c) return -1;
  758. int totallen = rev4i(data,ptr);
  759. rev4i(data,ptr); // might not be numchildren, it's really unk1
  760. corrid = rev4i(data,ptr);
  761. imagesize = rev4i(data,ptr);
  762. return totallen;
  763. }
  764. int ArtFile::write(BYTE *data, int len) {
  765. int ptr=0;
  766. if(headerlen > len) return -1;
  767. putmh("mhif",data,ptr);
  768. rev4i(headerlen,data,ptr);
  769. rev4i(0,data,ptr); // total len, fill in later
  770. rev4i(0,data,ptr); // numchildren/unk1
  771. rev4i(corrid,data,ptr);
  772. rev4i(imagesize,data,ptr);
  773. pad(data,headerlen,ptr);
  774. // write children, if we had any...
  775. rev4(ptr,&data[8]); // fill in total len
  776. return ptr;
  777. }
  778. struct ArtFileImageSort {
  779. bool operator()(ArtFileImage*& ap,ArtFileImage*& bp) {
  780. return ap->start < bp->start;
  781. }
  782. };
  783. void ArtFile::sortImages() {
  784. std::sort(images.begin(),images.end(),ArtFileImageSort());
  785. for(size_t i = 1; i != images.size(); i++)
  786. {
  787. if(images[i]->start == images[i-1]->start)
  788. {
  789. images.erase(images.begin() + i);
  790. i--;
  791. images[i]->refcount++;
  792. }
  793. }
  794. }
  795. size_t ArtFile::getNextHole(size_t size) {
  796. size_t s=0;
  797. for(auto i = images.begin(); i!=images.end(); i++) {
  798. if((*i)->start - s >= size) return s;
  799. s = (*i)->start + (*i)->len;
  800. }
  801. return s;
  802. }
  803. bool writeDataToThumb(wchar_t *file, unsigned short * data, int len) {
  804. FILE * f = _wfopen(file,L"ab");
  805. if(!f) return false;
  806. fwrite(data,len,sizeof(short),f);
  807. fclose(f);
  808. return true;
  809. }