Web file system implementation + fixes

This commit is contained in:
elasota
2021-04-19 01:02:10 -04:00
parent f15a87041a
commit 84a4d16aed
30 changed files with 373 additions and 81 deletions

View File

@@ -19,9 +19,13 @@ public:
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
#if GP_ASYNCIFY_PARANOID
void Close();
#endif
private:
HANDLE m_handle;
bool m_readable;

View File

@@ -18,6 +18,7 @@
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <emscripten.h>
#include "UTF8.h"
@@ -29,6 +30,111 @@ typedef off_t off64_t;
#define stat64 stat
#endif
EM_JS(void, FlushFileSystem, (), {
Asyncify.handleSleep(wakeUp => {
FS.syncfs(false, function (err) {
assert(!err);
wakeUp();
});
});
});
class GpDirectoryCursor_Web final : public IGpDirectoryCursor
{
public:
explicit GpDirectoryCursor_Web(DIR *dir, const std::string &prefix);
~GpDirectoryCursor_Web();
bool GetNext(const char *&outFileName) override;
void Destroy() override;
private:
DIR *m_dir;
std::string m_prefix;
std::string m_decodedFileName;
};
GpDirectoryCursor_Web::GpDirectoryCursor_Web(DIR *dir, const std::string &prefix)
: m_dir(dir)
, m_prefix(prefix)
{
}
GpDirectoryCursor_Web::~GpDirectoryCursor_Web()
{
closedir(m_dir);
}
bool GpDirectoryCursor_Web::GetNext(const char *&outFileName)
{
const size_t prefixLength = m_prefix.size();
for (;;)
{
struct dirent *dir = readdir(m_dir);
if (!dir)
return false;
const char *fname = dir->d_name;
const size_t fnameLen = strlen(fname);
if (fnameLen > prefixLength && (prefixLength == 0 || !memcmp(&m_prefix[0], fname, prefixLength)))
{
const char *encodedResult = fname + prefixLength;
m_decodedFileName.clear();
for (size_t i = 0; encodedResult[i] != 0; i++)
{
char c = encodedResult[i];
if (c == '%')
{
char highNibble = encodedResult[i + 1];
if ((highNibble >= '0' && highNibble <= '9') || (highNibble >= 'a' && highNibble <= 'f') || (highNibble >= 'A' && highNibble <= 'F'))
{
char lowNibble = encodedResult[i + 2];
if ((lowNibble >= '0' && lowNibble <= '9') || (lowNibble >= 'a' && lowNibble <= 'f') || (lowNibble >= 'A' && lowNibble <= 'F'))
{
bool failedNibble = false;
char nibbles[2] = { highNibble, lowNibble };
int decNibbles[2];
for (int ni = 0; ni < 2; ni++)
{
char nc = nibbles[ni];
if (nc >= '0' && nc <= '9')
decNibbles[ni] = nc - '0';
else if (nc >= 'a' && nc <= 'f')
decNibbles[ni] = 0xa + (nc - 'a');
else if (nc >= 'A' && nc <= 'F')
decNibbles[ni] = 0xa + (nc - 'A');
else
failedNibble = true;
}
if (!failedNibble)
{
c = static_cast<char>((decNibbles[0] << 4) + decNibbles[1]);
i += 2;
}
}
}
}
m_decodedFileName += c;
}
outFileName = m_decodedFileName.c_str();
return true;
}
}
return true;
}
void GpDirectoryCursor_Web::Destroy()
{
delete this;
}
class GpFileStream_Web_StaticMemFile final : public GpIOStream
{
@@ -46,7 +152,7 @@ public:
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
private:
@@ -136,7 +242,7 @@ GpUFilePos_t GpFileStream_Web_StaticMemFile::Tell() const
return m_offset;
}
void GpFileStream_Web_StaticMemFile::Close()
void GpFileStream_Web_StaticMemFile::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
delete this;
}
@@ -149,7 +255,7 @@ void GpFileStream_Web_StaticMemFile::Flush()
class GpFileStream_Web_File final : public GpIOStream
{
public:
GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly);
GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly, bool synchronizeOnClose);
~GpFileStream_Web_File();
size_t Read(void *bytesOut, size_t size) override;
@@ -162,7 +268,7 @@ public:
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
private:
@@ -170,13 +276,15 @@ private:
bool m_seekable;
bool m_isReadOnly;
bool m_isWriteOnly;
bool m_synchronizeOnClose;
};
GpFileStream_Web_File::GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly)
GpFileStream_Web_File::GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly, bool synchronizeOnClose)
: m_f(f)
, m_isReadOnly(readOnly)
, m_isWriteOnly(writeOnly)
, m_synchronizeOnClose(synchronizeOnClose)
{
m_seekable = (fseek(m_f, 0, SEEK_CUR) == 0);
}
@@ -184,6 +292,9 @@ GpFileStream_Web_File::GpFileStream_Web_File(FILE *f, bool readOnly, bool writeO
GpFileStream_Web_File::~GpFileStream_Web_File()
{
fclose(m_f);
if (m_synchronizeOnClose)
GpFileSystem_Web::MarkFSStateDirty();
}
size_t GpFileStream_Web_File::Read(void *bytesOut, size_t size)
@@ -258,7 +369,7 @@ GpUFilePos_t GpFileStream_Web_File::Tell() const
return static_cast<GpUFilePos_t>(ftell(m_f));
}
void GpFileStream_Web_File::Close()
void GpFileStream_Web_File::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
this->~GpFileStream_Web_File();
free(this);
@@ -269,20 +380,25 @@ void GpFileStream_Web_File::Flush()
fflush(m_f);
}
bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution)
bool GpFileSystem_Web::ms_fsStateDirty;
bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution)
{
const char *prefsAppend = nullptr;
std::string unsanitized;
switch (virtualDirectory)
{
case PortabilityLayer::VirtualDirectories::kApplicationData:
resolution = std::string("Packaged");
unsanitized = std::string("Packaged");
break;
case PortabilityLayer::VirtualDirectories::kGameData:
resolution = std::string("Packaged/Houses");
unsanitized = std::string("Packaged/Houses");
break;
case PortabilityLayer::VirtualDirectories::kFonts:
resolution = std::string("Resources");
unsanitized = std::string("Resources");
break;
case PortabilityLayer::VirtualDirectories::kHighScores:
prefsAppend = "HighScores";
@@ -301,14 +417,50 @@ bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualD
};
if (prefsAppend)
resolution = m_prefsPath + prefsAppend;
else
resolution = m_basePath + resolution;
for (size_t i = 0; i < numPaths; i++)
{
resolution += "/";
resolution += paths[i];
unsanitized = prefsAppend;
for (size_t i = 0; i < numPaths; i++)
{
unsanitized += "/";
unsanitized += paths[i];
}
if (trailingSlash)
unsanitized += "/";
std::string sanitized;
for (size_t i = 0; i < unsanitized.size(); i++)
{
char c = unsanitized[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')
sanitized += c;
else
{
const char *nibbles = "0123456789abcdef";
char subPath[4];
subPath[0] = '%';
subPath[1] = nibbles[(c >> 4) & 0xf];
subPath[2] = nibbles[c & 0xf];
subPath[3] = 0;
sanitized += subPath;
}
}
resolution = m_prefsPath + "/" + sanitized;
}
else
{
std::string sanitized = m_basePath + unsanitized;
for (size_t i = 0; i < numPaths; i++)
{
sanitized += "/";
sanitized += paths[i];
}
resolution = sanitized;
}
return true;
@@ -325,8 +477,7 @@ GpFileSystem_Web::~GpFileSystem_Web()
void GpFileSystem_Web::Init()
{
char *prefsDir = SDL_GetPrefPath("aerofoil", "aerofoil");
m_prefsPath = prefsDir;
m_prefsPath = "/aerofoil";
char *baseDir = SDL_GetBasePath();
m_basePath = baseDir;
@@ -335,14 +486,6 @@ void GpFileSystem_Web::Init()
char baseDirSeparator = m_basePath[m_basePath.size() - 1];
if (m_basePath.size() >= 4 && m_basePath.substr(m_basePath.size() - 4, 3) == "bin")
m_basePath = m_basePath.substr(0, m_basePath.size() - 4) + "lib" + baseDirSeparator + "aerofoil" + baseDirSeparator;
const char *extensions[] = { "HighScores", "Houses", "SavedGames", "Prefs", "FontCache" };
for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++)
{
std::string prefsPath = std::string(prefsDir) + extensions[i];
int created = mkdir(prefsPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
SDL_free(prefsDir);
}
bool GpFileSystem_Web::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
@@ -360,7 +503,7 @@ bool GpFileSystem_Web::FileExists(PortabilityLayer::VirtualDirectory_t virtualDi
}
std::string resolvedPath;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath))
if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath))
return false;
struct stat s;
@@ -386,7 +529,7 @@ bool GpFileSystem_Web::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDi
}
std::string resolvedPath;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath))
if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath))
{
if (exists)
exists = false;
@@ -445,7 +588,7 @@ GpIOStream *GpFileSystem_Web::OpenFileNested(PortabilityLayer::VirtualDirectory_
return nullptr;
std::string resolvedPath;
if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, resolvedPath))
if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, false, resolvedPath))
return nullptr;
void *objStorage = malloc(sizeof(GpFileStream_Web_File));
@@ -472,7 +615,7 @@ GpIOStream *GpFileSystem_Web::OpenFileNested(PortabilityLayer::VirtualDirectory_
}
}
return new (objStorage) GpFileStream_Web_File(f, !writeAccess, false);
return new (objStorage) GpFileStream_Web_File(f, !writeAccess, false, writeAccess);
}
bool GpFileSystem_Web::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed)
@@ -481,7 +624,7 @@ bool GpFileSystem_Web::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDi
return false;
std::string resolvedPath;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath))
if (!ResolvePath(virtualDirectory, &path, 1, false, resolvedPath))
{
existed = false;
return false;
@@ -490,6 +633,9 @@ bool GpFileSystem_Web::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDi
if (unlink(resolvedPath.c_str()) < 0)
{
existed = (errno != ENOENT);
if (existed)
FlushFileSystem();
return false;
}
existed = true;
@@ -596,7 +742,17 @@ IGpDirectoryCursor *GpFileSystem_Web::ScanDirectoryNested(PortabilityLayer::Virt
if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory))
return ScanCatalog(*catalog);
return nullptr;
std::string resolvedPrefix;
if (!ResolvePath(virtualDirectory, paths, numPaths, true, resolvedPrefix))
return nullptr;
std::string trimmedPrefix = resolvedPrefix.substr(m_prefsPath.size() + 1);
DIR *d = opendir(m_prefsPath.c_str());
if (!d)
return nullptr;
return new GpDirectoryCursor_Web(d, trimmedPrefix);
}
const GpFileSystem_Web_Resources::FileCatalog *GpFileSystem_Web::GetCatalogForVirtualDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory)
@@ -619,5 +775,33 @@ IGpDirectoryCursor *GpFileSystem_Web::ScanCatalog(const GpFileSystem_Web_Resourc
return new GpDirectoryCursor_StringList(paths);
}
void GpFileSystem_Web::MarkFSStateDirty()
{
ms_fsStateDirty = true;
}
void GpFileSystem_Web::FlushFS()
{
if (ms_fsStateDirty)
{
ms_fsStateDirty = false;
FlushFileSystem();
}
}
#if GP_ASYNCIFY_PARANOID
void GpIOStream::Close()
{
this->GP_ASYNCIFY_PARANOID_NAMED(Close)();
GpFileSystem_Web::FlushFS();
}
bool IGpFileSystem::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed)
{
return static_cast<GpFileSystem_Web*>(this)->DeleteFile(virtualDirectory, path, existed);
}
#endif
GpFileSystem_Web GpFileSystem_Web::ms_instance;

