Update DUMB to revision 5bee3e5ba3d57d1b16dda6d82c18fb417781625b

- Fixed XM reader for files with smaller than expected instrument or sample header sizes



SVN r4092 (trunk)
This commit is contained in:
Randy Heit 2013-02-08 00:40:36 +00:00
parent 3681a6673f
commit 4163817eda

View file

@ -111,6 +111,7 @@ typedef struct XM_INSTRUMENT_EXTRA
int vibrato_sweep; /* 0-0xFF */ int vibrato_sweep; /* 0-0xFF */
int vibrato_depth; /* 0-0x0F */ int vibrato_depth; /* 0-0x0F */
int vibrato_speed; /* 0-0x3F */ int vibrato_speed; /* 0-0x3F */
int sample_header_size;
} }
XM_INSTRUMENT_EXTRA; XM_INSTRUMENT_EXTRA;
@ -359,6 +360,116 @@ static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data
typedef struct LIMITED_XM LIMITED_XM;
struct LIMITED_XM
{
unsigned char *buffered;
long ptr, limit, allocated;
DUMBFILE *remaining;
};
/* XXX */
struct DUMBFILE
{
DUMBFILE_SYSTEM *dfs;
void *file;
long pos;
};
static int limit_xm_resize(void *f, long n)
{
DUMBFILE *df = f;
LIMITED_XM *lx = df->file;
if (lx->buffered || n) {
if (n > lx->allocated) {
unsigned char *buffered = realloc( lx->buffered, n );
if ( !buffered ) return -1;
lx->buffered = buffered;
memset( buffered + lx->allocated, 0, n - lx->allocated );
lx->allocated = n;
}
if ( dumbfile_getnc( lx->buffered, n, lx->remaining ) < n ) return -1;
} else if (!n) {
if ( lx->buffered ) free( lx->buffered );
lx->buffered = NULL;
lx->allocated = 0;
}
lx->limit = n;
lx->ptr = 0;
return 0;
}
static int limit_xm_skip(void *f, long n)
{
LIMITED_XM *lx = f;
lx->ptr += n;
return 0;
}
static int limit_xm_getc(void *f)
{
LIMITED_XM *lx = f;
if (lx->ptr >= lx->allocated) {
return 0;
}
return lx->buffered[lx->ptr++];
}
static long limit_xm_getnc(char *ptr, long n, void *f)
{
LIMITED_XM *lx = f;
int left;
left = lx->allocated - lx->ptr;
if (n > left) {
if (left > 0) {
memcpy( ptr, lx->buffered + lx->ptr, left );
memset( ptr + left, 0, n - left );
} else {
memset( ptr, 0, n );
}
} else {
memcpy( ptr, lx->buffered + lx->ptr, n );
}
lx->ptr += n;
return n;
}
static void limit_xm_close(void *f)
{
LIMITED_XM *lx = f;
if (lx->buffered) free(lx->buffered);
/* Do NOT close lx->remaining */
free(f);
}
DUMBFILE_SYSTEM limit_xm_dfs = {
NULL,
&limit_xm_skip,
&limit_xm_getc,
&limit_xm_getnc,
&limit_xm_close
};
static DUMBFILE *dumbfile_limit_xm(DUMBFILE *f)
{
LIMITED_XM * lx = malloc(sizeof(*lx));
lx->remaining = f;
lx->buffered = NULL;
lx->ptr = 0;
lx->limit = 0;
lx->allocated = 0;
return dumbfile_open_ex( lx, &limit_xm_dfs );
}
static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f) static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f)
{ {
uint32 size, bytes_read; uint32 size, bytes_read;
@ -370,8 +481,15 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA
* So unread bytes must be skipped before reading the first sample * So unread bytes must be skipped before reading the first sample
* header. * header.
*/ */
if ( limit_xm_resize( f, 4 ) < 0 ) return -1;
size = dumbfile_igetl(f); size = dumbfile_igetl(f);
if ( size == 0 ) size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2;
if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1;
dumbfile_getnc(instrument->name, 22, f); dumbfile_getnc(instrument->name, 22, f);
instrument->name[22] = 0; instrument->name[22] = 0;
instrument->filename[0] = 0; instrument->filename[0] = 0;
@ -385,12 +503,9 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA
if (extra->n_samples) { if (extra->n_samples) {
/* sample header size */ /* sample header size */
dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here i = dumbfile_igetl(f);
/*i = dumbfile_igetl(f); if (!i) i = 0x28;
if (i && i != 0x28) { // XXX some crap with 0 here extra->sample_header_size = i;
TRACE("XM error: unexpected sample header size\n");
return -1;
}*/
/* sample map */ /* sample map */
for (i = 0; i < 96; i++) { for (i = 0; i < 96; i++) {
@ -476,7 +591,7 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA
for (i = 0; i < 96; i++) for (i = 0; i < 96; i++)
instrument->map_sample[i] = 0; instrument->map_sample[i] = 0;
if (dumbfile_skip(f, size - bytes_read)) if (size > bytes_read && dumbfile_skip(f, size - bytes_read))
return -1; return -1;
instrument->new_note_action = NNA_NOTE_CUT; instrument->new_note_action = NNA_NOTE_CUT;
@ -924,16 +1039,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
for (i = 0; i < sigdata->n_instruments; i++) { for (i = 0; i < sigdata->n_instruments; i++) {
XM_INSTRUMENT_EXTRA extra; XM_INSTRUMENT_EXTRA extra;
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) { DUMBFILE * lf = dumbfile_limit_xm( f );
if ( !lf ) {
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) {
// XXX // XXX
if ( ! i ) if ( ! i )
{ {
TRACE("XM error: instrument %d\n", i+1); TRACE("XM error: instrument %d\n", i+1);
dumbfile_close( lf );
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
return NULL; return NULL;
} }
else else
{ {
dumbfile_close( lf );
sigdata->n_instruments = i; sigdata->n_instruments = i;
break; break;
} }
@ -948,17 +1071,31 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
if (!sigdata->sample) { if (!sigdata->sample) {
dumbfile_close( lf );
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
return NULL; return NULL;
} }
for (j = total_samples; j < total_samples+extra.n_samples; j++) for (j = total_samples; j < total_samples+extra.n_samples; j++)
sigdata->sample[j].data = NULL; sigdata->sample[j].data = NULL;
if ( limit_xm_resize( lf, 0 ) < 0 ) {
dumbfile_close( lf );
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
/* read instrument's samples */ /* read instrument's samples */
for (j = 0; j < extra.n_samples; j++) { for (j = 0; j < extra.n_samples; j++) {
IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
int b = it_xm_read_sample_header(sample, f); int b;
if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) {
dumbfile_close( lf );
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
b = it_xm_read_sample_header(sample, lf);
if (b < 0) { if (b < 0) {
dumbfile_close( lf );
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
return NULL; return NULL;
} }
@ -975,12 +1112,15 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
} }
for (j = 0; j < extra.n_samples; j++) { for (j = 0; j < extra.n_samples; j++) {
if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) { if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
dumbfile_close( lf );
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
return NULL; return NULL;
} }
} }
total_samples += extra.n_samples; total_samples += extra.n_samples;
} }
dumbfile_close( lf );
} }
sigdata->n_samples = total_samples; sigdata->n_samples = total_samples;
@ -1012,8 +1152,16 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
for (i = 0; i < sigdata->n_instruments; i++) { for (i = 0; i < sigdata->n_instruments; i++) {
XM_INSTRUMENT_EXTRA extra; XM_INSTRUMENT_EXTRA extra;
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) { DUMBFILE * lf = dumbfile_limit_xm( f );
if ( !lf ) {
free(roguebytes);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
if (it_xm_read_instrument(&sigdata->instrument[i], &extra, lf) < 0) {
TRACE("XM error: instrument %d\n", i+1); TRACE("XM error: instrument %d\n", i+1);
dumbfile_close(lf);
free(roguebytes); free(roguebytes);
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
return NULL; return NULL;
@ -1026,6 +1174,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
if (!sigdata->sample) { if (!sigdata->sample) {
dumbfile_close( lf );
free(roguebytes); free(roguebytes);
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
return NULL; return NULL;
@ -1033,10 +1182,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
for (j = total_samples; j < total_samples+extra.n_samples; j++) for (j = total_samples; j < total_samples+extra.n_samples; j++)
sigdata->sample[j].data = NULL; sigdata->sample[j].data = NULL;
if ( limit_xm_resize( lf, 0 ) < 0 ) {
dumbfile_close( lf );
free( roguebytes );
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
/* read instrument's samples */ /* read instrument's samples */
for (j = 0; j < extra.n_samples; j++) { for (j = 0; j < extra.n_samples; j++) {
IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
int b = it_xm_read_sample_header(sample, f); int b;
if ( limit_xm_resize( lf, extra.sample_header_size ) < 0 ) {
dumbfile_close( lf );
free( roguebytes );
_dumb_it_unload_sigdata( sigdata );
return NULL;
}
b = it_xm_read_sample_header(sample, lf);
if (b < 0) { if (b < 0) {
free(roguebytes); free(roguebytes);
_dumb_it_unload_sigdata(sigdata); _dumb_it_unload_sigdata(sigdata);
@ -1055,6 +1218,8 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
} }
total_samples += extra.n_samples; total_samples += extra.n_samples;
} }
dumbfile_close( lf );
} }
sigdata->n_samples = total_samples; sigdata->n_samples = total_samples;