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

其他游戏

开发平台:

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. int libmpq_decrypt_block(MPQ_ARCHIVE *mpq_a, unsigned int *block, unsigned int length, unsigned int seed1) 
  10. {
  11. unsigned int seed2 = 0xEEEEEEEE;
  12. unsigned int ch;
  13. /* Round to unsigned int's */
  14. length >>= 2;
  15. while (length-- > 0) {
  16. seed2    += mpq_a->buf[0x400 + (seed1 & 0xFF)];
  17. ch        = *block ^ (seed1 + seed2);
  18. seed1     = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
  19. seed2     = ch + seed2 + (seed2 << 5) + 3;
  20. *block++  = ch;
  21. }
  22. return LIBMPQ_TOOLS_SUCCESS;
  23. }
  24. /*
  25.  *  This function hashes a string to a hash code.
  26.  *  *o1 and *o2 will contain the resulting values.
  27.  * type 1 and 2 are used for hashing filenames, type 3 for hashing the key that encrypts the hash table,
  28.  * and type 4 for encrypting the actual data.
  29.  */
  30. unsigned int libmpq_hash_string(MPQ_ARCHIVE *mpq_a, unsigned int type, const unsigned char *pbKey) {
  31. unsigned int seed1 = 0x7FED7FED;
  32. unsigned int seed2 = 0xEEEEEEEE;
  33. unsigned int ch; /* One key character */
  34. /* Prepare seeds */
  35. while (*pbKey != 0) {
  36. ch = toupper(*pbKey++);
  37. seed1 = mpq_a->buf[(type<<8) + ch] ^ (seed1 + seed2);
  38. seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
  39. }
  40. return seed1;
  41. }
  42. /*
  43.  *  This function decrypts the hashtable for the
  44.  *  file informations.
  45.  */
  46. int libmpq_decrypt_hashtable(MPQ_ARCHIVE *mpq_a, unsigned char *pbKey) {
  47. unsigned int seed1, seed2;
  48.     unsigned int ch; /* One key character */
  49. unsigned int *pdwTable = (unsigned int *)(mpq_a->hashtable);
  50. unsigned int length = mpq_a->header->hashtablesize * 4;
  51. /* Decrypt it */
  52.     seed1 = libmpq_hash_string(mpq_a, 3, pbKey);
  53. seed2 = 0xEEEEEEEE;
  54. while (length-- > 0) {
  55. seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
  56. ch     = *pdwTable ^ (seed1 + seed2);
  57. seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
  58. seed2  = ch + seed2 + (seed2 << 5) + 3;
  59. *pdwTable++ = ch;
  60. }
  61. return LIBMPQ_TOOLS_SUCCESS;
  62. }
  63. /*
  64.  *  This function hashes a filename to a hash code.
  65.  *  *o1 and *o2 will contain the resulting values.
  66.  */
  67. int libmpq_hash_filename(MPQ_ARCHIVE *mpq_a, const unsigned char *pbKey, unsigned int *o1, unsigned int *o2) {
  68. //unsigned int seed1, seed2, seed3, seed4;
  69. *o1 = libmpq_hash_string(mpq_a, 1, pbKey);
  70. *o2 = libmpq_hash_string(mpq_a, 2, pbKey);
  71. return LIBMPQ_TOOLS_SUCCESS;
  72. }
  73. /*
  74.  *  This function decrypts the blocktable.
  75.  */
  76. int libmpq_decrypt_blocktable(MPQ_ARCHIVE *mpq_a, unsigned char *pbKey) {
  77. unsigned int seed1, seed2;
  78. unsigned int ch; /* One key character */
  79. unsigned int *pdwTable = (unsigned int *)(mpq_a->blocktable);
  80. unsigned int length = mpq_a->header->blocktablesize * 4;
  81. /* Decrypt it */
  82.     seed1 = libmpq_hash_string(mpq_a, 3, pbKey);
  83. seed2 = 0xEEEEEEEE;
  84. while(length-- > 0) {
  85. seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
  86. ch     = *pdwTable ^ (seed1 + seed2);
  87. seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
  88. seed2  = ch + seed2 + (seed2 << 5) + 3;
  89. *pdwTable++ = ch;
  90. }
  91. return LIBMPQ_TOOLS_SUCCESS;
  92. }
  93. /*
  94.  *  This functions tries to get file decryption key. The trick comes from block
  95.  *  positions which are stored at the begin of each compressed file. We know the
  96.  *  file size, that means we know number of blocks that means we know the first
  97.  *  int value in block position. And if we know encrypted and decrypted value,
  98.  *  we can find the decryption key.
  99.  */
  100. int libmpq_detect_fileseed(MPQ_ARCHIVE *mpq_a, unsigned int *block, unsigned int decrypted) {
  101. unsigned int saveseed1;
  102. unsigned int temp = *block ^ decrypted; /* temp = seed1 + seed2 */
  103. int i = 0;
  104. temp -= 0xEEEEEEEE; /* temp = seed1 + mpq_a->buf[0x400 + (seed1 & 0xFF)] */
  105. for (i = 0; i < 0x100; i++) { /* Try all 255 possibilities */
  106. unsigned int seed1;
  107. unsigned int seed2 = 0xEEEEEEEE;
  108. unsigned int ch;
  109. /* Try the first unsigned int's (We exactly know the value) */
  110. seed1  = temp - mpq_a->buf[0x400 + i];
  111. seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
  112. ch     = block[0] ^ (seed1 + seed2);
  113. if (ch != decrypted) {
  114. continue;
  115. }
  116. /* Add 1 because we are decrypting block positions */
  117. saveseed1 = seed1 + 1;
  118. /*
  119.  *  If OK, continue and test the second value. We don't know exactly the value,
  120.  *  but we know that the second one has lower 16 bits set to zero
  121.  *  (no compressed block is larger than 0xFFFF bytes)
  122.  */
  123. seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
  124. seed2  = ch + seed2 + (seed2 << 5) + 3;
  125. seed2 += mpq_a->buf[0x400 + (seed1 & 0xFF)];
  126. ch     = block[1] ^ (seed1 + seed2);
  127. if ((ch & 0xFFFF0000) == 0) {
  128. return saveseed1;
  129. }
  130. }
  131. return LIBMPQ_TOOLS_SUCCESS;
  132. }
  133. /*
  134.  *  This function initialize the decryption buffer
  135.  */
  136. int libmpq_init_buffer(MPQ_ARCHIVE *mpq_a) {
  137. unsigned int seed   = 0x00100001;
  138. unsigned int index1 = 0;
  139. unsigned int index2 = 0;
  140. int i;
  141. memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
  142. /* Initialize the decryption buffer. */
  143. for (index1 = 0; index1 < 0x100; index1++) {
  144. for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) {
  145. unsigned int temp1, temp2;
  146. seed  = (seed * 125 + 3) % 0x2AAAAB;
  147. temp1 = (seed & 0xFFFF) << 0x10;
  148. seed  = (seed * 125 + 3) % 0x2AAAAB;
  149. temp2 = (seed & 0xFFFF);
  150. mpq_a->buf[index2] = (temp1 | temp2);
  151. }
  152. }
  153. return LIBMPQ_TOOLS_SUCCESS;
  154. }
  155. /*
  156.  *  This functions fills the MPQ_HASH structure with the
  157.  *  hashtable found in the MPQ file. The hashtable will
  158.  *  be decrypted for later use.
  159.  */
  160. int libmpq_read_hashtable(MPQ_ARCHIVE *mpq_a) {
  161. unsigned int bytes = 0;
  162. int rb = 0;
  163. /*
  164.  *  Allocate memory. Note that the block table should be as large as the
  165.  *  hash table. (for later file additions)
  166.  */
  167. mpq_a->hashtable = (MPQ_HASH*)malloc(sizeof(MPQ_HASH) * mpq_a->header->hashtablesize);
  168. if (!mpq_a->hashtable) {
  169. return LIBMPQ_EALLOCMEM;
  170. }
  171. /* Read the hash table into the buffer */
  172. bytes = mpq_a->header->hashtablesize * sizeof(MPQ_HASH);
  173. _lseeki64(mpq_a->fd, mpq_a->header->hashtablepos, SEEK_SET);
  174. rb = read(mpq_a->fd, mpq_a->hashtable, bytes);
  175. if (rb != bytes) {
  176. return LIBMPQ_EFILE_CORRUPT;
  177. }
  178. /* Decrypt hash table and check if it is correctly decrypted */
  179. MPQ_HASH *mpq_h_end = mpq_a->hashtable + mpq_a->header->hashtablesize;
  180. MPQ_HASH *mpq_h     = NULL;
  181. libmpq_decrypt_hashtable(mpq_a, (unsigned char*)"(hash table)");
  182. /* Check hash table if is correctly decrypted */
  183. for (mpq_h = mpq_a->hashtable; mpq_h < mpq_h_end; mpq_h++) {
  184. // WoW: patch.MPQ breaks this
  185. //if (mpq_h->locale != 0xFFFFFFFF && (mpq_h->locale & 0xFFFF0000) != 0) {
  186. // return LIBMPQ_EFILE_FORMAT;
  187. //}
  188. /* Remember the highest block table entry */
  189. if (mpq_h->blockindex < LIBMPQ_HASH_ENTRY_DELETED && mpq_h->blockindex > 0) {
  190. mpq_a->maxblockindex = mpq_h->blockindex;
  191. }
  192. }
  193. return LIBMPQ_TOOLS_SUCCESS;
  194. }
  195. /*
  196.  *  This functions fills the MPQ_BLOCK structure with the
  197.  *  blocktable found in the MPQ file. The blocktable will
  198.  *  be decrypted for later use.
  199.  *
  200.  *  NOTICE: Some MPQs have decrypted block table, e.g.
  201.  *          cracked Diablo versions.
  202.  */
  203. int libmpq_read_blocktable(MPQ_ARCHIVE *mpq_a) {
  204. unsigned int bytes = 0;
  205. int rb = 0;
  206. /*
  207.  *  Allocate memory. Note that the block table should be as large as the
  208.  *  hash table. (for later file additions)
  209.  */
  210. mpq_a->blocktable = (MPQ_BLOCK*)malloc(sizeof(MPQ_BLOCK) * mpq_a->header->hashtablesize);
  211. mpq_a->blockbuf   = (unsigned char*)malloc(mpq_a->blocksize);
  212. if (!mpq_a->blocktable || !mpq_a->blockbuf) {
  213. return LIBMPQ_EALLOCMEM;
  214. }
  215. /* Read the block table into the buffer */
  216. bytes = mpq_a->header->blocktablesize * sizeof(MPQ_BLOCK);
  217. memset(mpq_a->blocktable, 0, mpq_a->header->blocktablesize * sizeof(MPQ_BLOCK));
  218. _lseeki64(mpq_a->fd, mpq_a->header->blocktablepos, SEEK_SET);
  219. rb = read(mpq_a->fd, mpq_a->blocktable, bytes);
  220. if (rb != bytes) {
  221. return LIBMPQ_EFILE_CORRUPT;
  222. }
  223. /*
  224.  *  Decrypt block table. Some MPQs don't have encrypted block table,
  225.  *  e.g. cracked Diablo version. We have to check if block table is
  226.  *  already decrypted
  227.  */
  228. MPQ_BLOCK *mpq_b_end     = mpq_a->blocktable + mpq_a->maxblockindex + 1;
  229. MPQ_BLOCK *mpq_b         = NULL;
  230. unsigned int archivesize = mpq_a->header->archivesize + mpq_a->mpqpos;
  231. if (mpq_a->header->offset != mpq_a->blocktable->filepos) {
  232. libmpq_decrypt_blocktable(mpq_a, (unsigned char*)"(block table)");
  233. }
  234. for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
  235. if (mpq_b->filepos > archivesize || mpq_b->csize > archivesize) {
  236. if ((mpq_a->flags & LIBMPQ_FLAG_PROTECTED) == 0) {
  237. return LIBMPQ_EFILE_FORMAT;
  238. }
  239. }
  240. mpq_b->filepos += mpq_a->mpqpos;
  241. }
  242. return LIBMPQ_TOOLS_SUCCESS;
  243. }
  244. int libmpq_file_read_block(MPQ_ARCHIVE *mpq_a, MPQ_FILE *mpq_f, unsigned int blockpos, char *buffer, unsigned int blockbytes) {
  245. unsigned char *tempbuf = NULL; /* Buffer for reading compressed data from the file */
  246. unsigned int readpos = 0; /* Reading position from the file */
  247. unsigned int toread = 0; /* Number of bytes to read */
  248. unsigned int blocknum = 0; /* Block number (needed for decrypt) */
  249. unsigned int bytesread = 0; /* Total number of bytes read */
  250. unsigned int nblocks = 0; /* Number of blocks to load */
  251. unsigned int i = 0;
  252. /* Test parameters. Block position and block size must be block-aligned, block size nonzero */
  253. if ((blockpos & (mpq_a->blocksize - 1)) || blockbytes == 0) {
  254. return 0;
  255. }
  256. /* Check the end of file */
  257. if ((blockpos + blockbytes) > mpq_f->mpq_b->fsize) {
  258. blockbytes = mpq_f->mpq_b->fsize - blockpos;
  259. }
  260. blocknum = blockpos   / mpq_a->blocksize;
  261. nblocks  = blockbytes / mpq_a->blocksize;
  262. if (blockbytes % mpq_a->blocksize) {
  263. nblocks++;
  264. }
  265. /* If file has variable block positions, we have to load them */
  266. if ((mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) && mpq_f->blockposloaded == FALSE) {
  267. unsigned int nread;
  268. if (mpq_f->mpq_b->filepos != mpq_a->filepos) {
  269. _lseeki64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
  270. }
  271. /* Read block positions from begin of file. */
  272. nread = (mpq_f->nblocks + 1) * sizeof(int);
  273. nread = read(mpq_a->fd, mpq_f->blockpos, nread);
  274. /*
  275. //If the archive is protected some way, perform additional check
  276. //Sometimes, the file appears not to be encrypted, but it is.
  277. if (mpq_f->blockpos[0] != nread) {
  278. mpq_f->mpq_b->flags |= LIBMPQ_FILE_ENCRYPTED;
  279. }
  280. // Decrypt loaded block positions if necessary
  281. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) {
  282. // If we don't know the file seed, try to find it.
  283. if (mpq_f->seed == 0) {
  284. mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread);
  285. }
  286. // If we don't know the file seed, sorry but we cannot extract the file.
  287. if (mpq_f->seed == 0) {
  288. return 0;
  289. }
  290. // Decrypt block positions
  291. libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1);
  292. // Check if the block positions are correctly decrypted
  293. // I don't know why, but sometimes it will result invalid
  294. // block positions on some files.
  295. if (mpq_f->blockpos[0] != nread) {
  296. // * Try once again to detect file seed and decrypt the blocks
  297. _lseeki64(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET);
  298. nread = read(mpq_a->fd, mpq_f->blockpos, (mpq_f->nblocks + 1) * sizeof(int));
  299. mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread);
  300. libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1);
  301. // Check if the block positions are correctly decrypted.
  302. if (mpq_f->blockpos[0] != nread) {
  303. return 0;
  304. }
  305. }
  306. }
  307. &/
  308. /* Update mpq_f's variables */
  309. mpq_f->blockposloaded = TRUE;
  310. mpq_a->filepos        = mpq_f->mpq_b->filepos + nread;
  311. }
  312. /* Get file position and number of bytes to read */
  313. readpos = blockpos;
  314. toread  = blockbytes;
  315. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  316. readpos = mpq_f->blockpos[blocknum];
  317. toread  = mpq_f->blockpos[blocknum + nblocks] - readpos;
  318. }
  319. readpos += mpq_f->mpq_b->filepos;
  320. /* Get work buffer for store read data */
  321. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  322. if ((tempbuf = (unsigned char*)malloc(toread)) == NULL) {
  323. /* Hmmm... We should add a better error handling here :) */
  324. return 0;
  325. }
  326. }
  327. /* Set file pointer, if necessary. */
  328. if (mpq_a->filepos != readpos) {
  329. mpq_a->filepos = (unsigned int)_lseeki64(mpq_a->fd, readpos, SEEK_SET);
  330. }
  331. /* 15018F87 - Read all requested blocks. */
  332. bytesread = read(mpq_a->fd, tempbuf, toread);
  333. mpq_a->filepos = readpos + bytesread;
  334. /* Block processing part. */
  335. unsigned int blockstart = 0; /* Index of block start in work buffer. */
  336. unsigned int blocksize  = min(blockbytes, mpq_a->blocksize);
  337. unsigned int index      = blocknum; /* Current block index. */
  338. bytesread = 0; /* Clear read byte counter */
  339. /* Walk through all blocks. */
  340. for (i = 0; i < nblocks; i++, index++) {
  341. int outlength = mpq_a->blocksize;
  342. if ((mpq_f->mpq_b->flags & (LIBMPQ_FILE_COMPRESS_PKWARE|LIBMPQ_FILE_COMPRESS_MULTI)) == 0 ) {
  343. memcpy(buffer, tempbuf+blockstart, blocksize);
  344. }
  345. /* Get current block length */
  346. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  347. blocksize = mpq_f->blockpos[index + 1] - mpq_f->blockpos[index];
  348. }
  349. /* If block is encrypted, we have to decrypt it. */
  350. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) {
  351. if (mpq_f->seed == 0) {
  352. return 0;
  353. }
  354. libmpq_decrypt_block(mpq_a, (unsigned int *)&tempbuf[blockstart], blocksize, mpq_f->seed + index);
  355. }
  356. /*
  357.  *  If the block is really compressed, recompress it.
  358.  *  WARNING: Some block may not be compressed, it can
  359.  *  only be determined by comparing uncompressed and
  360.  *  compressed size!
  361.  */
  362. if (blocksize < blockbytes) {
  363. /* Is the file compressed with PKWARE Data Compression Library? */
  364. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
  365. libmpq_pkzip_decompress(buffer, &outlength, (char*)&tempbuf[blockstart], blocksize);
  366. }
  367. /*
  368.  *  Is it a file compressed by Blizzard's multiple compression ?
  369.  *  Note that Storm.dll v 1.0.9 distributed with Warcraft III
  370.  *  passes the full path name of the opened archive as the new
  371.  *  last parameter.
  372.  */
  373. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
  374. libmpq_multi_decompress(buffer, &outlength, (char*)&tempbuf[blockstart], blocksize);
  375. }
  376. bytesread += outlength;
  377. buffer    += outlength;
  378. } else {
  379. memcpy(buffer, tempbuf, blocksize);
  380. bytesread += blocksize;
  381. buffer    += blocksize;
  382. }
  383. blockstart += blocksize;
  384. }
  385. /* Delete input buffer, if necessary. */
  386. if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
  387. free(tempbuf);
  388. }
  389. return bytesread;
  390. }
  391. int libmpq_file_read_file(MPQ_ARCHIVE *mpq_a, MPQ_FILE *mpq_f, unsigned int filepos, char *buffer, unsigned int toread) {
  392. unsigned int bytesread = 0; /* Number of bytes read from the file */
  393. unsigned int blockpos; /* Position in the file aligned to the whole blocks */
  394. unsigned int loaded = 0;
  395. /* File position is greater or equal to file size? */
  396. if (filepos >= mpq_f->mpq_b->fsize) {
  397. return 0;
  398. }
  399. /* If to few bytes in the file remaining, cut them */
  400. if ((mpq_f->mpq_b->fsize - filepos) < toread) {
  401. toread = (mpq_f->mpq_b->fsize - filepos);
  402. }
  403. /* Block position in the file */
  404. blockpos = filepos & ~(mpq_a->blocksize - 1);
  405. /*
  406.  *  Load the first block, if noncomplete. It may be loaded in the cache buffer.
  407.  *  We have to check if this block is loaded. If not, load it.
  408.  */
  409. if ((filepos % mpq_a->blocksize) != 0) {
  410. /* Number of bytes remaining in the buffer */
  411. unsigned int tocopy;
  412. unsigned int loaded = mpq_a->blocksize;
  413. /* Check if data are loaded in the cache */
  414. if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) {   
  415. /* Load one MPQ block into archive buffer */
  416. loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char*)mpq_a->blockbuf, mpq_a->blocksize);
  417. if (loaded == 0) {
  418. return 0;
  419. }
  420. /* Save lastly accessed file and block position for later use */
  421. mpq_f->accessed = TRUE;
  422. mpq_a->blockpos = blockpos;
  423. mpq_a->bufpos   = filepos % mpq_a->blocksize;
  424. }
  425. tocopy = loaded - mpq_a->bufpos;
  426. if (tocopy > toread) {
  427. tocopy = toread;
  428. }
  429. /* Copy data from block buffer into target buffer */
  430. memcpy(buffer, mpq_a->blockbuf + mpq_a->bufpos, tocopy);
  431. /* Update pointers */
  432. toread        -= tocopy;
  433. bytesread     += tocopy;
  434. buffer        += tocopy;
  435. blockpos      += mpq_a->blocksize;
  436. mpq_a->bufpos += tocopy;
  437. /* If all, return. */
  438. if (toread == 0) {
  439. return bytesread;
  440. }
  441. }
  442. /* Load the whole ("middle") blocks only if there are more or equal one block */
  443. if (toread > mpq_a->blocksize) {
  444. unsigned int blockbytes = toread & ~(mpq_a->blocksize - 1);
  445. loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, buffer, blockbytes);
  446. if (loaded == 0) {
  447. return 0;
  448. }
  449. /* Update pointers */
  450. toread    -= loaded;
  451. bytesread += loaded;
  452. buffer    += loaded;
  453. blockpos  += loaded;
  454. /* If all, return. */
  455. if (toread == 0) {
  456. return bytesread;
  457. }
  458. }
  459. /* Load the terminating block */
  460. if (toread > 0) {
  461. unsigned int tocopy = mpq_a->blocksize;
  462. /* Check if data are loaded in the cache */
  463. if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) {
  464. /* Load one MPQ block into archive buffer */
  465. tocopy = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char*)mpq_a->blockbuf, mpq_a->blocksize);
  466. if (tocopy == 0) {
  467. return 0;
  468. }
  469. /* Save lastly accessed file and block position for later use */
  470. mpq_f->accessed = TRUE;
  471. mpq_a->blockpos = blockpos;
  472. }
  473. mpq_a->bufpos  = 0;
  474. /* Check number of bytes read */
  475. if (tocopy > toread) {
  476. tocopy = toread;
  477. }
  478. memcpy(buffer, mpq_a->blockbuf, tocopy);
  479. bytesread     += tocopy;
  480. mpq_a->bufpos  = tocopy;
  481. }
  482. /* Return what we've read */
  483. return bytesread;
  484. }