View File

@@ -21,7 +21,7 @@ public:
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) override;
GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) GP_ASYNCIFY_PARANOID_OVERRIDE;
IGpDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
bool ValidateFilePath(const char *path, size_t pathLen) const override;
@@ -29,6 +29,9 @@ public:
void SetDelayCallback(DelayCallback_t delayCallback) override;
static void MarkFSStateDirty();
static void FlushFS();
static GpFileSystem_Web *GetInstance();
private:
@@ -51,12 +54,13 @@ private:
static IGpDirectoryCursor *ScanCatalog(const GpFileSystem_Web_Resources::FileCatalog &catalog);
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution);
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool trailingSlash, std::string &resolution);
DelayCallback_t m_delayCallback;
std::string m_prefsPath;
std::string m_basePath;
static bool ms_fsStateDirty;
static GpFileSystem_Web ms_instance;
};

View File

@@ -19,18 +19,29 @@
#include "IGpVOSEventQueue.h"
#include <string>
#include <emscripten.h>
GpXGlobals g_gpXGlobals;
extern "C" IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties);
IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties);
IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties);
IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties);
EM_JS(void, InitFileSystem, (), {
Asyncify.handleSleep(wakeUp => {
FS.mkdir('/aerofoil');
FS.mount(IDBFS, {}, '/aerofoil');
FS.syncfs(true, function (err) {
assert(!err);
wakeUp();
});
});
});
int main(int argc, char* argv[])
{
InitFileSystem();
GpLogDriver_Web::Init();
IGpLogDriver *logger = GpLogDriver_Web::GetInstance();

View File

@@ -1,5 +1,4 @@
set INPUT_DIR=.
set OUTPUT_DIR=bin
set FLAGS=-flto -O3 -s USE_SDL=2 -s USE_ZLIB=1 -s ASYNCIFY -s ASYNCIFY_IGNORE_INDIRECT -s INITIAL_MEMORY=33554432 -s ASYNCIFY_ADVISE
set FLAGS=-flto -O3 -s USE_SDL=2 -s USE_ZLIB=1 -s ASYNCIFY -s ASYNCIFY_IGNORE_INDIRECT -s INITIAL_MEMORY=33554432 -s ASYNCIFY_ADVISE -lidbfs.js -s ASYNCIFY_IMPORTS=['InitFileSystem','FlushFileSystem']
emcc obj/AerofoilWeb_Combined.o obj/AerofoilWeb_Resources.o obj/GpShell_Combined.o obj/AerofoilSDL_Combined.o obj/GpApp_Combined.o obj/PortabilityLayer_Combined.o obj/MacRomanConversion.o -o %OUTPUT_DIR%/aerofoil.html %FLAGS%

View File

@@ -60,12 +60,16 @@ static const size_t GP_SYSTEM_MEMORY_ALIGNMENT = 16;
#define GP_ASYNCIFY_PARANOID 0
#endif
#define GP_ASYNCIFY_PARANOID_VALIDATION 0
#if GP_ASYNCIFY_PARANOID
#define GP_ASYNCIFY_PARANOID_VIRTUAL
#define GP_ASYNCIFY_PARANOID_PURE
#define GP_ASYNCIFY_PARANOID_OVERRIDE
#define GP_ASYNCIFY_PARANOID_NAMED(n) GpAsyncifyParanoid##n
#else
#define GP_ASYNCIFY_PARANOID_VIRTUAL virtual
#define GP_ASYNCIFY_PARANOID_PURE = 0
#define GP_ASYNCIFY_PARANOID_OVERRIDE override
#define GP_ASYNCIFY_PARANOID_NAMED(n) n
#endif

View File

@@ -31,7 +31,7 @@ public:
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
const uint8_t *GetBytes() const;

View File

@@ -602,6 +602,7 @@ Boolean ReadHouse (GpIOStream *houseStream)
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount), false);
numberRooms = (*thisHouse)->nRooms;
#ifdef COMPILEDEMO
if (numberRooms != 45)
return (false);
@@ -685,7 +686,7 @@ Boolean WriteHouse (Boolean checkIt)
}
GpIOStream *houseStream = nil;
theErr = houseCFile->OpenData(PortabilityLayer::EFilePermission_Write, GpFileCreationDispositions::kCreateOrOpen, houseStream);
theErr = houseCFile->OpenData(PortabilityLayer::EFilePermission_Write, GpFileCreationDispositions::kCreateOrOverwrite, houseStream);
if (theErr != PLErrors::kNone)
return (false);

