Removed exception throwing from MusicInformation constructor, and

use a simple static function to create a MusicInformation object.
This simplifies handling of errors in calling functions, and
appears to have fixed a (minor) memory leak as well.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9973 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-10-13 11:15:53 +00:00
parent a294b36ced
commit 9767765cb9
5 changed files with 96 additions and 120 deletions

View File

@ -29,7 +29,46 @@
#include "tracks/track_manager.hpp"
#include "utils/string_utils.hpp"
MusicInformation::MusicInformation(const std::string& filename) throw (std::runtime_error)
/** A simple factory to create music information files without raising
* an exception on error, instead a NULL will be returned. This avoids
* resource freeing problems if the exception is raised, and simplifies
* calling code.
* \param filename The name of a music file.
* \return The MusicInformation object, or NULL in case of an error.
*/
MusicInformation *MusicInformation::create(const std::string &filename)
{
assert(filename.size() > 0);
XMLNode* root = file_manager->createXMLTree(filename);
if (!root) return NULL;
if(root->getName()!="music")
{
fprintf(stderr, "Music file '%s' does not contain music node.\n",
filename.c_str());
delete root;
return NULL;
}
std::string s;
if(!root->get("title", &s) ||
!root->get("composer", &s) ||
!root->get("file", &s) )
{
fprintf(stderr, "One of 'title', 'composer' or 'file' attribute "
"is missing in the music XML file '%s'!\n",
filename.c_str());
delete root;
return NULL;
}
MusicInformation *mi = new MusicInformation(root, filename);
delete root;
return mi;
} // create()
// ----------------------------------------------------------------------------
MusicInformation::MusicInformation(const XMLNode *root,
const std::string &filename)
{
m_title = "";
m_mode = SOUND_NORMAL;
@ -45,69 +84,19 @@ MusicInformation::MusicInformation(const std::string& filename) throw (std::runt
m_gain = 1.0f;
m_adjusted_gain = 1.0f;
assert(filename.size() > 0);
if (StringUtils::getExtension(filename) != "music")
{
// Create information just from ogg file
// -------------------------------------
m_title = core::stringw(StringUtils::removeExtension(StringUtils::getBasename(filename)).c_str());
m_normal_filename = filename;
return;
}
// Otherwise read config file
// --------------------------
XMLNode* root = file_manager->createXMLTree(filename);
if (!root)
{
// Don't print a message here - not finding a music file
// is normal since the file is searched in several different
// directories (e.g. in data/tracks/XX and data/music).
throw std::runtime_error("Could not open music XML file");
}
if(root->getName()!="music")
{
std::ostringstream msg;
fprintf(stderr, "Music XML file '%s' does not contain music node.",
filename.c_str());
throw std::runtime_error("No music node found");
}
std::string title;
if(!root->get("title", &title))
{
fprintf(stderr,
"The 'title' attribute is missing in the music XML file '%s'!\n",
filename.c_str());
throw std::runtime_error("Incomplete or corrupt music XML file");
return;
}
m_title = StringUtils::decodeFromHtmlEntities(title);
std::string composer;
if(!root->get("composer", &composer))
{
fprintf(stderr,
"The 'composer' attribute is missing in the music XML file '%s'!\n",
filename.c_str());
throw std::runtime_error("Incomplete or corrupt music XML file");
return;
}
m_composer = StringUtils::decodeFromHtmlEntities(composer);
if(!root->get("file", &m_normal_filename))
{
fprintf(stderr,
"The 'file' attribute is mandatory in the music XML file '%s'!\n",
filename.c_str());
throw std::runtime_error("Incomplete or corrupt music XML file");
return;
}
root->get("gain", &m_adjusted_gain);
root->get("tracks", &m_all_tracks );
root->get("fast", &m_enable_fast );
root->get("fast-filename", &m_fast_filename);
delete root;
std::string s;
root->get("title", &s );
m_title = StringUtils::decodeFromHtmlEntities(s);
root->get("composer", &s );
m_composer = StringUtils::decodeFromHtmlEntities(s);
root->get("file", &m_normal_filename);
root->get("gain", &m_adjusted_gain );
root->get("tracks", &m_all_tracks );
root->get("fast", &m_enable_fast );
root->get("fast-filename", &m_fast_filename );
// Get the path from the filename and add it to the ogg filename
std::string path = StringUtils::getPath(filename);

View File

@ -31,6 +31,7 @@
using irr::core::stringw;
class Music;
class XMLNode;
/**
* \brief Wrapper around an instance of the Music interface
@ -55,27 +56,31 @@ private:
float m_gain;
float m_adjusted_gain;
/** Either time for fading faster music in, or time to change pitch */
/** Either time for fading faster music in, or time to change pitch. */
float m_faster_time;
float m_max_pitch; //!< maximum pitch for faster music
/** Maximum pitch for faster music. */
float m_max_pitch;
static const int LOOP_FOREVER=-1;
Music *m_normal_music,
*m_fast_music;
enum {SOUND_NORMAL, //!< normal music is played
SOUND_FADING, //!< normal music fading out, faster fading in
SOUND_FASTER, //!< change pitch of normal music
SOUND_FAST} //!< playing faster music or max pitch reached
enum {SOUND_NORMAL, //!< normal music is played
SOUND_FADING, //!< normal music fading out, faster fading in
SOUND_FASTER, //!< change pitch of normal music
SOUND_FAST} //!< playing faster music or max pitch reached
m_mode;
float m_time_since_faster;
// The constructor is private so that the
// static create function must be used.
MusicInformation (const XMLNode *root, const std::string &filename);
public:
LEAK_CHECK()
#if defined(WIN32) || defined(_WIN32)
#pragma warning(disable:4290)
#endif
MusicInformation (const std::string& filename) throw (std::runtime_error);
~MusicInformation ();
static MusicInformation *create(const std::string &filename);
const stringw& getComposer () const {return m_composer; }
const stringw& getTitle () const {return m_title; }
const std::string& getNormalFilename() const {return m_normal_filename; }

View File

@ -118,16 +118,11 @@ void MusicManager::loadMusicFromOneDir(const std::string& dir)
for(std::set<std::string>::iterator i = files.begin(); i != files.end(); ++i)
{
if(StringUtils::getExtension(*i)!="music") continue;
try
{
m_all_music[StringUtils::getBasename(*i)] = new MusicInformation(*i);
}
catch (std::exception& e)
{
(void)e; // avoid compiler warning
continue;
}
MusicInformation *mi = MusicInformation::create(*i);
if(mi)
m_all_music[StringUtils::getBasename(*i)] = mi;
} // for i
} // loadMusicFromOneDir
//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------
@ -188,7 +183,8 @@ void MusicManager::setMasterMusicVolume(float gain)
}
//-----------------------------------------------------------------------------
/**
*/
MusicInformation* MusicManager::getMusicInformation(const std::string& filename)
{
if(filename=="")
@ -196,15 +192,20 @@ MusicInformation* MusicManager::getMusicInformation(const std::string& filename)
return NULL;
}
const std::string basename = StringUtils::getBasename(filename);
MusicInformation* mi = m_all_music[basename];
if(!mi)
std::map<std::string, MusicInformation*>::iterator p;
p = m_all_music.find(basename);
if(p==m_all_music.end())
{
// Note that this might raise an exception
mi = new MusicInformation(filename);
m_all_music[basename] = mi;
MusicInformation *mi = MusicInformation::create(filename);
if(mi)
{
mi->volumeMusic(m_masterGain);
m_all_music[basename] = mi;
}
return mi;
}
mi->volumeMusic(m_masterGain);
return mi;
return p->second;
} // getMusicInformation
//----------------------------------------------------------------------------

View File

@ -244,14 +244,10 @@ void STKConfig::getAllData(const XMLNode * root)
music_node->get("title", &title_music);
assert(title_music.size() > 0);
try
{
m_title_music = new MusicInformation(file_manager->getDataDir() + "/music/" + title_music);
}
catch (std::runtime_error& e)
{
fprintf(stderr, "Cannot load title music : %s\n", e.what());
}
m_title_music = MusicInformation::create(file_manager->getDataDir()
+ "/music/" + title_music );
if(!m_title_music)
fprintf(stderr, "Cannot load title music : %s\n", title_music);
}
if(const XMLNode *history_node = root->getNode("history"))

View File

@ -97,6 +97,9 @@ Track::Track(const std::string &filename)
/** Destructor, removes quad data structures etc. */
Track::~Track()
{
// Note that the music information in m_music is globally managed
// by the music_manager, and is freed there. So no need to free it
// here (esp. since various track might share the same music).
#ifdef DEBUG
assert(m_magic_number == 0x17AC3802);
m_magic_number = 0xDEADBEEF;
@ -333,47 +336,29 @@ void Track::getMusicInformation(std::vector<std::string>& filenames,
for(int i=0; i<(int)filenames.size(); i++)
{
std::string full_path = m_root+"/"+filenames[i];
MusicInformation* mi;
try
{
mi = music_manager->getMusicInformation(full_path);
}
catch(std::runtime_error)
{
mi = NULL;
}
MusicInformation* mi = music_manager->getMusicInformation(full_path);
if(!mi)
{
try
{
std::string shared_name = file_manager->getMusicFile(filenames[i]);
if(shared_name!="")
{
try
{
mi = music_manager->getMusicInformation(shared_name);
}
catch(std::runtime_error)
{
mi = NULL;
}
} // shared_name!=""
mi = music_manager->getMusicInformation(shared_name);
}
catch (std::exception& e)
catch (...)
{
(void)e;
mi = NULL;
}
}
if(!mi)
{
fprintf(stderr, "Music information file '%s' not found - ignored.\n",
if(mi)
m_music.push_back(mi);
else
fprintf(stderr,
"Music information file '%s' not found - ignored.\n",
filenames[i].c_str());
continue;
}
m_music.push_back(mi);
} // for i in filenames
} // getMusicInformation
//-----------------------------------------------------------------------------