mpq.cpp
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:14k
源码类别:

其他游戏

开发平台:

Visual C++

  1. #include <windows.h> 
  2. #include <stdlib.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. //#include <string.h>
  7. #include <io.h>
  8. #include "mpq.h"
  9. extern int libmpq_init_buffer(MPQ_ARCHIVE *mpq_a);
  10. extern int libmpq_read_hashtable(MPQ_ARCHIVE *mpq_a);
  11. extern int libmpq_read_blocktable(MPQ_ARCHIVE *mpq_a);
  12. extern int libmpq_file_read_block(MPQ_ARCHIVE *mpq_a, MPQ_FILE *mpq_f, unsigned int blockpos, char *buffer, unsigned int blockbytes);
  13. extern int libmpq_file_read_file(MPQ_ARCHIVE *mpq_a, MPQ_FILE *mpq_f, unsigned int filepos, char *buffer, unsigned int toread);
  14. char *libmpq_version() 
  15. {
  16. static char version[10];
  17. _snprintf(version, sizeof(version), "%i.%i.%i", LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);
  18. return version;
  19. }
  20. /*
  21.  *  This function reads a file and verify if it is a legit MPQ archive
  22.  *  or not. Then it fills the MPQ_HEADER structure and reads the hash
  23.  *  table.
  24.  */
  25. int libmpq_archive_open(MPQ_ARCHIVE *mpq_a, unsigned char *MPQ_FILEname)
  26. {
  27. int fd = 0;
  28. int rb = 0;
  29. int ncnt = FALSE;
  30. struct stat fileinfo;
  31. memset((void*)mpq_a, 0, sizeof(MPQ_ARCHIVE));
  32. mpq_a->fd = -1;
  33. /* allocate memory */
  34. mpq_a->header = static_cast<MPQ_HEADER*>(malloc(sizeof(MPQ_HEADER)));
  35. memset(mpq_a->header, 0, sizeof(MPQ_HEADER));
  36. /* Check if file exists and is readable */
  37. fd = open((const char*)MPQ_FILEname, O_RDONLY|O_BINARY);
  38. if (fd == LIBMPQ_EFILE) {
  39. return LIBMPQ_EFILE;
  40. }
  41. /* fill the structures with informations */
  42. strncpy((char*)mpq_a->filename, (const char*)MPQ_FILEname, strlen((const char*)MPQ_FILEname));
  43. libmpq_init_buffer(mpq_a);
  44. mpq_a->fd               = fd;
  45. mpq_a->header->id       = 0;
  46. mpq_a->maxblockindex    = 0;
  47. mpq_a->header->offset = 0;
  48. while (!ncnt) {
  49. mpq_a->header->id = 0;
  50. _lseeki64(mpq_a->fd, mpq_a->mpqpos, SEEK_SET);
  51. rb = read(mpq_a->fd, mpq_a->header, sizeof(MPQ_HEADER));
  52. /* if different number of bytes read, break the loop */
  53. if (rb != sizeof(MPQ_HEADER)) {
  54. return LIBMPQ_EFILE_FORMAT;
  55. }
  56. /* special offset for protected MPQs */
  57. if (mpq_a->header->offset == LIBMPQ_HEADER_W3M) {
  58. mpq_a->flags |= LIBMPQ_FLAG_PROTECTED;
  59. mpq_a->header->offset = sizeof(MPQ_HEADER);
  60. }
  61. /* if valid signature has been found, break the loop */
  62. if (mpq_a->header->id == LIBMPQ_ID_MPQ && mpq_a->header->hashtablepos < mpq_a->header->archivesize && mpq_a->header->blocktablepos < mpq_a->header->archivesize) { // && mpq_a->header->offset == sizeof(MPQ_HEADER)
  63. ncnt = TRUE;
  64. }
  65. /* move to the next possible offset */
  66. if (!ncnt) {
  67. mpq_a->mpqpos += 0x200;
  68. }
  69. }
  70. if (mpq_a->header->offset != sizeof(MPQ_HEADER)) {
  71. _lseeki64(mpq_a->fd, mpq_a->header->offset, SEEK_SET);
  72. }
  73. /* get the right positions of the hash table and the block table. */
  74. mpq_a->blocksize = (0x200 << mpq_a->header->blocksize);
  75. fstat(mpq_a->fd, &fileinfo);
  76. /* Normal MPQs must have position of */
  77. if ((mpq_a->header->hashtablepos + mpq_a->mpqpos < (unsigned int)fileinfo.st_size) && (mpq_a->header->blocktablepos + mpq_a->mpqpos < (unsigned int)fileinfo.st_size)) {
  78. mpq_a->header->hashtablepos  += mpq_a->mpqpos;
  79. mpq_a->header->blocktablepos += mpq_a->mpqpos;
  80. } else {
  81. return LIBMPQ_EFILE_FORMAT;
  82. }
  83. /* Try to read and decrypt the hashtable */
  84. if (libmpq_read_hashtable(mpq_a) != 0) {
  85. return LIBMPQ_EHASHTABLE;
  86. }
  87. /* Try to read and decrypt the blocktable */
  88. if (libmpq_read_blocktable(mpq_a) != 0) {
  89. return LIBMPQ_EBLOCKTABLE;
  90. }
  91. return LIBMPQ_TOOLS_SUCCESS;
  92. }
  93. /*
  94.  *  This function closes the file descriptor opened by
  95.  *  mpq_open_archive(); and frees the decryption buffer.
  96.  */
  97. int libmpq_archive_close(MPQ_ARCHIVE *mpq_a) 
  98. {
  99. /* free the allocated memory. */
  100. if (mpq_a->blockbuf) {
  101. free(mpq_a->blockbuf);
  102. mpq_a->blockbuf = NULL;
  103. }
  104. if (mpq_a->header) {
  105. free(mpq_a->header);
  106. mpq_a->header = NULL;
  107. }
  108. if (mpq_a->hashtable) {
  109. free(mpq_a->hashtable); /* Hash table */
  110. mpq_a->hashtable = NULL;
  111. }
  112. if (mpq_a->blocktable) {
  113. free(mpq_a->blocktable); /* Block table */
  114. mpq_a->blocktable = NULL;
  115. }
  116. /* Check if file descriptor is valid. */
  117. if ((close(mpq_a->fd)) == LIBMPQ_EFILE) {
  118. return LIBMPQ_EFILE;
  119. }
  120. mpq_a->fd = -1;
  121. /* // this isn't really needed
  122. memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
  123. memset(mpq_a->filename, 0, sizeof(mpq_a->filename));
  124. */
  125. return LIBMPQ_TOOLS_SUCCESS;
  126. }
  127. /*
  128.  * This function returns the value for the given infotype.
  129.  * If an error occurs something < 0 is returned.
  130.  */
  131. int libmpq_archive_info(MPQ_ARCHIVE *mpq_a, unsigned int infotype) 
  132. {
  133. unsigned int filecount = 0;
  134. unsigned int fsize = 0;
  135. unsigned int csize = 0;
  136. MPQ_BLOCK *mpq_b_end = mpq_a->blocktable + mpq_a->header->blocktablesize;
  137. MPQ_BLOCK *mpq_b = NULL;
  138. switch (infotype) {
  139. case LIBMPQ_MPQ_ARCHIVE_SIZE:
  140. return mpq_a->header->archivesize;
  141. case LIBMPQ_MPQ_HASHTABLE_SIZE:
  142. return mpq_a->header->hashtablesize;
  143. case LIBMPQ_MPQ_BLOCKTABLE_SIZE:
  144. return mpq_a->header->blocktablesize;
  145. case LIBMPQ_MPQ_BLOCKSIZE:
  146. return mpq_a->blocksize;
  147. case LIBMPQ_MPQ_NUMFILES:
  148. for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
  149. filecount++;
  150. }
  151. return filecount;
  152. case LIBMPQ_MPQ_COMPRESSED_SIZE:
  153. for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
  154. csize += mpq_b->csize;
  155. }
  156. return csize;
  157. case LIBMPQ_MPQ_UNCOMPRESSED_SIZE:
  158. for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
  159. fsize += mpq_b->fsize;
  160. }
  161. return fsize;
  162. default:
  163. return LIBMPQ_TOOLS_SUCCESS;
  164. }
  165. }
  166. /*
  167.  * This function returns some useful file information.
  168.  */
  169. int libmpq_file_info(MPQ_ARCHIVE *mpq_a, unsigned int infotype, const int number) 
  170. {
  171. int blockindex = -1;
  172. unsigned int i = 0;
  173. MPQ_BLOCK *mpq_b = NULL;
  174. MPQ_HASH *mpq_h = NULL;
  175. /* check if given number is not out of range */
  176. if (number < 1 || (unsigned int)number > mpq_a->header->blocktablesize) {
  177. return LIBMPQ_EINV_RANGE;
  178. }
  179. /* search for correct hashtable */
  180. blockindex = number - 1;
  181. if(LIBMPQ_FILE_HASH1 == infotype || LIBMPQ_FILE_HASH2 == infotype)
  182. {
  183. for (i = 0; i < mpq_a->header->hashtablesize; i++) 
  184. {
  185. if ((number - 1) == (int)(mpq_a->hashtable[i]).blockindex) {
  186. mpq_h = &(mpq_a->hashtable[i]);
  187. break;
  188. }
  189. }
  190. if(i >= mpq_a->header->hashtablesize)
  191. return LIBMPQ_EFILE_NOT_FOUND;
  192. }
  193. if (blockindex > (int)mpq_a->header->blocktablesize) 
  194. {
  195. return LIBMPQ_EFILE_NOT_FOUND;
  196. }
  197. /* check if sizes are correct */
  198. mpq_b = mpq_a->blocktable + blockindex;
  199. if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
  200. return LIBMPQ_EFILE_CORRUPT;
  201. }
  202. /* check if file exists */
  203. if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
  204. return LIBMPQ_EFILE_NOT_FOUND;
  205. }
  206. switch (infotype) {
  207. case LIBMPQ_FILE_COMPRESSED_SIZE:
  208. return mpq_b->csize;
  209. case LIBMPQ_FILE_UNCOMPRESSED_SIZE:
  210. return mpq_b->fsize;
  211. case LIBMPQ_FILE_HASH1:
  212. return mpq_h->name1;
  213. case LIBMPQ_FILE_HASH2:
  214. return mpq_h->name2;
  215. case LIBMPQ_FILE_COMPRESSION_TYPE:
  216. if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
  217. return LIBMPQ_FILE_COMPRESS_PKWARE;
  218. }
  219. if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
  220. return LIBMPQ_FILE_COMPRESS_MULTI;
  221. }
  222. default:
  223. return LIBMPQ_TOOLS_SUCCESS;
  224. }
  225. }
  226. /*
  227.  *  This function returns the number to the given
  228.  *  filename.
  229.  */
  230. int libmpq_file_number(MPQ_ARCHIVE *mpq_a, const char *name) {
  231. int i;
  232.     unsigned int hash1, hash2;
  233.     
  234.     // Search by hash first
  235.     libmpq_hash_filename(mpq_a, (unsigned char*)name, &hash1, &hash2);
  236.     i = libmpq_file_number_from_hash(mpq_a, hash1, hash2);
  237.     if(i >= 0)
  238.         return i;
  239. /* if no matching entry found return LIBMPQ_EFILE_NOT_FOUND */
  240. return LIBMPQ_EFILE_NOT_FOUND;
  241. }
  242. /*
  243.  *  This function returns the number to the given
  244.  *  file.
  245.  */
  246. int libmpq_file_number_from_hash(MPQ_ARCHIVE *mpq_a, unsigned int hash1, unsigned int hash2) {
  247. /* search for correct hashtable */
  248. for (unsigned int i=0; i < mpq_a->header->hashtablesize; i++) {
  249. if((mpq_a->hashtable[i]).name1 == hash1 &&
  250.    (mpq_a->hashtable[i]).name2 == hash2) {
  251. return (mpq_a->hashtable[i]).blockindex + 1;
  252. }
  253. }
  254. /* if no matching entry found return LIBMPQ_EFILE_NOT_FOUND */
  255. return LIBMPQ_EFILE_NOT_FOUND;
  256. }
  257. /*
  258.  *  This function verifies if a given file (by number
  259.  *  or name) is in the opened mpq archive. On success
  260.  *  it returns 0, otherwise LIBMPQ_EFILE_NOT_FOUND.
  261.  */
  262. int libmpq_file_check(MPQ_ARCHIVE *mpq_a, void *file, int type) {
  263. int found = 0;
  264.     unsigned int hash1, hash2;
  265. switch (type) {
  266. case LIBMPQ_FILE_TYPE_INT:
  267. /* check if we are in the range of available files. */
  268. if (*(int *)file > libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) || *(int *)file < 1) {
  269. return LIBMPQ_EFILE_NOT_FOUND;
  270. } else {
  271. return LIBMPQ_TOOLS_SUCCESS;
  272. }
  273. case LIBMPQ_FILE_TYPE_CHAR:
  274.             // Search by hash
  275.             libmpq_hash_filename(mpq_a, (unsigned char*)file, &hash1, &hash2);
  276.             if(libmpq_file_number_from_hash(mpq_a, hash1, hash2)>=0)
  277.                 found = 1;
  278.             
  279. /* if a file was found return 0 */
  280. if (found == 1) {
  281. return LIBMPQ_TOOLS_SUCCESS;
  282. } else {
  283. return LIBMPQ_EFILE_NOT_FOUND;
  284. }
  285. default:
  286. return LIBMPQ_TOOLS_SUCCESS;
  287. }
  288. }
  289. #if 0
  290. /*
  291.  *  This function extracts a file from a MPQ archive
  292.  *  by the given number.
  293.  */
  294. int libmpq_file_extract(MPQ_ARCHIVE *mpq_a, const int number) {
  295. int blockindex = -1;
  296. int fd = 0;
  297. int i = 0;
  298. char buffer[0x1000];
  299. char tempfile[PATH_MAX];
  300. unsigned int transferred = 1;
  301. MPQ_FILE *mpq_f = NULL;
  302. MPQ_BLOCK *mpq_b = NULL;
  303. MPQ_HASH *mpq_h = NULL;
  304. if (number < 1 || number > mpq_a->header->blocktablesize) {
  305. return LIBMPQ_EINV_RANGE;
  306. }
  307. snprintf(tempfile, PATH_MAX, libmpq_file_name(mpq_a, number));
  308. /* check if mpq_f->filename could be written here. */
  309. fd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, 0644);
  310. if (fd == LIBMPQ_EFILE) {
  311. return LIBMPQ_EFILE;
  312. }
  313. /* search for correct hashtable */
  314. for (i = 0; i < mpq_a->header->hashtablesize; i++) {
  315. if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
  316. blockindex = (mpq_a->hashtable[i]).blockindex;
  317. mpq_h = &(mpq_a->hashtable[i]);
  318. break;
  319. }
  320. }
  321. /* check if file was found */
  322. if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
  323. return LIBMPQ_EFILE_NOT_FOUND;
  324. }
  325. /* check if sizes are correct */
  326. mpq_b = mpq_a->blocktable + blockindex;
  327. if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
  328. return LIBMPQ_EFILE_CORRUPT;
  329. }
  330. /* check if file exists */
  331. if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
  332. return LIBMPQ_EFILE_NOT_FOUND;
  333. }
  334. /* allocate memory for file structure */
  335. mpq_f = (MPQ_FILE *)malloc(sizeof(MPQ_FILE));
  336. if (!mpq_f) {
  337. return LIBMPQ_EALLOCMEM;
  338. }
  339. /* initialize file structure */
  340. memset(mpq_f, 0, sizeof(MPQ_FILE));
  341. mpq_f->fd             = fd;
  342. mpq_f->mpq_b          = mpq_b;
  343. mpq_f->nblocks        = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
  344. mpq_f->mpq_h          = mpq_h;
  345. mpq_f->accessed       = FALSE;
  346. mpq_f->blockposloaded = FALSE;
  347. snprintf((char*)mpq_f->filename, PATH_MAX, tempfile);
  348. /* allocate buffers for decompression. */
  349. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  350. /*
  351.  *  Allocate buffer for block positions. At the begin of file are stored
  352.  *  unsigned ints holding positions of each block relative from begin of
  353.  *  file in the archive.
  354.  */
  355. if ((mpq_f->blockpos = (unsigned int*)malloc(sizeof(int) * mpq_f->nblocks + 1)) == NULL) {
  356. return LIBMPQ_EALLOCMEM;
  357. }
  358. }
  359. while (transferred > 0) {
  360. transferred = libmpq_file_read_file(mpq_a, mpq_f, mpq_f->filepos, buffer, sizeof(buffer));
  361. if (transferred == 0) {
  362. break;
  363. } else {
  364. mpq_f->accessed  = TRUE;
  365. mpq_f->filepos  += transferred;
  366. }
  367. transferred = write(mpq_f->fd, buffer, transferred);
  368. if (transferred == 0) {
  369. break;
  370. }
  371. }
  372. close(fd);
  373. /* freeing the file structure */
  374. free(mpq_f);
  375. return LIBMPQ_TOOLS_SUCCESS;
  376. }
  377. #endif
  378. int libmpq_file_getdata(MPQ_ARCHIVE *mpq_a, const int number, unsigned char *dest) {
  379. int blockindex = -1;
  380. unsigned int i=0;
  381. MPQ_FILE *mpq_f = NULL;
  382. MPQ_BLOCK *mpq_b = NULL;
  383. MPQ_HASH *mpq_h = NULL;
  384.     int success = 0;
  385. if (number < 1 || (unsigned int)number > mpq_a->header->blocktablesize) {
  386. return LIBMPQ_EINV_RANGE;
  387. }
  388. /* search for correct hashtable */
  389. for (i=0; i<mpq_a->header->hashtablesize; i++) {
  390. if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
  391. blockindex = (mpq_a->hashtable[i]).blockindex;
  392. mpq_h = &(mpq_a->hashtable[i]);
  393. break;
  394. }
  395. }
  396. /* check if file was found */
  397. if (blockindex == -1 || (unsigned int)blockindex > mpq_a->header->blocktablesize) {
  398. return LIBMPQ_EFILE_NOT_FOUND;
  399. }
  400. /* check if sizes are correct */
  401. mpq_b = mpq_a->blocktable + blockindex;
  402. if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
  403. return LIBMPQ_EFILE_CORRUPT;
  404. }
  405. /* check if file exists */
  406. if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
  407. return LIBMPQ_EFILE_NOT_FOUND;
  408. }
  409. /* allocate memory for file structure */
  410. mpq_f = (MPQ_FILE*)malloc(sizeof(MPQ_FILE));
  411. if (!mpq_f) {
  412. return LIBMPQ_EALLOCMEM;
  413. }
  414. /* initialize file structure */
  415. memset(mpq_f, 0, sizeof(MPQ_FILE));
  416. mpq_f->mpq_b          = mpq_b;
  417. mpq_f->nblocks        = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
  418. mpq_f->mpq_h          = mpq_h;
  419. mpq_f->accessed       = FALSE;
  420. mpq_f->blockposloaded = FALSE;
  421. /* allocate buffers for decompression. */
  422. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  423. /*
  424.  *  Allocate buffer for block positions. At the begin of file are stored
  425.  *  unsigned ints holding positions of each block relative from begin of
  426.  *  file in the archive.
  427.  */
  428. if ((mpq_f->blockpos = (unsigned int*)malloc(sizeof(int) * (mpq_f->nblocks + 1))) == NULL) {
  429. free(mpq_f);
  430. return LIBMPQ_EALLOCMEM;
  431. }
  432. }
  433.     if(libmpq_file_read_file(mpq_a, mpq_f, 0, (char*)dest, mpq_b->fsize) == mpq_b->fsize)
  434.         success = 1;
  435.     if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  436.         // Free buffer for block positions
  437.        free(mpq_f->blockpos);
  438. }
  439. /* freeing the file structure */
  440. free(mpq_f);
  441. return success?LIBMPQ_TOOLS_SUCCESS:LIBMPQ_EFILE_CORRUPT;
  442. }