View File

@@ -9,6 +9,7 @@
#include "PLNumberFormatting.h"
#include "PLStringCompare.h"
#include "PLStandardColors.h"
#include "PLSysCalls.h"
#include "Externs.h"
#include "ObjectEdit.h"
#include "PLStandardColors.h"
@@ -874,6 +875,7 @@ void KeepAllObjectsLegal (void)
GetLocalizedString(19, message);
SetMessageWindowMessage(message, StdColors::Red());
houseErrors++;
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}
@@ -908,6 +910,7 @@ void CheckForStaircasePairs (void)
{
GetLocalizedString(20, message);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
else
@@ -923,6 +926,7 @@ void CheckForStaircasePairs (void)
{
GetLocalizedString(21, message);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}
@@ -935,6 +939,7 @@ void CheckForStaircasePairs (void)
{
GetLocalizedString(22, message);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
else
@@ -950,6 +955,7 @@ void CheckForStaircasePairs (void)
{
GetLocalizedString(23, message);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}
@@ -992,6 +998,7 @@ void CheckHouseForProblems (void)
{
GetLocalizedString(27, message);
SetMessageWindowMessage(message, StdColors::Black());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
houseErrors = 0;
}
@@ -1008,6 +1015,7 @@ void CheckHouseForProblems (void)
GetLocalizedString(28, message2);
PasStringConcat(message, message2);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(45);
}
}
@@ -1027,6 +1035,7 @@ void CheckHouseForProblems (void)
GetLocalizedString(29, message2);
PasStringConcat(message, message2);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}
@@ -1042,6 +1051,7 @@ void CheckHouseForProblems (void)
GetLocalizedString(30, message2);
PasStringConcat(message, message2);
SetMessageWindowMessage(message, StdColors::Blue());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(45);
}
}
@@ -1057,6 +1067,7 @@ void CheckHouseForProblems (void)
GetLocalizedString(31, message2);
PasStringConcat(message, message2);
SetMessageWindowMessage(message, StdColors::Blue());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(45);
}
}
@@ -1072,6 +1083,7 @@ void CheckHouseForProblems (void)
GetLocalizedString(32, message2);
PasStringConcat(message, message2);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}
@@ -1089,6 +1101,7 @@ void CheckHouseForProblems (void)
GetLocalizedString(34, message2);
PasStringConcat(message, message2);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}
@@ -1107,6 +1120,7 @@ void CheckHouseForProblems (void)
{
GetLocalizedString(35, message);
SetMessageWindowMessage(message, StdColors::Red());
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
DelayTicks(60);
}
}

View File

@@ -208,7 +208,7 @@ void DragOutMarqueeRect (Window *window, Point start, Rect *theRect)
surface->InvertFrameRect(*theRect, pattern);
wasPt = start;
while (WaitMouseUp())
while (WaitMouseUp_DisarmAsyncify())
{
GetMouse(window, &newPt);
if (wasPt != newPt)
@@ -238,7 +238,7 @@ void DragMarqueeRect (Window *window, DrawSurface *surface, Point start, Rect *t
surface->InvertFrameRect(theMarquee.bounds, pattern);
wasPt = start;
while (WaitMouseUp())
while (WaitMouseUp_DisarmAsyncify())
{
GetMouse(window, &newPt);
if (wasPt != newPt)
@@ -283,7 +283,7 @@ void DragMarqueeHandle (Window *window, DrawSurface *surface, Point start, short
surface->InvertFillRect(theMarquee.handle, pattern);
wasPt = start;
while (WaitMouseUp())
while (WaitMouseUp_DisarmAsyncify())
{
GetMouse(window, &newPt);
if (wasPt != newPt)
@@ -365,7 +365,7 @@ void DragMarqueeCorner (Window *window, DrawSurface *surface, Point start, short
surface->InvertFillRect(theMarquee.handle, pattern);
wasPt = start;
while (WaitMouseUp())
while (WaitMouseUp_DisarmAsyncify())
{
GetMouse(window, &newPt);
if (wasPt != newPt)

View File

@@ -153,9 +153,9 @@ void DragMiniTile (Window *window, DrawSurface *surface, Point mouseIs, short *n
surface->InvertFrameRect(dragRect, pattern);
mouseWas = mouseIs;
while (WaitMouseUp()) // loop until mouse button let up
while (WaitMouseUp_DisarmAsyncify()) // loop until mouse button let up
{
GetMouse(window, &mouseIs); // get mouse coords
GetMouse(window, &mouseIs); // get mouse coords
if (mouseWas != mouseIs) // the mouse has moved
{
surface->InvertFrameRect(dragRect, pattern);

View File

@@ -3,6 +3,7 @@
#include <stddef.h>
#include "GpFilePos.h"
#include "CoreDefs.h"
class GpIOStream
{
@@ -17,11 +18,15 @@ public:
virtual bool SeekEnd(GpUFilePos_t loc) = 0;
virtual GpUFilePos_t Size() const = 0;
virtual GpUFilePos_t Tell() const = 0;
virtual void Close() = 0;
virtual void GP_ASYNCIFY_PARANOID_NAMED(Close)() = 0;
virtual void Flush() = 0;
bool ReadExact(void *bytesOut, size_t size);
bool WriteExact(const void *bytesOut, size_t size);
#if GP_ASYNCIFY_PARANOID
void Close();
#endif
};
inline bool GpIOStream::ReadExact(void *bytesOut, size_t size)

View File

@@ -1,6 +1,7 @@
#pragma once
#include "GpFileCreationDisposition.h"
#include "CoreDefs.h"
#include "VirtualDirectory.h"
#include <stdint.h>
@@ -17,7 +18,7 @@ public:
virtual bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) = 0;
virtual bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) = 0;
virtual GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) = 0;
virtual bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) GP_ASYNCIFY_PARANOID_PURE;
virtual IGpDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) = 0;
virtual bool ValidateFilePath(const char *path, size_t pathLen) const = 0;

View File

@@ -81,7 +81,7 @@ namespace PortabilityLayer
return static_cast<GpUFilePos_t>(ftell(m_file));
}
void CFileStream::Close()
void CFileStream::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
if (m_file)
{

View File

@@ -23,7 +23,7 @@ namespace PortabilityLayer
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
private:

View File

@@ -459,7 +459,13 @@ namespace PortabilityLayer
break;
}
if (WaitForEvent(&evtHolder, 1))
bool haveEvent = false;
{
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
haveEvent = WaitForEvent(&evtHolder, 1);
}
if (haveEvent)
rcvEvt = &evtHolder;
else
rcvEvt = nullptr;

View File

@@ -39,17 +39,17 @@ namespace PortabilityLayer
bool CompositeFileExists(VirtualDirectory_t dirID, const PLPasStr &filename) override;
bool NonCompositeFileExists(VirtualDirectory_t dirID, const PLPasStr &filename, const char *extension) override;
bool DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext) override;
bool DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename) override;
bool DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext) GP_ASYNCIFY_PARANOID_OVERRIDE;
bool DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename) GP_ASYNCIFY_PARANOID_OVERRIDE;
PLError_t CreateFile(VirtualDirectory_t dirID, const PLPasStr &filename, const MacFileProperties &mfp) override;
PLError_t CreateFileAtCurrentTime(VirtualDirectory_t dirID, const PLPasStr &filename, const ResTypeID &fileCreator, const ResTypeID &fileType) override;
PLError_t CreateFile(VirtualDirectory_t dirID, const PLPasStr &filename, const MacFileProperties &mfp) GP_ASYNCIFY_PARANOID_OVERRIDE;
PLError_t CreateFileAtCurrentTime(VirtualDirectory_t dirID, const PLPasStr &filename, const ResTypeID &fileCreator, const ResTypeID &fileType) GP_ASYNCIFY_PARANOID_OVERRIDE;
PLError_t RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override;
PLError_t RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override;
bool PromptSaveFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) override;
bool PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) override;
bool PromptSaveFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) GP_ASYNCIFY_PARANOID_OVERRIDE;
bool PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) GP_ASYNCIFY_PARANOID_OVERRIDE;
static FileManagerImpl *GetInstance();
@@ -506,4 +506,36 @@ namespace PortabilityLayer
if (m_stream)
m_stream->Close();
}
#if GP_ASYNCIFY_PARANOID
bool FileManager::PromptSaveFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI)
{
return static_cast<FileManagerImpl*>(this)->PromptSaveFile(dirID, extension, path, outPathLength, pathCapacity, initialFileName, promptText, composites, callbackAPI);
}
bool FileManager::PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI)
{
return static_cast<FileManagerImpl*>(this)->PromptOpenFile(dirID, extension, path, outPathLength, pathCapacity, promptText, composites, callbackAPI);
}
PLError_t FileManager::CreateFile(VirtualDirectory_t dirID, const PLPasStr &filename, const MacFileProperties &mfp)
{
return static_cast<FileManagerImpl*>(this)->CreateFile(dirID, filename, mfp);
}
PLError_t FileManager::CreateFileAtCurrentTime(VirtualDirectory_t dirID, const PLPasStr &filename, const ResTypeID &fileCreator, const ResTypeID &fileType)
{
return static_cast<FileManagerImpl*>(this)->CreateFileAtCurrentTime(dirID, filename, fileCreator, fileType);
}
bool FileManager::DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext)
{
return static_cast<FileManagerImpl*>(this)->DeleteNonCompositeFile(dirID, filename, ext);
}
bool FileManager::DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename)
{
return static_cast<FileManagerImpl*>(this)->DeleteCompositeFile(dirID, filename);
}
#endif
}

