fios.cpp

Go to the documentation of this file.
00001 /* $Id: fios.cpp 15299 2009-01-31 20:16:06Z smatz $ */
00002 
00007 #include "stdafx.h"
00008 #include "openttd.h"
00009 #include "fios.h"
00010 #include "fileio_func.h"
00011 #include "string_func.h"
00012 #include <sys/stat.h>
00013 
00014 #ifdef WIN32
00015 # include <tchar.h>
00016 # ifndef UNICODE
00017 #  include <io.h>
00018 # endif
00019 # define access _taccess
00020 # define unlink _tunlink
00021 #else
00022 # include <unistd.h>
00023 #endif /* WIN32 */
00024 
00025 #include "table/strings.h"
00026 
00027 /* Variables to display file lists */
00028 SmallVector<FiosItem, 32> _fios_items;
00029 static char *_fios_path;
00030 SmallFiosItem _file_to_saveload;
00031 
00032 /* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */
00033 extern bool FiosIsRoot(const char *path);
00034 extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
00035 extern bool FiosIsHiddenFile(const struct dirent *ent);
00036 extern void FiosGetDrives();
00037 extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot);
00038 
00039 /* get the name of an oldstyle savegame */
00040 extern void GetOldSaveGameName(const char *path, const char *file, char *title, const char *last);
00041 
00048 int CDECL compare_FiosItems(const void *a, const void *b)
00049 {
00050   const FiosItem *da = (const FiosItem *)a;
00051   const FiosItem *db = (const FiosItem *)b;
00052   int r;
00053 
00054   if (_savegame_sort_order & SORT_BY_NAME) {
00055     r = strcasecmp(da->title, db->title);
00056   } else {
00057     r = da->mtime < db->mtime ? -1 : 1;
00058   }
00059 
00060   if (_savegame_sort_order & SORT_DESCENDING) r = -r;
00061   return r;
00062 }
00063 
00065 void FiosFreeSavegameList()
00066 {
00067   _fios_items.Clear();
00068   _fios_items.Compact();
00069 };
00070 
00078 StringID FiosGetDescText(const char **path, uint64 *total_free)
00079 {
00080   *path = _fios_path;
00081   return FiosGetDiskFreeSpace(*path, total_free) ? STR_4005_BYTES_FREE : STR_4006_UNABLE_TO_READ_DRIVE;
00082 }
00083 
00084 /* Browse to a new path based on the passed FiosItem struct
00085  * @param *item FiosItem object telling us what to do
00086  * @return a string if we have given a file as a target, otherwise NULL */
00087 char *FiosBrowseTo(const FiosItem *item)
00088 {
00089   char *path = _fios_path;
00090 
00091   switch (item->type) {
00092     case FIOS_TYPE_DRIVE:
00093 #if defined(WINCE)
00094       snprintf(path, MAX_PATH, PATHSEP "");
00095 #elif defined(WIN32) || defined(__OS2__)
00096       snprintf(path, MAX_PATH, "%c:" PATHSEP, item->title[0]);
00097 #endif
00098     /* Fallthrough */
00099     case FIOS_TYPE_INVALID:
00100       break;
00101 
00102     case FIOS_TYPE_PARENT: {
00103       /* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */
00104       char *s = strrchr(path, PATHSEPCHAR);
00105       if (s != NULL && s != path) {
00106         s[0] = '\0'; // Remove last path separator character, so we can go up one level.
00107       }
00108       s = strrchr(path, PATHSEPCHAR);
00109       if (s != NULL) s[1] = '\0'; // go up a directory
00110 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
00111       /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
00112       else if ((s = strrchr(path, ':')) != NULL) s[1] = '\0';
00113 #endif
00114       break;
00115     }
00116 
00117     case FIOS_TYPE_DIR:
00118       strcat(path, item->name);
00119       strcat(path, PATHSEP);
00120       break;
00121 
00122     case FIOS_TYPE_DIRECT:
00123       snprintf(path, MAX_PATH, "%s", item->name);
00124       break;
00125 
00126     case FIOS_TYPE_FILE:
00127     case FIOS_TYPE_OLDFILE:
00128     case FIOS_TYPE_SCENARIO:
00129     case FIOS_TYPE_OLD_SCENARIO:
00130     case FIOS_TYPE_PNG:
00131     case FIOS_TYPE_BMP:
00132     {
00133       static char str_buffr[512];
00134       snprintf(str_buffr, lengthof(str_buffr), "%s%s", path, item->name);
00135       return str_buffr;
00136     }
00137   }
00138 
00139   return NULL;
00140 }
00141 
00142 void FiosMakeSavegameName(char *buf, const char *name, size_t size)
00143 {
00144   const char *extension, *period;
00145 
00146   extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav";
00147 
00148   /* Don't append the extension if it is already there */
00149   period = strrchr(name, '.');
00150   if (period != NULL && strcasecmp(period, extension) == 0) extension = "";
00151 #if  defined(__MORPHOS__) || defined(__AMIGAOS__)
00152   if (_fios_path != NULL) {
00153     unsigned char sepchar = _fios_path[(strlen(_fios_path) - 1)];
00154 
00155     if (sepchar != ':' && sepchar != '/') {
00156       snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00157     } else {
00158       snprintf(buf, size, "%s%s%s", _fios_path, name, extension);
00159     }
00160   } else {
00161     snprintf(buf, size, "%s%s", name, extension);
00162   }
00163 #else
00164   snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00165 #endif
00166 }
00167 
00168 #if defined(WIN32)
00169 # define unlink _tunlink
00170 #endif
00171 
00172 bool FiosDelete(const char *name)
00173 {
00174   char filename[512];
00175 
00176   FiosMakeSavegameName(filename, name, lengthof(filename));
00177   return unlink(OTTD2FS(filename)) == 0;
00178 }
00179 
00180 bool FileExists(const char *filename)
00181 {
00182 #if defined(WINCE)
00183   /* There is always one platform that doesn't support basic commands... */
00184   HANDLE hand = CreateFile(OTTD2FS(filename), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
00185   if (hand == INVALID_HANDLE_VALUE) return 1;
00186   CloseHandle(hand);
00187   return 0;
00188 #else
00189   return access(OTTD2FS(filename), 0) == 0;
00190 #endif
00191 }
00192 
00193 typedef FiosType fios_getlist_callback_proc(SaveLoadDialogMode mode, const char *filename, const char *ext, char *title, const char *last);
00194 
00199 static FiosItem *FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc)
00200 {
00201   struct stat sb;
00202   struct dirent *dirent;
00203   DIR *dir;
00204   FiosItem *fios;
00205   int sort_start;
00206   char d_name[sizeof(fios->name)];
00207 
00208   _fios_items.Clear();
00209 
00210   /* A parent directory link exists if we are not in the root directory */
00211   if (!FiosIsRoot(_fios_path) && mode != SLD_NEW_GAME) {
00212     fios = _fios_items.Append();
00213     fios->type = FIOS_TYPE_PARENT;
00214     fios->mtime = 0;
00215     strecpy(fios->name, "..", lastof(fios->name));
00216     strecpy(fios->title, ".. (Parent directory)", lastof(fios->title));
00217   }
00218 
00219   /* Show subdirectories */
00220   if (mode != SLD_NEW_GAME && (dir = ttd_opendir(_fios_path)) != NULL) {
00221     while ((dirent = readdir(dir)) != NULL) {
00222       strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name));
00223 
00224       /* found file must be directory, but not '.' or '..' */
00225       if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) &&
00226           (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
00227           strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
00228         fios = _fios_items.Append();
00229         fios->type = FIOS_TYPE_DIR;
00230         fios->mtime = 0;
00231         strecpy(fios->name, d_name, lastof(fios->name));
00232         snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name);
00233         str_validate(fios->title);
00234       }
00235     }
00236     closedir(dir);
00237   }
00238 
00239   /* Sort the subdirs always by name, ascending, remember user-sorting order */
00240   {
00241     byte order = _savegame_sort_order;
00242     _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
00243     qsort(_fios_items.Begin(), _fios_items.Length(), sizeof(FiosItem), compare_FiosItems);
00244     _savegame_sort_order = order;
00245   }
00246 
00247   /* This is where to start sorting for the filenames */
00248   sort_start = _fios_items.Length();
00249 
00250   /* Show files */
00251   dir = ttd_opendir(_fios_path);
00252   if (dir != NULL) {
00253     while ((dirent = readdir(dir)) != NULL) {
00254       char fios_title[64];
00255       char *t;
00256       strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name));
00257 
00258       if (!FiosIsValidFile(_fios_path, dirent, &sb) || !S_ISREG(sb.st_mode) || FiosIsHiddenFile(dirent)) continue;
00259 
00260       /* File has no extension, skip it */
00261       if ((t = strrchr(d_name, '.')) == NULL) continue;
00262       fios_title[0] = '\0'; // reset the title;
00263 
00264       FiosType type = callback_proc(mode, d_name, t, fios_title, lastof(fios_title));
00265       if (type != FIOS_TYPE_INVALID) {
00266         fios = _fios_items.Append();
00267         fios->mtime = sb.st_mtime;
00268         fios->type = type;
00269         strecpy(fios->name, d_name, lastof(fios->name));
00270 
00271         /* Some callbacks want to lookup the title of the file. Allow that.
00272          * If we just copy the title from the filename, strip the extension */
00273         t = (fios_title[0] == '\0') ? *t = '\0', d_name : fios_title;
00274         strecpy(fios->title, t, lastof(fios->title));
00275         str_validate(fios->title);
00276       }
00277     }
00278     closedir(dir);
00279   }
00280 
00281   qsort(_fios_items.Get(sort_start), _fios_items.Length() - sort_start, sizeof(FiosItem), compare_FiosItems);
00282 
00283   /* Show drives */
00284   if (mode != SLD_NEW_GAME) FiosGetDrives();
00285 
00286   _fios_items.Compact();
00287 
00288   return _fios_items.Begin();
00289 }
00290 
00302 FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
00303 {
00304   /* Show savegame files
00305    * .SAV OpenTTD saved game
00306    * .SS1 Transport Tycoon Deluxe preset game
00307    * .SV1 Transport Tycoon Deluxe (Patch) saved game
00308    * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
00309   if (strcasecmp(ext, ".sav") == 0) return FIOS_TYPE_FILE;
00310 
00311   if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
00312     if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
00313         strcasecmp(ext, ".sv2") == 0) {
00314       if (title != NULL) GetOldSaveGameName(_fios_path, file, title, last);
00315       return FIOS_TYPE_OLDFILE;
00316     }
00317   }
00318 
00319   return FIOS_TYPE_INVALID;
00320 }
00321 
00328 void FiosGetSavegameList(SaveLoadDialogMode mode)
00329 {
00330   static char *fios_save_path = NULL;
00331 
00332   if (fios_save_path == NULL) {
00333     fios_save_path = MallocT<char>(MAX_PATH);
00334     FioGetDirectory(fios_save_path, MAX_PATH, SAVE_DIR);
00335   }
00336 
00337   _fios_path = fios_save_path;
00338 
00339   FiosGetFileList(mode, &FiosGetSavegameListCallback);
00340 }
00341 
00353 static FiosType FiosGetScenarioListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
00354 {
00355   /* Show scenario files
00356    * .SCN OpenTTD style scenario file
00357    * .SV0 Transport Tycoon Deluxe (Patch) scenario
00358    * .SS0 Transport Tycoon Deluxe preset scenario */
00359   if (strcasecmp(ext, ".scn") == 0) return FIOS_TYPE_SCENARIO;
00360 
00361   if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
00362     if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
00363       GetOldSaveGameName(_fios_path, file, title, last);
00364       return FIOS_TYPE_OLD_SCENARIO;
00365     }
00366   }
00367 
00368   return FIOS_TYPE_INVALID;
00369 }
00370 
00377 void FiosGetScenarioList(SaveLoadDialogMode mode)
00378 {
00379   static char *fios_scn_path = NULL;
00380 
00381   /* Copy the default path on first run or on 'New Game' */
00382   if (fios_scn_path == NULL) {
00383     fios_scn_path = MallocT<char>(MAX_PATH);
00384     FioGetDirectory(fios_scn_path, MAX_PATH, SCENARIO_DIR);
00385   }
00386 
00387   _fios_path = fios_scn_path;
00388 
00389   FiosGetFileList(mode, &FiosGetScenarioListCallback);
00390 }
00391 
00392 static FiosType FiosGetHeightmapListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
00393 {
00394   /* Show heightmap files
00395    * .PNG PNG Based heightmap files
00396    * .BMP BMP Based heightmap files
00397    */
00398 
00399 #ifdef WITH_PNG
00400   if (strcasecmp(ext, ".png") == 0) return FIOS_TYPE_PNG;
00401 #endif /* WITH_PNG */
00402 
00403   if (strcasecmp(ext, ".bmp") == 0) return FIOS_TYPE_BMP;
00404 
00405   return FIOS_TYPE_INVALID;
00406 }
00407 
00408 /* Get a list of Heightmaps */
00409 void FiosGetHeightmapList(SaveLoadDialogMode mode)
00410 {
00411   static char *fios_hmap_path = NULL;
00412 
00413   if (fios_hmap_path == NULL) {
00414     fios_hmap_path = MallocT<char>(MAX_PATH);
00415     FioGetDirectory(fios_hmap_path, MAX_PATH, HEIGHTMAP_DIR);
00416   }
00417 
00418   _fios_path = fios_hmap_path;
00419 
00420   FiosGetFileList(mode, &FiosGetHeightmapListCallback);
00421 }

Generated on Mon Feb 16 23:12:06 2009 for openttd by  doxygen 1.5.6