diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index d71bdac7..4211e31f 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -1032,6 +1032,15 @@ static void update_retrig(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *channel) } +static void update_smooth_effects_playing(IT_PLAYING *playing) +{ + playing->vibrato_time += playing->vibrato_n * + (playing->vibrato_speed << 2); + playing->tremolo_time += playing->tremolo_speed << 2; + playing->panbrello_time += playing->panbrello_speed; + if (playing->panbrello_waveform == 3) + playing->panbrello_random = (rand() % 129) - 64; +} static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer) { @@ -1042,12 +1051,15 @@ static void update_smooth_effects(DUMB_IT_SIGRENDERER *sigrenderer) IT_PLAYING *playing = channel->playing; if (playing) { - playing->vibrato_time += playing->vibrato_n * - (playing->vibrato_speed << 2); - playing->tremolo_time += playing->tremolo_speed << 2; - playing->panbrello_time += playing->panbrello_speed; - if (playing->panbrello_waveform == 3) - playing->panbrello_random = (rand() % 129) - 64; + update_smooth_effects_playing(playing); + } + } + + for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { + IT_PLAYING *playing = sigrenderer->playing[i]; + + if (playing) { + update_smooth_effects_playing(playing); } } } @@ -1083,7 +1095,7 @@ static void update_invert_loop(IT_CHANNEL *channel, IT_SAMPLE *sample) static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) { - int i; + int i, j; if (sigrenderer->globalvolslide) { sigrenderer->globalvolume += sigrenderer->globalvolslide; @@ -1167,6 +1179,10 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) } if (channel->playing) channel->playing->channel_volume = channel->channelvolume; + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) + sigrenderer->playing[j]->channel_volume = channel->channelvolume; + } } update_tremor(channel); @@ -1177,80 +1193,121 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) if (channel->inv_loop_speed) update_invert_loop(channel, playing ? playing->sample : NULL); - if (playing) { - playing->slide += channel->portamento; + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) break; + } + + if (playing || j < DUMB_IT_N_NNA_CHANNELS) { + if (playing) playing->slide += channel->portamento; + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) + sigrenderer->playing[j]->slide += channel->portamento; + } if (channel->okt_toneslide) { if (channel->okt_toneslide--) { - playing->note += channel->toneslide; - if (playing->note >= 120) { - if (channel->toneslide < 0) playing->note = 0; - else playing->note = 119; + if (playing) { + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + } + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) { + IT_PLAYING *playing = sigrenderer->playing[j]; + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + } } } } else if (channel->ptm_toneslide) { if (--channel->toneslide_tick == 0) { channel->toneslide_tick = channel->ptm_toneslide; - playing->note += channel->toneslide; - if (playing->note >= 120) { - if (channel->toneslide < 0) playing->note = 0; - else playing->note = 119; - } - channel->note = channel->truenote = playing->note; - if (channel->toneslide_retrig) { - it_playing_reset_resamplers(playing, 0); + if (playing) { + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + channel->note = channel->truenote = playing->note; + if (channel->toneslide_retrig) { + it_playing_reset_resamplers(playing, 0); #ifdef END_RAMPING - playing->declick_stage = 0; - playing->declick_volume = 1.f / 256.f; + playing->declick_stage = 0; + playing->declick_volume = 1.f / 256.f; #endif + } + } + for (j = 0; j < DUMB_IT_N_NNA_CHANNELS; j++) { + if (sigrenderer->playing[j] && sigrenderer->playing[j]->channel == channel) { + IT_PLAYING *playing = sigrenderer->playing[j]; + playing->note += channel->toneslide; + if (playing->note >= 120) { + if (channel->toneslide < 0) playing->note = 0; + else playing->note = 119; + } + if (channel->toneslide_retrig) { + it_playing_reset_resamplers(playing, 0); +#ifdef END_RAMPING + playing->declick_stage = 0; + playing->declick_volume = 1.f / 256.f; +#endif + } + } } } } - if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { - if (channel->toneporta && channel->destnote < 120) { - int currpitch = ((playing->note - 60) << 8) + playing->slide; - int destpitch = (channel->destnote - 60) << 8; - if (currpitch > destpitch) { - currpitch -= channel->toneporta; - if (currpitch < destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; - } - } else if (currpitch < destpitch) { - currpitch += channel->toneporta; + if (playing) { + if (sigrenderer->sigdata->flags & IT_LINEAR_SLIDES) { + if (channel->toneporta && channel->destnote < 120) { + int currpitch = ((playing->note - 60) << 8) + playing->slide; + int destpitch = (channel->destnote - 60) << 8; if (currpitch > destpitch) { - currpitch = destpitch; - channel->destnote = IT_NOTE_OFF; + currpitch -= channel->toneporta; + if (currpitch < destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } + } else if (currpitch < destpitch) { + currpitch += channel->toneporta; + if (currpitch > destpitch) { + currpitch = destpitch; + channel->destnote = IT_NOTE_OFF; + } } + playing->slide = currpitch - ((playing->note - 60) << 8); } - playing->slide = currpitch - ((playing->note - 60) << 8); - } - } else { - if (channel->toneporta && channel->destnote < 120) { - float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); + } else { + if (channel->toneporta && channel->destnote < 120) { + float amiga_multiplier = playing->sample->C5_speed * (1.0f / AMIGA_DIVISOR); - float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); - /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ + float deltanote = (float)pow(DUMB_SEMITONE_BASE, 60 - playing->note); + /* deltanote is 1.0 for C-5, 0.5 for C-6, etc. */ - float deltaslid = deltanote - playing->slide * amiga_multiplier; + float deltaslid = deltanote - playing->slide * amiga_multiplier; - float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); - if (deltaslid < destdelta) { - playing->slide -= channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; - if (deltaslid > destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; - } - } else { - playing->slide += channel->toneporta; - deltaslid = deltanote - playing->slide * amiga_multiplier; + float destdelta = (float)pow(DUMB_SEMITONE_BASE, 60 - channel->destnote); if (deltaslid < destdelta) { - playing->note = channel->destnote; - playing->slide = 0; - channel->destnote = IT_NOTE_OFF; + playing->slide -= channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid > destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; + } + } else { + playing->slide += channel->toneporta; + deltaslid = deltanote - playing->slide * amiga_multiplier; + if (deltaslid < destdelta) { + playing->note = channel->destnote; + playing->slide = 0; + channel->destnote = IT_NOTE_OFF; + } } } } @@ -1563,7 +1620,7 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan nna = channel->playing->instrument->new_note_action; #endif - if ((sigdata->flags & IT_USE_INSTRUMENTS) && (channel->playing->enabled_envelopes) && channel->playing->instnum == channel->instrument) { + if (!(channel->playing->flags & IT_PLAYING_DEAD) && (sigdata->flags & IT_USE_INSTRUMENTS) && (channel->playing->enabled_envelopes) && channel->playing->instnum == channel->instrument) { IT_PLAYING * playing = channel->playing; IT_INSTRUMENT * inst = &sigdata->instrument[channel->instrument-1]; if ((playing->enabled_envelopes & IT_ENV_VOLUME) && (inst->volume_envelope.flags & IT_ENVELOPE_CARRY)) { @@ -1684,7 +1741,8 @@ static void it_retrigger_note(DUMB_IT_SIGRENDERER *sigrenderer, IT_CHANNEL *chan if (!flags && sigdata->flags & IT_USE_INSTRUMENTS) { for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { IT_PLAYING * playing = sigrenderer->playing[i]; - if (playing && (playing->enabled_envelopes) && playing->instnum == channel->instrument) { + if (!playing || playing->channel != channel) continue; + if (playing->enabled_envelopes && playing->instnum == channel->instrument) { IT_INSTRUMENT * inst = &sigdata->instrument[channel->instrument-1]; if ((playing->enabled_envelopes & IT_ENV_VOLUME) && (inst->volume_envelope.flags & IT_ENVELOPE_CARRY)) { flags |= 1; @@ -1974,10 +2032,19 @@ static void xm_envelope_calculate_value(IT_ENVELOPE *envelope, IT_PLAYING_ENVELO extern const char xm_convert_vibrato[]; +const char mod_convert_vibrato[] = { + IT_VIBRATO_SINE, + IT_VIBRATO_RAMP_UP, /* this will be inverted by IT_OLD_EFFECTS */ + IT_VIBRATO_XM_SQUARE, + IT_VIBRATO_XM_SQUARE +}; + /* Returns 1 if a callback caused termination of playback. */ static int process_effects(DUMB_IT_SIGRENDERER *sigrenderer, IT_ENTRY *entry, int ignore_cxx) { DUMB_IT_SIGDATA *sigdata = sigrenderer->sigdata; + IT_PLAYING *playing; + int i; IT_CHANNEL *channel = &sigrenderer->channel[(int)entry->channel]; @@ -2034,10 +2101,17 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than break; case IT_VOLSLIDE_VIBRATO: - if (channel->playing) { - channel->playing->vibrato_speed = channel->lastHspeed; - channel->playing->vibrato_depth = channel->lastHdepth; - channel->playing->vibrato_n++; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->vibrato_speed = channel->lastHspeed; + playing->vibrato_depth = channel->lastHdepth; + playing->vibrato_n++; + } } /* Fall through and process volume slide. */ case IT_VOLUME_SLIDE: @@ -2133,15 +2207,22 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than v = channel->lastEF; channel->lastEF = v; } - if (channel->playing) { - if ((v & 0xF0) == 0xF0) - channel->playing->slide -= (v & 15) << 4; - else if ((v & 0xF0) == 0xE0) - channel->playing->slide -= (v & 15) << 2; - else if (sigdata->flags & IT_WAS_A_669) - channel->portamento -= v << 3; - else - channel->portamento -= v << 4; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + if ((v & 0xF0) == 0xF0) + playing->slide -= (v & 15) << 4; + else if ((v & 0xF0) == 0xE0) + playing->slide -= (v & 15) << 2; + else if (i < 0 && sigdata->flags & IT_WAS_A_669) + channel->portamento -= v << 3; + else if (i < 0) + channel->portamento -= v << 4; + } } } break; @@ -2168,15 +2249,22 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than v = channel->lastEF; channel->lastEF = v; } - if (channel->playing) { - if ((v & 0xF0) == 0xF0) - channel->playing->slide += (v & 15) << 4; - else if ((v & 0xF0) == 0xE0) - channel->playing->slide += (v & 15) << 2; - else if (sigdata->flags & IT_WAS_A_669) - channel->portamento += v << 3; - else - channel->portamento += v << 4; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (channel->playing) { + if ((v & 0xF0) == 0xF0) + channel->playing->slide += (v & 15) << 4; + else if ((v & 0xF0) == 0xE0) + channel->playing->slide += (v & 15) << 2; + else if (i < 0 && sigdata->flags & IT_WAS_A_669) + channel->portamento += v << 3; + else if (i < 0) + channel->portamento += v << 4; + } } } break; @@ -2219,16 +2307,23 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than if (depth == 0) depth = channel->lastHdepth; else { - if (sigdata->flags & IT_OLD_EFFECTS) + if (sigdata->flags & IT_OLD_EFFECTS && !(sigdata->flags & IT_WAS_A_MOD)) depth <<= 3; else depth <<= 2; channel->lastHdepth = depth; } - if (channel->playing) { - channel->playing->vibrato_speed = speed; - channel->playing->vibrato_depth = depth; - channel->playing->vibrato_n++; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->vibrato_speed = speed; + playing->vibrato_depth = depth; + playing->vibrato_n++; + } } } } @@ -2284,8 +2379,15 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than else channel->channelvolume = 64; #endif - if (channel->playing) - channel->playing->channel_volume = channel->channelvolume; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) + playing->channel_volume = channel->channelvolume; + } break; case IT_CHANNEL_VOLUME_SLIDE: { @@ -2306,8 +2408,15 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than if (channel->channelvolume > 64) channel->channelvolume = 0; } else break; - if (channel->playing) - channel->playing->channel_volume = channel->channelvolume; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) + playing->channel_volume = channel->channelvolume; + } } } break; @@ -2460,9 +2569,16 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than depth = channel->lastRdepth; channel->lastRdepth = depth; } - if (channel->playing) { - channel->playing->tremolo_speed = speed; - channel->playing->tremolo_depth = depth; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->tremolo_speed = speed; + playing->tremolo_depth = depth; + } } } break; @@ -2491,7 +2607,8 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than case IT_S_SET_VIBRATO_WAVEFORM: { int waveform = effectvalue & 3; - if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; + if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; + else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; channel->vibrato_waveform = waveform; if (channel->playing) { channel->playing->vibrato_waveform = waveform; @@ -2503,7 +2620,8 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than case IT_S_SET_TREMOLO_WAVEFORM: { int waveform = effectvalue & 3; - if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; + if (sigdata->flags & IT_WAS_A_MOD) waveform = mod_convert_vibrato[waveform]; + else if (sigdata->flags & IT_WAS_AN_XM) waveform = xm_convert_vibrato[waveform]; channel->tremolo_waveform = waveform; if (channel->playing) { channel->playing->tremolo_waveform = waveform; @@ -2681,10 +2799,17 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than depth <<= 1; channel->lastHdepth = depth; } - if (channel->playing) { - channel->playing->vibrato_speed = speed; - channel->playing->vibrato_depth = depth; - channel->playing->vibrato_n++; + for (i = -1; i < DUMB_IT_N_NNA_CHANNELS; i++) { + if (i < 0) playing = channel->playing; + else { + playing = sigrenderer->playing[i]; + if (!playing || playing->channel != channel) continue; + } + if (playing) { + playing->vibrato_speed = speed; + playing->vibrato_depth = depth; + playing->vibrato_n++; + } } } break; @@ -3571,7 +3696,7 @@ static int it_envelope_end(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYIN /* Returns 1 when fading should be initiated for a volume envelope. */ static int update_it_envelope(IT_PLAYING *playing, IT_ENVELOPE *envelope, IT_PLAYING_ENVELOPE *pe, int flags) { - if (!(playing->enabled_envelopes & flags)) + if (!(playing->enabled_envelopes & flags) || !envelope->n_nodes) return 0; ASSERT(envelope->n_nodes > 0); @@ -4287,13 +4412,13 @@ static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *play vol = (rand() % 129) - 64; break; case 4: - vol = it_xm_squarewave[playing->vibrato_time]; + vol = it_xm_squarewave[playing->tremolo_time]; break; case 5: - vol = it_xm_ramp[playing->vibrato_time]; + vol = it_xm_ramp[playing->tremolo_time]; break; case 6: - vol = it_xm_ramp[255-playing->vibrato_time]; + vol = it_xm_ramp[255-((sigrenderer->sigdata->flags & IT_WAS_A_MOD)?playing->vibrato_time:playing->tremolo_time)]; break; } vol *= playing->tremolo_depth; @@ -4314,7 +4439,7 @@ static float calculate_volume(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *play volume *= 1.0f / ((64 << 5) * 64.0f * 64.0f * 128.0f * 128.0f); if (volume && playing->instrument) { - if (playing->enabled_envelopes & IT_ENV_VOLUME) { + if (playing->enabled_envelopes & IT_ENV_VOLUME && playing->env_instrument->volume_envelope.n_nodes) { volume *= envelope_get_y(&playing->env_instrument->volume_envelope, &playing->volume_envelope); volume *= 1.0f / (64 << IT_ENVELOPE_SHIFT); } diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 05c1ba86..6995ffc2 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -631,7 +631,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) /* Work out how many patterns there are. */ sigdata->n_patterns = -1; - for (i = 0; i < 128; i++) + for (i = 0; i < sigdata->n_orders; i++) if (sigdata->n_patterns < sigdata->order[i]) sigdata->n_patterns = sigdata->order[i]; sigdata->n_patterns++; diff --git a/dumb/src/it/readokt.c b/dumb/src/it/readokt.c index 9ae05957..1f2fa944 100644 --- a/dumb/src/it/readokt.c +++ b/dumb/src/it/readokt.c @@ -497,7 +497,7 @@ static DUMB_IT_SIGDATA *it_okt_load_sigdata(DUMBFILE *f, int restrict) j++; } } - for (; i < sigdata->n_samples; i++) { + for (; i < (unsigned)sigdata->n_samples; i++) { sigdata->sample[i].flags = 0; } diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index be1b1572..a4b00f79 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -354,7 +354,7 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) for ( n = 0, q = o / 16; n < sigdata->n_samples; ++n ) { if ( sample_offset[ n ] ) { - sample_offset[ n ] -= q; + sample_offset[ n ] = (unsigned short)(sample_offset[ n ] - q); } } diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 7d1b4657..1930ba93 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -111,6 +111,7 @@ typedef struct XM_INSTRUMENT_EXTRA int vibrato_sweep; /* 0-0xFF */ int vibrato_depth; /* 0-0x0F */ int vibrato_speed; /* 0-0x3F */ + int sample_header_size; } XM_INSTRUMENT_EXTRA; @@ -359,19 +360,150 @@ 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_end(void *f, int32 n) +{ + DUMBFILE *df = f; + LIMITED_XM *lx = df->file; + return dumbfile_skip( lx->remaining, n ); +} + +static int limit_xm_skip(void *f, int32 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, int32 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) { uint32 size, bytes_read; unsigned short vol_points[24]; unsigned short pan_points[24]; int i, type; + const unsigned long max_size = 4 + 22 + 1 + 2 + 4 + 96 + 48 + 48 + 1 * 14 + 2 + 2; + unsigned long skip_end = 0; /* Header size. Tends to be more than the actual size of the structure. * So unread bytes must be skipped before reading the first sample * header. */ + + if ( limit_xm_resize( f, 4 ) < 0 ) return -1; + size = dumbfile_igetl(f); + if ( size == 0 ) size = max_size; + else if ( size > max_size ) + { + skip_end = size - max_size; + size = max_size; + } + + if ( limit_xm_resize( f, size - 4 ) < 0 ) return -1; + dumbfile_getnc(instrument->name, 22, f); instrument->name[22] = 0; instrument->filename[0] = 0; @@ -385,12 +517,11 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA if (extra->n_samples) { /* 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); - if (i && i != 0x28) { // XXX some crap with 0 here - TRACE("XM error: unexpected sample header size\n"); - return -1; - }*/ + if (!i || i > 0x28) i = 0x28;*/ + dumbfile_skip(f, 4); + i = 0x28; + extra->sample_header_size = i; /* sample map */ for (i = 0; i < 96; i++) { @@ -476,7 +607,10 @@ static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA for (i = 0; i < 96; i++) instrument->map_sample[i] = 0; - if (dumbfile_skip(f, size - bytes_read)) + if (size > bytes_read && dumbfile_skip(f, size - bytes_read)) + return -1; + + if (skip_end && limit_xm_skip_end(f, skip_end)) return -1; instrument->new_note_action = NNA_NOTE_CUT; @@ -924,16 +1058,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) for (i = 0; i < sigdata->n_instruments; i++) { 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 if ( ! i ) { TRACE("XM error: instrument %d\n", i+1); + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } else { + dumbfile_close( lf ); sigdata->n_instruments = i; break; } @@ -948,17 +1090,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)); if (!sigdata->sample) { + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } for (j = total_samples; j < total_samples+extra.n_samples; j++) 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 */ for (j = 0; j < extra.n_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) { + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } @@ -975,12 +1131,15 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) } for (j = 0; j < extra.n_samples; j++) { if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) { + dumbfile_close( lf ); _dumb_it_unload_sigdata(sigdata); return NULL; } } total_samples += extra.n_samples; } + + dumbfile_close( lf ); } sigdata->n_samples = total_samples; @@ -1012,8 +1171,16 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) for (i = 0; i < sigdata->n_instruments; i++) { 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); + dumbfile_close(lf); free(roguebytes); _dumb_it_unload_sigdata(sigdata); return NULL; @@ -1026,6 +1193,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)); if (!sigdata->sample) { + dumbfile_close( lf ); free(roguebytes); _dumb_it_unload_sigdata(sigdata); return NULL; @@ -1033,10 +1201,24 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) for (j = total_samples; j < total_samples+extra.n_samples; j++) 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 */ for (j = 0; j < extra.n_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) { free(roguebytes); _dumb_it_unload_sigdata(sigdata); @@ -1055,6 +1237,8 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) } total_samples += extra.n_samples; } + + dumbfile_close( lf ); } sigdata->n_samples = total_samples; diff --git a/src/svnrevision.h b/src/svnrevision.h index cea54423..0c9a1c08 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "4090" -#define ZD_SVN_REVISION_NUMBER 4090 +#define ZD_SVN_REVISION_STRING "4100" +#define ZD_SVN_REVISION_NUMBER 4100