📄 common.cpp
字号:
if (mpq_b->filepos > archivesize || mpq_b->csize > archivesize) { if ((mpq_a->flags & LIBMPQ_FLAG_PROTECTED) == 0) { return LIBMPQ_EFILE_FORMAT; } } mpq_b->filepos += mpq_a->mpqpos; } return LIBMPQ_TOOLS_SUCCESS;}int libmpq_file_read_block(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int blockpos, char *buffer, unsigned int blockbytes) { unsigned char *tempbuf = NULL; /* Buffer for reading compressed data from the file */ unsigned int readpos; /* Reading position from the file */ unsigned int toread = 0; /* Number of bytes to read */ unsigned int blocknum; /* Block number (needed for decrypt) */ unsigned int bytesread = 0; /* Total number of bytes read */ unsigned int nblocks; /* Number of blocks to load */ unsigned int i; /* Test parameters. Block position and block size must be block-aligned, block size nonzero */ if ((blockpos & (mpq_a->blocksize - 1)) || blockbytes == 0) { return 0; } /* Check the end of file */ if ((blockpos + blockbytes) > mpq_f->mpq_b->fsize) { blockbytes = mpq_f->mpq_b->fsize - blockpos; } blocknum = blockpos / mpq_a->blocksize; nblocks = blockbytes / mpq_a->blocksize; if (blockbytes % mpq_a->blocksize) { nblocks++; } /* If file has variable block positions, we have to load them */ if ((mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) && mpq_f->blockposloaded == FALSE) { unsigned int nread; if (mpq_f->mpq_b->filepos != mpq_a->filepos) { lseek(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET); } /* Read block positions from begin of file. */ nread = (mpq_f->nblocks + 1) * sizeof(int); nread = read(mpq_a->fd, mpq_f->blockpos, nread); /* * If the archive is protected some way, perform additional check * Sometimes, the file appears not to be encrypted, but it is. */ if (mpq_f->blockpos[0] != nread) { mpq_f->mpq_b->flags |= LIBMPQ_FILE_ENCRYPTED; } /* Decrypt loaded block positions if necessary */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) { /* If we don't know the file seed, try to find it. */ if (mpq_f->seed == 0) { mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread); } /* If we don't know the file seed, sorry but we cannot extract the file. */ if (mpq_f->seed == 0) { return 0; } /* Decrypt block positions */ libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1); /* * Check if the block positions are correctly decrypted * I don't know why, but sometimes it will result invalid * block positions on some files. */ if (mpq_f->blockpos[0] != nread) { /* Try once again to detect file seed and decrypt the blocks */ lseek(mpq_a->fd, mpq_f->mpq_b->filepos, SEEK_SET); nread = read(mpq_a->fd, mpq_f->blockpos, (mpq_f->nblocks + 1) * sizeof(int)); mpq_f->seed = libmpq_detect_fileseed(mpq_a, mpq_f->blockpos, nread); libmpq_decrypt_block(mpq_a, mpq_f->blockpos, nread, mpq_f->seed - 1); /* Check if the block positions are correctly decrypted. */ if (mpq_f->blockpos[0] != nread) { return 0; } } } /* Update mpq_f's variables */ mpq_f->blockposloaded = TRUE; mpq_a->filepos = mpq_f->mpq_b->filepos + nread; } /* Get file position and number of bytes to read */ readpos = blockpos; toread = blockbytes; if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) { readpos = mpq_f->blockpos[blocknum]; toread = mpq_f->blockpos[blocknum + nblocks] - readpos; } readpos += mpq_f->mpq_b->filepos; /* Get work buffer for store read data */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) { if ((tempbuf = (unsigned char*)malloc(toread)) == NULL) { /* Hmmm... We should add a better error handling here :) */ return 0; } } /* Set file pointer, if necessary. */ if (mpq_a->filepos != readpos) { mpq_a->filepos = lseek(mpq_a->fd, readpos, SEEK_SET); } /* 15018F87 - Read all requested blocks. */ bytesread = read(mpq_a->fd, tempbuf, toread); mpq_a->filepos = readpos + bytesread; /* Block processing part. */ unsigned int blockstart = 0; /* Index of block start in work buffer. */ unsigned int blocksize = min(blockbytes, mpq_a->blocksize); unsigned int index = blocknum; /* Current block index. */ bytesread = 0; /* Clear read byte counter */ /* Walk through all blocks. */ for (i = 0; i < nblocks; i++, index++) { int outlength = mpq_a->blocksize; /* Get current block length */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) { blocksize = mpq_f->blockpos[index + 1] - mpq_f->blockpos[index]; } /* If block is encrypted, we have to decrypt it. */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_ENCRYPTED) { if (mpq_f->seed == 0) { return 0; } libmpq_decrypt_block(mpq_a, (unsigned int *)&tempbuf[blockstart], blocksize, mpq_f->seed + index); } /* * If the block is really compressed, recompress it. * WARNING: Some block may not be compressed, it can * only be determined by comparing uncompressed and * compressed size! */ if (blocksize < blockbytes) { /* Is the file compressed with PKWARE Data Compression Library? */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_PKWARE) { libmpq_pkzip_decompress(buffer, &outlength, (char*)&tempbuf[blockstart], blocksize); } /* * Is it a file compressed by Blizzard's multiple compression ? * Note that Storm.dll v 1.0.9 distributed with Warcraft III * passes the full path name of the opened archive as the new * last parameter. */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESS_MULTI) { libmpq_multi_decompress(buffer, &outlength, (char*)&tempbuf[blockstart], blocksize); } bytesread += outlength; buffer += outlength; } else { memcpy(buffer, tempbuf, blocksize); bytesread += blocksize; buffer += blocksize; } blockstart += blocksize; } /* Delete input buffer, if necessary. */ if (mpq_f->mpq_b->flags & LIBMPQ_FILE_COMPRESSED) { free(tempbuf); } return bytesread;}int libmpq_file_read_file(mpq_archive *mpq_a, mpq_file *mpq_f, unsigned int filepos, char *buffer, unsigned int toread) { unsigned int bytesread = 0; /* Number of bytes read from the file */ unsigned int blockpos; /* Position in the file aligned to the whole blocks */ unsigned int loaded = 0; /* File position is greater or equal to file size? */ if (filepos >= mpq_f->mpq_b->fsize) { return 0; } /* If to few bytes in the file remaining, cut them */ if ((mpq_f->mpq_b->fsize - filepos) < toread) { toread = (mpq_f->mpq_b->fsize - filepos); } /* Block position in the file */ blockpos = filepos & ~(mpq_a->blocksize - 1); /* * Load the first block, if noncomplete. It may be loaded in the cache buffer. * We have to check if this block is loaded. If not, load it. */ if ((filepos % mpq_a->blocksize) != 0) { /* Number of bytes remaining in the buffer */ unsigned int tocopy; unsigned int loaded = mpq_a->blocksize; /* Check if data are loaded in the cache */ if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) { /* Load one MPQ block into archive buffer */ loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char*)mpq_a->blockbuf, mpq_a->blocksize); if (loaded == 0) { return 0; } /* Save lastly accessed file and block position for later use */ mpq_f->accessed = TRUE; mpq_a->blockpos = blockpos; mpq_a->bufpos = filepos % mpq_a->blocksize; } tocopy = loaded - mpq_a->bufpos; if (tocopy > toread) { tocopy = toread; } /* Copy data from block buffer into target buffer */ memcpy(buffer, mpq_a->blockbuf + mpq_a->bufpos, tocopy); /* Update pointers */ toread -= tocopy; bytesread += tocopy; buffer += tocopy; blockpos += mpq_a->blocksize; mpq_a->bufpos += tocopy; /* If all, return. */ if (toread == 0) { return bytesread; } } /* Load the whole ("middle") blocks only if there are more or equal one block */ if (toread > mpq_a->blocksize) { unsigned int blockbytes = toread & ~(mpq_a->blocksize - 1); loaded = libmpq_file_read_block(mpq_a, mpq_f, blockpos, buffer, blockbytes); if (loaded == 0) { return 0; } /* Update pointers */ toread -= loaded; bytesread += loaded; buffer += loaded; blockpos += loaded; /* If all, return. */ if (toread == 0) { return bytesread; } } /* Load the terminating block */ if (toread > 0) { unsigned int tocopy = mpq_a->blocksize; /* Check if data are loaded in the cache */ if (mpq_f->accessed == FALSE || blockpos != mpq_a->blockpos) { /* Load one MPQ block into archive buffer */ tocopy = libmpq_file_read_block(mpq_a, mpq_f, blockpos, (char*)mpq_a->blockbuf, mpq_a->blocksize); if (tocopy == 0) { return 0; } /* Save lastly accessed file and block position for later use */ mpq_f->accessed = TRUE; mpq_a->blockpos = blockpos; } mpq_a->bufpos = 0; /* Check number of bytes read */ if (tocopy > toread) { tocopy = toread; } memcpy(buffer, mpq_a->blockbuf, tocopy); bytesread += tocopy; mpq_a->bufpos = tocopy; } /* Return what we've read */ return bytesread;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -