Back to index

supertuxkart  0.5+dfsg1
file_manager.cpp
Go to the documentation of this file.
00001 //  $Id: file_manager.cpp 2111 2008-05-31 07:04:30Z cosmosninja $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2004 Steve Baker <sjbaker1@airmail.net>
00005 //            (C) 2008 Steve Baker, Joerg Henrichs
00006 //
00007 //  This program is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU General Public License
00009 //  as published by the Free Software Foundation; either version 2
00010 //  of the License, or (at your option) any later version.
00011 //
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 
00022 #include <stdexcept>
00023 #include <sstream>
00024 #include <sys/stat.h>
00025 #include <string>
00026 #ifdef WIN32
00027 #  include <io.h>
00028 #  include <stdio.h>
00029 #  ifndef __CYGWIN__
00030 #    define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
00031      //   Some portabilty defines
00032 #    define snprintf       _snprintf
00033 #    define access         _access
00034 #    define                F_OK  04
00035 #  endif
00036 #  define CONFIGDIR       "."
00037 #else
00038 #  define CONFIGDIR       ".supertuxkart"
00039 #endif
00040 #include "plib/ul.h"
00041 #include "file_manager.hpp"
00042 #include "world.hpp"
00043 #include "btBulletDynamicsCommon.h"
00044 #include "moving_physics.hpp"
00045 #include "moving_texture.hpp"
00046 #include "translation.hpp"
00047 #include "material_manager.hpp"
00048 #include "string_utils.hpp"
00049 
00050 #ifdef __APPLE__
00051 // dynamic data path detection onmac
00052 #  include <CoreFoundation/CoreFoundation.h>
00053 
00054 bool macSetBundlePathIfRelevant(std::string& data_dir)
00055 {
00056     printf("checking whether we are using an app bundle... ");
00057     // the following code will enable STK to find its data when placed in an app bundle on mac OS X.
00058     // returns true if path is set, returns false if path was not set
00059     char path[1024];
00060     CFBundleRef main_bundle = CFBundleGetMainBundle(); assert(main_bundle);
00061     CFURLRef main_bundle_URL = CFBundleCopyBundleURL(main_bundle); assert(main_bundle_URL);
00062     CFStringRef cf_string_ref = CFURLCopyFileSystemPath( main_bundle_URL, kCFURLPOSIXPathStyle); assert(cf_string_ref);
00063     CFStringGetCString(cf_string_ref, path, 1024, kCFStringEncodingASCII);
00064     CFRelease(main_bundle_URL);
00065     CFRelease(cf_string_ref);
00066     
00067     std::string contents = std::string(path) + std::string("/Contents");
00068     if(contents.find(".app") != std::string::npos)
00069     {
00070         printf("yes\n");
00071         // executable is inside an app bundle, use app bundle-relative paths
00072         data_dir = contents + std::string("/Resources/data");
00073         return true;
00074     }
00075     else
00076     {
00077         printf("no\n");
00078         return false;
00079     }
00080 }
00081 #endif
00082 
00083 FileManager* file_manager = 0;
00084 
00085 FileManager::FileManager()
00086 {
00087     m_is_full_path = false;
00088     
00089     if ( getenv ( "SUPERTUXKART_DATADIR" ) != NULL )
00090         m_root_dir= getenv ( "SUPERTUXKART_DATADIR" ) ;
00091 #ifdef __APPLE__
00092     else if( macSetBundlePathIfRelevant( m_root_dir ) ) { /* nothing to do */ }
00093 #endif
00094     else if ( access ( "data/stk_config.data", F_OK ) == 0 )
00095         m_root_dir = "." ;
00096     else if ( access ( "../data/stk_config.data", F_OK ) == 0 )
00097         m_root_dir = ".." ;
00098     else
00099 #ifdef SUPERTUXKART_DATADIR
00100         m_root_dir = SUPERTUXKART_DATADIR ;
00101 #else
00102         m_root_dir = "/usr/local/share/games/supertuxkart" ;
00103 #endif
00104     // We can't use _() here, since translations will only be initalised
00105     // after the filemanager (to get the path to the tranlsations from it)
00106     fprintf(stderr, "Data files will be fetched from: '%s'\n", 
00107             m_root_dir.c_str() );
00108 
00109     pushTextureSearchPath(m_root_dir+"/data/textures");
00110     pushModelSearchPath  (m_root_dir+"/data/models"  );
00111     pushMusicSearchPath  (m_root_dir+"/data/music"   );
00112     // Add more paths from the STK_MUSIC_PATH environment variable
00113     if(getenv("SUPERTUXKART_MUSIC_PATH")!=NULL)
00114     {
00115         std::string path=getenv("SUPERTUXKART_MUSIC_PATH");
00116         std::vector<std::string> dirs=StringUtils::split(path,':');
00117         for(int i=(int)dirs.size()-1; i>=0; i--)
00118         {
00119             // Remove '/' at the end of paths, since this can cause
00120             // problems with windows when using stat()
00121             while(dirs[i].size()>=1 && dirs[i][dirs[i].size()-1]=='/')
00122             {
00123                 dirs[i]=dirs[i].substr(0, dirs[i].size()-1);
00124             }
00125             // remove empty entries
00126             if(dirs[i].size()==0)
00127             {
00128                 dirs.erase(dirs.begin()+i);
00129                 continue;
00130             }
00131         }
00132 #ifdef WIN32
00133         // Handle filenames like d:/dir, which becomes ["d","/dir"]
00134         for(int i=(int)dirs.size()-1; i>=0; i--)
00135         {
00136             if(dirs[i].size()>1) continue;
00137             if(i==dirs.size()-1)    // last element
00138             {
00139                 dirs[i]+=":";      // turn "c" back into "c:"
00140             }
00141             else
00142             {
00143                 dirs[i]+=":"+dirs[i+1]; // restore "d:/dir" back 
00144                 dirs.erase(dirs.begin()+i+1);
00145             }
00146         }
00147 #endif
00148         for(int i=0;i<(int)dirs.size(); i++)
00149             pushMusicSearchPath(dirs[i]);
00150     }
00151 }  // FileManager
00152 
00153 //-----------------------------------------------------------------------------
00154 FileManager::~FileManager()
00155 {
00156     popMusicSearchPath();
00157     popModelSearchPath();
00158     popTextureSearchPath();
00159 }   // ~FileManager
00160 
00161 //-----------------------------------------------------------------------------
00162 bool FileManager::findFile(std::string& full_path,
00163                       const std::string& fname, 
00164                       const std::vector<std::string>& search_path) const
00165 {
00166     struct stat mystat;
00167     
00168     for(std::vector<std::string>::const_iterator i = search_path.begin();
00169         i != search_path.end(); ++i)
00170     {
00171         //full_path=m_root_dir + "/" + *i + "/" + fname;
00172         full_path = *i + "/" + fname;
00173         if(stat(full_path.c_str(), &mystat) >= 0) return true;
00174     }
00175     full_path="";
00176     return false;
00177 }   // findFile
00178 
00179 //-----------------------------------------------------------------------------
00180 std::string FileManager::getTextureFile(const std::string& FNAME) const
00181 {
00182     std::string path;
00183     findFile(path, FNAME, m_texture_search_path);
00184     return path;
00185 }   // makeTexturePath
00186 
00187 //-----------------------------------------------------------------------------
00188 std::string FileManager::getModelFile(const std::string& FNAME) const
00189 {
00190     std::string path;
00191     findFile(path, FNAME, m_model_search_path);
00192     return path;
00193 }   // getModelFile
00194 
00195 //-----------------------------------------------------------------------------
00196 std::string FileManager::getTrackDir() const
00197 {
00198     return m_root_dir+"/data/tracks";
00199 }   // getTrackDir
00200 
00201 //-----------------------------------------------------------------------------
00202 std::string FileManager::getKartDir() const
00203 {
00204     return m_root_dir+"/data/karts";
00205 }   // getKartDir
00206 
00207 //-----------------------------------------------------------------------------
00208 std::string FileManager::getHerringDir() const
00209 {
00210     return m_root_dir+"/data/herrings";
00211 }   // getHerringDir
00212 //-----------------------------------------------------------------------------
00213 std::string FileManager::getTranslationDir() const
00214 {
00215     return m_root_dir+"/data/po";
00216 }   // getTranslationDir
00217 
00218 //-----------------------------------------------------------------------------
00219 std::vector<std::string> FileManager::getMusicDirs() const
00220 {
00221     return m_music_search_path;
00222 }   // getMusicDirs
00223 
00224 //-----------------------------------------------------------------------------
00225 std::string FileManager::getTrackFile(const std::string& fname,
00226                                       const std::string& track_name) const
00227 {
00228     // tracks file are in data/tracks/TRACKNAME/TRACKNAME.ext
00229     // but if a track name is supplied use it (which is necessary
00230     // e.g. to load a model from a track directory
00231     std::string basename = (track_name!="") ? track_name 
00232                            : StringUtils::without_extension(fname);
00233     return getTrackDir()+"/"+basename+"/"+fname;
00234 }   // getTrackFile
00235 
00236 //-----------------------------------------------------------------------------
00237 std::string FileManager::getKartFile(const std::string& fname,
00238                                      const std::string& kart_name) const
00239 {
00240     // kart file are in data/karts/KARTNAME/KARTNAME.ext
00241     // but if a kart name is supplied use it (which is necessary
00242     // e.g. to load a model from a kart directory
00243     std::string basename = (kart_name!="") ? kart_name 
00244                            : StringUtils::without_extension(fname);
00245     return getKartDir()+"/"+basename+"/"+fname;
00246 }   // getKartFile
00247 
00248 //-----------------------------------------------------------------------------
00249 std::string FileManager::getConfigFile(const std::string& fname) const
00250 {
00251     return m_root_dir+"/data/"+fname;
00252 }   // getConfigFile
00253 
00254 //-----------------------------------------------------------------------------
00255 std::string FileManager::getHerringFile(const std::string& fname) const
00256 {
00257     return getHerringDir()+"/"+fname;
00258 }   // getConfigFile
00259 
00260 //-----------------------------------------------------------------------------
00261 std::string FileManager::getHomeDir() const
00262 {
00263     std::string DIRNAME;
00264 #ifdef WIN32
00265     // For now the old windows config way is used: store a config file
00266     // in the current directory (in other OS a special subdirectory is created)
00267     DIRNAME=".";
00268 #else
00269     if(getenv("HOME")!=NULL)
00270     {
00271         DIRNAME = getenv("HOME");
00272     }
00273     else
00274     {
00275         DIRNAME = ".";
00276     }
00277     DIRNAME += "/";
00278     DIRNAME += CONFIGDIR;
00279 #endif
00280     return DIRNAME;
00281 }   // getHomeDir
00282 
00283 //-----------------------------------------------------------------------------
00284 std::string FileManager::getLogFile(const std::string& fname) const
00285 {
00286     return getHomeDir()+"/"+fname;
00287 }   // getLogFile
00288 
00289 //-----------------------------------------------------------------------------
00290 std::string FileManager::getMusicFile(const std::string& fname) const
00291 {
00292     std::string path;
00293     findFile(path, fname, m_music_search_path);
00294     return path;
00295 }   // getMusicFile
00296 
00297 //-----------------------------------------------------------------------------
00298 std::string FileManager::getSFXFile(const std::string& fname) const
00299 {
00300     return m_root_dir+"/data/sfx/"+fname;
00301 }   // getSFXFile
00302 //-----------------------------------------------------------------------------
00303 std::string FileManager::getFontFile(const std::string& fname) const
00304 {
00305     return m_root_dir+"/data/fonts/"+fname;
00306 }   // getFontFile
00307 //-----------------------------------------------------------------------------
00308 std::string FileManager::getHighscoreFile(const std::string& fname) const
00309 {
00310     return getHomeDir()+"/"+fname;
00311 }   // getHighscoreFile
00312 
00313 //-----------------------------------------------------------------------------
00314 #ifdef HAVE_GHOST_REPLAY
00315 std::string FileManager::getReplayFile(const std::string& fname) const
00316 {
00317     return m_root_dir+"/replay/"+fname;
00318 }   // getReplayFile
00319 #endif
00320 //-----------------------------------------------------------------------------
00321 void FileManager::initConfigDir()
00322 {
00323 #ifdef WIN32
00324     /*nothing*/
00325 #else
00326     /*if HOME environment variable exists
00327     create directory $HOME/.supertuxkart*/
00328     if(getenv("HOME")!=NULL)
00329     {
00330         std::string pathname;
00331         pathname = getenv("HOME");
00332         pathname += "/.supertuxkart";
00333         mkdir(pathname.c_str(), 0755);
00334     }
00335 #endif
00336 }   // initConfigDir
00337 
00338 //-----------------------------------------------------------------------------
00339 void FileManager::listFiles(std::set<std::string>& result, const std::string& dir,
00340                             bool is_full_path, bool make_full_path) const
00341 {
00342         struct stat mystat;
00343 
00344         // don't list directories with a slash on the end, it'll fail on win32
00345 //        assert(dir[dir.size()-1] != '/');
00346 
00347         result.clear();
00348 
00349         std::string path = is_full_path ? dir : m_root_dir+"/"+dir;
00350 
00351         if(stat(path.c_str(), &mystat) < 0) return;
00352         if(! S_ISDIR(mystat.st_mode))       return; 
00353 
00354         ulDir* mydir = ulOpenDir(path.c_str());
00355         if(!mydir) return;
00356 
00357         ulDirEnt* mydirent;
00358         while( (mydirent = ulReadDir(mydir)) != 0)
00359         {
00360             result.insert(make_full_path ? path+"/"+mydirent->d_name
00361                                          :          mydirent->d_name);
00362         }
00363         ulCloseDir(mydir);
00364 }   // listFiles
00365 
00366 //-----------------------------------------------------------------------------