Fix the replay menu for people with non-latin characters in their username.

Use OsPath instead of CStr and CStrW where possible,
wstring_from_utf8(OsPath.string8()) to pass printable strings to the
JSAPI,
OsString when opening a filestream and
off_t instead of int for filesizes.

Fixes #4320
Differential Revision: https://code.wildfiregames.com/D518
Reviewed By: Imarok
Tested By: Imarok on Windows, wraitii on OSX
Special thanks to Philip for advice and the lib/path.h fix in
47cc447322.

This was SVN commit r19824.
This commit is contained in:
elexis
2017-06-25 14:54:00 +00:00
parent 47cc447322
commit e7ab22286e
11 changed files with 59 additions and 60 deletions
+31 -33
View File
@@ -49,7 +49,7 @@ OsPath VisualReplay::GetDirectoryName()
return OsPath(paths.UserData() / "replays" / engine_version);
}
void VisualReplay::StartVisualReplay(const CStrW& directory)
void VisualReplay::StartVisualReplay(const OsPath& directory)
{
ENSURE(!g_NetServer);
ENSURE(!g_NetClient);
@@ -61,7 +61,7 @@ void VisualReplay::StartVisualReplay(const CStrW& directory)
return;
g_Game = new CGame(false, false);
g_Game->StartVisualReplay(replayFile.string8());
g_Game->StartVisualReplay(replayFile);
}
bool VisualReplay::ReadCacheFile(ScriptInterface& scriptInterface, JS::MutableHandleObject cachedReplaysObject)
@@ -72,7 +72,7 @@ bool VisualReplay::ReadCacheFile(ScriptInterface& scriptInterface, JS::MutableHa
if (!FileExists(cacheFileName))
return false;
std::ifstream cacheStream(cacheFileName.string8().c_str());
std::ifstream cacheStream(OsString(cacheFileName).c_str());
CStr cacheStr((std::istreambuf_iterator<char>(cacheStream)), std::istreambuf_iterator<char>());
cacheStream.close();
@@ -95,7 +95,7 @@ void VisualReplay::StoreCacheFile(ScriptInterface& scriptInterface, JS::HandleOb
JSAutoRequest rq(cx);
JS::RootedValue replaysRooted(cx, JS::ObjectValue(*replays));
std::ofstream cacheStream(tempCacheFileName.string8().c_str(), std::ofstream::out | std::ofstream::trunc);
std::ofstream cacheStream(OsString(tempCacheFileName).c_str(), std::ofstream::out | std::ofstream::trunc);
cacheStream << scriptInterface.StringifyJSON(&replaysRooted);
cacheStream.close();
@@ -111,7 +111,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(ScriptInterface& scriptInterfac
JSAutoRequest rq(cx);
// Maps the filename onto the index and size
typedef std::map<CStr, std::pair<u32, off_t>> replayCacheMap;
typedef std::map<OsPath, std::pair<u32, off_t>> replayCacheMap;
replayCacheMap fileList;
@@ -127,7 +127,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(ScriptInterface& scriptInterfac
JS_GetElement(cx, cachedReplaysObject, j, &replay);
JS::RootedValue file(cx);
CStr fileName;
OsPath fileName;
double fileSize;
scriptInterface.GetProperty(replay, "directory", fileName);
scriptInterface.GetProperty(replay, "fileSize", fileSize);
@@ -158,7 +158,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(ScriptInterface& scriptInterfac
continue;
bool isNew = true;
replayCacheMap::iterator it = fileList.find(directory.string8());
replayCacheMap::iterator it = fileList.find(directory);
if (it != fileList.end())
{
if (compareFiles)
@@ -180,7 +180,7 @@ JS::HandleObject VisualReplay::ReloadReplayCache(ScriptInterface& scriptInterfac
CFileInfo fileInfo;
GetFileInfo(replayFile, &fileInfo);
scriptInterface.Eval("({})", &replayData);
scriptInterface.SetProperty(replayData, "directory", directory);
scriptInterface.SetProperty(replayData, "directory", directory.string());
scriptInterface.SetProperty(replayData, "fileSize", (double)fileInfo.Size());
}
JS_SetElement(cx, replays, i++, replayData);
@@ -241,7 +241,7 @@ JS::Value VisualReplay::GetReplays(ScriptInterface& scriptInterface, bool compar
*
* @return The current cursor position or -1 on error.
*/
inline int goBackToLineBeginning(std::istream* replayStream, const CStr& fileName, const u64& fileSize)
inline off_t goBackToLineBeginning(std::istream* replayStream, const OsPath& fileName, off_t fileSize)
{
int currentPos;
char character;
@@ -255,7 +255,7 @@ inline int goBackToLineBeginning(std::istream* replayStream, const CStr& fileNam
if (!replayStream->good())
{
LOGERROR("Unknown error when returning to the last line (%i of %lu) of %s", currentPos, fileSize, fileName.c_str());
LOGERROR("Unknown error when returning to the last line (%i of %lu) of %s", currentPos, fileSize, fileName.string8().c_str());
return -1;
}
@@ -269,7 +269,7 @@ inline int goBackToLineBeginning(std::istream* replayStream, const CStr& fileNam
replayStream->seekg(-2, std::ios_base::cur);
}
LOGERROR("Infinite loop when going back to a line beginning in %s", fileName.c_str());
LOGERROR("Infinite loop when going back to a line beginning in %s", fileName.string8().c_str());
return -1;
}
@@ -279,7 +279,7 @@ inline int goBackToLineBeginning(std::istream* replayStream, const CStr& fileNam
*
* @return seconds or -1 on error
*/
inline int getReplayDuration(std::istream* replayStream, const CStr& fileName, const u64& fileSize)
inline int getReplayDuration(std::istream* replayStream, const OsPath& fileName, off_t fileSize)
{
CStr type;
@@ -290,7 +290,7 @@ inline int getReplayDuration(std::istream* replayStream, const CStr& fileName, c
// There should be about 5 lines to read until a turn is found.
for (int linesRead = 1; linesRead < 1000; ++linesRead)
{
int currentPosition = goBackToLineBeginning(replayStream, fileName, fileSize);
off_t currentPosition = goBackToLineBeginning(replayStream, fileName, fileSize);
// Read error or reached file beginning. No turns exist.
if (currentPosition < 1)
@@ -298,12 +298,12 @@ inline int getReplayDuration(std::istream* replayStream, const CStr& fileName, c
if (!replayStream->good())
{
LOGERROR("Read error when determining replay duration at %i of %llu in %s", currentPosition - 2, fileSize, fileName.c_str());
LOGERROR("Read error when determining replay duration at %i of %llu in %s", currentPosition - 2, fileSize, fileName.string8().c_str());
return -1;
}
// Found last turn, compute duration.
if ((u64) currentPosition + 4 < fileSize && (*replayStream >> type).good() && type == "turn")
if (currentPosition + 4 < fileSize && (*replayStream >> type).good() && type == "turn")
{
u32 turn = 0, turnLength = 0;
*replayStream >> turn >> turnLength;
@@ -314,7 +314,7 @@ inline int getReplayDuration(std::istream* replayStream, const CStr& fileName, c
replayStream->seekg(currentPosition - 2, std::ios_base::beg);
}
LOGERROR("Infinite loop when determining replay duration for %s", fileName.c_str());
LOGERROR("Infinite loop when determining replay duration for %s", fileName.string8().c_str());
return -1;
}
@@ -329,26 +329,24 @@ JS::Value VisualReplay::LoadReplayData(ScriptInterface& scriptInterface, const O
// Get file size and modification date
CFileInfo fileInfo;
GetFileInfo(replayFile, &fileInfo);
const u64 fileSize = (u64)fileInfo.Size();
const off_t fileSize = fileInfo.Size();
if (fileSize == 0)
return JSVAL_NULL;
// Open file
const CStr fileName = replayFile.string8();
std::ifstream* replayStream = new std::ifstream(fileName.c_str());
std::ifstream* replayStream = new std::ifstream(OsString(replayFile).c_str());
// File must begin with "start"
CStr type;
if (!(*replayStream >> type).good())
{
LOGERROR("Couldn't open %s. Non-latin characters are not supported yet.", fileName.c_str());
LOGERROR("Couldn't open %s.", replayFile.string8().c_str());
SAFE_DELETE(replayStream);
return JSVAL_NULL;
}
if (type != "start")
{
LOGWARNING("The replay %s is broken!", fileName.c_str());
LOGWARNING("The replay %s doesn't begin with 'start'!", replayFile.string8().c_str());
SAFE_DELETE(replayStream);
return JSVAL_NULL;
}
@@ -361,7 +359,7 @@ JS::Value VisualReplay::LoadReplayData(ScriptInterface& scriptInterface, const O
JS::RootedValue attribs(cx);
if (!scriptInterface.ParseJSON(header, &attribs))
{
LOGERROR("Couldn't parse replay header of %s", fileName.c_str());
LOGERROR("Couldn't parse replay header of %s", replayFile.string8().c_str());
SAFE_DELETE(replayStream);
return JSVAL_NULL;
}
@@ -382,7 +380,7 @@ JS::Value VisualReplay::LoadReplayData(ScriptInterface& scriptInterface, const O
return JSVAL_NULL;
}
int duration = getReplayDuration(replayStream, fileName, fileSize);
int duration = getReplayDuration(replayStream, replayFile, fileSize);
SAFE_DELETE(replayStream);
@@ -393,14 +391,14 @@ JS::Value VisualReplay::LoadReplayData(ScriptInterface& scriptInterface, const O
// Return the actual data
JS::RootedValue replayData(cx);
scriptInterface.Eval("({})", &replayData);
scriptInterface.SetProperty(replayData, "directory", directory);
scriptInterface.SetProperty(replayData, "directory", directory.string());
scriptInterface.SetProperty(replayData, "fileSize", (double)fileSize);
scriptInterface.SetProperty(replayData, "attribs", attribs);
scriptInterface.SetProperty(replayData, "duration", duration);
return replayData;
}
bool VisualReplay::DeleteReplay(const CStrW& replayDirectory)
bool VisualReplay::DeleteReplay(const OsPath& replayDirectory)
{
if (replayDirectory.empty())
return false;
@@ -409,7 +407,7 @@ bool VisualReplay::DeleteReplay(const CStrW& replayDirectory)
return DirectoryExists(directory) && DeleteDirectory(directory) == INFO::OK;
}
JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& directoryName)
JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CxPrivate* pCxPrivate, const OsPath& directoryName)
{
// Create empty JS object
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
@@ -423,7 +421,7 @@ JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CxPrivate* pCxPriva
return attribs;
// Open file
std::istream* replayStream = new std::ifstream(replayFile.string8().c_str());
std::istream* replayStream = new std::ifstream(OsString(replayFile).c_str());
CStr type, line;
ENSURE((*replayStream >> type).good() && type == "start");
@@ -473,13 +471,13 @@ void VisualReplay::SaveReplayMetadata(ScriptInterface* scriptInterface)
const OsPath fileName = g_Game->GetReplayLogger().GetDirectory() / L"metadata.json";
CreateDirectories(fileName.Parent(), 0700);
std::ofstream stream (fileName.string8().c_str(), std::ofstream::out | std::ofstream::trunc);
std::ofstream stream (OsString(fileName).c_str(), std::ofstream::out | std::ofstream::trunc);
stream << scriptInterface->StringifyJSON(&metadata, false);
stream.close();
debug_printf("Saved replay metadata to %s\n", fileName.string8().c_str());
}
bool VisualReplay::HasReplayMetadata(const CStrW& directoryName)
bool VisualReplay::HasReplayMetadata(const OsPath& directoryName)
{
const OsPath filePath(GetDirectoryName() / directoryName / L"metadata.json");
@@ -492,7 +490,7 @@ bool VisualReplay::HasReplayMetadata(const CStrW& directoryName)
return fileInfo.Size() > 0;
}
JS::Value VisualReplay::GetReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& directoryName)
JS::Value VisualReplay::GetReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate, const OsPath& directoryName)
{
if (!HasReplayMetadata(directoryName))
return JSVAL_NULL;
@@ -501,7 +499,7 @@ JS::Value VisualReplay::GetReplayMetadata(ScriptInterface::CxPrivate* pCxPrivate
JSAutoRequest rq(cx);
JS::RootedValue metadata(cx);
std::ifstream* stream = new std::ifstream(OsPath(GetDirectoryName() / directoryName / L"metadata.json").string8());
std::ifstream* stream = new std::ifstream(OsString(GetDirectoryName() / directoryName / L"metadata.json").c_str());
ENSURE(stream->good());
CStr line;
std::getline(*stream, line);