View File

@@ -46,17 +46,17 @@ namespace PortabilityLayer
virtual bool CompositeFileExists(VirtualDirectory_t dirID, const PLPasStr &filename) = 0;
virtual bool NonCompositeFileExists(VirtualDirectory_t dirID, const PLPasStr &filename, const char *extension) = 0;
virtual bool DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext) = 0;
virtual bool DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL bool DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext) GP_ASYNCIFY_PARANOID_PURE;
GP_ASYNCIFY_PARANOID_VIRTUAL bool DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename) GP_ASYNCIFY_PARANOID_PURE;
virtual PLError_t CreateFile(VirtualDirectory_t dirID, const PLPasStr &filename, const MacFileProperties &mfp) = 0;
virtual PLError_t CreateFileAtCurrentTime(VirtualDirectory_t dirID, const PLPasStr &filename, const ResTypeID &fileCreator, const ResTypeID &fileType) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL PLError_t CreateFile(VirtualDirectory_t dirID, const PLPasStr &filename, const MacFileProperties &mfp) GP_ASYNCIFY_PARANOID_PURE;
GP_ASYNCIFY_PARANOID_VIRTUAL PLError_t CreateFileAtCurrentTime(VirtualDirectory_t dirID, const PLPasStr &filename, const ResTypeID &fileCreator, const ResTypeID &fileType) GP_ASYNCIFY_PARANOID_PURE;
virtual PLError_t RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream) = 0;
virtual PLError_t RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream) = 0;
virtual bool PromptSaveFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) = 0;
virtual bool PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL bool PromptSaveFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) GP_ASYNCIFY_PARANOID_PURE;
GP_ASYNCIFY_PARANOID_VIRTUAL bool PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) GP_ASYNCIFY_PARANOID_PURE;
static FileManager *GetInstance();
};

