Fixed bugs 1003, 1021, 1168 - fixed memory leak loading music
authorSam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 18:32:49 -0500
changeset 521565549e046b0
parent 520 61a1516bc06a
child 522 a70c0ee38c9f
Fixed bugs 1003, 1021, 1168 - fixed memory leak loading music

jjs@jjs.at 2011-03-11 11:37:57 PST
When using SDL_Mixer to play WAVE music, the call to Mix_FreeMusic does not
close the associated file handle.

There is a check in WAVStream_FreeSong() of wavestream.c like this:

if ( wave->freerw ) {
SDL_FreeRW(wave->rw);
}

But the variable freerw is not referenced anywhere else. SDL_FreeRW would also
not close the file from what I can tell.
CHANGES
fluidsynth.c
fluidsynth.h
music.c
music_flac.c
music_flac.h
music_mad.c
music_mad.h
music_mod.c
music_mod.h
music_modplug.c
music_modplug.h
music_ogg.c
music_ogg.h
native_midi/native_midi.h
native_midi/native_midi_haiku.cpp
native_midi/native_midi_mac.c
native_midi/native_midi_macosx.c
native_midi/native_midi_win32.c
playmus.c
timidity/playmidi.c
timidity/timidity.h
wavestream.c
wavestream.h
     1.1 --- a/CHANGES	Sat Dec 31 14:23:44 2011 -0500
     1.2 +++ b/CHANGES	Sat Dec 31 18:32:49 2011 -0500
     1.3 @@ -1,4 +1,6 @@
     1.4  1.2.12:
     1.5 +Sam Lantinga - Sat Dec 31 18:32:05 EST 2011
     1.6 + * Fixed memory leak in SDL_LoadMUS()
     1.7  Sam Lantinga - Sat Dec 31 10:22:05 EST 2011
     1.8   * SDL_mixer is now under the zlib license
     1.9  James Le Cuirot - Mon Mar 21 16:54:11 PDT 2011
     2.1 --- a/fluidsynth.c	Sat Dec 31 14:23:44 2011 -0500
     2.2 +++ b/fluidsynth.c	Sat Dec 31 18:32:49 2011 -0500
     2.3 @@ -148,9 +148,15 @@
     2.4  	return fluidsynth_loadsong_common(fluidsynth_loadsong_internal, (void*) midifile);
     2.5  }
     2.6  
     2.7 -FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw)
     2.8 +FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw)
     2.9  {
    2.10 -	return fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
    2.11 +	FluidSynthMidiSong *song;
    2.12 +
    2.13 +	song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
    2.14 +	if (freerw) {
    2.15 +		SDL_RWclose(rw);
    2.16 +	}
    2.17 +	return song;
    2.18  }
    2.19  
    2.20  void fluidsynth_freesong(FluidSynthMidiSong *song)
     3.1 --- a/fluidsynth.h	Sat Dec 31 14:23:44 2011 -0500
     3.2 +++ b/fluidsynth.h	Sat Dec 31 18:32:49 2011 -0500
     3.3 @@ -37,7 +37,7 @@
     3.4  
     3.5  int fluidsynth_init(SDL_AudioSpec *mixer);
     3.6  FluidSynthMidiSong *fluidsynth_loadsong(const char *midifile);
     3.7 -FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw);
     3.8 +FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw);
     3.9  void fluidsynth_freesong(FluidSynthMidiSong *song);
    3.10  void fluidsynth_start(FluidSynthMidiSong *song);
    3.11  void fluidsynth_stop(FluidSynthMidiSong *song);
     4.1 --- a/music.c	Sat Dec 31 14:23:44 2011 -0500
     4.2 +++ b/music.c	Sat Dec 31 18:32:49 2011 -0500
     4.3 @@ -1391,6 +1391,7 @@
     4.4  	Uint8 moremagic[9];
     4.5  	Mix_Music *music;
     4.6  	int start;
     4.7 +	int freerw = 0;
     4.8  
     4.9  	if (!rw) {
    4.10  		Mix_SetError("RWops pointer is NULL");
    4.11 @@ -1423,7 +1424,7 @@
    4.12  	if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
    4.13  	     (strcmp((char *)magic, "FORM") == 0) ) {
    4.14  		music->type = MUS_WAV;
    4.15 -		music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic);
    4.16 +		music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freerw);
    4.17  		if ( music->data.wave == NULL ) {
    4.18  			music->error = 1;
    4.19  		}
    4.20 @@ -1434,7 +1435,7 @@
    4.21  	/* Ogg Vorbis files have the magic four bytes "OggS" */
    4.22  	if ( strcmp((char *)magic, "OggS") == 0 ) {
    4.23  		music->type = MUS_OGG;
    4.24 -		music->data.ogg = OGG_new_RW(rw);
    4.25 +		music->data.ogg = OGG_new_RW(rw, freerw);
    4.26  		if ( music->data.ogg == NULL ) {
    4.27  			music->error = 1;
    4.28  		}
    4.29 @@ -1444,7 +1445,7 @@
    4.30  	/* FLAC files have the magic four bytes "fLaC" */
    4.31  	if ( strcmp((char *)magic, "fLaC") == 0 ) {
    4.32  		music->type = MUS_FLAC;
    4.33 -		music->data.flac = FLAC_new_RW(rw);
    4.34 +		music->data.flac = FLAC_new_RW(rw, freerw);
    4.35  		if ( music->data.flac == NULL ) {
    4.36  			music->error = 1;
    4.37  		}
    4.38 @@ -1470,7 +1471,7 @@
    4.39  #ifdef MP3_MAD_MUSIC
    4.40  	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
    4.41  		music->type = MUS_MP3_MAD;
    4.42 -		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
    4.43 +		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freerw);
    4.44  		if (music->data.mp3_mad == 0) {
    4.45  			Mix_SetError("Could not initialize MPEG stream.");
    4.46  			music->error = 1;
    4.47 @@ -1483,7 +1484,7 @@
    4.48  		music->type = MUS_MID;
    4.49  #ifdef USE_NATIVE_MIDI
    4.50  		if ( native_midi_ok ) {
    4.51 -			music->data.nativemidi = native_midi_loadsong_RW(rw);
    4.52 +			music->data.nativemidi = native_midi_loadsong_RW(rw, freerw);
    4.53  	  		if ( music->data.nativemidi == NULL ) {
    4.54  		  		Mix_SetError("%s", native_midi_error());
    4.55  			  	music->error = 1;
    4.56 @@ -1493,7 +1494,7 @@
    4.57  #endif
    4.58  #ifdef USE_FLUIDSYNTH_MIDI
    4.59  		if ( fluidsynth_ok ) {
    4.60 -			music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw);
    4.61 +			music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freerw);
    4.62  			if ( music->data.fluidsynthmidi == NULL ) {
    4.63  				music->error = 1;
    4.64  			}
    4.65 @@ -1502,7 +1503,7 @@
    4.66  #endif
    4.67  #ifdef USE_TIMIDITY_MIDI
    4.68  		if ( timidity_ok ) {
    4.69 -			music->data.midi = Timidity_LoadSong_RW(rw);
    4.70 +			music->data.midi = Timidity_LoadSong_RW(rw, freerw);
    4.71  			if ( music->data.midi == NULL ) {
    4.72  				Mix_SetError("%s", Timidity_Error());
    4.73  				music->error = 1;
    4.74 @@ -1520,7 +1521,7 @@
    4.75  #ifdef MODPLUG_MUSIC
    4.76  		if ( music->error ) {
    4.77  			music->type = MUS_MODPLUG;
    4.78 -			music->data.modplug = modplug_new_RW(rw);
    4.79 +			music->data.modplug = modplug_new_RW(rw, freerw);
    4.80  			if ( music->data.modplug ) {
    4.81  				music->error = 0;
    4.82  			}
    4.83 @@ -1529,7 +1530,7 @@
    4.84  #ifdef MOD_MUSIC
    4.85  		if ( music->error ) {
    4.86  			music->type = MUS_MOD;
    4.87 -			music->data.module = MOD_new_RW(rw);
    4.88 +			music->data.module = MOD_new_RW(rw, freerw);
    4.89  			if ( music->data.module ) {
    4.90  				music->error = 0;
    4.91  			}
     5.1 --- a/music_flac.c	Sat Dec 31 14:23:44 2011 -0500
     5.2 +++ b/music_flac.c	Sat Dec 31 18:32:49 2011 -0500
     5.3 @@ -60,7 +60,7 @@
     5.4  		SDL_SetError ("Couldn't open %s", file);
     5.5  		return NULL;
     5.6  	}
     5.7 -	return FLAC_new_RW (rw);
     5.8 +	return FLAC_new_RW (rw, 1);
     5.9  }
    5.10  
    5.11  static FLAC__StreamDecoderReadStatus flac_read_music_cb(
    5.12 @@ -313,7 +313,7 @@
    5.13  }
    5.14  
    5.15  /* Load an FLAC stream from an SDL_RWops object */
    5.16 -FLAC_music *FLAC_new_RW(SDL_RWops *rw)
    5.17 +FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw)
    5.18  {
    5.19  	FLAC_music *music;
    5.20  	int init_stage = 0;
    5.21 @@ -327,6 +327,7 @@
    5.22  		FLAC_setvolume (music, MIX_MAX_VOLUME);
    5.23  		music->section = -1;
    5.24  		music->rwops = rw;
    5.25 +		music->freerw = freerw;
    5.26  		music->flac_data.max_to_read = 0;
    5.27  		music->flac_data.overflow = NULL;
    5.28  		music->flac_data.overflow_len = 0;
    5.29 @@ -375,14 +376,19 @@
    5.30  				case 1:
    5.31  				case 0:
    5.32  					free(music);
    5.33 -					SDL_RWclose(rw);
    5.34 +					if (freerw) {
    5.35 +						SDL_RWclose(rw);
    5.36 +					}
    5.37  					break;
    5.38  			}
    5.39  			return NULL;
    5.40  		}
    5.41 -	}
    5.42 -	else {
    5.43 +	} else {
    5.44  		SDL_OutOfMemory();
    5.45 +		if (freerw) {
    5.46 +			SDL_RWclose(rw);
    5.47 +		}
    5.48 +		return NULL;
    5.49  	}
    5.50  
    5.51  	return music;
    5.52 @@ -556,6 +562,9 @@
    5.53  			free (music->cvt.buf);
    5.54  		}
    5.55  
    5.56 +		if (music->freerw) {
    5.57 +			SDL_RWclose(music->rwops);
    5.58 +		}
    5.59  		free (music);
    5.60  	}
    5.61  }
     6.1 --- a/music_flac.h	Sat Dec 31 14:23:44 2011 -0500
     6.2 +++ b/music_flac.h	Sat Dec 31 18:32:49 2011 -0500
     6.3 @@ -52,6 +52,7 @@
     6.4  	FLAC__StreamDecoder *flac_decoder;
     6.5  	FLAC_Data flac_data;
     6.6  	SDL_RWops *rwops;
     6.7 +	int freerw;
     6.8  	SDL_AudioCVT cvt;
     6.9  	int len_available;
    6.10  	Uint8 *snd_available;
    6.11 @@ -69,7 +70,7 @@
    6.12  extern FLAC_music *FLAC_new(const char *file);
    6.13  
    6.14  /* Load an FLAC stream from an SDL_RWops object */
    6.15 -extern FLAC_music *FLAC_new_RW(SDL_RWops *rw);
    6.16 +extern FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw);
    6.17  
    6.18  /* Start playback of a given FLAC stream */
    6.19  extern void FLAC_play(FLAC_music *music);
     7.1 --- a/music_mad.c	Sat Dec 31 14:23:44 2011 -0500
     7.2 +++ b/music_mad.c	Sat Dec 31 18:32:49 2011 -0500
     7.3 @@ -26,7 +26,8 @@
     7.4  #include "music_mad.h"
     7.5  
     7.6  mad_data *
     7.7 -mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
     7.8 +mad_openFile(const char *filename, SDL_AudioSpec *mixer)
     7.9 +{
    7.10    SDL_RWops *rw;
    7.11    mad_data *mp3_mad;
    7.12  
    7.13 @@ -35,23 +36,18 @@
    7.14  	return NULL;
    7.15    }
    7.16  
    7.17 -  mp3_mad = mad_openFileRW(rw, mixer);
    7.18 -  if (mp3_mad == NULL) {
    7.19 -	SDL_FreeRW(rw);
    7.20 -	return NULL;
    7.21 -  }
    7.22 -  mp3_mad->freerw = SDL_TRUE;
    7.23 -  return mp3_mad;
    7.24 +  return mad_openFileRW(rw, mixer, 1);
    7.25  }
    7.26  
    7.27  mad_data *
    7.28 -mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
    7.29 +mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw)
    7.30 +{
    7.31    mad_data *mp3_mad;
    7.32  
    7.33    mp3_mad = (mad_data *)malloc(sizeof(mad_data));
    7.34    if (mp3_mad) {
    7.35  	mp3_mad->rw = rw;
    7.36 -	mp3_mad->freerw = SDL_FALSE;
    7.37 +	mp3_mad->freerw = freerw;
    7.38  	mad_stream_init(&mp3_mad->stream);
    7.39  	mad_frame_init(&mp3_mad->frame);
    7.40  	mad_synth_init(&mp3_mad->synth);
    7.41 @@ -67,13 +63,14 @@
    7.42  }
    7.43  
    7.44  void
    7.45 -mad_closeFile(mad_data *mp3_mad) {
    7.46 +mad_closeFile(mad_data *mp3_mad)
    7.47 +{
    7.48    mad_stream_finish(&mp3_mad->stream);
    7.49    mad_frame_finish(&mp3_mad->frame);
    7.50    mad_synth_finish(&mp3_mad->synth);
    7.51  
    7.52    if (mp3_mad->freerw) {
    7.53 -	SDL_FreeRW(mp3_mad->rw);
    7.54 +	SDL_RWclose(mp3_mad->rw);
    7.55    }
    7.56    free(mp3_mad);
    7.57  }
     8.1 --- a/music_mad.h	Sat Dec 31 14:23:44 2011 -0500
     8.2 +++ b/music_mad.h	Sat Dec 31 18:32:49 2011 -0500
     8.3 @@ -42,7 +42,7 @@
     8.4  
     8.5  typedef struct {
     8.6    SDL_RWops *rw;
     8.7 -  SDL_bool freerw;
     8.8 +  int freerw;
     8.9    struct mad_stream stream;
    8.10    struct mad_frame frame;
    8.11    struct mad_synth synth;
    8.12 @@ -59,7 +59,7 @@
    8.13  } mad_data;
    8.14  
    8.15  mad_data *mad_openFile(const char *filename, SDL_AudioSpec *mixer);
    8.16 -mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer);
    8.17 +mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw);
    8.18  void mad_closeFile(mad_data *mp3_mad);
    8.19  
    8.20  void mad_start(mad_data *mp3_mad);
     9.1 --- a/music_mod.c	Sat Dec 31 14:23:44 2011 -0500
     9.2 +++ b/music_mod.c	Sat Dec 31 18:32:49 2011 -0500
     9.3 @@ -152,7 +152,7 @@
     9.4  		SDL_SetError("Couldn't open %s", file);
     9.5  		return NULL;
     9.6  	}
     9.7 -	return MOD_new_RW(rw);
     9.8 +	return MOD_new_RW(rw, 1);
     9.9  }
    9.10  
    9.11  
    9.12 @@ -215,18 +215,24 @@
    9.13  }
    9.14  
    9.15  /* Load a MOD stream from an SDL_RWops object */
    9.16 -MODULE *MOD_new_RW(SDL_RWops *rw)
    9.17 +MODULE *MOD_new_RW(SDL_RWops *rw, int freerw)
    9.18  {
    9.19  	MODULE *module;
    9.20  
    9.21  	/* Make sure the mikmod library is loaded */
    9.22  	if ( !Mix_Init(MIX_INIT_MOD) ) {
    9.23 +		if ( freerw ) {
    9.24 +			SDL_RWclose(rw);
    9.25 +		}
    9.26  		return NULL;
    9.27  	}
    9.28  
    9.29  	module = MikMod_LoadSongRW(rw,64);
    9.30  	if (!module) {
    9.31  		Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
    9.32 +		if ( freerw ) {
    9.33 +			SDL_RWclose(rw);
    9.34 +		}
    9.35  		return NULL;
    9.36  	}
    9.37  
    9.38 @@ -239,6 +245,10 @@
    9.39  to query the status of the song or set trigger actions.  Hum. */
    9.40  	module->fadeout = 1;
    9.41  #endif
    9.42 +
    9.43 +	if ( freerw ) {
    9.44 +		SDL_RWclose(rw);
    9.45 +	}
    9.46  	return module;
    9.47  }
    9.48  
    10.1 --- a/music_mod.h	Sat Dec 31 14:23:44 2011 -0500
    10.2 +++ b/music_mod.h	Sat Dec 31 18:32:49 2011 -0500
    10.3 @@ -42,7 +42,7 @@
    10.4  extern struct MODULE *MOD_new(const char *file);
    10.5  
    10.6  /* Load a MOD stream from an SDL_RWops object */
    10.7 -extern struct MODULE *MOD_new_RW(SDL_RWops *rw);
    10.8 +extern struct MODULE *MOD_new_RW(SDL_RWops *rw, int freerw);
    10.9  
   10.10  /* Start playback of a given MOD stream */
   10.11  extern void MOD_play(struct MODULE *music);
    11.1 --- a/music_modplug.c	Sat Dec 31 14:23:44 2011 -0500
    11.2 +++ b/music_modplug.c	Sat Dec 31 18:32:49 2011 -0500
    11.3 @@ -85,12 +85,12 @@
    11.4  		SDL_SetError("Couldn't open %s", file);
    11.5  		return NULL;
    11.6  	}
    11.7 -	return modplug_new_RW(rw);
    11.8 +	return modplug_new_RW(rw, 1);
    11.9  
   11.10  }
   11.11  
   11.12  /* Load a modplug stream from an SDL_RWops object */
   11.13 -modplug_data *modplug_new_RW(SDL_RWops *rw)
   11.14 +modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw)
   11.15  {
   11.16  	modplug_data *music=NULL;
   11.17  	long offset,sz;
   11.18 @@ -101,20 +101,35 @@
   11.19  	sz = SDL_RWtell(rw)-offset;
   11.20  	SDL_RWseek(rw, offset, RW_SEEK_SET);
   11.21  	buf=(char*)malloc(sz);
   11.22 -	if(!buf)
   11.23 -		return NULL;
   11.24 -	if(SDL_RWread(rw, buf, sz, 1)==1)
   11.25 +	if(buf)
   11.26  	{
   11.27 -		music=(modplug_data*)malloc(sizeof(modplug_data));
   11.28 -		music->playing=0;
   11.29 -		music->file=ModPlug_Load(buf,sz);
   11.30 -		if(!music->file)
   11.31 +		if(SDL_RWread(rw, buf, sz, 1)==1)
   11.32  		{
   11.33 -			free(music);
   11.34 -			music=NULL;
   11.35 +			music=(modplug_data*)malloc(sizeof(modplug_data));
   11.36 +			if (music)
   11.37 +			{
   11.38 +				music->playing=0;
   11.39 +				music->file=ModPlug_Load(buf,sz);
   11.40 +				if(!music->file)
   11.41 +				{
   11.42 +					free(music);
   11.43 +					music=NULL;
   11.44 +				}
   11.45 +			}
   11.46 +			else
   11.47 +			{
   11.48 +				SDL_OutOfMemory();
   11.49 +			}
   11.50  		}
   11.51 +		free(buf);
   11.52  	}
   11.53 -	free(buf);
   11.54 +	else
   11.55 +	{
   11.56 +		SDL_OutOfMemory();
   11.57 +	}
   11.58 +	if (freerw) {
   11.59 +		SDL_RWclose(rw);
   11.60 +	}
   11.61  	return music;
   11.62  }
   11.63  
    12.1 --- a/music_modplug.h	Sat Dec 31 14:23:44 2011 -0500
    12.2 +++ b/music_modplug.h	Sat Dec 31 18:32:49 2011 -0500
    12.3 @@ -22,7 +22,7 @@
    12.4  modplug_data *modplug_new(const char *file);
    12.5  
    12.6  /* Load a modplug stream from an SDL_RWops object */
    12.7 -modplug_data *modplug_new_RW(SDL_RWops *rw);
    12.8 +modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw);
    12.9  
   12.10  /* Start playback of a given modplug stream */
   12.11  void modplug_play(modplug_data *music);
    13.1 --- a/music_ogg.c	Sat Dec 31 14:23:44 2011 -0500
    13.2 +++ b/music_ogg.c	Sat Dec 31 18:32:49 2011 -0500
    13.3 @@ -61,7 +61,7 @@
    13.4  		SDL_SetError("Couldn't open %s", file);
    13.5  		return NULL;
    13.6  	}
    13.7 -	return OGG_new_RW(rw);
    13.8 +	return OGG_new_RW(rw, 1);
    13.9  }
   13.10  
   13.11  
   13.12 @@ -75,46 +75,52 @@
   13.13      return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
   13.14  }
   13.15  
   13.16 -static int sdl_close_func(void *datasource)
   13.17 -{
   13.18 -    return SDL_RWclose((SDL_RWops*)datasource);
   13.19 -}
   13.20 -
   13.21  static long sdl_tell_func(void *datasource)
   13.22  {
   13.23      return SDL_RWtell((SDL_RWops*)datasource);
   13.24  }
   13.25  
   13.26  /* Load an OGG stream from an SDL_RWops object */
   13.27 -OGG_music *OGG_new_RW(SDL_RWops *rw)
   13.28 +OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw)
   13.29  {
   13.30  	OGG_music *music;
   13.31  	ov_callbacks callbacks;
   13.32  
   13.33 +	SDL_memset(&callbacks, 0, sizeof(callbacks));
   13.34  	callbacks.read_func = sdl_read_func;
   13.35  	callbacks.seek_func = sdl_seek_func;
   13.36 -	callbacks.close_func = sdl_close_func;
   13.37  	callbacks.tell_func = sdl_tell_func;
   13.38  
   13.39  	music = (OGG_music *)malloc(sizeof *music);
   13.40  	if ( music ) {
   13.41  		/* Initialize the music structure */
   13.42  		memset(music, 0, (sizeof *music));
   13.43 +		music->rw = rw;
   13.44 +		music->freerw = freerw;
   13.45  		OGG_stop(music);
   13.46  		OGG_setvolume(music, MIX_MAX_VOLUME);
   13.47  		music->section = -1;
   13.48  
   13.49  		if ( !Mix_Init(MIX_INIT_OGG) ) {
   13.50 +			if ( freerw ) {
   13.51 +				SDL_RWclose(rw);
   13.52 +			}
   13.53  			return(NULL);
   13.54  		}
   13.55  		if ( vorbis.ov_open_callbacks(rw, &music->vf, NULL, 0, callbacks) < 0 ) {
   13.56  			free(music);
   13.57 -			SDL_RWclose(rw);
   13.58 +			if ( freerw ) {
   13.59 +				SDL_RWclose(rw);
   13.60 +			}
   13.61  			SDL_SetError("Not an Ogg Vorbis audio stream");
   13.62  			return(NULL);
   13.63  		}
   13.64  	} else {
   13.65 +		if ( freerw ) {
   13.66 +			SDL_RWclose(rw);
   13.67 +		}
   13.68  		SDL_OutOfMemory();
   13.69 +		return(NULL);
   13.70  	}
   13.71  	return(music);
   13.72  }
   13.73 @@ -220,6 +226,9 @@
   13.74  		if ( music->cvt.buf ) {
   13.75  			free(music->cvt.buf);
   13.76  		}
   13.77 +		if ( music->freerw ) {
   13.78 +			SDL_RWclose(music->rw);
   13.79 +		}
   13.80  		vorbis.ov_clear(&music->vf);
   13.81  		free(music);
   13.82  	}
    14.1 --- a/music_ogg.h	Sat Dec 31 14:23:44 2011 -0500
    14.2 +++ b/music_ogg.h	Sat Dec 31 18:32:49 2011 -0500
    14.3 @@ -32,6 +32,8 @@
    14.4  #endif
    14.5  
    14.6  typedef struct {
    14.7 +	SDL_RWops *rw;
    14.8 +	int freerw;
    14.9  	int playing;
   14.10  	int volume;
   14.11  	OggVorbis_File vf;
   14.12 @@ -53,7 +55,7 @@
   14.13  extern OGG_music *OGG_new(const char *file);
   14.14  
   14.15  /* Load an OGG stream from an SDL_RWops object */
   14.16 -extern OGG_music *OGG_new_RW(SDL_RWops *rw);
   14.17 +extern OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw);
   14.18  
   14.19  /* Start playback of a given OGG stream */
   14.20  extern void OGG_play(OGG_music *music);
    15.1 --- a/native_midi/native_midi.h	Sat Dec 31 14:23:44 2011 -0500
    15.2 +++ b/native_midi/native_midi.h	Sat Dec 31 18:32:49 2011 -0500
    15.3 @@ -28,7 +28,7 @@
    15.4  
    15.5  int native_midi_detect();
    15.6  NativeMidiSong *native_midi_loadsong(const char *midifile);
    15.7 -NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw);
    15.8 +NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw);
    15.9  void native_midi_freesong(NativeMidiSong *song);
   15.10  void native_midi_start(NativeMidiSong *song);
   15.11  void native_midi_stop();
    16.1 --- a/native_midi/native_midi_haiku.cpp	Sat Dec 31 14:23:44 2011 -0500
    16.2 +++ b/native_midi/native_midi_haiku.cpp	Sat Dec 31 18:32:49 2011 -0500
    16.3 @@ -213,12 +213,15 @@
    16.4    synth.SetVolume(volume / 128.0);
    16.5  }
    16.6  
    16.7 -NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
    16.8 +NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
    16.9  {
   16.10    NativeMidiSong *song = new NativeMidiSong;
   16.11    song->store = new MidiEventsStore;
   16.12    status_t res = song->store->Import(rw);
   16.13  
   16.14 +  if (freerw) {
   16.15 +    SDL_RWclose(rw);
   16.16 +  }
   16.17    if (res != B_OK)
   16.18    {
   16.19      snprintf(lasterr, sizeof lasterr, "Cannot Import() midi file: status_t=%d", res);
   16.20 @@ -233,9 +236,7 @@
   16.21  {
   16.22    SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
   16.23    if (!rw) return NULL;
   16.24 -  NativeMidiSong *song = native_midi_loadsong_RW(rw);
   16.25 -  SDL_RWclose(rw);
   16.26 -  return song;
   16.27 +  return native_midi_loadsong_RW(rw, 1);
   16.28  }
   16.29  
   16.30  void native_midi_freesong(NativeMidiSong *song)
    17.1 --- a/native_midi/native_midi_mac.c	Sat Dec 31 14:23:44 2011 -0500
    17.2 +++ b/native_midi/native_midi_mac.c	Sat Dec 31 18:32:49 2011 -0500
    17.3 @@ -90,73 +90,17 @@
    17.4  
    17.5  NativeMidiSong *native_midi_loadsong(const char *midifile)
    17.6  {
    17.7 -	NativeMidiSong	*song = NULL;
    17.8 -	MIDIEvent		*evntlist = NULL;
    17.9 -	int				part_to_inst[32];
   17.10 -	int				part_poly_max[32];
   17.11 -	int				numParts = 0;
   17.12 -	Uint16			ppqn;
   17.13 -	SDL_RWops		*rw;
   17.14 +	SDL_RWops *rw;
   17.15  
   17.16 -	/* Init the arrays */
   17.17 -	memset(part_poly_max,0,sizeof(part_poly_max));
   17.18 -	memset(part_to_inst,-1,sizeof(part_to_inst));
   17.19 -	
   17.20  	/* Attempt to load the midi file */
   17.21  	rw = SDL_RWFromFile(midifile, "rb");
   17.22 -	if (rw) {
   17.23 -		evntlist = CreateMIDIEventList(rw, &ppqn);
   17.24 -		SDL_RWclose(rw);
   17.25 -		if (!evntlist)
   17.26 -			goto bail;
   17.27 +	if (!rw) {
   17.28 +		return NULL;
   17.29  	}
   17.30 -
   17.31 -	/* Allocate memory for the song struct */
   17.32 -	song = malloc(sizeof(NativeMidiSong));
   17.33 -	if (!song)
   17.34 -		goto bail;
   17.35 -
   17.36 -	/* Build a tune sequence from the event list */
   17.37 -	song->tuneSequence = BuildTuneSequence(evntlist, ppqn, part_poly_max, part_to_inst, &numParts);
   17.38 -	if(!song->tuneSequence)
   17.39 -		goto bail;
   17.40 -
   17.41 -	/* Now build a tune header from the data we collect above, create
   17.42 -	   all parts as needed and assign them the correct instrument.
   17.43 -	*/
   17.44 -	song->tuneHeader = BuildTuneHeader(part_poly_max, part_to_inst, numParts);
   17.45 -	if(!song->tuneHeader)
   17.46 -		goto bail;
   17.47 -	
   17.48 -	/* Increment the instance count */
   17.49 -	gInstaceCount++;
   17.50 -	if (gTunePlayer == NULL)
   17.51 -		gTunePlayer = OpenDefaultComponent(kTunePlayerComponentType, 0);
   17.52 -
   17.53 -	/* Finally, free the event list */
   17.54 -	FreeMIDIEventList(evntlist);
   17.55 -	
   17.56 -	return song;
   17.57 -	
   17.58 -bail:
   17.59 -	if (evntlist)
   17.60 -		FreeMIDIEventList(evntlist);
   17.61 -	
   17.62 -	if (song)
   17.63 -	{
   17.64 -		if(song->tuneSequence)
   17.65 -			free(song->tuneSequence);
   17.66 -		
   17.67 -		if(song->tuneHeader)
   17.68 -			DisposePtr((Ptr)song->tuneHeader);
   17.69 -
   17.70 -		free(song);
   17.71 -	}
   17.72 -	
   17.73 -	return NULL;
   17.74 +	return native_midi_loadsong_RW(rw, 1);
   17.75  }
   17.76  
   17.77 -NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
   17.78 +NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
   17.79  {
   17.80  	NativeMidiSong	*song = NULL;
   17.81  	MIDIEvent		*evntlist = NULL;
   17.82 @@ -198,7 +142,10 @@
   17.83  
   17.84  	/* Finally, free the event list */
   17.85  	FreeMIDIEventList(evntlist);
   17.86 -	
   17.87 +
   17.88 +	if (freerw) {
   17.89 +		SDL_RWclose(rw);
   17.90 +	}
   17.91  	return song;
   17.92  	
   17.93  bail:
   17.94 @@ -216,6 +163,9 @@
   17.95  		free(song);
   17.96  	}
   17.97  	
   17.98 +	if (freerw) {
   17.99 +		SDL_RWclose(rw);
  17.100 +	}
  17.101  	return NULL;
  17.102  }
  17.103  
    18.1 --- a/native_midi/native_midi_macosx.c	Sat Dec 31 14:23:44 2011 -0500
    18.2 +++ b/native_midi/native_midi_macosx.c	Sat Dec 31 18:32:49 2011 -0500
    18.3 @@ -149,14 +149,13 @@
    18.4      NativeMidiSong *retval = NULL;
    18.5      SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
    18.6      if (rw != NULL) {
    18.7 -        retval = native_midi_loadsong_RW(rw);
    18.8 -        SDL_RWclose(rw);
    18.9 +        retval = native_midi_loadsong_RW(rw, 1);
   18.10      }
   18.11  
   18.12      return retval;
   18.13  }
   18.14  
   18.15 -NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
   18.16 +NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
   18.17  {
   18.18      NativeMidiSong *retval = NULL;
   18.19      void *buf = NULL;
   18.20 @@ -213,6 +212,9 @@
   18.21      if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
   18.22          goto fail;
   18.23  
   18.24 +    if (freerw)
   18.25 +        SDL_RWclose(rw);
   18.26 +
   18.27      return retval;
   18.28  
   18.29  fail:
   18.30 @@ -230,6 +232,9 @@
   18.31      if (buf)
   18.32          free(buf);
   18.33  
   18.34 +    if (freerw)
   18.35 +        SDL_RWclose(rw);
   18.36 +
   18.37      return NULL;
   18.38  }
   18.39  
    19.1 --- a/native_midi/native_midi_win32.c	Sat Dec 31 14:23:44 2011 -0500
    19.2 +++ b/native_midi/native_midi_win32.c	Sat Dec 31 18:32:49 2011 -0500
    19.3 @@ -189,42 +189,28 @@
    19.4  
    19.5  NativeMidiSong *native_midi_loadsong(const char *midifile)
    19.6  {
    19.7 -	NativeMidiSong *newsong;
    19.8 -	MIDIEvent		*evntlist = NULL;
    19.9 -	SDL_RWops	*rw;
   19.10 -
   19.11 -	newsong=malloc(sizeof(NativeMidiSong));
   19.12 -	if (!newsong)
   19.13 -		return NULL;
   19.14 -	memset(newsong,0,sizeof(NativeMidiSong));
   19.15 +	SDL_RWops *rw;
   19.16  
   19.17  	/* Attempt to load the midi file */
   19.18  	rw = SDL_RWFromFile(midifile, "rb");
   19.19 -	if (rw) {
   19.20 -		evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
   19.21 -		SDL_RWclose(rw);
   19.22 -		if (!evntlist)
   19.23 -		{
   19.24 -			free(newsong);
   19.25 -			return NULL;
   19.26 -		}
   19.27 +	if (!rw) {
   19.28 +		return NULL;
   19.29  	}
   19.30 -
   19.31 -	MIDItoStream(newsong, evntlist);
   19.32 -
   19.33 -	FreeMIDIEventList(evntlist);
   19.34 -
   19.35 -	return newsong;
   19.36 +	return native_midi_loadsong_RW(rw, 1);
   19.37  }
   19.38  
   19.39 -NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
   19.40 +NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
   19.41  {
   19.42  	NativeMidiSong *newsong;
   19.43  	MIDIEvent		*evntlist = NULL;
   19.44  
   19.45  	newsong=malloc(sizeof(NativeMidiSong));
   19.46 -	if (!newsong)
   19.47 +	if (!newsong) {
   19.48 +		if (freerw) {
   19.49 +			SDL_RWclose(rw);
   19.50 +		}
   19.51  		return NULL;
   19.52 +	}
   19.53  	memset(newsong,0,sizeof(NativeMidiSong));
   19.54  
   19.55  	/* Attempt to load the midi file */
   19.56 @@ -232,6 +218,9 @@
   19.57  	if (!evntlist)
   19.58  	{
   19.59  		free(newsong);
   19.60 +		if (freerw) {
   19.61 +			SDL_RWclose(rw);
   19.62 +		}
   19.63  		return NULL;
   19.64  	}
   19.65  
   19.66 @@ -239,6 +228,9 @@
   19.67  
   19.68  	FreeMIDIEventList(evntlist);
   19.69  
   19.70 +	if (freerw) {
   19.71 +		SDL_RWclose(rw);
   19.72 +	}
   19.73  	return newsong;
   19.74  }
   19.75  
    20.1 --- a/playmus.c	Sat Dec 31 14:23:44 2011 -0500
    20.2 +++ b/playmus.c	Sat Dec 31 18:32:49 2011 -0500
    20.3 @@ -222,7 +222,7 @@
    20.4  		}
    20.5  		Mix_FreeMusic(music);
    20.6  		if ( rwops ) {
    20.7 -			SDL_FreeRW(rwfp);
    20.8 +			SDL_RWclose(rwfp);
    20.9  		}
   20.10  		music = NULL;
   20.11  
    21.1 --- a/timidity/playmidi.c	Sat Dec 31 14:23:44 2011 -0500
    21.2 +++ b/timidity/playmidi.c	Sat Dec 31 18:32:49 2011 -0500
    21.3 @@ -1703,7 +1703,7 @@
    21.4    return(song);
    21.5  }
    21.6  
    21.7 -MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw)
    21.8 +MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw, int freerw)
    21.9  {
   21.10    MidiSong *song;
   21.11    int32 events;
   21.12 @@ -1714,7 +1714,10 @@
   21.13  
   21.14    strcpy(midi_name, "SDLrwops source");
   21.15  
   21.16 -  song->events=read_midi_file(rw, &events, &song->samples);
   21.17 +  song->events = read_midi_file(rw, &events, &song->samples);
   21.18 +  if (freerw) {
   21.19 +    SDL_RWclose(rw);
   21.20 +  }
   21.21  
   21.22    /* Make sure everything is okay */
   21.23    if (!song->events) {
    22.1 --- a/timidity/timidity.h	Sat Dec 31 14:23:44 2011 -0500
    22.2 +++ b/timidity/timidity.h	Sat Dec 31 18:32:49 2011 -0500
    22.3 @@ -13,7 +13,7 @@
    22.4  extern void Timidity_SetVolume(int volume);
    22.5  extern int Timidity_PlaySome(void *stream, int samples);
    22.6  extern MidiSong *Timidity_LoadSong(const char *midifile);
    22.7 -extern MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw);
    22.8 +extern MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw, int freerw);
    22.9  extern void Timidity_Start(MidiSong *song);
   22.10  extern int Timidity_Active(void);
   22.11  extern void Timidity_Stop(void);
    23.1 --- a/wavestream.c	Sat Dec 31 14:23:44 2011 -0500
    23.2 +++ b/wavestream.c	Sat Dec 31 18:32:49 2011 -0500
    23.3 @@ -116,34 +116,32 @@
    23.4  WAVStream *WAVStream_LoadSong(const char *file, const char *magic)
    23.5  {
    23.6  	SDL_RWops *rw;
    23.7 -	WAVStream *wave;
    23.8  
    23.9  	rw = SDL_RWFromFile(file, "rb");
   23.10  	if ( rw == NULL ) {
   23.11  		SDL_SetError("Couldn't open %s", file);
   23.12  		return NULL;
   23.13  	}
   23.14 -	wave = WAVStream_LoadSong_RW(rw, magic);
   23.15 -	if ( wave == NULL ) {
   23.16 -		SDL_FreeRW(rw);
   23.17 -		return NULL;
   23.18 -	}
   23.19 -	return wave;
   23.20 +	return WAVStream_LoadSong_RW(rw, magic, 1);
   23.21  }
   23.22  
   23.23  /* Load a WAV stream from the given file */
   23.24 -WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic)
   23.25 +WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw)
   23.26  {
   23.27  	WAVStream *wave;
   23.28  	SDL_AudioSpec wavespec;
   23.29  
   23.30  	if ( ! mixer.format ) {
   23.31  		Mix_SetError("WAV music output not started");
   23.32 +		if ( freerw ) {
   23.33 +			SDL_RWclose(rw);
   23.34 +		}
   23.35  		return(NULL);
   23.36  	}
   23.37  	wave = (WAVStream *)malloc(sizeof *wave);
   23.38  	if ( wave ) {
   23.39  		memset(wave, 0, (sizeof *wave));
   23.40 +		wave->freerw = freerw;
   23.41  		if ( strcmp(magic, "RIFF") == 0 ) {
   23.42  			wave->rw = LoadWAVStream(rw, &wavespec,
   23.43  					&wave->start, &wave->stop);
   23.44 @@ -156,11 +154,20 @@
   23.45  		}
   23.46  		if ( wave->rw == NULL ) {
   23.47  			free(wave);
   23.48 +			if ( freerw ) {
   23.49 +				SDL_RWclose(rw);
   23.50 +			}
   23.51  			return(NULL);
   23.52  		}
   23.53  		SDL_BuildAudioCVT(&wave->cvt,
   23.54  			wavespec.format, wavespec.channels, wavespec.freq,
   23.55  			mixer.format, mixer.channels, mixer.freq);
   23.56 +	} else {
   23.57 +		SDL_OutOfMemory();
   23.58 +		if ( freerw ) {
   23.59 +			SDL_RWclose(rw);
   23.60 +		}
   23.61 +		return(NULL);
   23.62  	}
   23.63  	return(wave);
   23.64  }
   23.65 @@ -242,12 +249,12 @@
   23.66  {
   23.67  	if ( wave ) {
   23.68  		/* Clean up associated data */
   23.69 -		if ( wave->freerw ) {
   23.70 -			SDL_FreeRW(wave->rw);
   23.71 -		}
   23.72  		if ( wave->cvt.buf ) {
   23.73  			free(wave->cvt.buf);
   23.74  		}
   23.75 +		if ( wave->freerw ) {
   23.76 +			SDL_RWclose(wave->rw);
   23.77 +		}
   23.78  		free(wave);
   23.79  	}
   23.80  }
    24.1 --- a/wavestream.h	Sat Dec 31 14:23:44 2011 -0500
    24.2 +++ b/wavestream.h	Sat Dec 31 18:32:49 2011 -0500
    24.3 @@ -45,7 +45,7 @@
    24.4  extern WAVStream *WAVStream_LoadSong(const char *file, const char *magic);
    24.5  
    24.6  /* Load a WAV stream from an SDL_RWops object */
    24.7 -extern WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic);
    24.8 +extern WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw);
    24.9  
   24.10  /* Start playback of a given WAV stream */
   24.11  extern void WAVStream_Start(WAVStream *wave);