ref: a2f781fe0e786384ed36edb93aceb42b3b1b76ab
dir: /wav.c/
#include "quakedef.h" int wavinfo(byte *in, int len, wavinfo_t *info) { int i, n, sz, fmt, loopsamples; byte *p; memset(info, 0, sizeof(*info)); p = in; if(len < 36 || memcmp(p, "RIFF", 4) != 0){ werrstr("not a RIFF"); return -1; } p += 4; len -= 4; sz = le32(p); len -= 4; if(sz < 36 || sz > len){ werrstr("trucated? sz=%d len=%d", sz, len); return -1; } if(memcmp(p, "WAVE", 4) != 0){ werrstr("not a WAVE"); return -1; } p += 4; sz -= 4; loopsamples = 0; info->loopofs = -1; for(; sz >= 8;){ p += 4; sz -= 4; n = le32(p); sz -= 4; if(n > sz || n <= 0) break; if(n < 4) goto skip; if(memcmp(p-8, "fmt ", 4) == 0){ fmt = le16(p); sz -= 2; n -= 2; if(fmt != 1){ werrstr("not Microsoft PCM format: %d", fmt); return -1; } info->channels = le16(p); sz -= 2; n -= 2; info->rate = le32(p); sz -= 4; n -= 4; p += 4+2; sz -= 4+2; n -= 4+2; /* skip ByteRate + BlockAlign */ info->width = le16(p); sz -= 2; n -= 2; if(info->width < 1 || (info->width % 8) != 0){ werrstr("invalid width: %d", info->width); return -1; } info->width /= 8; }else if(memcmp(p-8, "cue ", 4) == 0){ i = le32(p); sz -= 4; n -= 4; /* CuePoints - usually two of those */ if(i >= 1 && n >= i*6*4){ p += 5*4; sz -= 5*4; n -= 5*4; /* Name+Position+Chunk+ChunkStart+BlockStart */ info->loopofs = le32(p); sz -= 4; n -= 4; /* FIXME(sigrid): check if this is needed and whether it works at all */ if(i > 1){ if(info->width < 1){ werrstr("cue chunk before fmt"); return -1; } p += 5*4; sz -= 5*4; n -= 5*4; /* Name+Position+Chunk+ChunkStart+BlockStart */ loopsamples = info->loopofs + le32(p); sz -= 4; n -= 4; if(loopsamples > info->samples) /* eg "nehahra/sounds/vondur/fan1.wav" */ loopsamples = info->samples; } } }else if(memcmp(p-8, "data", 4) == 0 && info->dataofs == 0){ info->samples = n / info->width; info->dataofs = p - in; }else if(memcmp(p-8, "LIST", 4) == 0 && info->loopofs >= 0 && loopsamples == 0){ p += 4; sz -= 4; n -= 4; /* skip "adtl" */ if(n >= 20 && memcmp(p, "ltxt", 4) == 0 && memcmp(p+16, "mark", 4) == 0){ p += 12; sz -= 12; n -= 12; loopsamples = info->loopofs + le32(p); sz -= 4; n -= 4; } } skip: n = (n + 1) & ~1; p += n; sz -= n; } if(info->width < 1 || info->channels < 1 || info->rate < 1){ werrstr("invalid/missing fmt chunk?"); return -1; } if(loopsamples > info->samples || info->loopofs > info->samples){ werrstr("invalid loop: (%d,%d) > %d", info->loopofs, loopsamples, info->samples); return -1; } if(loopsamples > 0) info->samples = loopsamples; return 0; }