View File

@@ -21,7 +21,7 @@ namespace PortabilityLayer
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
private:
@@ -148,7 +148,7 @@ namespace PortabilityLayer
return m_expectedPosition - m_start;
}
void FileSectionStreamImpl::Close()
void FileSectionStreamImpl::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
this->~FileSectionStreamImpl();
free(this);

View File

@@ -22,7 +22,7 @@ namespace PortabilityLayer
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
private:
@@ -222,7 +222,7 @@ namespace PortabilityLayer
return m_decompressedPos;
}
void InflateStreamImpl::Close()
void InflateStreamImpl::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
this->~InflateStreamImpl();
free(this);

View File

@@ -104,7 +104,7 @@ namespace PortabilityLayer
return static_cast<GpUFilePos_t>(m_loc);
}
void MemReaderStream::Close()
void MemReaderStream::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
}
@@ -128,7 +128,7 @@ namespace PortabilityLayer
return new (storage) MemBufferReaderStream(buffer, size);
}
void MemBufferReaderStream::Close()
void MemBufferReaderStream::GP_ASYNCIFY_PARANOID_NAMED(Close)()
{
this->~MemBufferReaderStream();
MemoryManager::GetInstance()->Release(this);

View File

@@ -23,7 +23,7 @@ namespace PortabilityLayer
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
void Flush() override;
private:
@@ -41,7 +41,7 @@ namespace PortabilityLayer
static MemBufferReaderStream *Create(void *buffer, size_t size);
void Close() override;
void GP_ASYNCIFY_PARANOID_NAMED(Close)() override;
private:
MemBufferReaderStream() GP_DELETED;

View File

@@ -155,7 +155,7 @@ namespace PortabilityLayer
bool FindMenuShortcut(uint16_t &menuID, uint16_t &itemID, uint8_t shortcutChar) override;
void MenuSelect(const Vec2i &initialPoint, int16_t *outMenu, uint16_t *outItem) GP_ASYNCIFY_PARANOID_OVERRIDE;
void PopupMenuSelect(const THandle<Menu> &menu, const Vec2i &popupMenuPos, const Vec2i &initialPoint, size_t initialItem, uint16_t *outItem) override;
void PopupMenuSelect(const THandle<Menu> &menu, const Vec2i &popupMenuPos, const Vec2i &initialPoint, size_t initialItem, uint16_t *outItem) GP_ASYNCIFY_PARANOID_OVERRIDE;
void DrawMenuBar() override;
void SetMenuVisible(bool isVisible) override;
@@ -776,7 +776,14 @@ namespace PortabilityLayer
bool canDismiss = false;
while (!canDismiss)
{
if (WaitForEvent(&evt, 1))
bool haveEvent = false;
{
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
haveEvent = WaitForEvent(&evt, 1);
}
if (haveEvent)
{
if (evt.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput)
{
@@ -1589,5 +1596,10 @@ namespace PortabilityLayer
{
static_cast<MenuManagerImpl*>(this)->MenuSelect(initialPoint, outMenu, outItem);
}
void MenuManager::PopupMenuSelect(const THandle<Menu> &menu, const Vec2i &popupMenuPos, const Vec2i &initialPoint, size_t initialItem, uint16_t *outItem)
{
static_cast<MenuManagerImpl*>(this)->PopupMenuSelect(menu, popupMenuPos, initialPoint, initialItem, outItem);
}
#endif
}

View File

@@ -50,7 +50,7 @@ namespace PortabilityLayer
virtual bool FindMenuShortcut(uint16_t &menuID, uint16_t &itemID, uint8_t shortcutChar) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL void MenuSelect(const Vec2i &initialPoint, int16_t *outMenu, uint16_t *outItem) GP_ASYNCIFY_PARANOID_PURE;
virtual void PopupMenuSelect(const THandle<Menu> &menu, const Vec2i &popupMenuPos, const Vec2i &initialPoint, size_t initialItem, uint16_t *outItem) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL void PopupMenuSelect(const THandle<Menu> &menu, const Vec2i &popupMenuPos, const Vec2i &initialPoint, size_t initialItem, uint16_t *outItem) GP_ASYNCIFY_PARANOID_PURE;
virtual void DrawMenuBar() = 0;
virtual void SetMenuVisible(bool isVisible) = 0;

View File

@@ -515,6 +515,12 @@ Boolean WaitMouseUp()
return isDown;
}
Boolean WaitMouseUp_DisarmAsyncify()
{
PL_ASYNCIFY_PARANOID_DISARM_FOR_SCOPE();
return WaitMouseUp();
}
short Random()
{
// Should return with range -32767..32767

View File

@@ -249,6 +249,7 @@ void DisposeDirectoryFiles(DirectoryFileListEntry *firstDFL);
void GetMouse(Window *window, Point *point);
Boolean StillDown();
Boolean WaitMouseUp();
Boolean WaitMouseUp_DisarmAsyncify();
short Random();
void GetTime(DateTimeRec *dateTime);

View File

@@ -116,7 +116,7 @@ namespace PortabilityLayer
IResourceArchive *GetAppResourceArchive() const override;
IResourceArchive *LoadResFile(CompositeFile *file) const override;
PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) override;
PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) GP_ASYNCIFY_PARANOID_OVERRIDE;
void DissociateHandle(MMHandleBlock *hdl) const override;
const ResourceArchiveRef *ResourceForHandle(MMHandleBlock *hdl) const override;
@@ -524,4 +524,11 @@ namespace PortabilityLayer
if (m_stream)
m_stream->Close();
}
#if GP_ASYNCIFY_PARANOID
PLError_t ResourceManager::CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename)
{
return static_cast<ResourceManagerImpl*>(this)->CreateBlankResFile(virtualDir, filename);
}
#endif
}

