aboutsummaryrefslogtreecommitdiff
path: root/src/SFileAddFile.cpp
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2014-02-24 10:49:04 +0100
committerLadislav Zezula <ladislav.zezula@avg.com>2014-02-24 10:49:04 +0100
commit11f1d89cee7d09b8ffa2350cd2ee5a1b929260bf (patch)
tree29cd34b53b63645a4bbacd4999d601f465a6ff90 /src/SFileAddFile.cpp
parenta49ccff3d122825d8f1a46737a9b5c11e87c4ff4 (diff)
+ If BitsPerSample in a WAVE file is less than 16, StormLib does not use ADPCM compression
+ Added unit test for MONO and MONO-less-than-16-BitsPerSample WAVE files
Diffstat (limited to 'src/SFileAddFile.cpp')
-rw-r--r--src/SFileAddFile.cpp64
1 files changed, 38 insertions, 26 deletions
diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp
index 1fa5873..a7d99ea 100644
--- a/src/SFileAddFile.cpp
+++ b/src/SFileAddFile.cpp
@@ -14,7 +14,17 @@
#include "StormCommon.h"
//-----------------------------------------------------------------------------
-// Local structures
+// Local variables
+
+// Mask for lossy compressions
+#define MPQ_LOSSY_COMPRESSION_MASK (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN)
+
+// Data compression for SFileAddFile
+// Kept here for compatibility with code that was created with StormLib version < 6.50
+static DWORD DefaultDataCompression = MPQ_COMPRESSION_PKWARE;
+
+//-----------------------------------------------------------------------------
+// WAVE verification
#define FILE_SIGNATURE_RIFF 0x46464952
#define FILE_SIGNATURE_WAVE 0x45564157
@@ -40,34 +50,29 @@ typedef struct _WAVE_FILE_HEADER
// Followed by "data" sub-chunk (we don't care)
} WAVE_FILE_HEADER, *PWAVE_FILE_HEADER;
-//-----------------------------------------------------------------------------
-// Local variables
-
-// Data compression for SFileAddFile
-// Kept here for compatibility with code that was created with StormLib version < 6.50
-static DWORD DefaultDataCompression = MPQ_COMPRESSION_PKWARE;
-
-
-//-----------------------------------------------------------------------------
-// MPQ write data functions
-
-#define LOSSY_COMPRESSION_MASK (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN)
-
-static bool IsWaveFile(
+static bool IsWaveFile_16BitsPerAdpcmSample(
LPBYTE pbFileData,
DWORD cbFileData,
LPDWORD pdwChannels)
{
PWAVE_FILE_HEADER pWaveHdr = (PWAVE_FILE_HEADER)pbFileData;
+ // The amount of file data must be at least size of WAVE header
if(cbFileData > sizeof(WAVE_FILE_HEADER))
{
+ // Check for the RIFF header
if(pWaveHdr->dwChunkId == FILE_SIGNATURE_RIFF && pWaveHdr->dwFormat == FILE_SIGNATURE_WAVE)
{
+ // Check for ADPCM format
if(pWaveHdr->dwSubChunk1Id == FILE_SIGNATURE_FMT && pWaveHdr->wAudioFormat == AUDIO_FORMAT_PCM)
{
- *pdwChannels = pWaveHdr->wChannels;
- return true;
+ // Now the number of bits per sample must be at least 16.
+ // If not, the WAVE file gets corrupted by the ADPCM compression
+ if(pWaveHdr->wBitsPerSample >= 0x10)
+ {
+ *pdwChannels = pWaveHdr->wChannels;
+ return true;
+ }
}
}
}
@@ -75,6 +80,8 @@ static bool IsWaveFile(
return false;
}
+//-----------------------------------------------------------------------------
+// MPQ write data functions
static int WriteDataToMpqFile(
TMPQArchive * ha,
@@ -178,7 +185,7 @@ static int WriteDataToMpqFile(
// If the caller wants ADPCM compression, we will set wave compression level to 4,
// which corresponds to medium quality
- nCompressionLevel = (dwCompression & LOSSY_COMPRESSION_MASK) ? 4 : -1;
+ nCompressionLevel = (dwCompression & MPQ_LOSSY_COMPRESSION_MASK) ? 4 : -1;
SCompCompress(pbCompressed, &nOutBuffer, hf->pbFileSector, nInBuffer, (unsigned)dwCompression, 0, nCompressionLevel);
}
@@ -751,7 +758,7 @@ bool WINAPI SFileWriteFile(
// nError = ERROR_INVALID_PARAMETER;
// Lossy compression is not allowed on single unit files
- if(dwCompression & LOSSY_COMPRESSION_MASK)
+ if(dwCompression & MPQ_LOSSY_COMPRESSION_MASK)
nError = ERROR_INVALID_PARAMETER;
}
@@ -855,7 +862,8 @@ bool WINAPI SFileAddFileEx(
// 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
+ // The compression of the first file sector must not be ADPCM
+ // in order not to corrupt the headers
if(dwCompression & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO))
dwCompression = MPQ_COMPRESSION_PKWARE;
@@ -888,15 +896,19 @@ bool WINAPI SFileAddFileEx(
// 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 will corrupt the file
- if(!IsWaveFile(pbFileData, dwBytesToRead, &dwChannels))
+ // The file must really be a WAVE file with at least 16 bits per sample,
+ // otherwise the ADPCM compression will corrupt it
+ if(IsWaveFile_16BitsPerAdpcmSample(pbFileData, dwBytesToRead, &dwChannels))
{
- nError = ERROR_BAD_FORMAT;
- break;
+ // Setup the compression of next sectors according to number of channels
+ dwCompressionNext |= (dwChannels == 1) ? MPQ_COMPRESSION_ADPCM_MONO : MPQ_COMPRESSION_ADPCM_STEREO;
+ }
+ else
+ {
+ // Setup the compression of next sectors to a lossless compression
+ dwCompressionNext = (dwCompression & MPQ_LOSSY_COMPRESSION_MASK) ? MPQ_COMPRESSION_PKWARE : dwCompression;
}
- // Setup the compression according to number of channels
- dwCompressionNext |= (dwChannels == 1) ? MPQ_COMPRESSION_ADPCM_MONO : MPQ_COMPRESSION_ADPCM_STEREO;
bIsFirstSector = false;
}