Skip to content

Commit e44ffe7

Browse files
committed
Save/language listing fixes:
- Fixed listing bugs. - Lists are now sorted on any platform. - Invalid files are ignored instead of crashing the game.
1 parent b3e2c6b commit e44ffe7

4 files changed

Lines changed: 114 additions & 64 deletions

File tree

src/Engine/CrossPlatform.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <iostream>
2121
#include <algorithm>
2222
#include <sys/stat.h>
23+
#include "../dirent.h"
2324
#include "Exception.h"
2425
#include "Options.h"
2526
#ifdef _WIN32
@@ -277,5 +278,55 @@ int createFolder(const char *path)
277278
#endif
278279
}
279280

281+
/**
282+
* Gets the name of all the files
283+
* contained in a certain folder.
284+
* @param path Full path to folder.
285+
* @param ext Extension of files ("" if it doesn't matter).
286+
*/
287+
std::vector<std::string> getFolderContents(const std::string &path, const std::string &ext)
288+
{
289+
std::vector<std::string> files;
290+
291+
DIR *dp = opendir(path.c_str());
292+
if (dp == 0)
293+
{
294+
throw Exception("Failed to open saves directory");
295+
}
296+
297+
struct dirent *dirp;
298+
while ((dirp = readdir(dp)) != 0)
299+
{
300+
std::string file = dirp->d_name;
301+
302+
if (file == "." || file == "..")
303+
{
304+
continue;
305+
}
306+
if (!ext.empty())
307+
{
308+
if (file.length() >= ext.length() + 1)
309+
{
310+
std::string end = file.substr(file.length() - ext.length() - 1);
311+
if (end != "." + ext)
312+
{
313+
continue;
314+
}
315+
}
316+
else
317+
{
318+
continue;
319+
}
320+
}
321+
322+
files.push_back(file);
323+
}
324+
closedir(dp);
325+
#ifndef _WIN32
326+
std::sort(files.begin(), files.end());
327+
#endif
328+
return files;
329+
}
330+
280331
}
281332
}

src/Engine/CrossPlatform.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define OPENXCOM_CROSSPLATFORM_H
2121

2222
#include <string>
23+
#include <vector>
2324

2425
namespace OpenXcom
2526
{
@@ -42,6 +43,8 @@ namespace CrossPlatform
4243
std::string findUserFolder(bool exists);
4344
/// Creates a folder.
4445
int createFolder(const char *path);
46+
/// Returns the list of files in a folder.
47+
std::vector<std::string> getFolderContents(const std::string &path, const std::string &ext = "");
4548
}
4649

4750
}

