mpq.cpp
上传用户:yisoukefu
上传日期:2020-08-09
资源大小:39506k
文件大小:14k
- #include <windows.h>
- #include <stdlib.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- //#include <string.h>
- #include <io.h>
- #include "mpq.h"
- extern int libmpq_init_buffer(MPQ_ARCHIVE *mpq_a);
- extern int libmpq_read_hashtable(MPQ_ARCHIVE *mpq_a);
- extern int libmpq_read_blocktable(MPQ_ARCHIVE *mpq_a);
- extern int libmpq_file_read_block(MPQ_ARCHIVE *mpq_a, MPQ_FILE *mpq_f, unsigned int blockpos, char *buffer, unsigned int blockbytes);
- extern int libmpq_file_read_file(MPQ_ARCHIVE *mpq_a, MPQ_FILE *mpq_f, unsigned int filepos, char *buffer, unsigned int toread);
- char *libmpq_version()
- {
- static char version[10];
- _snprintf(version, sizeof(version), "%i.%i.%i", LIBMPQ_MAJOR_VERSION, LIBMPQ_MINOR_VERSION, LIBMPQ_PATCH_VERSION);
- return version;
- }
- /*
- * This function reads a file and verify if it is a legit MPQ archive
- * or not. Then it fills the MPQ_HEADER structure and reads the hash
- * table.
- */
- int libmpq_archive_open(MPQ_ARCHIVE *mpq_a, unsigned char *MPQ_FILEname)
- {
- int fd = 0;
- int rb = 0;
- int ncnt = FALSE;
- struct stat fileinfo;
- memset((void*)mpq_a, 0, sizeof(MPQ_ARCHIVE));
- mpq_a->fd = -1;
- /* allocate memory */
- mpq_a->header = static_cast<MPQ_HEADER*>(malloc(sizeof(MPQ_HEADER)));
- memset(mpq_a->header, 0, sizeof(MPQ_HEADER));
- /* Check if file exists and is readable */
- fd = open((const char*)MPQ_FILEname, O_RDONLY|O_BINARY);
- if (fd == LIBMPQ_EFILE) {
- return LIBMPQ_EFILE;
- }
- /* fill the structures with informations */
- strncpy((char*)mpq_a->filename, (const char*)MPQ_FILEname, strlen((const char*)MPQ_FILEname));
- libmpq_init_buffer(mpq_a);
- mpq_a->fd = fd;
- mpq_a->header->id = 0;
- mpq_a->maxblockindex = 0;
- mpq_a->header->offset = 0;
- while (!ncnt) {
- mpq_a->header->id = 0;
- _lseeki64(mpq_a->fd, mpq_a->mpqpos, SEEK_SET);
- rb = read(mpq_a->fd, mpq_a->header, sizeof(MPQ_HEADER));
- /* if different number of bytes read, break the loop */
- if (rb != sizeof(MPQ_HEADER)) {
- return LIBMPQ_EFILE_FORMAT;
- }
- /* special offset for protected MPQs */
- if (mpq_a->header->offset == LIBMPQ_HEADER_W3M) {
- mpq_a->flags |= LIBMPQ_FLAG_PROTECTED;
- mpq_a->header->offset = sizeof(MPQ_HEADER);
- }
- /* if valid signature has been found, break the loop */
- 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)
- ncnt = TRUE;
- }
- /* move to the next possible offset */
- if (!ncnt) {
- mpq_a->mpqpos += 0x200;
- }
- }
- if (mpq_a->header->offset != sizeof(MPQ_HEADER)) {
- _lseeki64(mpq_a->fd, mpq_a->header->offset, SEEK_SET);
- }
- /* get the right positions of the hash table and the block table. */
- mpq_a->blocksize = (0x200 << mpq_a->header->blocksize);
- fstat(mpq_a->fd, &fileinfo);
- /* Normal MPQs must have position of */
- 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)) {
- mpq_a->header->hashtablepos += mpq_a->mpqpos;
- mpq_a->header->blocktablepos += mpq_a->mpqpos;
- } else {
- return LIBMPQ_EFILE_FORMAT;
- }
- /* Try to read and decrypt the hashtable */
- if (libmpq_read_hashtable(mpq_a) != 0) {
- return LIBMPQ_EHASHTABLE;
- }
- /* Try to read and decrypt the blocktable */
- if (libmpq_read_blocktable(mpq_a) != 0) {
- return LIBMPQ_EBLOCKTABLE;
- }
- return LIBMPQ_TOOLS_SUCCESS;
- }
- /*
- * This function closes the file descriptor opened by
- * mpq_open_archive(); and frees the decryption buffer.
- */
- int libmpq_archive_close(MPQ_ARCHIVE *mpq_a)
- {
- /* free the allocated memory. */
- if (mpq_a->blockbuf) {
- free(mpq_a->blockbuf);
- mpq_a->blockbuf = NULL;
- }
- if (mpq_a->header) {
- free(mpq_a->header);
- mpq_a->header = NULL;
- }
- if (mpq_a->hashtable) {
- free(mpq_a->hashtable); /* Hash table */
- mpq_a->hashtable = NULL;
- }
- if (mpq_a->blocktable) {
- free(mpq_a->blocktable); /* Block table */
- mpq_a->blocktable = NULL;
- }
- /* Check if file descriptor is valid. */
- if ((close(mpq_a->fd)) == LIBMPQ_EFILE) {
- return LIBMPQ_EFILE;
- }
- mpq_a->fd = -1;
- /* // this isn't really needed
- memset(mpq_a->buf, 0, sizeof(mpq_a->buf));
- memset(mpq_a->filename, 0, sizeof(mpq_a->filename));
- */
- return LIBMPQ_TOOLS_SUCCESS;
- }
- /*
- * This function returns the value for the given infotype.
- * If an error occurs something < 0 is returned.
- */
- int libmpq_archive_info(MPQ_ARCHIVE *mpq_a, unsigned int infotype)
- {
- unsigned int filecount = 0;
- unsigned int fsize = 0;
- unsigned int csize = 0;
- MPQ_BLOCK *mpq_b_end = mpq_a->blocktable + mpq_a->header->blocktablesize;
- MPQ_BLOCK *mpq_b = NULL;
- switch (infotype) {
- case LIBMPQ_MPQ_ARCHIVE_SIZE:
- return mpq_a->header->archivesize;
- case LIBMPQ_MPQ_HASHTABLE_SIZE:
- return mpq_a->header->hashtablesize;
- case LIBMPQ_MPQ_BLOCKTABLE_SIZE:
- return mpq_a->header->blocktablesize;
- case LIBMPQ_MPQ_BLOCKSIZE:
- return mpq_a->blocksize;
- case LIBMPQ_MPQ_NUMFILES:
- for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
- filecount++;
- }
- return filecount;
- case LIBMPQ_MPQ_COMPRESSED_SIZE:
- for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
- csize += mpq_b->csize;
- }
- return csize;
- case LIBMPQ_MPQ_UNCOMPRESSED_SIZE:
- for (mpq_b = mpq_a->blocktable; mpq_b < mpq_b_end; mpq_b++) {
- fsize += mpq_b->fsize;
- }
- return fsize;
- default:
- return LIBMPQ_TOOLS_SUCCESS;
- }
- }
- /*
- * This function returns some useful file information.
- */
- int libmpq_file_info(MPQ_ARCHIVE *mpq_a, unsigned int infotype, const int number)
- {
- int blockindex = -1;
- unsigned int i = 0;
- MPQ_BLOCK *mpq_b = NULL;
- MPQ_HASH *mpq_h = NULL;
- /* check if given number is not out of range */
- if (number < 1 || (unsigned int)number > mpq_a->header->blocktablesize) {
- return LIBMPQ_EINV_RANGE;
- }
- /* search for correct hashtable */
- blockindex = number - 1;
- if(LIBMPQ_FILE_HASH1 == infotype || LIBMPQ_FILE_HASH2 == infotype)
- {
- for (i = 0; i < mpq_a->header->hashtablesize; i++)
- {
- if ((number - 1) == (int)(mpq_a->hashtable[i]).blockindex) {
- mpq_h = &(mpq_a->hashtable[i]);
- break;
- }
- }
- if(i >= mpq_a->header->hashtablesize)
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- if (blockindex > (int)mpq_a->header->blocktablesize)
- {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /* check if sizes are correct */
- mpq_b = mpq_a->blocktable + blockindex;
- if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
- return LIBMPQ_EFILE_CORRUPT;
- }
- /* check if file exists */
- if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- switch (infotype) {
- case LIBMPQ_FILE_COMPRESSED_SIZE:
- return mpq_b->csize;
- case LIBMPQ_FILE_UNCOMPRESSED_SIZE:
- return mpq_b->fsize;
- case LIBMPQ_FILE_HASH1:
- return mpq_h->name1;
- case LIBMPQ_FILE_HASH2:
- return mpq_h->name2;
- case LIBMPQ_FILE_COMPRESSION_TYPE:
- if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) {
- return LIBMPQ_FILE_COMPRESS_PKWARE;
- }
- if (mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) {
- return LIBMPQ_FILE_COMPRESS_MULTI;
- }
- default:
- return LIBMPQ_TOOLS_SUCCESS;
- }
- }
- /*
- * This function returns the number to the given
- * filename.
- */
- int libmpq_file_number(MPQ_ARCHIVE *mpq_a, const char *name) {
- int i;
- unsigned int hash1, hash2;
-
- // Search by hash first
- libmpq_hash_filename(mpq_a, (unsigned char*)name, &hash1, &hash2);
- i = libmpq_file_number_from_hash(mpq_a, hash1, hash2);
- if(i >= 0)
- return i;
- /* if no matching entry found return LIBMPQ_EFILE_NOT_FOUND */
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /*
- * This function returns the number to the given
- * file.
- */
- int libmpq_file_number_from_hash(MPQ_ARCHIVE *mpq_a, unsigned int hash1, unsigned int hash2) {
- /* search for correct hashtable */
- for (unsigned int i=0; i < mpq_a->header->hashtablesize; i++) {
- if((mpq_a->hashtable[i]).name1 == hash1 &&
- (mpq_a->hashtable[i]).name2 == hash2) {
- return (mpq_a->hashtable[i]).blockindex + 1;
- }
- }
- /* if no matching entry found return LIBMPQ_EFILE_NOT_FOUND */
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /*
- * This function verifies if a given file (by number
- * or name) is in the opened mpq archive. On success
- * it returns 0, otherwise LIBMPQ_EFILE_NOT_FOUND.
- */
- int libmpq_file_check(MPQ_ARCHIVE *mpq_a, void *file, int type) {
- int found = 0;
- unsigned int hash1, hash2;
- switch (type) {
- case LIBMPQ_FILE_TYPE_INT:
- /* check if we are in the range of available files. */
- if (*(int *)file > libmpq_archive_info(mpq_a, LIBMPQ_MPQ_NUMFILES) || *(int *)file < 1) {
- return LIBMPQ_EFILE_NOT_FOUND;
- } else {
- return LIBMPQ_TOOLS_SUCCESS;
- }
- case LIBMPQ_FILE_TYPE_CHAR:
- // Search by hash
- libmpq_hash_filename(mpq_a, (unsigned char*)file, &hash1, &hash2);
- if(libmpq_file_number_from_hash(mpq_a, hash1, hash2)>=0)
- found = 1;
-
- /* if a file was found return 0 */
- if (found == 1) {
- return LIBMPQ_TOOLS_SUCCESS;
- } else {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- default:
- return LIBMPQ_TOOLS_SUCCESS;
- }
- }
- #if 0
- /*
- * This function extracts a file from a MPQ archive
- * by the given number.
- */
- int libmpq_file_extract(MPQ_ARCHIVE *mpq_a, const int number) {
- int blockindex = -1;
- int fd = 0;
- int i = 0;
- char buffer[0x1000];
- char tempfile[PATH_MAX];
- unsigned int transferred = 1;
- MPQ_FILE *mpq_f = NULL;
- MPQ_BLOCK *mpq_b = NULL;
- MPQ_HASH *mpq_h = NULL;
- if (number < 1 || number > mpq_a->header->blocktablesize) {
- return LIBMPQ_EINV_RANGE;
- }
- snprintf(tempfile, PATH_MAX, libmpq_file_name(mpq_a, number));
- /* check if mpq_f->filename could be written here. */
- fd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, 0644);
- if (fd == LIBMPQ_EFILE) {
- return LIBMPQ_EFILE;
- }
- /* search for correct hashtable */
- for (i = 0; i < mpq_a->header->hashtablesize; i++) {
- if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
- blockindex = (mpq_a->hashtable[i]).blockindex;
- mpq_h = &(mpq_a->hashtable[i]);
- break;
- }
- }
- /* check if file was found */
- if (blockindex == -1 || blockindex > mpq_a->header->blocktablesize) {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /* check if sizes are correct */
- mpq_b = mpq_a->blocktable + blockindex;
- if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
- return LIBMPQ_EFILE_CORRUPT;
- }
- /* check if file exists */
- if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /* allocate memory for file structure */
- mpq_f = (MPQ_FILE *)malloc(sizeof(MPQ_FILE));
- if (!mpq_f) {
- return LIBMPQ_EALLOCMEM;
- }
- /* initialize file structure */
- memset(mpq_f, 0, sizeof(MPQ_FILE));
- mpq_f->fd = fd;
- mpq_f->mpq_b = mpq_b;
- mpq_f->nblocks = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
- mpq_f->mpq_h = mpq_h;
- mpq_f->accessed = FALSE;
- mpq_f->blockposloaded = FALSE;
- snprintf((char*)mpq_f->filename, PATH_MAX, tempfile);
- /* allocate buffers for decompression. */
- if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
- /*
- * Allocate buffer for block positions. At the begin of file are stored
- * unsigned ints holding positions of each block relative from begin of
- * file in the archive.
- */
- if ((mpq_f->blockpos = (unsigned int*)malloc(sizeof(int) * mpq_f->nblocks + 1)) == NULL) {
- return LIBMPQ_EALLOCMEM;
- }
- }
- while (transferred > 0) {
- transferred = libmpq_file_read_file(mpq_a, mpq_f, mpq_f->filepos, buffer, sizeof(buffer));
- if (transferred == 0) {
- break;
- } else {
- mpq_f->accessed = TRUE;
- mpq_f->filepos += transferred;
- }
- transferred = write(mpq_f->fd, buffer, transferred);
- if (transferred == 0) {
- break;
- }
- }
- close(fd);
- /* freeing the file structure */
- free(mpq_f);
- return LIBMPQ_TOOLS_SUCCESS;
- }
- #endif
- int libmpq_file_getdata(MPQ_ARCHIVE *mpq_a, const int number, unsigned char *dest) {
- int blockindex = -1;
- unsigned int i=0;
- MPQ_FILE *mpq_f = NULL;
- MPQ_BLOCK *mpq_b = NULL;
- MPQ_HASH *mpq_h = NULL;
- int success = 0;
- if (number < 1 || (unsigned int)number > mpq_a->header->blocktablesize) {
- return LIBMPQ_EINV_RANGE;
- }
- /* search for correct hashtable */
- for (i=0; i<mpq_a->header->hashtablesize; i++) {
- if ((number - 1) == (mpq_a->hashtable[i]).blockindex) {
- blockindex = (mpq_a->hashtable[i]).blockindex;
- mpq_h = &(mpq_a->hashtable[i]);
- break;
- }
- }
- /* check if file was found */
- if (blockindex == -1 || (unsigned int)blockindex > mpq_a->header->blocktablesize) {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /* check if sizes are correct */
- mpq_b = mpq_a->blocktable + blockindex;
- if (mpq_b->filepos > (mpq_a->header->archivesize + mpq_a->mpqpos) || mpq_b->csize > mpq_a->header->archivesize) {
- return LIBMPQ_EFILE_CORRUPT;
- }
- /* check if file exists */
- if ((mpq_b->flags & LIBMPQ_FILE_EXISTS) == 0) {
- return LIBMPQ_EFILE_NOT_FOUND;
- }
- /* allocate memory for file structure */
- mpq_f = (MPQ_FILE*)malloc(sizeof(MPQ_FILE));
- if (!mpq_f) {
- return LIBMPQ_EALLOCMEM;
- }
- /* initialize file structure */
- memset(mpq_f, 0, sizeof(MPQ_FILE));
- mpq_f->mpq_b = mpq_b;
- mpq_f->nblocks = (mpq_f->mpq_b->fsize + mpq_a->blocksize - 1) / mpq_a->blocksize;
- mpq_f->mpq_h = mpq_h;
- mpq_f->accessed = FALSE;
- mpq_f->blockposloaded = FALSE;
- /* allocate buffers for decompression. */
- if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
- /*
- * Allocate buffer for block positions. At the begin of file are stored
- * unsigned ints holding positions of each block relative from begin of
- * file in the archive.
- */
- if ((mpq_f->blockpos = (unsigned int*)malloc(sizeof(int) * (mpq_f->nblocks + 1))) == NULL) {
- free(mpq_f);
- return LIBMPQ_EALLOCMEM;
- }
- }
- if(libmpq_file_read_file(mpq_a, mpq_f, 0, (char*)dest, mpq_b->fsize) == mpq_b->fsize)
- success = 1;
- if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) {
- // Free buffer for block positions
-
- free(mpq_f->blockpos);
- }
- /* freeing the file structure */
- free(mpq_f);
- return success?LIBMPQ_TOOLS_SUCCESS:LIBMPQ_EFILE_CORRUPT;
- }