gboolean
gst_wavpack_read_header (WavpackHeader * header, guint8 * buf)
{
  memmove (header, buf, sizeof (WavpackHeader));

#ifndef WAVPACK_OLD_API
  WavpackLittleEndianToNative (header, (char *) WavpackHeaderFormat);
#else
  little_endian_to_native (header, WavpackHeaderFormat);
#endif

  return (memcmp (header->ckID, "wvpk", 4) == 0);
}
Example #2
0
WavpackContext *open_file3 (WavpackContext *wpc, char *error)
{
    RiffChunkHeader RiffChunkHeader;
    WpChunkHeader WpChunkHeader;
    WavpackHeader3 wphdr;
    WavpackStream3 *wps;
    WaveHeader3 wavhdr;

    CLEAR (wavhdr);
    wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3));
    CLEAR (*wps);

    if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) !=
        sizeof (RiffChunkHeader)) {
            if (error) strcpy (error, "not a valid WavPack file!");
            return WavpackCloseFile (wpc);
    }

    if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) {

        if (wpc->open_flags & OPEN_WRAPPER) {
            wpc->wrapper_data = malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader));
            memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader));
        }

    // If the first chunk is a wave RIFF header, then read the various chunks
    // until we get to the "data" chunk (and WavPack header should follow). If
    // the first chunk is not a RIFF, then we assume a "raw" WavPack file and
    // the WavPack header must be first.

        while (1) {

            if (wpc->reader->read_bytes (wpc->wv_in, &WpChunkHeader, sizeof (WpChunkHeader)) !=
                sizeof (WpChunkHeader)) {
                    if (error) strcpy (error, "not a valid WavPack file!");
                    return WavpackCloseFile (wpc);
            }
            else {
                if (wpc->open_flags & OPEN_WRAPPER) {
                    wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (WpChunkHeader));
                    memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &WpChunkHeader, sizeof (WpChunkHeader));
                    wpc->wrapper_bytes += sizeof (WpChunkHeader);
                }

                WavpackLittleEndianToNative (&WpChunkHeader, ChunkHeaderFormat);

                if (!strncmp (WpChunkHeader.ckID, "fmt ", 4)) {

                    if (WpChunkHeader.ckSize < sizeof (wavhdr) ||
                        wpc->reader->read_bytes (wpc->wv_in, &wavhdr, sizeof (wavhdr)) != sizeof (wavhdr)) {
                            if (error) strcpy (error, "not a valid WavPack file!");
                            return WavpackCloseFile (wpc);
                    }
                    else if (wpc->open_flags & OPEN_WRAPPER) {
                        wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr));
                        memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr));
                        wpc->wrapper_bytes += sizeof (wavhdr);
                    }

                    WavpackLittleEndianToNative (&wavhdr, WaveHeader3Format);

                    if (WpChunkHeader.ckSize > sizeof (wavhdr)) {
                        uint32_t bytes_to_skip = (WpChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L;

                        if (bytes_to_skip > 1024 * 1024) {
                            if (error) strcpy (error, "not a valid WavPack file!");
                            return WavpackCloseFile (wpc);
                        }

                        if (wpc->open_flags & OPEN_WRAPPER) {
                            wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
                            wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
                            wpc->wrapper_bytes += bytes_to_skip;
                        }
                        else {
                            unsigned char *temp = malloc (bytes_to_skip);
                            wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
                            free (temp);
                        }
                    }
                }
                else if (!strncmp (WpChunkHeader.ckID, "data", 4))
                    break;
                else if ((WpChunkHeader.ckSize + 1) & ~1L) {
                    uint32_t bytes_to_skip = (WpChunkHeader.ckSize + 1) & ~1L;

                    if (bytes_to_skip > 1024 * 1024) {
                        if (error) strcpy (error, "not a valid WavPack file!");
                        return WavpackCloseFile (wpc);
                    }

                    if (wpc->open_flags & OPEN_WRAPPER) {
                        wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
                        wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
                        wpc->wrapper_bytes += bytes_to_skip;
                    }
                    else {
                        unsigned char *temp = malloc (bytes_to_skip);
                        wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
                        free (temp);
                    }
                }
            }
        }
    }
    else {
        if (error) strcpy (error, "not a valid WavPack file!");
        return WavpackCloseFile (wpc);
    }

    if (wavhdr.FormatTag != 1 || !wavhdr.NumChannels || wavhdr.NumChannels > 2 ||
        !wavhdr.SampleRate || wavhdr.BitsPerSample < 16 || wavhdr.BitsPerSample > 24 ||
        wavhdr.BlockAlign / wavhdr.NumChannels > 3 || wavhdr.BlockAlign % wavhdr.NumChannels ||
        wavhdr.BlockAlign / wavhdr.NumChannels < (wavhdr.BitsPerSample + 7) / 8) {
            if (error) strcpy (error, "not a valid WavPack file!");
            return WavpackCloseFile (wpc);
    }

    wpc->total_samples = WpChunkHeader.ckSize / wavhdr.NumChannels /
        ((wavhdr.BitsPerSample > 16) ? 3 : 2);

    if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) {
        if (error) strcpy (error, "not a valid WavPack file!");
        return WavpackCloseFile (wpc);
    }

    if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) {
        if (error) strcpy (error, "not a valid WavPack file!");
        return WavpackCloseFile (wpc);
    }
    else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10,
        sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) {
            if (error) strcpy (error, "not a valid WavPack file!");
            return WavpackCloseFile (wpc);
    }

    WavpackLittleEndianToNative (&wphdr, WavpackHeader3Format);

    // make sure this is a version we know about

    if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) {
        if (error) strcpy (error, "not a valid WavPack file!");
        return WavpackCloseFile (wpc);
    }

    // Because I ran out of flag bits in the WavPack header, an amazingly ugly
    // kludge was forced upon me! This code takes care of preparing the flags
    // field for internal use and checking for unknown formats we can't decode

    if (wphdr.version == 3) {

        if (wphdr.flags & EXTREME_DECORR) {

            if ((wphdr.flags & NOT_STORED_FLAGS) ||
                ((wphdr.bits) &&
                (((wphdr.flags & NEW_HIGH_FLAG) &&
                (wphdr.flags & (FAST_FLAG | HIGH_FLAG))) ||
                (wphdr.flags & CROSS_DECORR)))) {
                    if (error) strcpy (error, "not a valid WavPack file!");
                    return WavpackCloseFile (wpc);
            }

            if (wphdr.flags & CANCEL_EXTREME)
                wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME);
        }
        else
            wphdr.flags &= ~CROSS_DECORR;
    }

    // check to see if we should look for a "correction" file, and if so try
    // to open it for reading, then set WVC_FLAG accordingly

    if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) {
        wpc->file2len = wpc->reader->get_length (wpc->wvc_in);
        wphdr.flags |= WVC_FLAG;
        wpc->wvc_flag = TRUE;
    }
    else
        wphdr.flags &= ~WVC_FLAG;

    // check WavPack version to handle special requirements of versions
    // before 3.0 that had smaller headers

    if (wphdr.version < 3) {
        wphdr.total_samples = (int32_t) wpc->total_samples;
        wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0;
        wphdr.shift = 16 - wavhdr.BitsPerSample;

        if (wphdr.version == 1)
            wphdr.bits = 0;
    }

    wpc->config.sample_rate = wavhdr.SampleRate;
    wpc->config.num_channels = wavhdr.NumChannels;
    wpc->config.channel_mask = 5 - wavhdr.NumChannels;

    if (wphdr.flags & MONO_FLAG)
        wpc->config.flags |= CONFIG_MONO_FLAG;

    if (wphdr.flags & EXTREME_DECORR)
        wpc->config.flags |= CONFIG_HIGH_FLAG;

    if (wphdr.bits) {
        if (wphdr.flags & NEW_HIGH_FLAG)
            wpc->config.flags |= CONFIG_HYBRID_FLAG;
        else
            wpc->config.flags |= CONFIG_LOSSY_MODE;
    }
    else if (!(wphdr.flags & HIGH_FLAG))
        wpc->config.flags |= CONFIG_FAST_FLAG;

    wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2;
    wpc->config.bits_per_sample = wavhdr.BitsPerSample;

    memcpy (&wps->wphdr, &wphdr, sizeof (wphdr));
    wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024;
    return wpc;
}