ref: ad8a234f3c6c9b3e7a2d590c81f297bf20375f6d
parent: 347a1170d6d00ec2ea9db2a3667ee7c8d2ef422b
author: Chris Moeller <kode54@gmail.com>
date: Sun Dec 23 08:32:31 EST 2012
Buffer entire file into memory to allow for weird file offsets, and add minimal Open/MPT extension reading
--- a/dumb/src/it/itread.c
+++ b/dumb/src/it/itread.c
@@ -32,17 +32,73 @@
-static int it_seek(DUMBFILE *f, long offset)
+typedef struct tdumbfile_mem_status
{
- long pos = dumbfile_pos(f);
+ const unsigned char * ptr;
+ unsigned offset, size;
+} dumbfile_mem_status;
- if (pos > offset)
- return -1;
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
+static int dumbfile_mem_skip(void * f, long n)
+{
+ dumbfile_mem_status * s = (dumbfile_mem_status *) f;
+ s->offset += n;
+ if (s->offset > s->size)
+ {
+ s->offset = s->size;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+static int dumbfile_mem_getc(void * f)
+{
+ dumbfile_mem_status * s = (dumbfile_mem_status *) f;
+ if (s->offset < s->size)
+ {
+ return *(s->ptr + s->offset++);
+ }
+ return -1;
+}
+
+
+
+static long dumbfile_mem_getnc(char * ptr, long n, void * f)
+{
+ dumbfile_mem_status * s = (dumbfile_mem_status *) f;
+ long max = s->size - s->offset;
+ if (max > n) max = n;
+ if (max)
+ {
+ memcpy(ptr, s->ptr + s->offset, max);
+ s->offset += max;
+ }
+ return max;
+}
+
+
+
+static DUMBFILE_SYSTEM mem_dfs = {
+ NULL, // open
+ &dumbfile_mem_skip,
+ &dumbfile_mem_getc,
+ &dumbfile_mem_getnc,
+ NULL // close
+};
+
+
+
+static int it_seek(dumbfile_mem_status * s, long offset)
+{
+ if ( offset > s->size )
+ return -1;
+
+ s->offset = offset;
+
return 0;
}
@@ -631,7 +687,7 @@
signed char * ptr, * end;
signed char compression_table[16];
if (dumbfile_getnc(compression_table, 16, f) != 16)
- return -1;
+ return -1;
ptr = (signed char *) sample->data;
delta = 0;
@@ -957,13 +1013,58 @@
unsigned char *buffer;
+ unsigned char *file_buffer = NULL;
+ unsigned int file_size = 0;
+ int block_size;
+
+ dumbfile_mem_status memdata;
+
+ do
+ {
+ void * temp = realloc( file_buffer, file_size + 32768 );
+ if ( !temp )
+ {
+ if ( file_buffer ) free( file_buffer );
+ return NULL;
+ }
+ file_buffer = temp;
+ block_size = dumbfile_getnc( file_buffer + file_size, 32768, f );
+ if ( block_size < 0 )
+ {
+ free( file_buffer );
+ return NULL;
+ }
+ file_size += block_size;
+ }
+ while ( block_size == 32768 );
+
+ memdata.ptr = file_buffer;
+ memdata.offset = 0;
+ memdata.size = file_size;
+
+ f = dumbfile_open_ex(&memdata, &mem_dfs);
+
+ if ( !f )
+ {
+ free( file_buffer );
+ return NULL;
+ }
+
if (dumbfile_mgetl(f) != IT_SIGNATURE)
+ {
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
+ }
sigdata = malloc(sizeof(*sigdata));
if (!sigdata)
+ {
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
+ }
sigdata->song_message = NULL;
sigdata->order = NULL;
@@ -1012,6 +1113,8 @@
// XXX sample count
if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1018,6 +1121,8 @@
sigdata->order = malloc(sigdata->n_orders);
if (!sigdata->order) {
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1025,6 +1130,8 @@
sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
if (!sigdata->instrument) {
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
}
@@ -1033,6 +1140,8 @@
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
if (!sigdata->sample) {
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
for (n = 0; n < sigdata->n_samples; n++)
@@ -1043,6 +1152,8 @@
sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
if (!sigdata->pattern) {
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
for (n = 0; n < sigdata->n_patterns; n++)
@@ -1055,6 +1166,8 @@
component = malloc(769 * sizeof(*component));
if (!component) {
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1099,6 +1212,8 @@
if (dumbfile_error(f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1119,6 +1234,8 @@
if (!sigdata->midi) {
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
// Should we be happy with this outcome in some situations?
}
@@ -1127,6 +1244,8 @@
if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
/* Read embedded MIDI configuration */
@@ -1134,6 +1253,8 @@
if (dumbfile_skip(f, 32*9)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
for (i = 0; i < 16; i++) {
@@ -1142,6 +1263,8 @@
if (dumbfile_getnc(mididata, 32, f) < 32) {
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
sigdata->midi->SFmacroz[i] = 0;
@@ -1197,12 +1320,14 @@
sigdata->flags &= IT_REAL_FLAGS;
- qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
+ qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
buffer = malloc(65536);
if (!buffer) {
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1231,10 +1356,12 @@
continue;
}
- if (it_seek(f, component[n].offset)) {
+ if (it_seek(&memdata, component[n].offset)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1250,6 +1377,8 @@
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
sigdata->song_message[message_length] = 0;
@@ -1266,6 +1395,8 @@
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
break;
@@ -1275,6 +1406,8 @@
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
break;
@@ -1284,6 +1417,8 @@
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1310,10 +1445,12 @@
m = component[n].sampfirst;
while (m >= 0) {
- if (it_seek(f, component[m].offset)) {
+ if (it_seek(&memdata, component[m].offset)) {
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
@@ -1321,15 +1458,78 @@
free(buffer);
free(component);
_dumb_it_unload_sigdata(sigdata);
+ dumbfile_close(f);
+ free(file_buffer);
return NULL;
}
m = component[m].sampnext;
}
- }
+ }
- free(buffer);
+ for ( n = 0; n < 10; n++ )
+ {
+ if ( dumbfile_getc( f ) == 'X' )
+ {
+ if ( dumbfile_getc( f ) == 'T' )
+ {
+ if ( dumbfile_getc( f ) == 'P' )
+ {
+ if ( dumbfile_getc( f ) == 'M' )
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ( !dumbfile_error( f ) && n < 10 )
+ {
+ unsigned int mptx_id = dumbfile_igetl( f );
+ while ( mptx_id != DUMB_ID('M','P','T','S') )
+ {
+ unsigned int size = dumbfile_igetw( f );
+ switch (mptx_id)
+ {
+ /* TODO: Add instrument extension readers */
+
+ default:
+ dumbfile_skip(f, size * sigdata->n_instruments);
+ break;
+ }
+
+ mptx_id = dumbfile_igetl( f );
+ }
+
+ mptx_id = dumbfile_igetl( f );
+ while ( memdata.offset < file_size )
+ {
+ unsigned int size = dumbfile_igetw( f );
+ switch (mptx_id)
+ {
+ /* TODO: Add more song extension readers */
+
+ case DUMB_ID('D','T','.','.'):
+ if ( size == 2 )
+ sigdata->tempo = dumbfile_igetw( f );
+ else if ( size == 4 )
+ sigdata->tempo = dumbfile_igetl( f );
+ break;
+
+ default:
+ dumbfile_skip(f, size);
+ break;
+ }
+ mptx_id = dumbfile_igetl( f );
+ }
+ }
+
+ free(buffer);
free(component);
+
+ dumbfile_close(f);
+ free(file_buffer);
_dumb_it_fix_invalid_orders(sigdata);