shithub: dumb

Download patch

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);