file-handling · advanced · ~15 min

WAV RIFF Audio Header Parser

Parse real-world binary multimedia containers with magic byte verification and bounds checking.

Challenge

The RIFF WAV format is a ubiquitous binary container. The header specifies sample rate, audio channels, bit depth, and data chunk lengths encoded in Little-Endian format.

Your Task

Given the parsed WAV header structure:

typedef struct {
    uint16_t num_channels;   // 1 for mono, 2 for stereo
    uint32_t sample_rate;    // e.g. 44100
    uint16_t bits_per_sample;// e.g. 16
    uint32_t data_bytes;     // audio payload size
} WavHeaderInfo;

Implement:

int parse_wav_header(const uint8_t *raw, size_t len, WavHeaderInfo *out);

WAV Header Format (Minimum 44 bytes)

  • Bytes 0..3: "RIFF"
  • Bytes 4..7: File size - 8
  • Bytes 8..11: "WAVE"
  • Bytes 12..15: "fmt "
  • Bytes 16..19: fmt chunk size (Must equal 16 for standard PCM)
  • Bytes 20..21: Audio format (Must equal 1 for uncompressed PCM)
  • Bytes 22..23: num_channels (Little Endian)
  • Bytes 24..27: sample_rate (Little Endian)
  • Bytes 34..35: bits_per_sample (Little Endian)
  • Bytes 36..39: "data"
  • Bytes 40..43: data_bytes (Little Endian)

Rules

  1. If raw == NULL, out == NULL, or len < 44, return -1.
  2. Check magic markers: bytes 0..3 == "RIFF", bytes 8..11 == "WAVE", bytes 12..15 == "fmt ", bytes 36..39 == "data". If any mismatch, return -1.
  3. Verify PCM format: 16-bit format at bytes 20..21 must equal 1.
  4. Check 44 + (size_t)data_bytes <= len. If payload exceeds file, return -1.
  5. Populate out and return 0.

Example

WavHeaderInfo info;
parse_wav_header(wav_bytes, 44 + 1000, &info); // returns 0, info.sample_rate == 44100

Input format

raw: pointer to binary WAV header; len: total buffer length; out: output struct.

Output format

Returns 0 on valid PCM WAV header, or -1 on invalid format/truncation.

Constraints

Zero heap allocations. Little-endian integer decoding.

Starter code

#include <stddef.h>
#include <stdint.h>

typedef struct {
    uint16_t num_channels;
    uint32_t sample_rate;
    uint16_t bits_per_sample;
    uint32_t data_bytes;
} WavHeaderInfo;

int parse_wav_header(const uint8_t *raw, size_t len, WavHeaderInfo *out) {
    (void)raw; (void)len; (void)out;
    return -1;
}

Common mistakes

Decoding integers as big-endian instead of little-endian; ignoring audio format check.

Edge cases to handle

len < 44 returns -1; audio format != 1 returns -1; data_bytes exceeding len returns -1.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.