src/Engine/Language.cpp

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "Language.h"
2020
#include <iostream>
2121
#include <fstream>
22-
#include "../dirent.h"
22+
#include "CrossPlatform.h"
2323
#include "Exception.h"
2424
#include "Options.h"
2525
#include "../Interface/TextList.h"
@@ -171,48 +171,43 @@ void Language::replace(std::string &str, const std::string &find, const std::str
171171
*/
172172
std::vector<std::string> Language::getList(TextList *list)
173173
{
174-
std::vector<std::string> langs;
175-
std::string dir = Options::getDataFolder() + "Language/";
176-
DIR *dp = opendir(dir.c_str());
177-
if (dp == 0)
178-
{
179-
throw Exception("Failed to open language directory");
180-
}
174+
std::vector<std::string> langs = CrossPlatform::getFolderContents(Options::getDataFolder() + "Language/", "lng");
181175

182-
struct dirent *dirp;
183-
while ((dirp = readdir(dp)) != 0)
176+
for (std::vector<std::string>::iterator i = langs.begin(); i != langs.end(); ++i)
184177
{
185-
std::string file = dirp->d_name;
186-
// Check if it's a valid language
187-
if (file.find(".lng") == std::string::npos)
188-
{
189-
continue;
190-
}
191-
std::string fullname = dir + file;
178+
std::string file = (*i);
179+
std::string fullname = Options::getDataFolder() + "Language/" + file;
192180
std::ifstream fin(fullname.c_str(), std::ios::in | std::ios::binary);
193-
if (!fin)
194-
{
195-
closedir(dp);
196-
throw Exception("Failed to load language");
197-
}
198-
char value;
199-
std::string langname;
200-
while (fin.read(&value, 1))
181+
try
201182
{
202-
if (value != '\n')
183+
if (!fin)
203184
{
204-
langname += value;
185+
throw Exception("Failed to load language");
205186
}
206-
else
187+
char value;
188+
std::string langname;
189+
while (fin.read(&value, 1))
207190
{
208-
break;
191+
if (value != '\n')
192+
{
193+
langname += value;
194+
}
195+
else
196+
{
197+
break;
198+
}
209199
}
200+
fin.close();
201+
list->addRow(1, Language::utf8ToWstr(langname).c_str());
202+
(*i) = file.substr(0, file.length()-4);
203+
}
204+
catch (Exception &e)
205+
{
206+
std::cerr << e.what() << std::endl;
207+
i = langs.erase(i);
208+
continue;
210209
}
211-
fin.close();
212-
list->addRow(1, Language::utf8ToWstr(langname).c_str());
213-
langs.push_back(file.substr(0, file.length()-4));
214210
}
215-
closedir(dp);
216211
return langs;
217212
}
218213

src/Savegame/SavedGame.cpp

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
#include <fstream>
2121
#include <sstream>
2222
#include <iomanip>
23-
#include "../dirent.h"
2423
#include "yaml.h"
2524
#include "../Ruleset/Ruleset.h"
2625
#include "../Engine/RNG.h"
2726
#include "../Engine/Language.h"
2827
#include "../Interface/TextList.h"
2928
#include "../Engine/Exception.h"
3029
#include "../Engine/Options.h"
30+
#include "../Engine/CrossPlatform.h"
3131
#include "SavedBattleGame.h"
3232
#include "GameTime.h"
3333
#include "Country.h"
@@ -129,44 +129,45 @@ SavedGame::~SavedGame()
129129
*/
130130
void SavedGame::getList(TextList *list, Language *lang)
131131
{
132-
DIR *dp = opendir(Options::getUserFolder().c_str());
133-
if (dp == 0)
134-
{
135-
throw Exception("Failed to open saves directory");
136-
}
132+
std::vector<std::string> saves = CrossPlatform::getFolderContents(Options::getUserFolder(), "sav");
137133

138-
struct dirent *dirp;
139-
while ((dirp = readdir(dp)) != 0)
134+
for (std::vector<std::string>::iterator i = saves.begin(); i != saves.end(); ++i)
140135
{
141-
std::string file = dirp->d_name;
142-
// Check if it's a valid save
143-
if (file.size() < 4 || file.rfind(".sav") != file.size() - 4)
136+
std::string file = (*i);
137+
std::string fullname = Options::getUserFolder() + file;
138+
std::ifstream fin(fullname.c_str());
139+
try
144140
{
141+
if (!fin)
142+
{
143+
throw Exception("Failed to load savegame");
144+
}
145+
YAML::Parser parser(fin);
146+
YAML::Node doc;
147+
148+
parser.GetNextDocument(doc);
149+
GameTime time = GameTime(6, 1, 1, 1999, 12, 0, 0);
150+
time.load(doc["time"]);
151+
std::stringstream saveTime;
152+
std::wstringstream saveDay, saveMonth, saveYear;
153+
saveTime << time.getHour() << ":" << std::setfill('0') << std::setw(2) << time.getMinute();
154+
saveDay << time.getDay() << lang->getString(time.getDayString());
155+
saveMonth << lang->getString(time.getMonthString());
156+
saveYear << time.getYear();
157+
list->addRow(5, Language::utf8ToWstr(file.substr(0, file.length()-4)).c_str(), Language::utf8ToWstr(saveTime.str()).c_str(), saveDay.str().c_str(), saveMonth.str().c_str(), saveYear.str().c_str());
158+
fin.close();
159+
}
160+
catch (Exception &e)
161+
{
162+
std::cerr << e.what() << std::endl;
145163
continue;
146164
}
147-
std::string fullname = Options::getUserFolder() + file;
148-
std::ifstream fin(fullname.c_str());
149-
if (!fin)
165+
catch (YAML::Exception &e)
150166
{
151-
closedir(dp);
152-
throw Exception("Failed to load savegame");
167+
std::cerr << e.what() << std::endl;
168+
continue;
153169
}
154-
YAML::Parser parser(fin);
155-
YAML::Node doc;
156-
157-
parser.GetNextDocument(doc);
158-
GameTime time = GameTime(6, 1, 1, 1999, 12, 0, 0);
159-
time.load(doc["time"]);
160-
std::stringstream saveTime;
161-
std::wstringstream saveDay, saveMonth, saveYear;
162-
saveTime << time.getHour() << ":" << std::setfill('0') << std::setw(2) << time.getMinute();
163-
saveDay << time.getDay() << lang->getString(time.getDayString());
164-
saveMonth << lang->getString(time.getMonthString());
165-
saveYear << time.getYear();
166-
list->addRow(5, Language::utf8ToWstr(file.substr(0, file.length()-4)).c_str(), Language::utf8ToWstr(saveTime.str()).c_str(), saveDay.str().c_str(), saveMonth.str().c_str(), saveYear.str().c_str());
167-
fin.close();
168170
}
169-
closedir(dp);
170171
}
171172

172173
/**

0 commit comments

Comments
 (0)