summaryrefslogtreecommitdiff
path: root/plugins/dumb/dumb-kode54/src/helpers/riff.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/dumb/dumb-kode54/src/helpers/riff.c')
-rw-r--r--plugins/dumb/dumb-kode54/src/helpers/riff.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/plugins/dumb/dumb-kode54/src/helpers/riff.c b/plugins/dumb/dumb-kode54/src/helpers/riff.c
new file mode 100644
index 00000000..62a7eccc
--- /dev/null
+++ b/plugins/dumb/dumb-kode54/src/helpers/riff.c
@@ -0,0 +1,88 @@
+#include "internal/riff.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct riff * riff_parse( unsigned char * ptr, unsigned size, unsigned proper )
+{
+ unsigned stream_size;
+ struct riff * stream;
+
+ if ( size < 8 ) return 0;
+
+ if ( ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F' ) return 0;
+
+ stream_size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
+ if ( stream_size + 8 > size ) return 0;
+ if ( stream_size < 4 ) return 0;
+
+ stream = malloc( sizeof( struct riff ) );
+ if ( ! stream ) return 0;
+
+ stream->type = ( ptr[8] << 24 ) | ( ptr[9] << 16 ) | ( ptr[10] << 8 ) | ptr[11];
+ stream->chunk_count = 0;
+ stream->chunks = 0;
+
+ ptr += 12;
+ stream_size -= 4;
+
+ while ( stream_size )
+ {
+ struct riff_chunk * chunk;
+ if ( stream_size < 8 ) break;
+ stream->chunks = realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) );
+ if ( ! stream->chunks ) break;
+ chunk = stream->chunks + stream->chunk_count;
+ chunk->type = ( ptr[0] << 24 ) | ( ptr[1] << 16 ) | ( ptr[2] << 8 ) | ptr[3];
+ chunk->size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
+ ptr += 8;
+ stream_size -= 8;
+ if ( stream_size < chunk->size ) break;
+ if ( chunk->type == 'RIFF' )
+ {
+ chunk->data = riff_parse( ptr - 8, chunk->size + 8, proper );
+ if ( ! chunk->data ) break;
+ }
+ else
+ {
+ chunk->data = malloc( chunk->size );
+ if ( ! chunk->data ) break;
+ memcpy( chunk->data, ptr, chunk->size );
+ }
+ ptr += chunk->size;
+ stream_size -= chunk->size;
+ if ( proper && ( chunk->size & 1 ) )
+ {
+ ++ ptr;
+ -- 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->type == 'RIFF' ) riff_free( ( struct riff * ) chunk->data );
+ else free( chunk->data );
+ }
+ free( stream->chunks );
+ }
+ free( stream );
+ }
+}