fios.cpp

Go to the documentation of this file.
00001 /* $Id: fios.cpp 13871 2008-07-29 22:37:54Z rubidium $ */
00002 
00007 #include "stdafx.h"
00008 #include "openttd.h"
00009 #include "variables.h"
00010 #include "heightmap.h"
00011 #include "fios.h"
00012 #include "fileio.h"
00013 #include "core/alloc_func.hpp"
00014 #include "functions.h"
00015 #include "string_func.h"
00016 #include <sys/types.h>
00017 #include <sys/stat.h>
00018 
00019 #ifdef WIN32
00020 # include <tchar.h>
00021 # include <io.h>
00022 # define access _taccess
00023 # define unlink _tunlink
00024 #else
00025 # include <unistd.h>
00026 #endif /* WIN32 */
00027 
00028 #include "table/strings.h"
00029 
00030 /* Variables to display file lists */
00031 int _fios_num;
00032 
00033 static char *_fios_path;
00034 static FiosItem *_fios_items;
00035 SmallFiosItem _file_to_saveload;
00036 static int _fios_count, _fios_alloc;
00037 
00038 /* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */
00039 extern bool FiosIsRoot(const char *path);
00040 extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
00041 extern bool FiosIsHiddenFile(const struct dirent *ent);
00042 extern void FiosGetDrives();
00043 extern bool FiosGetDiskFreeSpace(const char *path, uint32 *tot);
00044 
00045 /* get the name of an oldstyle savegame */
00046 extern void GetOldSaveGameName(char *title, const char *path, const char *file);
00047 
00052 FiosItem *FiosAlloc()
00053 {
00054   if (_fios_count == _fios_alloc) {
00055     _fios_alloc += 256;
00056     _fios_items = ReallocT(_fios_items, _fios_alloc);
00057   }
00058   return &_fios_items[_fios_count++];
00059 }
00060 
00067 int CDECL compare_FiosItems(const void *a, const void *b)
00068 {
00069   const FiosItem *da = (const FiosItem *)a;
00070   const FiosItem *db = (const FiosItem *)b;
00071   int r;
00072 
00073   if (_savegame_sort_order & SORT_BY_NAME) {
00074     r = strcasecmp(da->title, db->title);
00075   } else {
00076     r = da->mtime < db->mtime ? -1 : 1;
00077   }
00078 
00079   if (_savegame_sort_order & SORT_DESCENDING) r = -r;
00080   return r;
00081 }
00082 
00086 void FiosFreeSavegameList()
00087 {
00088   free(_fios_items);
00089   _fios_items = NULL;
00090   _fios_alloc = _fios_count = 0;
00091 }
00092 
00100 StringID FiosGetDescText(const char **path, uint32 *total_free)
00101 {
00102   *path = _fios_path;
00103   return FiosGetDiskFreeSpace(*path, total_free) ? STR_4005_BYTES_FREE : STR_4006_UNABLE_TO_READ_DRIVE;
00104 }
00105 
00106 /* Browse to a new path based on the passed FiosItem struct
00107  * @param *item FiosItem object telling us what to do
00108  * @return a string if we have given a file as a target, otherwise NULL */
00109 char *FiosBrowseTo(const FiosItem *item)
00110 {
00111   char *s;
00112   char *path = _fios_path;
00113 
00114   switch (item->type) {
00115 #if defined(WINCE)
00116   case FIOS_TYPE_DRIVE: sprintf(path, PATHSEP ""); break;
00117 #elif defined(WIN32) || defined(__OS2__)
00118   case FIOS_TYPE_DRIVE: sprintf(path, "%c:" PATHSEP, item->title[0]); break;
00119 #endif
00120 
00121   case FIOS_TYPE_PARENT:
00122     /* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */
00123     s = strrchr(path, PATHSEPCHAR);
00124     if (s != NULL && s != path) {
00125       s[0] = '\0'; // Remove last path separator character, so we can go up one level.
00126     }
00127     s = strrchr(path, PATHSEPCHAR);
00128     if (s != NULL) s[1] = '\0'; // go up a directory
00129 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
00130     /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
00131     else if ((s = strrchr(path, ':')) != NULL) s[1] = '\0';
00132 #endif
00133     break;
00134 
00135   case FIOS_TYPE_DIR:
00136     strcat(path, item->name);
00137     strcat(path, PATHSEP);
00138     break;
00139 
00140   case FIOS_TYPE_DIRECT:
00141     sprintf(path, "%s", item->name);
00142     break;
00143 
00144   case FIOS_TYPE_FILE:
00145   case FIOS_TYPE_OLDFILE:
00146   case FIOS_TYPE_SCENARIO:
00147   case FIOS_TYPE_OLD_SCENARIO:
00148   case FIOS_TYPE_PNG:
00149   case FIOS_TYPE_BMP:
00150   {
00151     static char str_buffr[512];
00152     snprintf(str_buffr, lengthof(str_buffr), "%s%s", path, item->name);
00153     return str_buffr;
00154   }
00155   }
00156 
00157   return NULL;
00158 }
00159 
00160 void FiosMakeSavegameName(char *buf, const char *name, size_t size)
00161 {
00162   const char *extension, *period;
00163 
00164   extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav";
00165 
00166   /* Don't append the extension if it is already there */
00167   period = strrchr(name, '.');
00168   if (period != NULL && strcasecmp(period, extension) == 0) extension = "";
00169 #if  defined(__MORPHOS__) || defined(__AMIGAOS__)
00170   if (_fios_path != NULL) {
00171     unsigned char sepchar = _fios_path[(strlen(_fios_path) - 1)];
00172 
00173     if (sepchar != ':' && sepchar != '/') {
00174       snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00175     } else {
00176       snprintf(buf, size, "%s%s%s", _fios_path, name, extension);
00177     }
00178   } else {
00179     snprintf(buf, size, "%s%s", name, extension);
00180   }
00181 #else
00182   snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00183 #endif
00184 }
00185 
00186 #if defined(WIN32)
00187 # define unlink _tunlink
00188 #endif
00189 
00190 bool FiosDelete(const char *name)
00191 {
00192   char filename[512];
00193 
00194   FiosMakeSavegameName(filename, name, lengthof(filename));
00195   return unlink(OTTD2FS(filename)) == 0;
00196 }
00197 
00198 bool FileExists(const char *filename)
00199 {
00200 #if defined(WINCE)
00201   /* There is always one platform that doesn't support basic commands... */
00202   HANDLE hand = CreateFile(OTTD2FS(filename), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
00203   if (hand == INVALID_HANDLE_VALUE) return 1;
00204   CloseHandle(hand);
00205   return 0;
00206 #else
00207   return access(OTTD2FS(filename), 0) == 0;
00208 #endif
00209 }
00210 
00211 typedef byte fios_getlist_callback_proc(int mode, const char *filename, const char *ext, char *title);
00212 
00217 static FiosItem *FiosGetFileList(int mode, fios_getlist_callback_proc *callback_proc)
00218 {
00219   struct stat sb;
00220   struct dirent *dirent;
00221   DIR *dir;
00222   FiosItem *fios;
00223   int sort_start;
00224   char d_name[sizeof(fios->name)];
00225 
00226   /* A parent directory link exists if we are not in the root directory */
00227   if (!FiosIsRoot(_fios_path) && mode != SLD_NEW_GAME) {
00228     fios = FiosAlloc();
00229     fios->type = FIOS_TYPE_PARENT;
00230     fios->mtime = 0;
00231     ttd_strlcpy(fios->name, "..", lengthof(fios->name));
00232     ttd_strlcpy(fios->title, ".. (Parent directory)", lengthof(fios->title));
00233   }
00234 
00235   /* Show subdirectories */
00236   if (mode != SLD_NEW_GAME && (dir = ttd_opendir(_fios_path)) != NULL) {
00237     while ((dirent = readdir(dir)) != NULL) {
00238       ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
00239 
00240       /* found file must be directory, but not '.' or '..' */
00241       if (FiosIsValidFile(_fios_path, dirent, &sb) && (sb.st_mode & S_IFDIR) &&
00242           (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
00243           strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
00244         fios = FiosAlloc();
00245         fios->type = FIOS_TYPE_DIR;
00246         fios->mtime = 0;
00247         ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
00248         snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name);
00249         str_validate(fios->title);
00250       }
00251     }
00252     closedir(dir);
00253   }
00254 
00255   /* Sort the subdirs always by name, ascending, remember user-sorting order */
00256   {
00257     byte order = _savegame_sort_order;
00258     _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
00259     qsort(_fios_items, _fios_count, sizeof(FiosItem), compare_FiosItems);
00260     _savegame_sort_order = order;
00261   }
00262 
00263   /* This is where to start sorting for the filenames */
00264   sort_start = _fios_count;
00265 
00266   /* Show files */
00267   dir = ttd_opendir(_fios_path);
00268   if (dir != NULL) {
00269     while ((dirent = readdir(dir)) != NULL) {
00270       char fios_title[64];
00271       char *t;
00272       ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
00273 
00274       if (!FiosIsValidFile(_fios_path, dirent, &sb) || !(sb.st_mode & S_IFREG) || FiosIsHiddenFile(dirent)) continue;
00275 
00276       /* File has no extension, skip it */
00277       if ((t = strrchr(d_name, '.')) == NULL) continue;
00278       fios_title[0] = '\0'; // reset the title;
00279 
00280       byte type = callback_proc(mode, d_name, t, fios_title);
00281       if (type != FIOS_TYPE_INVALID) {
00282         fios = FiosAlloc();
00283         fios->mtime = sb.st_mtime;
00284         fios->type = type;
00285         ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
00286 
00287         /* Some callbacks want to lookup the title of the file. Allow that.
00288          * If we just copy the title from the filename, strip the extension */
00289         t = (fios_title[0] == '\0') ? *t = '\0', d_name : fios_title;
00290         ttd_strlcpy(fios->title, t, lengthof(fios->title));
00291         str_validate(fios->title);
00292       }
00293     }
00294     closedir(dir);
00295   }
00296 
00297   qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems);
00298 
00299   /* Show drives */
00300   if (mode != SLD_NEW_GAME) FiosGetDrives();
00301 
00302   _fios_num = _fios_count;
00303   return _fios_items;
00304 }
00305 
00316 byte FiosGetSavegameListCallback(int mode, const char *file, const char *ext, char *title)
00317 {
00318   /* Show savegame files
00319    * .SAV OpenTTD saved game
00320    * .SS1 Transport Tycoon Deluxe preset game
00321    * .SV1 Transport Tycoon Deluxe (Patch) saved game
00322    * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
00323   if (strcasecmp(ext, ".sav") == 0) return FIOS_TYPE_FILE;
00324 
00325   if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
00326     if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
00327         strcasecmp(ext, ".sv2") == 0) {
00328       if (title != NULL) GetOldSaveGameName(title, _fios_path, file);
00329       return FIOS_TYPE_OLDFILE;
00330     }
00331   }
00332 
00333   return FIOS_TYPE_INVALID;
00334 }
00335 
00342 FiosItem *FiosGetSavegameList(int mode)
00343 {
00344   static char *_fios_save_path = NULL;
00345 
00346   if (_fios_save_path == NULL) {
00347     _fios_save_path = MallocT<char>(MAX_PATH);
00348     FioGetDirectory(_fios_save_path, MAX_PATH, SAVE_DIR);
00349   }
00350 
00351   _fios_path = _fios_save_path;
00352 
00353   return FiosGetFileList(mode, &FiosGetSavegameListCallback);
00354 }
00355 
00366 static byte FiosGetScenarioListCallback(int mode, const char *file, const char *ext, char *title)
00367 {
00368   /* Show scenario files
00369    * .SCN OpenTTD style scenario file
00370    * .SV0 Transport Tycoon Deluxe (Patch) scenario
00371    * .SS0 Transport Tycoon Deluxe preset scenario */
00372   if (strcasecmp(ext, ".scn") == 0) return FIOS_TYPE_SCENARIO;
00373 
00374   if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
00375     if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
00376       GetOldSaveGameName(title, _fios_path, file);
00377       return FIOS_TYPE_OLD_SCENARIO;
00378     }
00379   }
00380 
00381   return FIOS_TYPE_INVALID;
00382 }
00383 
00390 FiosItem *FiosGetScenarioList(int mode)
00391 {
00392   static char *_fios_scn_path = NULL;
00393 
00394   /* Copy the default path on first run or on 'New Game' */
00395   if (_fios_scn_path == NULL) {
00396     _fios_scn_path = MallocT<char>(MAX_PATH);
00397     FioGetDirectory(_fios_scn_path, MAX_PATH, SCENARIO_DIR);
00398   }
00399 
00400   _fios_path = _fios_scn_path;
00401 
00402   return FiosGetFileList(mode, &FiosGetScenarioListCallback);
00403 }
00404 
00405 static byte FiosGetHeightmapListCallback(int mode, const char *file, const char *ext, char *title)
00406 {
00407   /* Show heightmap files
00408    * .PNG PNG Based heightmap files
00409    * .BMP BMP Based heightmap files
00410    */
00411 
00412 #ifdef WITH_PNG
00413   if (strcasecmp(ext, ".png") == 0) return FIOS_TYPE_PNG;
00414 #endif /* WITH_PNG */
00415 
00416   if (strcasecmp(ext, ".bmp") == 0) return FIOS_TYPE_BMP;
00417 
00418   return FIOS_TYPE_INVALID;
00419 }
00420 
00421 /* Get a list of Heightmaps */
00422 FiosItem *FiosGetHeightmapList(int mode)
00423 {
00424   static char *_fios_hmap_path = NULL;
00425 
00426   if (_fios_hmap_path == NULL) {
00427     _fios_hmap_path = MallocT<char>(MAX_PATH);
00428     FioGetDirectory(_fios_hmap_path, MAX_PATH, HEIGHTMAP_DIR);
00429   }
00430 
00431   _fios_path = _fios_hmap_path;
00432 
00433   return FiosGetFileList(mode, &FiosGetHeightmapListCallback);
00434 }

Generated on Mon Sep 22 20:34:15 2008 for openttd by  doxygen 1.5.6