Commit message: Fix CVE-2018-17097 by rounding working buffer size up to nearest 4-byte boundary. Replaced also tab characters with spaces in indentation.
CVE: CVE-2018-17097
CWE: CWE-415
Vulnerability description: The WavFileBase class in WavFile.cpp in Olli Parviainen SoundTouch 2.0 allows remote attackers to cause a denial of service (double free) or possibly have unspecified other impact, as demonstrated by SoundStretch.

Project: soundtouch
File: WavFile.cpp

int WavInFile::readHeaderBlock()
{
    char label[5];
    string sLabel;

    // lead label string
    if (fread(label, 1, 4, fptr) !=4) return -1;
    label[4] = 0;

    if (isAlphaStr(label) == 0) return -1;    // not a valid label

    // Decode blocks according to their label
    if (strcmp(label, fmtStr) == 0)
    {
        int nLen, nDump;

        // 'fmt ' block 
        memcpy(header.format.fmt, fmtStr, 4);

        // read length of the format field
        if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
        // swap byte order if necessary
        _swap32(nLen);

        // calculate how much length differs from expected 
        nDump = nLen - ((int)sizeof(header.format) - 8);

        // verify that header length isn't smaller than expected structure
        if ((nLen < 0) || (nDump < 0)) return -1;

        header.format.format_len = nLen;

        // if format_len is larger than expected, read only as much data as we've space for
        if (nDump > 0)
        {
            nLen = sizeof(header.format) - 8;
        }

        // read data
        if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;

        // swap byte order if necessary
        _swap16((short &)header.format.fixed);            // short int fixed;
        _swap16((short &)header.format.channel_number);   // short int channel_number;
        _swap32((int &)header.format.sample_rate);        // int sample_rate;
        _swap32((int &)header.format.byte_rate);          // int byte_rate;
        _swap16((short &)header.format.byte_per_sample);  // short int byte_per_sample;
        _swap16((short &)header.format.bits_per_sample);  // short int bits_per_sample;

        // if format_len is larger than expected, skip the extra data
        if (nDump > 0)
        {
            fseek(fptr, nDump, SEEK_CUR);
        }

        return 0;
    }
    else if (strcmp(label, factStr) == 0)
    {
        int nLen, nDump;

        // 'fact' block 
        memcpy(header.fact.fact_field, factStr, 4);

        // read length of the fact field
        if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
        // swap byte order if necessary
        _swap32(nLen);

        // calculate how much length differs from expected
        nDump = nLen - ((int)sizeof(header.fact) - 8);

        // verify that fact length isn't smaller than expected structure
        if ((nLen < 0) || (nDump < 0)) return -1;

        header.fact.fact_len = nLen;

        // if format_len is larger than expected, read only as much data as we've space for
        if (nDump > 0)
        {
            nLen = sizeof(header.fact) - 8;
        }

        // read data
        if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1;

        // swap byte order if necessary
        _swap32((int &)header.fact.fact_sample_len);    // int sample_length;

        // if fact_len is larger than expected, skip the extra data
        if (nDump > 0)
        {
            fseek(fptr, nDump, SEEK_CUR);
        }

        return 0;
    }
    else if (strcmp(label, dataStr) == 0)
    {
        // 'data' block
        memcpy(header.data.data_field, dataStr, 4);
        if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;

        // swap byte order if necessary
        _swap32((int &)header.data.data_len);

        return 1;
    }
    else
    {
        uint len, i;
        uint temp;
        // unknown block

        // read length
        if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;
        // scan through the block
        for (i = 0; i < len; i ++)
        {
            if (fread(&temp, 1, 1, fptr) != 1) return -1;
            if (feof(fptr)) return -1;   // unexpected eof
        }
    }
    return 0;
}

Project: soundtouch
File: WavFile.cpp

void WavInFile::init()
{
    int hdrsOk;

    // assume file stream is already open
    assert(fptr);

    // Read the file headers
    hdrsOk = readWavHeaders();
    if (hdrsOk != 0) 
    {
        // Something didn't match in the wav file headers 
        ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");
    }

    // sanity check for format parameters
    if ((header.format.channel_number < 1)  || (header.format.channel_number > 9) ||
        (header.format.sample_rate < 4000)  || (header.format.sample_rate > 192000) ||
        (header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) ||
        (header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32))
    {
        // Something didn't match in the wav file headers 
        ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");
    }

    dataRead = 0;
}

Project: soundtouch
File: WavFile.cpp

void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
{
    // fill in the 'riff' part..

    // copy string 'RIFF' to riff_char
    memcpy(&(header.riff.riff_char), riffStr, 4);
    // package_len unknown so far
    header.riff.package_len = 0;
    // copy string 'WAVE' to wave
    memcpy(&(header.riff.wave), waveStr, 4);

    // fill in the 'format' part..

    // copy string 'fmt ' to fmt
    memcpy(&(header.format.fmt), fmtStr, 4);

    header.format.format_len = 0x10;
    header.format.fixed = 1;
    header.format.channel_number = (short)channels;
    header.format.sample_rate = (int)sampleRate;
    header.format.bits_per_sample = (short)bits;
    header.format.byte_per_sample = (short)(bits * channels / 8);
    header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
    header.format.sample_rate = (int)sampleRate;

    // fill in the 'fact' part...
    memcpy(&(header.fact.fact_field), factStr, 4);
    header.fact.fact_len = 4;
    header.fact.fact_sample_len = 0;

    // fill in the 'data' part..

    // copy string 'data' to data_field
    memcpy(&(header.data.data_field), dataStr, 4);
    // data_len unknown so far
    header.data.data_len = 0;
}

Project: soundtouch
File: WavFile.cpp

void WavOutFile::finishHeader()
{
    // supplement the file length into the header structure
    header.riff.package_len = bytesWritten + sizeof(WavHeader) - sizeof(WavRiff) + 4;
    header.data.data_len = bytesWritten;
    header.fact.fact_sample_len = bytesWritten / header.format.byte_per_sample; 
    
    writeHeader();
}