View File

@@ -19,6 +19,7 @@
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
static void TranslateMouseInputEvent(const GpVOSEvent &vosEventBase, uint32_t timestamp, PortabilityLayer::EventQueue *queue)
{
@@ -176,7 +177,7 @@ namespace PLSysCalls
{
// Asyncify disarm checks are for manually checking that a stack has no indirect calls.
// They should not be nested!
#if GP_DEBUG_CONFIG && GP_ASYNCIFY_PARANOID
#if GP_DEBUG_CONFIG && GP_ASYNCIFY_PARANOID_VALIDATION
static bool g_asyncifyParanoidDisarmed = false;
void AsyncifyParanoidSetDisarmed(bool state)
@@ -198,7 +199,7 @@ namespace PLSysCalls
void Sleep(uint32_t ticks)
{
#if GP_DEBUG_CONFIG && GP_ASYNCIFY_PARANOID
#if GP_DEBUG_CONFIG && GP_ASYNCIFY_PARANOID_VALIDATION
assert(g_asyncifyParanoidDisarmed);
#endif
if (ticks > 0)

View File

@@ -10,7 +10,7 @@ namespace PLSysCalls
void Sleep(uint32_t ticks);
void Exit(int exitCode);
#if GP_DEBUG_CONFIG && GP_ASYNCIFY_PARANOID
#if GP_DEBUG_CONFIG && GP_ASYNCIFY_PARANOID_VALIDATION
class AsyncifyDisarmScope
{
public:

View File

@@ -78,7 +78,7 @@ namespace PortabilityLayer
virtual IResourceArchive *GetAppResourceArchive() const = 0;
virtual IResourceArchive *LoadResFile(CompositeFile *file) const = 0;
virtual PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) = 0;
GP_ASYNCIFY_PARANOID_VIRTUAL PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) GP_ASYNCIFY_PARANOID_PURE;
virtual void DissociateHandle(MMHandleBlock *hdl) const = 0;
virtual const ResourceArchiveRef *ResourceForHandle(MMHandleBlock *hdl) const = 0;