Cog/Frameworks/Dumb/dumb/src/helpers/riff.c
2017-09-26 16:11:54 -07:00

88 lines
2.4 KiB
C

#include "dumb.h"
#include "internal/riff.h"
#include <stdlib.h>
struct riff *riff_parse(DUMBFILE *f, long offset, long size, unsigned proper) {
unsigned stream_size;
struct riff *stream;
if (size < 8)
return 0;
if (dumbfile_seek(f, offset, DFS_SEEK_SET))
return 0;
if (dumbfile_mgetl(f) != DUMB_ID('R', 'I', 'F', 'F'))
return 0;
stream_size = (int)dumbfile_igetl(f);
if (stream_size + 8 > size)
return 0;
if (stream_size < 4)
return 0;
stream = (struct riff *)malloc(sizeof(struct riff));
if (!stream)
return 0;
stream->type = (int)dumbfile_mgetl(f);
stream->chunk_count = 0;
stream->chunks = 0;
stream_size -= 4;
while (stream_size && !dumbfile_error(f)) {
struct riff_chunk *chunk;
if (stream_size < 8)
break;
stream->chunks = (struct riff_chunk *)realloc(
stream->chunks,
(stream->chunk_count + 1) * sizeof(struct riff_chunk));
if (!stream->chunks)
break;
chunk = stream->chunks + stream->chunk_count;
chunk->type = (int)dumbfile_mgetl(f);
chunk->size = (int)dumbfile_igetl(f);
chunk->offset = dumbfile_pos(f);
stream_size -= 8;
if (stream_size < chunk->size)
break;
if (chunk->type == DUMB_ID('R', 'I', 'F', 'F')) {
chunk->nested =
riff_parse(f, chunk->offset - 8, chunk->size + 8, proper);
if (!chunk->nested)
break;
} else {
chunk->nested = 0;
}
dumbfile_seek(f, chunk->offset + chunk->size, DFS_SEEK_SET);
stream_size -= chunk->size;
if (proper && (chunk->size & 1)) {
dumbfile_skip(f, 1);
--stream_size;
}
++stream->chunk_count;
}
if (stream_size) {
riff_free(stream);
stream = 0;
}
return stream;
}
void riff_free(struct riff *stream) {
if (stream) {
if (stream->chunks) {
unsigned i;
for (i = 0; i < stream->chunk_count; ++i) {
struct riff_chunk *chunk = stream->chunks + i;
if (chunk->nested)
riff_free(chunk->nested);
}
free(stream->chunks);
}
free(stream);
}
}