From 459257b0563f3c085e5e1f3cb988309309377f46 Mon Sep 17 00:00:00 2001 From: LordJZ Date: Tue, 5 Jun 2012 04:17:10 +0400 Subject: Update StormLib --- dep/StormLib/src/SFileAddFile.cpp | 139 +++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 32 deletions(-) (limited to 'dep/StormLib/src/SFileAddFile.cpp') diff --git a/dep/StormLib/src/SFileAddFile.cpp b/dep/StormLib/src/SFileAddFile.cpp index e908d644990..dda47370bd1 100644 --- a/dep/StormLib/src/SFileAddFile.cpp +++ b/dep/StormLib/src/SFileAddFile.cpp @@ -12,6 +12,33 @@ #include "StormLib.h" #include "StormCommon.h" +//----------------------------------------------------------------------------- +// Local structures + +#define FILE_SIGNATURE_RIFF 0x46464952 +#define FILE_SIGNATURE_WAVE 0x45564157 +#define FILE_SIGNATURE_FMT 0x20746D66 +#define AUDIO_FORMAT_PCM 1 + +typedef struct _WAVE_FILE_HEADER +{ + DWORD dwChunkId; // 0x52494646 ("RIFF") + DWORD dwChunkSize; // Size of that chunk, in bytes + DWORD dwFormat; // Must be 0x57415645 ("WAVE") + + // Format sub-chunk + DWORD dwSubChunk1Id; // 0x666d7420 ("fmt ") + DWORD dwSubChunk1Size; // 0x16 for PCM + USHORT wAudioFormat; // 1 = PCM. Other value means some sort of compression + USHORT wChannels; // Number of channels + DWORD dwSampleRate; // 8000, 44100, etc. + DWORD dwBytesRate; // SampleRate * NumChannels * BitsPerSample/8 + USHORT wBlockAlign; // NumChannels * BitsPerSample/8 + USHORT wBitsPerSample; // 8 bits = 8, 16 bits = 16, etc. + + // Followed by "data" sub-chunk (we don't care) +} WAVE_FILE_HEADER, *PWAVE_FILE_HEADER; + //----------------------------------------------------------------------------- // Local variables @@ -27,6 +54,29 @@ static void * pvUserData = NULL; #define LOSSY_COMPRESSION_MASK (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN) +static int IsWaveFile( + LPBYTE pbFileData, + DWORD cbFileData, + LPDWORD pdwChannels) +{ + PWAVE_FILE_HEADER pWaveHdr = (PWAVE_FILE_HEADER)pbFileData; + + if(cbFileData > sizeof(WAVE_FILE_HEADER)) + { + if(pWaveHdr->dwChunkId == FILE_SIGNATURE_RIFF && pWaveHdr->dwFormat == FILE_SIGNATURE_WAVE) + { + if(pWaveHdr->dwSubChunk1Id == FILE_SIGNATURE_FMT && pWaveHdr->wAudioFormat == AUDIO_FORMAT_PCM) + { + *pdwChannels = pWaveHdr->wChannels; + return true; + } + } + } + + return false; +} + + static int WriteDataToMpqFile( TMPQArchive * ha, TMPQFile * hf, @@ -86,16 +136,6 @@ static int WriteDataToMpqFile( // Set the position in the file ByteOffset = hf->RawFilePos + pFileEntry->dwCmpSize; - // If the file is compressed, allocate buffer for the compressed data. - // Note that we allocate buffer that is a bit longer than sector size, - // for case if the compression method performs a buffer overrun - if((pFileEntry->dwFlags & MPQ_FILE_COMPRESSED) && pbCompressed == NULL) - { - pbToWrite = pbCompressed = STORM_ALLOC(BYTE, hf->dwSectorSize + 0x100); - if(pbCompressed == NULL) - nError = ERROR_NOT_ENOUGH_MEMORY; - } - // Update CRC32 and MD5 of the file md5_process((hash_state *)hf->hctx, hf->pbFileSector, dwBytesInSector); hf->dwCrc32 = crc32(hf->dwCrc32, hf->pbFileSector, dwBytesInSector); @@ -106,7 +146,18 @@ static int WriteDataToMpqFile( int nOutBuffer = (int)dwBytesInSector; int nInBuffer = (int)dwBytesInSector; - assert(pbCompressed != NULL); + // If the file is compressed, allocate buffer for the compressed data. + // Note that we allocate buffer that is a bit longer than sector size, + // for case if the compression method performs a buffer overrun + if(pbCompressed == NULL) + { + pbToWrite = pbCompressed = STORM_ALLOC(BYTE, hf->dwSectorSize + 0x100); + if(pbCompressed == NULL) + { + nError = ERROR_NOT_ENOUGH_MEMORY; + break; + } + } // // Note that both SCompImplode and SCompCompress give original buffer, @@ -319,11 +370,17 @@ int SFileAddFile_Init( // flags get to this point // - // Adjust file flags for too-small files - if(dwFileSize < 0x04) - dwFlags &= ~(MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY); - if(dwFileSize < 0x20) - dwFlags &= ~(MPQ_FILE_COMPRESSED | MPQ_FILE_SECTOR_CRC); + // Sestor CRC is not allowed with single unit files + if(dwFlags & MPQ_FILE_SINGLE_UNIT) + dwFlags &= ~MPQ_FILE_SECTOR_CRC; + + // Sector CRC is not allowed if the file is not compressed + if(!(dwFlags & MPQ_FILE_COMPRESSED)) + dwFlags &= ~MPQ_FILE_SECTOR_CRC; + + // Fix Key is not allowed if the file is not enrypted + if(!(dwFlags & MPQ_FILE_ENCRYPTED)) + dwFlags &= ~MPQ_FILE_FIX_KEY; // If the MPQ is of version 3.0 or higher, we ignore file locale. // This is because HET and BET tables have no known support for it @@ -371,12 +428,9 @@ int SFileAddFile_Init( } else { - // If the file is marked as deleted, it's OK - if(!(pFileEntry->dwFlags & MPQ_FILE_DELETE_MARKER)) - { - if((dwFlags & MPQ_FILE_REPLACEEXISTING) == 0) - nError = ERROR_ALREADY_EXISTS; - } + // If the file exists and "replace existing" is not set, fail it + if((dwFlags & MPQ_FILE_REPLACEEXISTING) == 0) + nError = ERROR_ALREADY_EXISTS; // If the file entry already contains a file // and it is a pseudo-name, replace it @@ -459,7 +513,7 @@ int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD d } // Allocate patch info, if the data is patch - if(hf->pPatchInfo == NULL && IsPatchData(pvData, dwSize, &hf->dwPatchedFileSize)) + if(hf->pPatchInfo == NULL && IsIncrementalPatchFile(pvData, dwSize, &hf->dwPatchedFileSize)) { // Set the MPQ_FILE_PATCH_FILE flag hf->pFileEntry->dwFlags |= MPQ_FILE_PATCH_FILE; @@ -782,6 +836,9 @@ bool WINAPI SFileAddFileEx( DWORD dwBytesRemaining = 0; DWORD dwBytesToRead; DWORD dwSectorSize = 0x1000; + DWORD dwChannels = 0; + bool bIsAdpcmCompression = false; + bool bIsFirstSector = true; int nError = ERROR_SUCCESS; // Check parameters @@ -791,7 +848,7 @@ bool WINAPI SFileAddFileEx( // Open added file if(nError == ERROR_SUCCESS) { - pStream = FileStream_OpenFile(szFileName, false); + pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE); if(pStream == NULL) nError = GetLastError(); } @@ -799,7 +856,7 @@ bool WINAPI SFileAddFileEx( // Get the file size and file time if(nError == ERROR_SUCCESS) { - FileStream_GetLastWriteTime(pStream, &FileTime); + FileStream_GetTime(pStream, &FileTime); FileStream_GetSize(pStream, FileSize); // Files bigger than 4GB cannot be added to MPQ @@ -821,16 +878,19 @@ bool WINAPI SFileAddFileEx( { // When the compression for next blocks is set to default, // we will copy the compression for the first sector - if(dwCompressionNext == 0xFFFFFFFF) + if(dwCompressionNext == MPQ_COMPRESSION_NEXT_SAME) dwCompressionNext = dwCompression; - // If the caller wants ADPCM compression, we make sure that the first sector is not - // compressed with lossy compression - if(dwCompressionNext & (MPQ_COMPRESSION_WAVE_MONO | MPQ_COMPRESSION_WAVE_STEREO)) + // If the caller wants ADPCM compression, we make sure + // that the first sector is not compressed with lossy compression + if(dwCompressionNext & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO)) { // The first compression must not be WAVE - if(dwCompression & (MPQ_COMPRESSION_WAVE_MONO | MPQ_COMPRESSION_WAVE_STEREO)) + if(dwCompression & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO)) dwCompression = MPQ_COMPRESSION_PKWARE; + + dwCompressionNext &= ~(MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO); + bIsAdpcmCompression = true; } // Initiate adding file to the MPQ @@ -853,6 +913,21 @@ bool WINAPI SFileAddFileEx( break; } + // If the file being added is a WAVE file, we check number of channels + if(bIsFirstSector && bIsAdpcmCompression) + { + // The file must really be a wave file, otherwise it's data corruption + if(!IsWaveFile(pbFileData, dwBytesToRead, &dwChannels)) + { + nError = ERROR_BAD_FORMAT; + break; + } + + // Setup the compression according to number of channels + dwCompressionNext |= (dwChannels == 1) ? MPQ_COMPRESSION_ADPCM_MONO : MPQ_COMPRESSION_ADPCM_STEREO; + bIsFirstSector = false; + } + // Add the file sectors to the MPQ if(!SFileWriteFile(hMpqFile, pbFileData, dwBytesToRead, dwCompression)) { @@ -920,12 +995,12 @@ bool WINAPI SFileAddWave(HANDLE hMpq, const TCHAR * szFileName, const char * szA case MPQ_WAVE_QUALITY_MEDIUM: // WaveCompressionLevel = 4; - dwCompression = MPQ_COMPRESSION_WAVE_STEREO | MPQ_COMPRESSION_HUFFMANN; + dwCompression = MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN; break; case MPQ_WAVE_QUALITY_LOW: // WaveCompressionLevel = 2; - dwCompression = MPQ_COMPRESSION_WAVE_STEREO | MPQ_COMPRESSION_HUFFMANN; + dwCompression = MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN; break; } -- cgit v1.2.3