Compare commits

..

27 Commits

Author SHA1 Message Date
elasota
c147e1100e Change MiniRez to use WindowsUnicodeToolShim 2021-03-11 22:28:01 -05:00
elasota
0a2e730d26 Change FTagData to use WindowsUnicodeToolShim 2021-03-11 22:22:30 -05:00
elasota
922cd0fd06 Add debug/release props to WindowsUnicodeToolShim 2021-03-11 22:22:14 -05:00
elasota
b8bf6be44f Change hqx2gp to use WindowsUnicodeToolShim 2021-03-11 22:18:07 -05:00
elasota
2897c4ffab Fix saved game deletion not working 2021-03-11 21:40:22 -05:00
elasota
35c174984b Bump version to 1.0.16 2021-03-11 21:36:06 -05:00
elasota
da16edea8d Fix broken AA table preloader, use load bar first time on desktop 2021-03-09 04:15:59 -05:00
elasota
2fe1ea2ee7 Fix objects being draggable when there is no room 2021-03-08 21:59:11 -05:00
elasota
0931f25f23 Fix wrong house sort order 2021-03-08 21:58:46 -05:00
elasota
7f4d782c0d Fix room count mismatch 2021-03-08 21:58:34 -05:00
elasota
f2cda23b0f Bump version to 1.0.15 2021-03-08 19:08:12 -05:00
elasota
6292705968 Fix insensitive compare not working properly with strings of different length 2021-03-08 19:07:31 -05:00
elasota
6931b3f505 EOL fix 2021-03-08 19:07:06 -05:00
elasota
d70a5b3bfc Add more optimizations 2021-03-07 05:45:24 -05:00
elasota
f0913d0d6a Add MergeGPF to installer project 2021-03-07 05:37:29 -05:00
elasota
80584eb781 Fix California or Bust! house on Android 2021-03-07 05:16:15 -05:00
elasota
fe4a8a55c6 Don't partially delete house when overwriting the current house 2021-03-07 05:08:01 -05:00
elasota
55ec6c516c Fix overwrite warnings not working 2021-03-07 05:07:23 -05:00
elasota
3917e1a370 File system refactor, bug fixes 2021-03-07 04:31:05 -05:00
elasota
6715bcb030 Fix music playing in the editor 2021-03-06 11:34:47 -05:00
elasota
c981a97a20 Fix fullscreen prefs not working in SDL. Add SDL GameController support. 2021-03-05 01:56:32 -05:00
elasota
a5562f96e0 Move portable things to AerofoilPortable. 2021-03-05 00:35:43 -05:00
elasota
d97bd8ad1c Move some C++11 types from Android to AerofoilSDL. 2021-03-01 01:06:56 -05:00
elasota
a43f32ab88 Fix trademark usage 2021-03-01 00:40:30 -05:00
elasota
e94d1511b1 Add 32-bit support to SDL version 2021-02-28 23:31:13 -05:00
elasota
95e4eb4e34 Bump version to 1.0.14, update copyright year 2021-02-28 23:01:53 -05:00
elasota
15bdb97c38 Add volume control to SDL audio driver. 2021-02-28 22:58:01 -05:00
113 changed files with 3333 additions and 1571 deletions

View File

@@ -48,6 +48,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "ReleasePackageInstaller", "
{7EFF1E21-C375-45EA-A069-4E2232C8A72B} = {7EFF1E21-C375-45EA-A069-4E2232C8A72B}
{B852D549-4020-4477-8BFB-E199FF78B047} = {B852D549-4020-4477-8BFB-E199FF78B047}
{2FF15659-5C72-48B8-B55B-3C658E4125B5} = {2FF15659-5C72-48B8-B55B-3C658E4125B5}
{36DAF5FA-6ADB-4F20-9810-1610DE0AE653} = {36DAF5FA-6ADB-4F20-9810-1610DE0AE653}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsUnicodeToolShim", "WindowsUnicodeToolShim\WindowsUnicodeToolShim.vcxproj", "{15009625-1120-405E-8BBA-69A16CD6713D}"
@@ -60,6 +61,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpFontHandler_FreeType2", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AerofoilSDL", "AerofoilSDL\AerofoilSDL.vcxproj", "{33542FF0-0473-4802-BC79-3B8261790F65}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MergeGPF", "MergeGPF\MergeGPF.vcxproj", "{36DAF5FA-6ADB-4F20-9810-1610DE0AE653}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -168,6 +171,10 @@ Global
{33542FF0-0473-4802-BC79-3B8261790F65}.Debug|x64.Build.0 = Debug|x64
{33542FF0-0473-4802-BC79-3B8261790F65}.Release|x64.ActiveCfg = Release|x64
{33542FF0-0473-4802-BC79-3B8261790F65}.Release|x64.Build.0 = Release|x64
{36DAF5FA-6ADB-4F20-9810-1610DE0AE653}.Debug|x64.ActiveCfg = Debug|x64
{36DAF5FA-6ADB-4F20-9810-1610DE0AE653}.Debug|x64.Build.0 = Debug|x64
{36DAF5FA-6ADB-4F20-9810-1610DE0AE653}.Release|x64.ActiveCfg = Release|x64
{36DAF5FA-6ADB-4F20-9810-1610DE0AE653}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -99,24 +99,6 @@ bool GpFileStream_Win32::SeekEnd(GpUFilePos_t loc)
return SetFilePointerEx(m_handle, li, nullptr, FILE_END) != 0;
}
bool GpFileStream_Win32::Truncate(GpUFilePos_t loc)
{
if (!m_writeable)
return false;
GpUFilePos_t oldPos = Tell();
if (!SeekStart(loc))
return false;
if (!SetEndOfFile(m_handle))
return false;
if (!SeekStart(oldPos))
return false;
return true;
}
GpUFilePos_t GpFileStream_Win32::Size() const
{
LARGE_INTEGER fsize;

View File

@@ -17,7 +17,6 @@ public:
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;

View File

@@ -191,24 +191,24 @@ bool GpFileSystem_Win32::FileExists(PortabilityLayer::VirtualDirectory_t virtual
return PathFileExistsW(winPath) != 0;
}
bool GpFileSystem_Win32::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists)
bool GpFileSystem_Win32::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists)
{
wchar_t winPath[MAX_PATH + 1];
if (!ResolvePath(virtualDirectory, &path, 1, winPath))
{
*exists = false;
exists = false;
return false;
}
DWORD attribs = GetFileAttributesW(winPath);
if (attribs == INVALID_FILE_ATTRIBUTES)
{
*exists = false;
exists = false;
return false;
}
*exists = true;
exists = true;
return (attribs & FILE_ATTRIBUTE_READONLY) != 0;
}
@@ -319,11 +319,6 @@ bool GpFileSystem_Win32::ValidateFilePathUnicodeChar(uint32_t c) const
return false;
}
bool GpFileSystem_Win32::IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const
{
return false;
}
void GpFileSystem_Win32::SetMainThreadRelay(IGpThreadRelay *relay)
{
(void)relay;
@@ -341,7 +336,7 @@ bool GpFileSystem_Win32::ValidateFilePath(const char *str, size_t length) const
if (c >= '0' && c <= '9')
continue;
if (c == '_' || c == '.' || c == '\'')
if (c == '_' || c == '.' || c == '\'' || c == '!')
continue;
if (c == ' ' && i != 0 && i != length - 1)

View File

@@ -13,7 +13,7 @@ public:
GpFileSystem_Win32();
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) override;
GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
IGpDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
@@ -21,8 +21,6 @@ public:
bool ValidateFilePath(const char *path, size_t sz) const override;
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override;
void SetMainThreadRelay(IGpThreadRelay *relay) override;
void SetDelayCallback(DelayCallback_t delayCallback) override;

View File

@@ -256,6 +256,11 @@ bool GpSystemServices_Win32::IsFullscreenPreferred() const
return !m_isTouchscreenSimulation;
}
bool GpSystemServices_Win32::IsFullscreenOnStartup() const
{
return false;
}
unsigned int GpSystemServices_Win32::GetCPUCount() const
{
SYSTEM_INFO sysInfo;

View File

@@ -33,6 +33,7 @@ public:
bool IsUsingMouseAsTouch() const override;
bool IsTextInputObstructive() const override;
bool IsFullscreenPreferred() const override;
bool IsFullscreenOnStartup() const override;
unsigned int GetCPUCount() const override;
void SetTextInputEnabled(bool isEnabled) override;
bool IsTextInputEnabled() const override;

View File

@@ -15,8 +15,8 @@ android {
}
minSdkVersion 16
targetSdkVersion 29
versionCode 9
versionName "1.0.13"
versionCode 12
versionName "1.0.16"
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-16"
@@ -66,7 +66,7 @@ android {
}
aaptOptions {
noCompress 'gpa'
noCompress 'gpf'
}
}

View File

@@ -0,0 +1 @@
../../../AerofoilPortable

View File

@@ -9,6 +9,7 @@ SDL_PATH := ../SDL
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include \
$(LOCAL_PATH)/../GpShell \
$(LOCAL_PATH)/../GpCommon \
$(LOCAL_PATH)/../AerofoilPortable \
$(LOCAL_PATH)/../AerofoilSDL \
$(LOCAL_PATH)/../Common \
$(LOCAL_PATH)/../PortabilityLayer
@@ -23,7 +24,7 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := SDL2
LOCAL_STATIC_LIBRARIES := GpShell GpFontHandler_FreeType2 AerofoilSDL GpApp
LOCAL_STATIC_LIBRARIES := GpShell GpFontHandler_FreeType2 AerofoilPortable AerofoilSDL GpApp
LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog

View File

@@ -42,7 +42,6 @@ public:
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
@@ -70,7 +69,6 @@ public:
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
@@ -96,7 +94,6 @@ public:
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
@@ -168,11 +165,6 @@ bool GpFileStream_PFD::SeekEnd(GpUFilePos_t loc)
return lseek64(m_fd, loc, SEEK_END) >= 0;
}
bool GpFileStream_PFD::Truncate(GpUFilePos_t loc)
{
return ftruncate64(m_fd, static_cast<off64_t>(loc)) >= 0;
}
GpUFilePos_t GpFileStream_PFD::Size() const
{
struct stat64 s;
@@ -251,11 +243,6 @@ bool GpFileStream_SDLRWops::SeekEnd(GpUFilePos_t loc)
return m_rw->seek(m_rw, -static_cast<Sint64>(loc), RW_SEEK_END) >= 0;
}
bool GpFileStream_SDLRWops::Truncate(GpUFilePos_t loc)
{
return false;
}
GpUFilePos_t GpFileStream_SDLRWops::Size() const
{
return m_rw->size(m_rw);
@@ -346,12 +333,6 @@ bool GpFileStream_Android_File::SeekEnd(GpUFilePos_t loc)
return lseek64(m_fd, -static_cast<off64_t>(loc), SEEK_END) >= 0;
}
bool GpFileStream_Android_File::Truncate(GpUFilePos_t loc)
{
fflush(m_f);
return ftruncate64(m_fd, static_cast<off64_t>(loc)) >= 0;
}
GpUFilePos_t GpFileStream_Android_File::Size() const
{
fflush(m_f);
@@ -552,26 +533,26 @@ bool GpFileSystem_Android::FileExists(PortabilityLayer::VirtualDirectory_t virtu
return stat(resolvedPath.c_str(), &s) == 0;
}
bool GpFileSystem_Android::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists)
bool GpFileSystem_Android::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists)
{
std::string resolvedPath;
bool isAsset;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
{
if (exists)
*exists = false;
exists = false;
return false;
}
if (isAsset)
{
if (exists)
*exists = this->FileExists(virtualDirectory, path);
exists = this->FileExists(virtualDirectory, path);
return true;
}
int permissions = access(resolvedPath.c_str(), W_OK | F_OK);
*exists = ((permissions & F_OK) != 0);
exists = ((permissions & F_OK) != 0);
return ((permissions & W_OK) != 0);
}
@@ -733,7 +714,7 @@ bool GpFileSystem_Android::ValidateFilePath(const char *path, size_t length) con
if (c >= '0' && c <= '9')
continue;
if (c == '_' || c == '.' || c == '\'')
if (c == '_' || c == '.' || c == '\'' || c == '!')
continue;
if (c == ' ' && i != 0 && i != length - 1)
@@ -771,11 +752,6 @@ bool GpFileSystem_Android::ValidateFilePathUnicodeChar(uint32_t c) const
return false;
}
bool GpFileSystem_Android::IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const
{
return false;
}
void GpFileSystem_Android::SetMainThreadRelay(IGpThreadRelay *relay)
{
m_relay = relay;

View File

@@ -19,7 +19,7 @@ public:
void ShutdownJNI();
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists) 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;
IGpDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
@@ -27,8 +27,6 @@ public:
bool ValidateFilePath(const char *path, size_t pathLen) const override;
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override;
void SetMainThreadRelay(IGpThreadRelay *relay) override;
void SetDelayCallback(DelayCallback_t delayCallback) override;

View File

@@ -8,6 +8,7 @@
#include "GpFileSystem_Android.h"
#include "GpFontHandlerFactory.h"
#include "GpInputDriverFactory.h"
#include "GpInputDriver_SDL_Gamepad.h"
#include "GpAppInterface.h"
#include "GpSystemServices_Android.h"
#include "GpVOSEvent.h"
@@ -116,3 +117,8 @@ int main(int argc, char* argv[])
return returnCode;
}
IGpInputDriverSDLGamepad *IGpInputDriverSDLGamepad::GetInstance()
{
return nullptr;
}

View File

@@ -1,11 +1,9 @@
#include "GpSystemServices_Android.h"
#include "IGpMutex.h"
#include "IGpThreadEvent.h"
#include "SDL.h"
#include <time.h>
#include <mutex>
#include <condition_variable>
#include <unistd.h>
struct GpSystemServices_Android_ThreadStartParams
@@ -28,175 +26,11 @@ static int SDLCALL StaticStartThread(void *lpThreadParameter)
return threadFunc(threadContext);
}
template<class TMutex>
class GpMutex_Cpp11 final : public IGpMutex
{
public:
GpMutex_Cpp11();
~GpMutex_Cpp11();
void Destroy() override;
void Lock() override;
void Unlock() override;
private:
TMutex m_mutex;
};
template<class TMutex>
GpMutex_Cpp11<TMutex>::GpMutex_Cpp11()
{
}
template<class TMutex>
GpMutex_Cpp11<TMutex>::~GpMutex_Cpp11()
{
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Destroy()
{
this->~GpMutex_Cpp11();
free(this);
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Lock()
{
m_mutex.lock();
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Unlock()
{
m_mutex.unlock();
}
typedef GpMutex_Cpp11<std::mutex> GpMutex_Cpp11_Vanilla;
typedef GpMutex_Cpp11<std::recursive_mutex> GpMutex_Cpp11_Recursive;
class GpThreadEvent_Cpp11 final : public IGpThreadEvent
{
public:
GpThreadEvent_Cpp11(bool autoReset, bool startSignaled);
~GpThreadEvent_Cpp11();
void Wait() override;
bool WaitTimed(uint32_t msec) override;
void Signal() override;
void Destroy() override;
private:
std::mutex m_mutex;
std::condition_variable m_cvar;
bool m_flag;
bool m_autoReset;
};
GpThreadEvent_Cpp11::GpThreadEvent_Cpp11(bool autoReset, bool startSignaled)
: m_flag(startSignaled)
, m_autoReset(autoReset)
{
}
GpThreadEvent_Cpp11::~GpThreadEvent_Cpp11()
{
}
void GpThreadEvent_Cpp11::Wait()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_autoReset)
{
m_cvar.wait(lock,[&]()->bool{
if (m_flag)
{
m_flag = false;
return true;
}
else
return false;
});
}
else
m_cvar.wait(lock,[&]()->bool{ return m_flag; });
}
bool GpThreadEvent_Cpp11::WaitTimed(uint32_t msec)
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_autoReset)
{
if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{
if (m_flag)
{
m_flag = false;
return true;
}
else
return false;
}))
return false;
}
else
{
if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{ return m_flag; }))
return false;
}
return true;
}
void GpThreadEvent_Cpp11::Signal()
{
m_mutex.lock();
m_flag = true;
m_mutex.unlock();
if (m_autoReset)
m_cvar.notify_one();
else
m_cvar.notify_all();
}
void GpThreadEvent_Cpp11::Destroy()
{
this->~GpThreadEvent_Cpp11();
free(this);
}
GpSystemServices_Android::GpSystemServices_Android()
: m_textInputEnabled(false)
{
}
int64_t GpSystemServices_Android::GetTime() const
{
time_t t = time(nullptr);
return static_cast<int64_t>(t) - 2082844800;
}
void GpSystemServices_Android::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const
{
time_t t = time(nullptr);
tm *tmObject = localtime(&t);
year = static_cast<unsigned int>(tmObject->tm_year);
month = static_cast<unsigned int>(tmObject->tm_mon + 1);
hour = static_cast<unsigned int>(tmObject->tm_hour);
minute = static_cast<unsigned int>(tmObject->tm_min);
second = static_cast<unsigned int>(tmObject->tm_sec);
}
IGpMutex *GpSystemServices_Android::CreateMutex()
{
GpMutex_Cpp11_Vanilla *mutex = static_cast<GpMutex_Cpp11_Vanilla*>(malloc(sizeof(GpMutex_Cpp11_Vanilla)));
if (!mutex)
return nullptr;
return new (mutex) GpMutex_Cpp11_Vanilla();
}
void *GpSystemServices_Android::CreateThread(ThreadFunc_t threadFunc, void *context)
{
IGpThreadEvent *evt = CreateThreadEvent(true, false);
@@ -221,31 +55,6 @@ void *GpSystemServices_Android::CreateThread(ThreadFunc_t threadFunc, void *cont
return thread;
}
IGpMutex *GpSystemServices_Android::CreateRecursiveMutex()
{
GpMutex_Cpp11_Recursive *mutex = static_cast<GpMutex_Cpp11_Recursive*>(malloc(sizeof(GpMutex_Cpp11_Recursive)));
if (!mutex)
return nullptr;
return new (mutex) GpMutex_Cpp11_Recursive();
}
IGpThreadEvent *GpSystemServices_Android::CreateThreadEvent(bool autoReset, bool startSignaled)
{
GpThreadEvent_Cpp11 *evt = static_cast<GpThreadEvent_Cpp11*>(malloc(sizeof(GpThreadEvent_Cpp11)));
if (!evt)
return nullptr;
return new (evt) GpThreadEvent_Cpp11(autoReset, startSignaled);
}
uint64_t GpSystemServices_Android::GetFreeMemoryCosmetic() const
{
long pages = sysconf(_SC_AVPHYS_PAGES);
long pageSize = sysconf(_SC_PAGE_SIZE);
return pages * pageSize;
}
void GpSystemServices_Android::Beep() const
{
}
@@ -270,6 +79,11 @@ bool GpSystemServices_Android::IsFullscreenPreferred() const
return true;
}
bool GpSystemServices_Android::IsFullscreenOnStartup() const
{
return true;
}
unsigned int GpSystemServices_Android::GetCPUCount() const
{
return SDL_GetCPUCount();

View File

@@ -1,25 +1,20 @@
#pragma once
#include "IGpSystemServices.h"
#include "GpSystemServices_POSIX.h"
#include "GpCoreDefs.h"
class GpSystemServices_Android final : public IGpSystemServices
class GpSystemServices_Android final : public GpSystemServices_POSIX
{
public:
GpSystemServices_Android();
int64_t GetTime() const override;
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
IGpMutex *CreateMutex() override;
IGpMutex *CreateRecursiveMutex() override;
void *CreateThread(ThreadFunc_t threadFunc, void *context) override;
IGpThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override;
uint64_t GetFreeMemoryCosmetic() const override;
void Beep() const override;
bool IsTouchscreen() const override;
bool IsUsingMouseAsTouch() const override;
bool IsTextInputObstructive() const override;
bool IsFullscreenPreferred() const override;
bool IsFullscreenOnStartup() const override;
unsigned int GetCPUCount() const override;
void SetTextInputEnabled(bool isEnabled) override;
bool IsTextInputEnabled() const override;

View File

@@ -7,6 +7,6 @@ mkdir Packaged
cd Packaged
rmdir /S /Q Houses
mkdir Houses
copy ..\..\..\..\..\..\Packaged\*.gpa .\
copy ..\..\..\..\..\..\Packaged\*.gpf .\
copy ..\..\..\..\..\..\Packaged\Houses\* Houses\
cd ..

View File

@@ -5,6 +5,7 @@ call remove_symlinks.bat
mklink /D app\jni\AerofoilSDL ..\..\..\AerofoilSDL
mklink /D app\jni\AerofoilPortable ..\..\..\AerofoilPortable
mklink /D app\jni\Common ..\..\..\Common
mklink /D app\jni\SDL2 ..\..\..\SDL2-2.0.12
mklink /D app\jni\GpApp ..\..\..\GpApp

View File

@@ -2,6 +2,7 @@
@cd /d "%~dp0"
rmdir app\jni\AerofoilSDL
rmdir app\jni\AerofoilPortable
rmdir app\jni\Common
rmdir app\jni\SDL2
rmdir app\jni\GpShell

View File

@@ -0,0 +1,20 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := AerofoilPortable
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../GpCommon \
$(LOCAL_PATH)/../GpShell \
$(LOCAL_PATH)/../Common \
$(LOCAL_PATH)/../PortabilityLayer
LOCAL_CFLAGS := -DGP_DEBUG_CONFIG=0
# Add your application source files here...
LOCAL_SRC_FILES := \
GpThreadEvent_Cpp11.cpp \
GpSystemServices_POSIX.cpp
include $(BUILD_STATIC_LIBRARY)

View File

@@ -0,0 +1,66 @@
#pragma once
#include "IGpMutex.h"
#include <mutex>
template<class TMutex>
class GpMutex_Cpp11 final : public IGpMutex
{
public:
~GpMutex_Cpp11();
void Destroy() override;
static GpMutex_Cpp11<TMutex> *Create();
void Lock() override;
void Unlock() override;
private:
GpMutex_Cpp11();
TMutex m_mutex;
};
#include <stdlib.h>
template<class TMutex>
GpMutex_Cpp11<TMutex>::GpMutex_Cpp11()
{
}
template<class TMutex>
GpMutex_Cpp11<TMutex>::~GpMutex_Cpp11()
{
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Destroy()
{
this->~GpMutex_Cpp11();
free(this);
}
template<class TMutex>
GpMutex_Cpp11<TMutex> *GpMutex_Cpp11<TMutex>::Create()
{
GpMutex_Cpp11<TMutex> *mutex = static_cast<GpMutex_Cpp11<TMutex>*>(malloc(sizeof(GpMutex_Cpp11<TMutex>)));
if (!mutex)
return nullptr;
return new (mutex) GpMutex_Cpp11<TMutex>();
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Lock()
{
m_mutex.lock();
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Unlock()
{
m_mutex.unlock();
}
typedef GpMutex_Cpp11<std::mutex> GpMutex_Cpp11_NonRecursive;
typedef GpMutex_Cpp11<std::recursive_mutex> GpMutex_Cpp11_Recursive;

View File

@@ -0,0 +1,50 @@
#include "GpSystemServices_POSIX.h"
#include "GpMutex_Cpp11.h"
#include "GpThreadEvent_Cpp11.h"
#include <time.h>
#include <unistd.h>
GpSystemServices_POSIX::GpSystemServices_POSIX()
{
}
int64_t GpSystemServices_POSIX::GetTime() const
{
time_t t = time(nullptr);
return static_cast<int64_t>(t) - 2082844800;
}
void GpSystemServices_POSIX::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const
{
time_t t = time(nullptr);
tm *tmObject = localtime(&t);
year = static_cast<unsigned int>(tmObject->tm_year);
month = static_cast<unsigned int>(tmObject->tm_mon + 1);
hour = static_cast<unsigned int>(tmObject->tm_hour);
minute = static_cast<unsigned int>(tmObject->tm_min);
second = static_cast<unsigned int>(tmObject->tm_sec);
}
IGpMutex *GpSystemServices_POSIX::CreateMutex()
{
return GpMutex_Cpp11_NonRecursive::Create();
}
IGpMutex *GpSystemServices_POSIX::CreateRecursiveMutex()
{
return GpMutex_Cpp11_Recursive::Create();
}
IGpThreadEvent *GpSystemServices_POSIX::CreateThreadEvent(bool autoReset, bool startSignaled)
{
return GpThreadEvent_Cpp11::Create(autoReset, startSignaled);
}
uint64_t GpSystemServices_POSIX::GetFreeMemoryCosmetic() const
{
long pages = sysconf(_SC_AVPHYS_PAGES);
long pageSize = sysconf(_SC_PAGE_SIZE);
return pages * pageSize;
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "IGpSystemServices.h"
#include "GpCoreDefs.h"
class GpSystemServices_POSIX : public IGpSystemServices
{
public:
GpSystemServices_POSIX();
int64_t GetTime() const override;
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
IGpMutex *CreateMutex() override;
IGpMutex *CreateRecursiveMutex() override;
IGpThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override;
uint64_t GetFreeMemoryCosmetic() const override;
};

View File

@@ -0,0 +1,82 @@
#include "GpThreadEvent_Cpp11.h"
GpThreadEvent_Cpp11::GpThreadEvent_Cpp11(bool autoReset, bool startSignaled)
: m_flag(startSignaled)
, m_autoReset(autoReset)
{
}
GpThreadEvent_Cpp11::~GpThreadEvent_Cpp11()
{
}
void GpThreadEvent_Cpp11::Wait()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_autoReset)
{
m_cvar.wait(lock,[&]()->bool{
if (m_flag)
{
m_flag = false;
return true;
}
else
return false;
});
}
else
m_cvar.wait(lock,[&]()->bool{ return m_flag; });
}
bool GpThreadEvent_Cpp11::WaitTimed(uint32_t msec)
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_autoReset)
{
if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{
if (m_flag)
{
m_flag = false;
return true;
}
else
return false;
}))
return false;
}
else
{
if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{ return m_flag; }))
return false;
}
return true;
}
void GpThreadEvent_Cpp11::Signal()
{
m_mutex.lock();
m_flag = true;
m_mutex.unlock();
if (m_autoReset)
m_cvar.notify_one();
else
m_cvar.notify_all();
}
void GpThreadEvent_Cpp11::Destroy()
{
this->~GpThreadEvent_Cpp11();
free(this);
}
GpThreadEvent_Cpp11 *GpThreadEvent_Cpp11::Create(bool autoReset, bool startSignaled)
{
GpThreadEvent_Cpp11 *evt = static_cast<GpThreadEvent_Cpp11*>(malloc(sizeof(GpThreadEvent_Cpp11)));
if (!evt)
return nullptr;
return new (evt) GpThreadEvent_Cpp11(autoReset, startSignaled);
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "IGpThreadEvent.h"
#include <mutex>
#include <condition_variable>
class GpThreadEvent_Cpp11 final : public IGpThreadEvent
{
public:
~GpThreadEvent_Cpp11();
void Wait() override;
bool WaitTimed(uint32_t msec) override;
void Signal() override;
void Destroy() override;
static GpThreadEvent_Cpp11 *Create(bool autoReset, bool startSignaled);
private:
GpThreadEvent_Cpp11(bool autoReset, bool startSignaled);
GpThreadEvent_Cpp11() = delete;
std::mutex m_mutex;
std::condition_variable m_cvar;
bool m_flag;
bool m_autoReset;
};

View File

@@ -95,8 +95,10 @@
<ClCompile Include="GpDisplayDriver_SDL_GL2.cpp" />
<ClCompile Include="GpFiberStarter_SDL.cpp" />
<ClCompile Include="GpFiber_SDL.cpp" />
<ClCompile Include="GpInputDriver_SDL_Gamepad.cpp" />
<ClCompile Include="GpMain_SDL_Win32.cpp" />
<ClCompile Include="ShaderCode\CopyQuadP.cpp" />
<ClCompile Include="ShaderCode\DrawQuad32P.cpp" />
<ClCompile Include="ShaderCode\DrawQuadPaletteP.cpp" />
<ClCompile Include="ShaderCode\DrawQuadV.cpp" />
<ClCompile Include="ShaderCode\ScaleQuadP.cpp" />
@@ -111,15 +113,13 @@
<ProjectReference Include="..\GpFontHandler_FreeType2\GpFontHandler_FreeType2.vcxproj">
<Project>{4b564030-8985-4975-91e1-e1b2c16ae2a1}</Project>
</ProjectReference>
<ProjectReference Include="..\GpInputDriver_XInput\GpInputDriver_XInput.vcxproj">
<Project>{17b96f07-ef92-47cd-95a5-8e6ee38ab564}</Project>
</ProjectReference>
<ProjectReference Include="..\GpShell\GpShell.vcxproj">
<Project>{10cf9b5f-61d0-4b5b-89f4-810b58fc053d}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GpFiber_SDL.h" />
<ClInclude Include="GpInputDriver_SDL_Gamepad.h" />
<ClInclude Include="ShaderCode\DrawQuadPixelConstants.h" />
<ClInclude Include="ShaderCode\Functions.h" />
</ItemGroup>

View File

@@ -66,6 +66,12 @@
<ClCompile Include="ShaderCode\CopyQuadP.cpp">
<Filter>Source Files\ShaderCode</Filter>
</ClCompile>
<ClCompile Include="ShaderCode\DrawQuad32P.cpp">
<Filter>Source Files\ShaderCode</Filter>
</ClCompile>
<ClCompile Include="GpInputDriver_SDL_Gamepad.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ShaderCode\Functions.h">
@@ -77,5 +83,8 @@
<ClInclude Include="GpFiber_SDL.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpInputDriver_SDL_Gamepad.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -23,6 +23,7 @@ LOCAL_SRC_FILES := \
GpFiberStarter_SDL.cpp \
ShaderCode/CopyQuadP.cpp \
ShaderCode/DrawQuadPaletteP.cpp \
ShaderCode/DrawQuad32P.cpp \
ShaderCode/DrawQuadV.cpp \
ShaderCode/ScaleQuadP.cpp

View File

@@ -136,6 +136,7 @@ private:
static const size_t kMaxChannels = 16;
static const size_t kMixChunkSize = 256;
static const int16_t kMaxAudioVolumeScale = 25;
GpAudioChannel_SDL2 *m_channels[kMaxChannels];
size_t m_numChannels;
@@ -144,6 +145,8 @@ private:
GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) int16_t m_mixChunk[kMixChunkSize];
size_t m_mixChunkReadOffset;
int16_t m_audioVolumeScale;
};
GpAudioChannelBufferChain_SDL2::GpAudioChannelBufferChain_SDL2()
@@ -353,6 +356,7 @@ GpAudioDriver_SDL2::GpAudioDriver_SDL2(const GpAudioDriverProperties &properties
, m_numChannels(0)
, m_sdlAudioRunning(false)
, m_mixChunkReadOffset(kMixChunkSize)
, m_audioVolumeScale(kMaxAudioVolumeScale)
{
for (size_t i = 0; i < kMaxChannels; i++)
@@ -395,6 +399,9 @@ IGpAudioChannel *GpAudioDriver_SDL2::CreateChannel()
void GpAudioDriver_SDL2::SetMasterVolume(uint32_t vol, uint32_t maxVolume)
{
double scale = vol * static_cast<uint64_t>(kMaxAudioVolumeScale) / maxVolume;
m_audioVolumeScale = static_cast<int16_t>(scale);
}
void GpAudioDriver_SDL2::Shutdown()
@@ -527,6 +534,8 @@ void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, siz
bool noAudio = true;
const int16_t audioVolumeScale = m_audioVolumeScale;
for (size_t i = 0; i < numChannels; i++)
{
channels[i]->Consume(audioMixBuffer, kMixChunkSize);
@@ -535,12 +544,12 @@ void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, siz
{
noAudio = false;
for (size_t j = 0; j < kMixChunkSize; j++)
m_mixChunk[j] = (audioMixBuffer[j] - 0x80) * 25;
m_mixChunk[j] = (static_cast<int16_t>(audioMixBuffer[j]) - 0x80) * audioVolumeScale;
}
else
{
for (size_t j = 0; j < kMixChunkSize; j++)
m_mixChunk[j] += (audioMixBuffer[j] - 0x80) * 25;
m_mixChunk[j] += (static_cast<int16_t>(audioMixBuffer[j]) - 0x80) * audioVolumeScale;
}
}

View File

@@ -6,6 +6,7 @@
#include "GpDisplayDriverProperties.h"
#include "GpVOSEvent.h"
#include "GpRingBuffer.h"
#include "GpInputDriver_SDL_Gamepad.h"
#include "IGpCursor.h"
#include "IGpDisplayDriverSurface.h"
#include "IGpLogDriver.h"
@@ -39,6 +40,13 @@ class GpDisplayDriver_SDL_GL2;
static GpDisplayDriverSurfaceEffects gs_defaultEffects;
static const char *kPrefsIdentifier = "GpDisplayDriverSDL_GL2";
static uint32_t kPrefsVersion = 1;
struct GpDisplayDriver_SDL_GL2_Prefs
{
bool m_isFullScreen;
};
namespace DeleteMe
{
@@ -108,17 +116,13 @@ namespace GpBinarizedShaders
extern const char *g_drawQuadPalettePF_GL2;
extern const char *g_drawQuadPalettePNF_GL2;
extern const char *g_drawQuadRGBPF_GL2;
extern const char *g_drawQuadRGBPNF_GL2;
extern const char *g_drawQuad15BitPF_GL2;
extern const char *g_drawQuad15BitPNF_GL2;
extern const char *g_drawQuad32PF_GL2;
extern const char *g_drawQuad32PNF_GL2;
extern const char *g_drawQuadPaletteICCPF_GL2;
extern const char *g_drawQuadPaletteICCPNF_GL2;
extern const char *g_drawQuadRGBICCPF_GL2;
extern const char *g_drawQuadRGBICCPNF_GL2;
extern const char *g_drawQuad15BitICCPF_GL2;
extern const char *g_drawQuad15BitICCPNF_GL2;
extern const char *g_drawQuad32ICCPF_GL2;
extern const char *g_drawQuad32ICCPNF_GL2;
extern const char *g_copyQuadP_GL2;
extern const char *g_scaleQuadP_GL2;
@@ -849,12 +853,16 @@ private:
DrawQuadProgram m_drawQuadPaletteNoFlickerProgram;
DrawQuadProgram m_drawQuadPaletteFlickerProgram;
DrawQuadProgram m_drawQuadRGBProgram;
DrawQuadProgram m_drawQuad15BitProgram;
DrawQuadProgram m_drawQuad15NoFlickerProgram;
DrawQuadProgram m_drawQuad15FlickerProgram;
DrawQuadProgram m_drawQuad32NoFlickerProgram;
DrawQuadProgram m_drawQuad32FlickerProgram;
DrawQuadProgram m_drawQuadPaletteICCNoFlickerProgram;
DrawQuadProgram m_drawQuadPaletteICCFlickerProgram;
DrawQuadProgram m_drawQuadRGBICCProgram;
DrawQuadProgram m_drawQuad15BitICCProgram;
DrawQuadProgram m_drawQuad15ICCNoFlickerProgram;
DrawQuadProgram m_drawQuad15ICCFlickerProgram;
DrawQuadProgram m_drawQuad32ICCNoFlickerProgram;
DrawQuadProgram m_drawQuad32ICCFlickerProgram;
};
InstancedResources m_res;
@@ -1219,7 +1227,7 @@ GpDisplayDriver_SDL_GL2::GpDisplayDriver_SDL_GL2(const GpDisplayDriverProperties
m_bgColor[3] = 1.f;
// Stupid hack to detect mobile...
m_isFullScreenDesired = m_properties.m_systemServices->IsFullscreenPreferred();
m_isFullScreenDesired = m_properties.m_systemServices->IsFullscreenOnStartup();
const intmax_t periodNum = std::chrono::high_resolution_clock::period::num;
const intmax_t periodDen = std::chrono::high_resolution_clock::period::den;
@@ -1842,7 +1850,7 @@ void GpDisplayDriver_SDL_GL2::Run()
m_vosFiber = new GpFiber_SDL(nullptr, m_vosEvent);
uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
if (m_isFullScreenDesired)
if (m_properties.m_systemServices->IsFullscreenOnStartup())
{
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
m_isFullScreen = true;
@@ -1909,19 +1917,35 @@ void GpDisplayDriver_SDL_GL2::Run()
SDL_Event msg;
if (SDL_PollEvent(&msg) != 0)
{
if (msg.type == SDL_MOUSEMOTION)
switch (msg.type)
{
if (!m_mouseIsInClientArea)
m_mouseIsInClientArea = true;
}
//else if (msg.type == SDL_MOUSELEAVE) // Does SDL support this??
case SDL_MOUSEMOTION:
{
if (!m_mouseIsInClientArea)
m_mouseIsInClientArea = true;
}
break;
//case SDL_MOUSELEAVE: // Does SDL support this??
// m_mouseIsInClientArea = false;
else if (msg.type == SDL_RENDER_DEVICE_RESET || msg.type == SDL_RENDER_TARGETS_RESET)
{
if (logger)
logger->Printf(IGpLogDriver::Category_Information, "Triggering GL context reset due to device loss (Type: %i)", static_cast<int>(msg.type));
// break;
case SDL_RENDER_DEVICE_RESET:
case SDL_RENDER_TARGETS_RESET:
{
if (logger)
logger->Printf(IGpLogDriver::Category_Information, "Triggering GL context reset due to device loss (Type: %i)", static_cast<int>(msg.type));
m_contextLost = true;
m_contextLost = true;
}
break;
case SDL_CONTROLLERAXISMOTION:
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED:
case SDL_CONTROLLERDEVICEREMAPPED:
if (IGpInputDriverSDLGamepad *gamepadDriver = IGpInputDriverSDLGamepad::GetInstance())
gamepadDriver->ProcessSDLEvent(msg);
break;
}
TranslateSDLMessage(&msg, m_properties.m_eventQueue, m_pixelScaleX, m_pixelScaleY, obstructiveTextInput);
@@ -2117,7 +2141,20 @@ void GpDisplayDriver_SDL_GL2::DrawSurface(IGpDisplayDriverSurface *surface, int3
}
else if (pixelFormat == GpPixelFormats::kRGB32)
{
return;
if (m_useICCProfile)
{
if (effects->m_flicker)
program = &m_res.m_drawQuad32ICCFlickerProgram;
else
program = &m_res.m_drawQuad32ICCNoFlickerProgram;
}
else
{
if (effects->m_flicker)
program = &m_res.m_drawQuad32FlickerProgram;
else
program = &m_res.m_drawQuad32NoFlickerProgram;
}
}
else
{
@@ -2345,11 +2382,19 @@ bool GpDisplayDriver_SDL_GL2::SupportsSizedFormats() const
void GpDisplayDriver_SDL_GL2::ApplyPrefs(const void *identifier, size_t identifierSize, const void *contents, size_t contentsSize, uint32_t version)
{
if (version == kPrefsVersion && identifierSize == strlen(kPrefsIdentifier) && !memcmp(identifier, kPrefsIdentifier, identifierSize))
{
const GpDisplayDriver_SDL_GL2_Prefs *prefs = static_cast<const GpDisplayDriver_SDL_GL2_Prefs *>(contents);
m_isFullScreenDesired = prefs->m_isFullScreen;
}
}
bool GpDisplayDriver_SDL_GL2::SavePrefs(void *context, WritePrefsFunc_t writeFunc)
bool GpDisplayDriver_SDL_GL2::SavePrefs(void *context, IGpPrefsHandler::WritePrefsFunc_t writeFunc)
{
return true;
GpDisplayDriver_SDL_GL2_Prefs prefs;
prefs.m_isFullScreen = m_isFullScreenDesired;
return writeFunc(context, kPrefsIdentifier, strlen(kPrefsIdentifier), &prefs, sizeof(prefs), kPrefsVersion);
}
void GpDisplayDriver_SDL_GL2::UnlinkSurface(GpDisplayDriverSurface_GL2 *surface, GpDisplayDriverSurface_GL2 *prev, GpDisplayDriverSurface_GL2 *next)
@@ -2496,23 +2541,29 @@ bool GpDisplayDriver_SDL_GL2::InitResources(uint32_t physicalWidth, uint32_t phy
}
GpComPtr<GpGLShader<GL_VERTEX_SHADER>> drawQuadVertexShader = CreateShader<GL_VERTEX_SHADER>(GpBinarizedShaders::g_drawQuadV_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuadPaletteFlickerPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuadPalettePF_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuadPaletteNoFlickerPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuadPalettePNF_GL2);
//m_drawQuadRGBPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuadRGBP_GL2);
//m_drawQuad15BitPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuad15BitP_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuad32FlickerPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuad32PF_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuad32NoFlickerPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuad32PNF_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuadPaletteICCFPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuadPaletteICCPF_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuadPaletteICCNFPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuadPaletteICCPNF_GL2);
//m_drawQuadRGBICCPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuadRGBICCP_GL2);
//m_drawQuad15BitICCPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuad15BitICCP_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuad32ICCFPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuad32ICCPF_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> drawQuad32ICCNFPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_drawQuad32ICCPNF_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> scaleQuadPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_scaleQuadP_GL2);
GpComPtr<GpGLShader<GL_FRAGMENT_SHADER>> copyQuadPixelShader = CreateShader<GL_FRAGMENT_SHADER>(GpBinarizedShaders::g_copyQuadP_GL2);
if (!m_res.m_drawQuadPaletteFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteFlickerPixelShader)
|| !m_res.m_drawQuadPaletteNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteFlickerPixelShader)
//|| !m_drawQuadRGBProgram.Link(this, drawQuadVertexShader, drawQuadRGBPixelShader)
//|| !m_drawQuad15BitProgram.Link(this, drawQuadVertexShader, drawQuad15BitPixelShader)
|| !m_res.m_drawQuadPaletteNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteNoFlickerPixelShader)
|| !m_res.m_drawQuad32FlickerProgram.Link(this, drawQuadVertexShader, drawQuad32FlickerPixelShader)
|| !m_res.m_drawQuad32NoFlickerProgram.Link(this, drawQuadVertexShader, drawQuad32NoFlickerPixelShader)
|| !m_res.m_drawQuadPaletteICCFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteICCFPixelShader)
|| !m_res.m_drawQuadPaletteICCNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuadPaletteICCNFPixelShader)
|| !m_res.m_drawQuad32ICCFlickerProgram.Link(this, drawQuadVertexShader, drawQuad32ICCFPixelShader)
|| !m_res.m_drawQuad32ICCNoFlickerProgram.Link(this, drawQuadVertexShader, drawQuad32ICCNFPixelShader)
//|| !m_drawQuadRGBICCProgram.Link(this, drawQuadVertexShader, drawQuadRGBICCPixelShader)
//|| !m_drawQuad15BitICCProgram.Link(this, drawQuadVertexShader, drawQuad15BitICCPixelShader)
|| !m_res.m_scaleQuadProgram.Link(this, drawQuadVertexShader, scaleQuadPixelShader)

View File

@@ -0,0 +1,309 @@
#include "GpInputDriver_SDL_Gamepad.h"
#include "GpVOSEvent.h"
#include "GpWindows.h"
#include "IGpVOSEventQueue.h"
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "SDL_gamecontroller.h"
#include <stdlib.h>
#include <algorithm>
#include <new>
#include <vector>
class GpInputDriverSDLGamepad final : public IGpInputDriverSDLGamepad
{
public:
void ProcessInput() override;
void Shutdown() override;
IGpPrefsHandler *GetPrefsHandler() const override;
static GpInputDriverSDLGamepad *Create(const GpInputDriverProperties &props);
void ProcessSDLEvent(const SDL_Event &evt) override;
private:
static const int kMaxPlayers = 2;
GpInputDriverSDLGamepad(const GpInputDriverProperties &props);
~GpInputDriverSDLGamepad();
bool FindJoystickPlayer(uint8_t &playerNum, SDL_JoystickID joystickID);
void HandleDeviceAdded(SDL_JoystickID joystickID);
void HandleDeviceRemoved(SDL_JoystickID joystickID);
std::vector<GpVOSEvent> m_pendingEvents;
GpInputDriverProperties m_properties;
SDL_JoystickID m_playerJoystickIDs[kMaxPlayers];
SDL_GameController *m_playerControllers[kMaxPlayers];
bool m_playerButtonDown[kMaxPlayers][GpGamepadButtons::kCount];
};
static GpInputDriverSDLGamepad *gs_instance = nullptr;
IGpInputDriverSDLGamepad *IGpInputDriverSDLGamepad::GetInstance()
{
return gs_instance;
}
void GpInputDriverSDLGamepad::ProcessInput()
{
for (size_t i = 0; i < m_pendingEvents.size(); i++)
{
if (GpVOSEvent *evt = m_properties.m_eventQueue->QueueEvent())
*evt = m_pendingEvents[i];
}
m_pendingEvents.clear();
}
void GpInputDriverSDLGamepad::Shutdown()
{
this->~GpInputDriverSDLGamepad();
free(this);
gs_instance = nullptr;
}
IGpPrefsHandler *GpInputDriverSDLGamepad::GetPrefsHandler() const
{
return nullptr;
}
GpInputDriverSDLGamepad *GpInputDriverSDLGamepad::Create(const GpInputDriverProperties &props)
{
void *storage = malloc(sizeof(GpInputDriverSDLGamepad));
if (!storage)
return nullptr;
GpInputDriverSDLGamepad *driver = new (storage) GpInputDriverSDLGamepad(props);
gs_instance = driver;
return driver;
}
GpInputDriverSDLGamepad::GpInputDriverSDLGamepad(const GpInputDriverProperties &props)
: m_properties(props)
{
for (int i = 0; i < kMaxPlayers; i++)
{
m_playerJoystickIDs[i] = -1;
m_playerControllers[i] = nullptr;
for (int j = 0; j < GpGamepadButtons::kCount; j++)
m_playerButtonDown[i][j] = false;
}
}
GpInputDriverSDLGamepad::~GpInputDriverSDLGamepad()
{
for (int i = 0; i < kMaxPlayers; i++)
{
if (m_playerControllers[i])
SDL_GameControllerClose(m_playerControllers[i]);
}
}
bool GpInputDriverSDLGamepad::FindJoystickPlayer(uint8_t &playerNum, SDL_JoystickID joystickID)
{
for (int i = 0; i < kMaxPlayers; i++)
{
if (m_playerJoystickIDs[i] == joystickID)
{
playerNum = static_cast<uint8_t>(i);
return true;
}
}
return false;
}
void GpInputDriverSDLGamepad::HandleDeviceAdded(SDL_JoystickID joystickID)
{
for (int i = 0; i < kMaxPlayers; i++)
{
if (m_playerJoystickIDs[i] == -1)
{
SDL_GameController *controller = SDL_GameControllerOpen(joystickID);
if (controller)
{
m_playerJoystickIDs[i] = joystickID;
m_playerControllers[i] = controller;
}
return;
}
}
}
void GpInputDriverSDLGamepad::HandleDeviceRemoved(SDL_JoystickID joystickID)
{
int playerNum = 0;
bool foundPlayer = false;
for (int i = 0; i < kMaxPlayers; i++)
{
if (m_playerJoystickIDs[i] == joystickID)
{
SDL_GameControllerClose(m_playerControllers[i]);
m_playerJoystickIDs[i] = -1;
m_playerControllers[i] = nullptr;
playerNum = i;
foundPlayer = true;
}
}
if (!foundPlayer)
return;
for (int axis = 0; axis < GpGamepadAxes::kCount; axis++)
{
GpVOSEvent evt;
evt.m_eventType = GpVOSEventTypes::kGamepadInput;
evt.m_event.m_gamepadInputEvent.m_eventType = GpGamepadInputEventTypes::kAnalogAxisChanged;
evt.m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_axis = static_cast<GpGamepadAxis_t>(axis);
evt.m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_player = playerNum;
evt.m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_state = 0;
m_pendingEvents.push_back(evt);
}
for (int button = 0; button < GpGamepadButtons::kCount; button++)
{
if (m_playerButtonDown[playerNum][button])
{
m_playerButtonDown[playerNum][button] = false;
GpVOSEvent evt;
evt.m_eventType = GpVOSEventTypes::kKeyboardInput;
evt.m_event.m_keyboardInputEvent.m_eventType = GpKeyboardInputEventTypes::kUp;
evt.m_event.m_keyboardInputEvent.m_keyIDSubset = GpKeyIDSubsets::kGamepadButton;
evt.m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_player = playerNum;
evt.m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_button = static_cast<GpGamepadButton_t>(button);
evt.m_event.m_keyboardInputEvent.m_repeatCount = 0;
m_pendingEvents.push_back(evt);
}
}
}
void GpInputDriverSDLGamepad::ProcessSDLEvent(const SDL_Event &msg)
{
IGpVOSEventQueue *evtQueue = m_properties.m_eventQueue;
switch (msg.type)
{
case SDL_CONTROLLERAXISMOTION:
{
const SDL_ControllerAxisEvent &axisMsg = msg.caxis;
GpGamepadAxis_t axis = GpGamepadAxes::kCount;
uint8_t playerNumber = 0;
if (!FindJoystickPlayer(playerNumber, axisMsg.which))
break;
if (axisMsg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT)
axis = GpGamepadAxes::kLeftTrigger;
else if (axisMsg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
axis = GpGamepadAxes::kRightTrigger;
else if (axisMsg.axis == SDL_CONTROLLER_AXIS_LEFTX)
axis = GpGamepadAxes::kLeftStickX;
else if (axisMsg.axis == SDL_CONTROLLER_AXIS_LEFTY)
axis = GpGamepadAxes::kLeftStickY;
else if (axisMsg.axis == SDL_CONTROLLER_AXIS_RIGHTX)
axis = GpGamepadAxes::kRightStickX;
else if (axisMsg.axis == SDL_CONTROLLER_AXIS_RIGHTY)
axis = GpGamepadAxes::kRightStickY;
else
break;
GpVOSEvent evt;
evt.m_eventType = GpVOSEventTypes::kGamepadInput;
evt.m_event.m_gamepadInputEvent.m_eventType = GpGamepadInputEventTypes::kAnalogAxisChanged;
evt.m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_axis = axis;
evt.m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_player = playerNumber;
evt.m_event.m_gamepadInputEvent.m_event.m_analogAxisEvent.m_state = std::max<int16_t>(-32767, axisMsg.value);
m_pendingEvents.push_back(evt);
}
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
{
const bool isDown = (msg.type == SDL_CONTROLLERBUTTONDOWN);
const SDL_ControllerButtonEvent &buttonMsg = msg.cbutton;
GpGamepadButton_t gpButton = GpGamepadButtons::kCount;
uint8_t playerNumber = 0;
if (!FindJoystickPlayer(playerNumber, buttonMsg.which))
break;
if (buttonMsg.button == SDL_CONTROLLER_BUTTON_A)
gpButton = GpGamepadButtons::kFaceRight;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_B)
gpButton = GpGamepadButtons::kFaceDown;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_X)
gpButton = GpGamepadButtons::kFaceUp;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_Y)
gpButton = GpGamepadButtons::kFaceLeft;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_START)
gpButton = GpGamepadButtons::kMisc1;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_BACK)
gpButton = GpGamepadButtons::kMisc2;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_LEFTSTICK)
gpButton = GpGamepadButtons::kLeftStick;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK)
gpButton = GpGamepadButtons::kRightStick;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
gpButton = GpGamepadButtons::kLeftBumper;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
gpButton = GpGamepadButtons::kRightBumper;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_DPAD_UP)
gpButton = GpGamepadButtons::kDPadUp;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
gpButton = GpGamepadButtons::kDPadDown;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT)
gpButton = GpGamepadButtons::kDPadLeft;
else if (buttonMsg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
gpButton = GpGamepadButtons::kDPadRight;
else
break;
m_playerButtonDown[playerNumber][gpButton] = isDown;
GpVOSEvent evt;
evt.m_eventType = GpVOSEventTypes::kKeyboardInput;
evt.m_event.m_keyboardInputEvent.m_eventType = (isDown ? GpKeyboardInputEventTypes::kDown : GpKeyboardInputEventTypes::kUp);
evt.m_event.m_keyboardInputEvent.m_keyIDSubset = GpKeyIDSubsets::kGamepadButton;
evt.m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_player = playerNumber;
evt.m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_button = gpButton;
evt.m_event.m_keyboardInputEvent.m_repeatCount = 0;
m_pendingEvents.push_back(evt);
}
break;
case SDL_CONTROLLERDEVICEADDED:
HandleDeviceAdded(msg.cdevice.which);
break;
case SDL_CONTROLLERDEVICEREMOVED:
HandleDeviceRemoved(msg.cdevice.which);
break;
case SDL_CONTROLLERDEVICEREMAPPED:
// Not really sure what to do here, just re-add it
HandleDeviceRemoved(msg.cdevice.which);
HandleDeviceAdded(msg.cdevice.which);
break;
}
}
IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties)
{
return GpInputDriverSDLGamepad::Create(properties);
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "IGpInputDriver.h"
#include "GpInputDriverProperties.h"
#include "GpVOSEvent.h"
union SDL_Event;
struct IGpInputDriverSDLGamepad : public IGpInputDriver
{
virtual void ProcessSDLEvent(const SDL_Event &evt) = 0;
static IGpInputDriverSDLGamepad *GetInstance();
};

View File

@@ -29,16 +29,16 @@
GpWindowsGlobals g_gpWindowsGlobals;
extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties);
extern "C" __declspec(dllimport) 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);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0)
return -1;
LPWSTR cmdLine = GetCommandLineW();
@@ -79,7 +79,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
EGpInputDriverType inputDrivers[] =
{
EGpInputDriverType_XInput
EGpInputDriverType_SDL2_Gamepad
};
g_gpGlobalConfig.m_inputDriverTypes = inputDrivers;
@@ -91,7 +91,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2);
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_XInput, GpDriver_CreateInputDriver_XInput);
GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_SDL2_Gamepad, GpDriver_CreateInputDriver_SDL2_Gamepad);
GpFontHandlerFactory::RegisterFontHandlerFactory(EGpFontHandlerType_FreeType2, GpDriver_CreateFontHandler_FreeType2);
if (logger)

View File

@@ -0,0 +1,35 @@
#include "Functions.h"
#include "DrawQuadPixelConstants.h"
#define GP_GL_SHADER_CODE_DRAWQUAD32P_GLSL \
"\n"\
"varying vec4 texCoord;\n"\
"uniform sampler2D surfaceTexture;\n"\
"uniform sampler2D paletteTexture;\n"\
"\n"\
"vec3 SamplePixel(vec2 tc)\n"\
"{\n"\
" return texture2D(surfaceTexture, tc).rgb;\n"\
"}\n"\
"\n"\
"void main()\n"\
"{\n"\
" vec4 resultColor = vec4(SamplePixel(texCoord.xy), 1.0);\n"\
" resultColor *= constants_Modulation;\n"\
"#ifdef ENABLE_FLICKER\n"\
" resultColor = ApplyFlicker(constants_FlickerAxis, texCoord.zw, constants_FlickerStartThreshold, constants_FlickerEndThreshold, resultColor * constants_Modulation);\n"\
" if (resultColor.a < 1.0)\n"\
" discard;\n"\
"#endif\n"\
" resultColor = ApplyDesaturation(constants_Desaturation, resultColor);\n"\
"\n"\
" gl_FragColor = vec4(ApplyColorSpaceTransform(resultColor.rgb), resultColor.a);\n"\
"}\n"
namespace GpBinarizedShaders
{
const char *g_drawQuad32PF_GL2 = "#define ENABLE_FLICKER\n" GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUAD32P_GLSL;
const char *g_drawQuad32PNF_GL2 = GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUAD32P_GLSL;
const char *g_drawQuad32ICCPF_GL2 = "#define USE_ICC_PROFILE\n" "#define ENABLE_FLICKER\n" GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUAD32P_GLSL;
const char *g_drawQuad32ICCPNF_GL2 = "#define USE_ICC_PROFILE\n" GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUAD32P_GLSL;
}

View File

@@ -18,7 +18,7 @@
"enabled" : false
},
{
"name" : "Aerofoil ©2019-2020 Eric Lasota",
"name" : "Aerofoil ©2019-2021 Eric Lasota",
"itemType" : "Label",
"pos" : [ 16, 21 ],
"size" : [ 406, 20 ],

View File

@@ -2,14 +2,17 @@ rmdir /S /Q Packaged
mkdir Packaged
mkdir Packaged\Houses
mkdir Packaged\WinCursors
x64\Release\MiniRez.exe "GliderProData\Glider PRO.r" Packaged\ApplicationResources.gpr
x64\Release\gpr2gpa.exe "Packaged\ApplicationResources.gpr" "DefaultTimestamp.timestamp" "Packaged\ApplicationResources.gpa" "ApplicationResourcePatches\manifest.json"
x64\Release\FTagData.exe "DefaultTimestamp.timestamp" "Packaged\ApplicationResources.gpf" data ozm5 0 0 locked
x64\Release\MergeGPF.exe "Packaged\ApplicationResources.gpf"
x64\Release\ConvertColorCursors.exe
attrib -R Packaged\ApplicationResources.gpf
attrib -R Packaged\Houses\*
x64\Release\hqx2gp.exe "GliderProData\Houses\Art Museum.binhex" "DefaultTimestamp.timestamp" "Packaged\Houses\Art Museum"
@@ -70,11 +73,52 @@ x64\Release\FTagData.exe "DefaultTimestamp.timestamp" "Packaged\Houses\SpacePods
x64\Release\FTagData.exe "DefaultTimestamp.timestamp" "Packaged\Houses\Teddy World.mov.gpf" MooV ozm5 0 0 locked
x64\Release\FTagData.exe "DefaultTimestamp.timestamp" "Packaged\Houses\Titanic.mov.gpf" MooV ozm5 0 0 locked
del /Q Packaged\Houses\*.gpr
del /Q Packaged\ApplicationResources.gpr
copy /Y GliderProData\ConvertedMovies\*.mov.gpa Packaged\Houses\
x64\Release\MergeGPF.exe "Packaged\Houses\Art Museum.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\California or Bust!.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Castle o' the Air.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\CD Demo House.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Davis Station.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Demo House.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Fun House.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Grand Prix.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\ImagineHouse PRO II.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\In The Mirror.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Land of Illusion.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Leviathan.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Metropolis.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Nemo's Market.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Rainbow's End.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Slumberland.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\SpacePods.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Teddy World.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\The Asylum Pro.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Titanic.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Art Museum.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Castle o' the Air.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\CD Demo House.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Davis Station.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Demo House.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Grand Prix.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\ImagineHouse PRO II.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Land of Illusion.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Leviathan.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Nemo's Market.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Rainbow's End.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Slumberland.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\SpacePods.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Teddy World.mov.gpf"
x64\Release\MergeGPF.exe "Packaged\Houses\Titanic.mov.gpf"
del /Q Packaged\Houses\*.gpr
del /Q Packaged\Houses\*.gpa
del /Q Packaged\Houses\*.gpd
del /Q Packaged\ApplicationResources.gpr
del /Q Packaged\ApplicationResources.gpa
attrib +R Packaged\Houses\*
attrib +R Packaged\ApplicationResources.gpf
pause

View File

@@ -2,8 +2,12 @@
#include <string>
#include <Windows.h>
#include "MacFileInfo.h"
#include "CFileStream.h"
#include "CombinedTimestamp.h"
int main(int argc, const char **argv)
#include "WindowsUnicodeToolShim.h"
int toolMain(int argc, const char **argv)
{
if (argc < 7)
{
@@ -26,22 +30,18 @@ int main(int argc, const char **argv)
return -3;
}
FILE *tsF = nullptr;
errno_t ferr = fopen_s(&tsF, timestampPath.c_str(), "rb");
FILE *tsF = fopen_utf8(timestampPath.c_str(), "rb");
int64_t timestamp = 0;
PortabilityLayer::CombinedTimestamp ts;
if (!ferr)
if (tsF)
{
uint8_t encodedTimestamp[8];
if (fread(encodedTimestamp, 1, 8, tsF) != 8)
if (fread(&ts, 1, sizeof(ts), tsF) != sizeof(ts))
{
fprintf(stderr, "Error reading timestamp file");
return -1;
}
for (int i = 0; i < 8; i++)
timestamp |= static_cast<int64_t>(encodedTimestamp[i]) << (i * 8);
fclose(tsF);
}
@@ -52,7 +52,7 @@ int main(int argc, const char **argv)
mfp.m_yPos = atoi(argv[6]);
mfp.m_finderFlags = 0;
mfp.m_protected = 0;
mfp.m_modifiedDate = mfp.m_creationDate = timestamp;
mfp.m_modifiedTimeMacEpoch = mfp.m_createdTimeMacEpoch = timestamp;
for (int i = 7; i < argc; i++)
{
@@ -78,12 +78,14 @@ int main(int argc, const char **argv)
PortabilityLayer::MacFilePropertiesSerialized mps;
mps.Serialize(mfp);
FILE *file = nullptr;
errno_t err = fopen_s(&file, outPath.c_str(), "wb");
if (!err)
FILE *file = fopen_utf8(outPath.c_str(), "wb");
if (file)
{
fwrite(mps.m_data, PortabilityLayer::MacFilePropertiesSerialized::kSize, 1, file);
fclose(file);
PortabilityLayer::CFileStream stream(file);
mps.WriteAsPackage(stream, ts);
stream.Close();
}
return 0;

View File

@@ -41,6 +41,7 @@
<Import Project="..\GpCommon.props" />
<Import Project="..\Common.props" />
<Import Project="..\Debug.props" />
<Import Project="..\WindowsUnicodeToolShim.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -48,6 +49,7 @@
<Import Project="..\GpCommon.props" />
<Import Project="..\Common.props" />
<Import Project="..\Release.props" />
<Import Project="..\WindowsUnicodeToolShim.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
@@ -77,6 +79,9 @@
<ProjectReference Include="..\PortabilityLayer\PortabilityLayer.vcxproj">
<Project>{6ec62b0f-9353-40a4-a510-3788f1368b33}</Project>
</ProjectReference>
<ProjectReference Include="..\WindowsUnicodeToolShim\WindowsUnicodeToolShim.vcxproj">
<Project>{15009625-1120-405e-8bba-69a16cd6713d}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="FTagData.cpp" />

View File

@@ -48,6 +48,9 @@ Boolean CheckFileError (short resultCode, const PLPasStr &fileName)
case PLErrors::kOutOfMemory:
stringIndex = 7;
break;
case PLErrors::kFileIsBusy:
stringIndex = 12;
break;
default:
stringIndex = 1;
break;

View File

@@ -121,10 +121,10 @@ void ShiftWholeHouse (SInt16);
void DoHouseInfo (void); // --- HouseInfo.c
Boolean OpenHouse (void); // --- HouseIO.c
Boolean OpenHouse (Boolean load); // --- HouseIO.c
Boolean OpenSpecificHouse (const VFileSpec &);
Boolean SaveHouseAs (void);
Boolean ReadHouse (void);
Boolean ReadHouse (GpIOStream *houseStream);
Boolean WriteHouse (Boolean);
Boolean CloseHouse (void);
void OpenHouseResFork (void);

View File

@@ -50,7 +50,7 @@ void GetHighScoreName (short);
void UpdateBannerDialog (Dialog *);
int16_t BannerFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
void GetHighScoreBanner (void);
Boolean OpenHighScoresFile (const VFileSpec &spec, GpIOStream *&outStream);
Boolean OpenHighScoresFile (const VFileSpec &spec, GpIOStream *&outStream, Boolean write);
Str31 highBanner;
@@ -686,23 +686,18 @@ void GetHighScoreBanner (void)
//-------------------------------------------------------------- OpenHighScoresFile
Boolean OpenHighScoresFile (const VFileSpec &scoreSpec, GpIOStream *&scoresStream)
Boolean OpenHighScoresFile (const VFileSpec &spec, GpIOStream *&outStream, Boolean write)
{
PLError_t theErr;
PortabilityLayer::FileManager *fm = PortabilityLayer::FileManager::GetInstance();
theErr = fm->OpenFileData(scoreSpec.m_dir, scoreSpec.m_name, PortabilityLayer::EFilePermission_Any, scoresStream);
PLError_t theErr = fm->OpenNonCompositeFile(spec.m_dir, spec.m_name, ".dat", write ? PortabilityLayer::EFilePermission_Write : PortabilityLayer::EFilePermission_Read, write ? GpFileCreationDispositions::kCreateOrOverwrite : GpFileCreationDispositions::kOpenExisting, outStream);
if (theErr == PLErrors::kFileNotFound)
{
theErr = fm->CreateFileAtCurrentTime(scoreSpec.m_dir, scoreSpec.m_name, 'ozm5', 'gliS');
if (!CheckFileError(theErr, PSTR("New High Scores File")))
return (false);
theErr = fm->OpenFileData(scoreSpec.m_dir, scoreSpec.m_name, PortabilityLayer::EFilePermission_Any, scoresStream);
if (!CheckFileError(theErr, PSTR("High Score")))
return (false);
outStream = nil;
return (true);
}
else if (!CheckFileError(theErr, PSTR("High Score")))
if (!CheckFileError(theErr, PSTR("High Score")))
return (false);
return (true);
@@ -721,18 +716,11 @@ Boolean WriteScoresToDisk (void)
GpIOStream *scoresStream = nil;
scoreSpec = MakeVFileSpec(PortabilityLayer::VirtualDirectories::kHighScores, thisHouseName);
if (!OpenHighScoresFile(scoreSpec, scoresStream))
if (!OpenHighScoresFile(scoreSpec, scoresStream, true))
{
SysBeep(1);
return (false);
}
if (!scoresStream->SeekStart(0))
{
CheckFileError(PLErrors::kIOError, PSTR("High Scores File"));
scoresStream->Close();
return(false);
}
byteCount = sizeof(scoresType);
theScores = &((*thisHouse)->highScores);
@@ -744,13 +732,6 @@ Boolean WriteScoresToDisk (void)
return(false);
}
if (!scoresStream->Truncate(byteCount))
{
CheckFileError(PLErrors::kIOError, PSTR("High Scores File"));
scoresStream->Close();
return(false);
}
scoresStream->Close();
return (true);
@@ -777,15 +758,22 @@ Boolean ReadScoresFromDisk (void)
short volRefNum;
char wasState;
GpIOStream *scoresStream = nil;
VFileSpec scoreSpec = MakeVFileSpec(PortabilityLayer::VirtualDirectories::kHighScores, thisHouseName);
if (!OpenHighScoresFile(scoreSpec, scoresStream))
if (!OpenHighScoresFile(scoreSpec, scoresStream, false))
{
SysBeep(1);
return (false);
}
if (!scoresStream)
return (false);
byteCount = scoresStream->Size();
if (byteCount != sizeof(scoresType))
{
scoresStream->Close();
return (false);
}
theScores = &((*thisHouse)->highScores);

View File

@@ -16,7 +16,9 @@
#include "FileManager.h"
#include "FontFamily.h"
#include "House.h"
#include "MacFileInfo.h"
#include "PLStandardColors.h"
#include "PLStringCompare.h"
#include "PLTimeTaggedVOSEvent.h"
#include "RectUtils.h"
#include "ResourceManager.h"
@@ -31,6 +33,7 @@ void UpdateGoToDialog (Dialog *);
int16_t GoToFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt);
extern PortabilityLayer::IResourceArchive *houseResFork;
extern PortabilityLayer::CompositeFile *houseCFile;
houseHand thisHouse;
@@ -66,6 +69,13 @@ static void FBUI_FreeFileDetails(void *fileDetails)
{
}
static bool FBUI_FilterFile(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &filename)
{
PortabilityLayer::CompositeFile *cfile = PortabilityLayer::FileManager::GetInstance()->OpenCompositeFile(dirID, filename);
return PortabilityLayer::ResTypeIDCodec::Decode(cfile->GetProperties().m_fileType) == 'gliH';
}
static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetHouseDetailsAPI()
{
PortabilityLayer::FileBrowserUI_DetailsCallbackAPI api;
@@ -74,6 +84,7 @@ static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetHouseDetailsAPI()
api.m_drawFileDetailsCallback = FBUI_DrawFileDetails;
api.m_loadFileDetailsCallback = FBUI_LoadFileDetails;
api.m_freeFileDetailsCallback = FBUI_FreeFileDetails;
api.m_filterFileCallback = FBUI_FilterFile;
return api;
}
@@ -98,7 +109,7 @@ Boolean CreateNewHouse (void)
char savePath[sizeof(theSpec.m_name) + 1];
size_t savePathLength = 0;
if (!fm->PromptSaveFile(theSpec.m_dir, 'gliH', savePath, savePathLength, sizeof(theSpec.m_name), PSTR("My House"), PSTR("Create House"), GetHouseDetailsAPI()))
if (!fm->PromptSaveFile(theSpec.m_dir, ".gpf", savePath, savePathLength, sizeof(theSpec.m_name), PSTR("My House"), PSTR("Create House"), true, GetHouseDetailsAPI()))
return false;
assert(savePathLength < sizeof(theSpec.m_name) - 1);
@@ -106,9 +117,16 @@ Boolean CreateNewHouse (void)
theSpec.m_name[0] = static_cast<uint8_t>(savePathLength);
memcpy(theSpec.m_name + 1, savePath, savePathLength);
if (fm->FileExists(theSpec.m_dir, theSpec.m_name))
// Don't try to overwrite the current house
if (houseCFile && theSpec.m_dir == houseCFile->GetDirectory() && !StrCmp::CompareCaseInsensitive(theSpec.m_name, houseCFile->GetFileName()))
{
if (!fm->DeleteFile(theSpec.m_dir, theSpec.m_name))
CheckFileError(PLErrors::kFileIsBusy, theSpec.m_name);
return (false);
}
if (fm->CompositeFileExists(theSpec.m_dir, theSpec.m_name))
{
if (!fm->DeleteCompositeFile(theSpec.m_dir, theSpec.m_name))
{
CheckFileError(PLErrors::kAccessDenied, theSpec.m_name);
return (false);
@@ -133,7 +151,7 @@ Boolean CreateNewHouse (void)
AddExtraHouse(theSpec);
BuildHouseList();
InitCursor();
if (!OpenHouse())
if (!OpenHouse(false))
return (false);
WriteOutPrefs();
@@ -155,7 +173,7 @@ Boolean InitializeEmptyHouse (void)
if (thisHouse != nil)
thisHouse.Dispose();
thisHouse = NewHandle(sizeof(houseType)).StaticCast<houseType>();
thisHouse = NewHandle(sizeof(houseType) - sizeof(roomType)).StaticCast<houseType>();
if (thisHouse == nil)
{

View File

@@ -28,20 +28,18 @@
#define kDiscardChanges 2
void LoopMovie (void);
void OpenHouseMovie (void);
void CloseHouseMovie (void);
Boolean IsFileReadOnly (const VFileSpec &);
AnimationPlayer theMovie;
Rect movieRect;
PortabilityLayer::IResourceArchive *houseResFork;
short wasHouseVersion;
GpIOStream *houseStream;
Boolean houseOpen, fileDirty;
Boolean changeLockStateOfHouse, saveHouseLocked, houseIsReadOnly;
Boolean hasMovie, tvInRoom;
PortabilityLayer::CompositeFile *houseCFile;
extern VFileSpec *theHousesSpecs;
@@ -59,9 +57,7 @@ void OpenHouseMovie (void)
{
#ifdef COMPILEQT
VFileSpec theSpec;
VFileInfo finderInfo;
Handle spaceSaver;
PLError_t theErr;
short movieRefNum;
Boolean dataRefWasChanged;
@@ -69,19 +65,20 @@ void OpenHouseMovie (void)
{
theSpec = theHousesSpecs[thisHouseIndex];
PasStringConcat(theSpec.m_name, PSTR(".mov"));
theErr = FSpGetFInfo(theSpec, finderInfo);
if (theErr != PLErrors::kNone)
return;
AnimationPackage *anim = AnimationPackage::Create();
if (!anim)
return;
if (!anim->Load(theSpec.m_dir, theSpec.m_name))
PLError_t theErr = anim->Load(theSpec.m_dir, theSpec.m_name);
if (theErr != PLErrors::kNone)
{
anim->Destroy();
YellowAlert(kYellowQTMovieNotLoaded, theErr);
if (theErr != PLErrors::kFileNotFound)
YellowAlert(kYellowQTMovieNotLoaded, theErr);
return;
}
@@ -116,7 +113,7 @@ void CloseHouseMovie (void)
//-------------------------------------------------------------- OpenHouse
// Opens a house (whatever current selection is). Returns true if all went well.
Boolean OpenHouse (void)
Boolean OpenHouse (Boolean read)
{
PLError_t theErr;
@@ -132,12 +129,21 @@ Boolean OpenHouse (void)
if (!StrCmp::EqualCaseInsensitive(theHousesSpecs[thisHouseIndex].name, "\pDemo House"))
return (false);
#endif
houseIsReadOnly = IsFileReadOnly(theHousesSpecs[thisHouseIndex]);
theErr = PortabilityLayer::FileManager::GetInstance()->OpenFileData(theHousesSpecs[thisHouseIndex].m_dir, theHousesSpecs[thisHouseIndex].m_name, PortabilityLayer::EFilePermission_Any, houseStream);
if (!CheckFileError(theErr, thisHouseName))
houseCFile = PortabilityLayer::FileManager::GetInstance()->OpenCompositeFile(theHousesSpecs[thisHouseIndex].m_dir, theHousesSpecs[thisHouseIndex].m_name);
if (!houseCFile)
return (false);
houseIsReadOnly = houseCFile->IsDataReadOnly();
GpIOStream *houseStream = nil;
theErr = houseCFile->OpenData(PortabilityLayer::EFilePermission_Any, GpFileCreationDispositions::kCreateOrOpen, houseStream);
if (!CheckFileError(theErr, thisHouseName))
{
houseCFile->Close();
houseCFile = nil;
return (false);
}
houseOpen = true;
OpenHouseResFork();
@@ -148,6 +154,16 @@ Boolean OpenHouse (void)
tvInRoom = false;
tvWithMovieNumber = -1;
OpenHouseMovie();
if (read)
{
Boolean readOK = ReadHouse(houseStream);
houseStream->Close();
return readOK;
}
houseStream->Close();
return (true);
}
@@ -173,9 +189,7 @@ Boolean OpenSpecificHouse (const VFileSpec &specs)
{
thisHouseIndex = i;
PasStringCopy(theHousesSpecs[thisHouseIndex].m_name, thisHouseName);
if (OpenHouse())
itOpened = ReadHouse();
else
if (!OpenHouse(true))
itOpened = false;
break;
}
@@ -527,7 +541,7 @@ bool ByteSwapHouse(housePtr house, size_t sizeInBytes, bool isSwappedAfter)
return true;
}
Boolean ReadHouse (void)
Boolean ReadHouse (GpIOStream *houseStream)
{
long byteCount;
PLError_t theErr;
@@ -653,19 +667,27 @@ Boolean WriteHouse (Boolean checkIt)
UInt32 timeStamp;
long byteCount;
PLError_t theErr;
if ((housesFound < 1) || (thisHouseIndex == -1))
return(false);
if (!houseOpen)
{
YellowAlert(kYellowUnaccounted, 4);
return (false);
}
if (!houseStream->SeekStart(0))
if (!houseCFile)
{
CheckFileError(PLErrors::kIOError, thisHouseName);
return(false);
YellowAlert(kYellowUnaccounted, 4);
return (false);
}
GpIOStream *houseStream = nil;
theErr = houseCFile->OpenData(PortabilityLayer::EFilePermission_Write, GpFileCreationDispositions::kCreateOrOpen, houseStream);
if (theErr != PLErrors::kNone)
return (false);
CopyThisRoomToRoom();
if (checkIt)
@@ -699,6 +721,7 @@ Boolean WriteHouse (Boolean checkIt)
{
CheckFileError(PLErrors::kIOError, thisHouseName);
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount), false);
houseStream->Close();
return(false);
}
@@ -706,16 +729,13 @@ Boolean WriteHouse (Boolean checkIt)
{
CheckFileError(PLErrors::kIOError, thisHouseName);
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount), false);
houseStream->Close();
return(false);
}
ByteSwapHouse(*thisHouse, static_cast<size_t>(byteCount), false);
if (!houseStream->Truncate(byteCount))
{
CheckFileError(PLErrors::kIOError, thisHouseName);
return(false);
}
houseStream->Close();
if (changeLockStateOfHouse)
{
@@ -749,7 +769,11 @@ Boolean CloseHouse (void)
CloseHouseResFork();
CloseHouseMovie();
houseStream->Close();
if (houseCFile)
{
houseCFile->Close();
houseCFile = nil;
}
houseOpen = false;
@@ -764,7 +788,7 @@ void OpenHouseResFork (void)
PortabilityLayer::ResourceManager *rm = PortabilityLayer::ResourceManager::GetInstance();
if (houseResFork == nullptr)
{
houseResFork = rm->LoadResFile(theHousesSpecs[thisHouseIndex].m_dir, theHousesSpecs[thisHouseIndex].m_name);
houseResFork = rm->LoadResFile(houseCFile);
if (!houseResFork)
YellowAlert(kYellowFailedResOpen, PLErrors::kResourceError);
}
@@ -817,8 +841,7 @@ Boolean QuerySaveChanges (void)
if (!quitting)
{
whoCares = CloseHouse();
if (OpenHouse())
whoCares = ReadHouse();
OpenHouse(true);
}
UpdateMenus(false);
return (true);
@@ -850,17 +873,6 @@ void YellowAlert (short whichAlert, short identifier)
whoCares = PortabilityLayer::DialogManager::GetInstance()->DisplayAlert(kYellowAlert, &substitutions);
}
//-------------------------------------------------------------- IsFileReadOnly
Boolean IsFileReadOnly (const VFileSpec &spec)
{
// Kind of annoying, but itch.io doesn't preserve read-only flags and there doesn't seem to be any way around that.
if (spec.m_dir == PortabilityLayer::VirtualDirectories::kApplicationData || spec.m_dir == PortabilityLayer::VirtualDirectories::kGameData)
return true;
return PortabilityLayer::FileManager::GetInstance()->FileLocked(spec.m_dir, spec.m_name);
}
//-------------------------------------------------------------- LoadHousePicture
THandle<void> LoadHouseResource(const PortabilityLayer::ResTypeID &resTypeID, int16_t resID)

View File

@@ -616,7 +616,7 @@ void ValidateNumberOfRooms (void)
reportsRooms = (long)(*thisHouse)->nRooms;
countedRooms = (GetHandleSize(thisHouse.StaticCast<void>()) -
sizeof(houseType)) / sizeof(roomType);
sizeof(houseType)) / sizeof(roomType) + 1;
if (reportsRooms != countedRooms)
{
(*thisHouse)->nRooms = (short)countedRooms;

View File

@@ -8,6 +8,7 @@
#include "WindowDef.h"
#include "BitmapImage.h"
#include "FileManager.h"
#include "Externs.h"
#include "Environ.h"
#include "FontFamily.h"
@@ -70,7 +71,7 @@ extern Str15 leftName, rightName, batteryName, bandName;
extern Str15 highName;
//extern long encryptedNumber;
extern short maxFiles, numNeighbors, willMaxFiles;
extern GpIOStream *houseStream;
extern PortabilityLayer::CompositeFile *houseCFile;
extern short isEditH, isEditV, isMapH, isMapV;
extern short isToolsH, isToolsV, isCoordH, isCoordV;
extern short isLinkH, isLinkV, toolMode, mapLeftRoom, mapTopRoom;
@@ -225,12 +226,12 @@ void ReadInPrefs (void)
isEditV = 41;
isMapH = 3;
// isMapV = qd.screenBits.bounds.bottom - 100;
isMapV = 100;
isMapV = 385;
mapRoomsWide = 15;
mapRoomsHigh = 4;
// isToolsH = qd.screenBits.bounds.right - 120;
isToolsH = 100;
isToolsV = 35;
isToolsH = 525;
isToolsV = 41;
isLinkH = 50;
isLinkV = 80;
// isCoordH = qd.screenBits.bounds.right - 55;
@@ -361,8 +362,6 @@ void WriteOutPrefs (void)
SysBeep(1);
modulePrefs.Dispose();
UnivSetSoundVolume(wasVolume, thisMac.hasSM3);
}
void StepLoadScreenRing()
@@ -568,8 +567,7 @@ void StepLoadScreen(int steps, bool insertDelay)
void InitLoadingWindow()
{
// Only phones are slow enough for this to matter
if (!thisMac.isTouchscreen)
if (!thisMac.isTouchscreen && isPrefsLoaded)
return;
if (isPrefsLoaded)
@@ -782,6 +780,10 @@ void PreloadAATables()
PortabilityLayer::RGBAColor::Create(0, 255, 255, 255),
PortabilityLayer::RGBAColor::Create(0, 0, 255, 255),
PortabilityLayer::RGBAColor::Create(204, 102, 51, 255),
PortabilityLayer::RGBAColor::Create(102, 102, 102, 255),
PortabilityLayer::RGBAColor::Create(51, 51, 102, 255),
PortabilityLayer::RGBAColor::Create(255, 255, 51, 255),
PortabilityLayer::RGBAColor::Create(0, 0, 0, 255),
};
const size_t numPalettePreloads = sizeof(preloadColors) / sizeof(preloadColors[0]);
@@ -815,7 +817,7 @@ void PreloadAATables()
if (!toneAlreadyQueued)
{
PreloadAATableSpec &spec = specs[i + numTonePreloads];
PreloadAATableSpec &spec = specs[numPalettePreloads + numTonePreloads];
numTonePreloads++;
spec.m_color = PortabilityLayer::RGBAColor::Create(tone, tone, tone, 255);
@@ -912,7 +914,7 @@ void ShowInitialLaunchDisclaimer()
"on the 2016 release of the game\xd5s source code and assets.",
"",
"Glider PRO, a sequel to the original Glider, was released in 1994",
"for the Apple Macintosh, and is widely recognized as one of",
"for Apple Macintosh computers, and is widely recognized as one of",
"of the most iconic Macintosh-exclusive games of the 1990\xd5s.",
"",
"I hope that by adapting it to be playable on modern systems, more",
@@ -1167,8 +1169,7 @@ int gpAppMain()
InitSound(); SpinCursor(2);
InitMusic(); SpinCursor(2);
BuildHouseList();
if (OpenHouse())
whoCares = ReadHouse();
OpenHouse(true);
PlayPrioritySound(kBirdSound, kBirdPriority);
DelayTicks(6);
@@ -1201,7 +1202,8 @@ int gpAppMain()
if (!CloseHouse())
{
CloseHouseResFork();
houseStream->Close();
if (houseCFile)
houseCFile->Close();
houseOpen = false;
}
}

View File

@@ -426,6 +426,7 @@ void DoOptionsMenu (short theItem)
}
OpenMainWindow();
RedrawSplashScreen();
incrementModeTime = TickCount() + kIdleSplashTicks;
}
else if (theMode == kSplashMode) // switching to edit mode

View File

@@ -1963,6 +1963,12 @@ void GetThisRoomsObjRects (void)
if ((noRoomAtAll) || (!houseUnlocked))
{
// clear object handles so they're not draggable
QSetRect(&leftStartGliderDest, 0, 0, 0, 0);
QSetRect(&rightStartGliderDest, 0, 0, 0, 0);
for (i = 0; i < kMaxRoomObs; i++)
QSetRect(&roomObjectRects[i], 0, 0, 0, 0);
return;
}
else

View File

@@ -278,12 +278,11 @@ void DoDemoGame (void)
whoCares = CloseHouse();
thisHouseIndex = demoHouseIndex;
PasStringCopy(theHousesSpecs[thisHouseIndex].m_name, thisHouseName);
if (OpenHouse())
if (OpenHouse(true))
{
if (thisMac.isTouchscreen)
DismissMainMenuUI();
whoCares = ReadHouse();
demoGoing = true;
NewGame(kNewGameMode);
@@ -293,8 +292,7 @@ void DoDemoGame (void)
whoCares = CloseHouse();
thisHouseIndex = wasHouseIndex;
PasStringCopy(theHousesSpecs[thisHouseIndex].m_name, thisHouseName);
if (OpenHouse())
whoCares = ReadHouse();
OpenHouse(true);
incrementModeTime = TickCount() + kIdleSplashTicks;
RedrawSplashScreen();
}

View File

@@ -22,7 +22,7 @@
#define kPrefCreatorType 'ozm5'
#define kPrefFileType 'gliP'
#define kPrefFileName PSTR("Glider Prefs v2")
#define kPrefFileName PSTR("Glider Prefs")
#define kDefaultPrefFName PSTR("Preferences")
#define kPrefsStringsID 160
#define kNewPrefsAlertID 160
@@ -67,16 +67,8 @@ Boolean WritePrefs (const prefsInfo *thePrefs, short versionNow, THandle<moduleP
PasStringCopy(kPrefFileName, fileName);
VFileSpec theSpecs = MakeVFileSpec(PortabilityLayer::VirtualDirectories::kPrefs, fileName);
if (!fm->FileExists(PortabilityLayer::VirtualDirectories::kPrefs, fileName))
{
theErr = fm->CreateFileAtCurrentTime(theSpecs.m_dir, theSpecs.m_name, kPrefCreatorType, kPrefFileType);
if (theErr != PLErrors::kNone)
{
CheckFileError(theErr, PSTR("Preferences"));
return(false);
}
}
theErr = fm->OpenFileData(theSpecs.m_dir, theSpecs.m_name, PortabilityLayer::EFilePermission_Write, fileStream);
theErr = fm->OpenNonCompositeFile(theSpecs.m_dir, theSpecs.m_name, ".dat", PortabilityLayer::EFilePermission_Write, GpFileCreationDispositions::kCreateOrOverwrite, fileStream);
if (theErr != PLErrors::kNone)
{
CheckFileError(theErr, PSTR("Preferences"));
@@ -201,10 +193,10 @@ PLError_t ReadPrefs (prefsInfo *thePrefs, short versionNeed, Boolean *isOldVersi
theSpecs = MakeVFileSpec(PortabilityLayer::VirtualDirectory_t::kPrefs, fileName);
if (!PortabilityLayer::FileManager::GetInstance()->FileExists(theSpecs.m_dir, theSpecs.m_name))
return PLErrors::kFileNotFound;
theErr = fm->OpenNonCompositeFile(theSpecs.m_dir, theSpecs.m_name, ".dat", PortabilityLayer::EFilePermission_Read, GpFileCreationDispositions::kOpenExisting, fileStream);
if (theErr == PLErrors::kFileNotFound)
return theErr;
theErr = fm->OpenFileData(theSpecs.m_dir, theSpecs.m_name, PortabilityLayer::EFilePermission_Read, fileStream);
if (theErr != PLErrors::kNone)
{
CheckFileError(theErr, PSTR("Preferences"));
@@ -326,7 +318,7 @@ Boolean DeletePrefs ()
theSpecs = MakeVFileSpec(PortabilityLayer::VirtualDirectories::kPrefs, fileName);
return PortabilityLayer::FileManager::GetInstance()->DeleteFile(theSpecs.m_dir, theSpecs.m_name);
return PortabilityLayer::FileManager::GetInstance()->DeleteNonCompositeFile(theSpecs.m_dir, theSpecs.m_name, ".dat");
}
//-------------------------------------------------------------- RunFunctionOnAllPrefsHandlers

View File

@@ -73,7 +73,7 @@ static void FBUI_DrawFileDetails(DrawSurface *surface, const Point &basePoint, c
static void *FBUI_LoadFileDetails(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &filename)
{
GpIOStream *stream = nullptr;
if (PortabilityLayer::FileManager::GetInstance()->OpenFileData(dirID, filename, PortabilityLayer::EFilePermission_Read, stream) != PLErrors::kNone)
if (PortabilityLayer::FileManager::GetInstance()->OpenNonCompositeFile(dirID, filename, ".sav", PortabilityLayer::EFilePermission_Read, GpFileCreationDispositions::kOpenExisting, stream) != PLErrors::kNone)
return nullptr;
const size_t kPrefixSize = sizeof(game2Type) - sizeof(savedRoom);
@@ -102,6 +102,11 @@ static void FBUI_FreeFileDetails(void *fileDetails)
PortabilityLayer::MemoryManager::GetInstance()->Release(fileDetails);
}
static bool FBUI_FilterFile(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &filename)
{
return true;
}
static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetSavedGameDetailsAPI()
{
PortabilityLayer::FileBrowserUI_DetailsCallbackAPI api;
@@ -110,6 +115,7 @@ static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetSavedGameDetailsAPI
api.m_drawFileDetailsCallback = FBUI_DrawFileDetails;
api.m_loadFileDetailsCallback = FBUI_LoadFileDetails;
api.m_freeFileDetailsCallback = FBUI_FreeFileDetails;
api.m_filterFileCallback = FBUI_FilterFile;
return api;
}
@@ -163,7 +169,7 @@ Boolean SaveGame2 (void)
char savePath[sizeof(spec.m_name) + 1];
size_t savePathLength = 0;
if (!fm->PromptSaveFile(spec.m_dir, 'gliG', savePath, savePathLength, sizeof(spec.m_name), PLPasStr(gameNameStr), PSTR("Save Game"), GetSavedGameDetailsAPI()))
if (!fm->PromptSaveFile(spec.m_dir, ".sav", savePath, savePathLength, sizeof(spec.m_name), PLPasStr(gameNameStr), PSTR("Save Game"), false, GetSavedGameDetailsAPI()))
{
mm->Release(savedGame);
return false;
@@ -173,15 +179,6 @@ Boolean SaveGame2 (void)
spec.m_name[0] = static_cast<uint8_t>(savePathLength);
memcpy(spec.m_name + 1, savePath, savePathLength);
if (fm->FileExists(spec.m_dir, PLPasStr(spec.m_name)))
{
if (!fm->DeleteFile(spec.m_dir, spec.m_name))
{
CheckFileError(PLErrors::kAccessDenied, PSTR("Saved Game"));
return false;
}
}
thisHousePtr = *thisHouse;
@@ -216,20 +213,15 @@ Boolean SaveGame2 (void)
destRoom->objects[i] = srcRoom->objects[i];
}
PLError_t theErr = fm->CreateFileAtCurrentTime(spec.m_dir, spec.m_name, 'ozm5', 'gliG');
PLError_t theErr = fm->OpenNonCompositeFile(spec.m_dir, spec.m_name, ".sav", PortabilityLayer::EFilePermission_Write, GpFileCreationDispositions::kCreateOrOverwrite, gameStream);
if (CheckFileError(theErr, PSTR("Saved Game")))
{
theErr = fm->OpenFileData(spec.m_dir, spec.m_name, PortabilityLayer::EFilePermission_Write, gameStream);
if (CheckFileError(theErr, PSTR("Saved Game")))
if (gameStream->Write(savedGame, byteCount) != byteCount)
{
if (gameStream->Write(savedGame, byteCount) != byteCount)
{
CheckFileError(PLErrors::kIOError, PSTR("Saved Game"));
}
gameStream->Close();
CheckFileError(PLErrors::kIOError, PSTR("Saved Game"));
}
gameStream->Close();
}
mm->Release(savedGame);
@@ -274,7 +266,7 @@ Boolean OpenSavedGame (void)
char savePath[sizeof(spec.m_name) + 1];
size_t savePathLength = 0;
if (!fm->PromptOpenFile(spec.m_dir, 'gliG', savePath, savePathLength, sizeof(spec.m_name), PSTR("Open Saved Game"), GetSavedGameDetailsAPI()))
if (!fm->PromptOpenFile(spec.m_dir, ".sav", savePath, savePathLength, sizeof(spec.m_name), PSTR("Open Saved Game"), false, GetSavedGameDetailsAPI()))
return false;
assert(savePathLength < sizeof(spec.m_name) - 1);
@@ -282,15 +274,8 @@ Boolean OpenSavedGame (void)
spec.m_name[0] = static_cast<uint8_t>(savePathLength);
memcpy(spec.m_name + 1, savePath, savePathLength);
PortabilityLayer::MacFileProperties props;
if (!fm->ReadFileProperties(spec.m_dir, spec.m_name, props))
return false;
if (memcmp(props.m_fileType, "gliG", 4))
return false;
GpIOStream *gameStream = nullptr;
PLError_t theErr = fm->OpenFileData(spec.m_dir, spec.m_name, PortabilityLayer::EFilePermission_Read, gameStream);
PLError_t theErr = fm->OpenNonCompositeFile(spec.m_dir, spec.m_name, ".sav", PortabilityLayer::EFilePermission_Read, GpFileCreationDispositions::kOpenExisting, gameStream);
if (!CheckFileError(theErr, PSTR("Saved Game")))
return(false);

View File

@@ -101,18 +101,26 @@ void UpdateLoadDialog (Dialog *theDialog)
if (SectRect(&dialogRect, &tempRect, &dummyRect))
{
PortabilityLayer::IResourceArchive *resFile = PortabilityLayer::ResourceManager::GetInstance()->LoadResFile(theHousesSpecs[i].m_dir, theHousesSpecs[i].m_name);
if (resFile != nullptr)
PortabilityLayer::CompositeFile *cfile = PortabilityLayer::FileManager::GetInstance()->OpenCompositeFile(theHousesSpecs[i].m_dir, theHousesSpecs[i].m_name);
bool haveHouseIcon = false;
GpIOStream *resStream = nil;
if (cfile)
{
if (!LargeIconPlot(surface, resFile, -16455, tempRect))
PortabilityLayer::IResourceArchive *resFile = PortabilityLayer::ResourceManager::GetInstance()->LoadResFile(cfile);
if (resFile != nullptr)
{
LoadDialogPICT(theDialog, kLoadIconFirstItem + i - housePage,
kDefaultHousePict8);
if (LargeIconPlot(surface, resFile, -16455, tempRect))
haveHouseIcon = true;
resFile->Destroy();
}
resFile->Destroy();
cfile->Close();
}
else
if (!haveHouseIcon)
LoadDialogPICT(theDialog, kLoadIconFirstItem + i - housePage,
kDefaultHousePict8);
}
@@ -411,11 +419,8 @@ void DoLoadHouse (void)
whoCares = CloseHouse();
PasStringCopy(theHousesSpecs[thisHouseIndex].m_name,
thisHouseName);
if (OpenHouse())
{
whoCares = ReadHouse();
if (OpenHouse(true))
houseNameDirty = true;
}
}
leaving = true;
}
@@ -452,11 +457,8 @@ void DoLoadHouse (void)
whoCares = CloseHouse();
PasStringCopy(theHousesSpecs[thisHouseIndex].m_name,
thisHouseName);
if (OpenHouse())
{
whoCares = ReadHouse();
if (OpenHouse(true))
houseNameDirty = true;
}
}
leaving = true;
}
@@ -489,11 +491,8 @@ void DoLoadHouse (void)
whoCares = CloseHouse();
PasStringCopy(theHousesSpecs[thisHouseIndex].m_name,
thisHouseName);
if (OpenHouse())
{
whoCares = ReadHouse();
if (OpenHouse(true))
houseNameDirty = true;
}
}
leaving = true;
}
@@ -596,7 +595,7 @@ void DoDirSearch (void)
{
theHousesSpecs[housesFound] = MakeVFileSpec(theDirs[currentDir], f->name);
if (fm->FileExists(theDirs[currentDir], f->name))
if (fm->CompositeFileExists(theDirs[currentDir], f->name))
housesFound++;
}
}

View File

@@ -637,7 +637,7 @@ void HandleSoundMusicChange (short newVolume, Boolean sayIt)
isSoundOn = (newVolume != 0);
if (wasIdle)
if (wasIdle && theMode != kEditMode)
{
if (newVolume == 0)
StopTheMusic();
@@ -773,7 +773,7 @@ void DoSoundPrefs (void)
case kCancelButton:
UnivSetSoundVolume(wasLoudness, thisMac.hasSM3);
HandleSoundMusicChange(wasLoudness, false);
if (isPlayMusicIdle != wasIdle)
if (isPlayMusicIdle != wasIdle && theMode != kEditMode)
{
if (isPlayMusicIdle)
{
@@ -831,7 +831,7 @@ void DoSoundPrefs (void)
case kIdleMusicItem:
wasIdle = !wasIdle;
SetDialogItemValue(prefDlg, kIdleMusicItem, (short)wasIdle);
if (wasIdle)
if (wasIdle && theMode != kEditMode)
{
UnivGetSoundVolume(&tempVolume, thisMac.hasSM3);
if (tempVolume != 0)

View File

@@ -96,41 +96,6 @@ SortableEntry SortableEntry::Create(const char *zipLocation, PortabilityLayer::V
return entry;
}
static void ConvertToMSDOSTimestamp(const PortabilityLayer::CombinedTimestamp &ts, uint16_t &msdosDate, uint16_t &msdosTime)
{
int32_t yearsSince1980 = ts.GetLocalYear() - 1980;
uint8_t month = ts.m_localMonth;
uint8_t day = ts.m_localDay;
uint8_t hour = ts.m_localHour;
uint8_t minute = ts.m_localMinute;
uint8_t second = ts.m_localSecond;
if (yearsSince1980 < 0)
{
// Time machine
yearsSince1980 = 0;
second = 0;
minute = 0;
hour = 0;
day = 1;
month = 1;
}
else if (yearsSince1980 > 127)
{
// I was promised flying cars, but it's 2107 and you're still flying paper airplanes...
yearsSince1980 = 127;
second = 59;
minute = 59;
hour = 23;
day = 31;
month = 12;
}
msdosTime = (second / 2) | (minute << 5) | (hour << 11);
msdosDate = day | (month << 5) | (yearsSince1980 << 9);
}
static void InitSourceExportWindow(SourceExportState *state)
{
static const int kLoadScreenHeight = 32;
@@ -403,7 +368,7 @@ static bool RepackDirectory(SourceExportState &state, GpIOStream *outStream, std
uint16_t dosDate = 0;
uint16_t dosTime = 0;
ConvertToMSDOSTimestamp(state.m_ts, dosDate, dosTime);
state.m_ts.GetAsMSDOSTimestamp(dosDate, dosTime);
IGpDirectoryCursor *dirCursor = PLDrivers::GetFileSystem()->ScanDirectory(virtualDir);
if (!dirCursor)
@@ -610,7 +575,7 @@ static bool AddZipDirectory(GpIOStream *stream, std::vector<PortabilityLayer::Zi
uint16_t dosDate = 0;
uint16_t dosTime = 0;
ConvertToMSDOSTimestamp(ts, dosDate, dosTime);
ts.GetAsMSDOSTimestamp(dosDate, dosTime);
GpUFilePos_t localHeaderPos = stream->Tell();

View File

@@ -70,9 +70,9 @@ short WhichStringFirst (StringPtr p1, StringPtr p2)
{
if (!foundIt)
{
if (p1[0] < p2[0]) // shortest string wins
if (p1[0] > p2[0]) // shortest string wins
greater = 1;
else if (p1[0] > p2[0])
else if (p1[0] < p2[0])
greater = 2;
}
foundIt = true;

View File

@@ -3,6 +3,7 @@
enum EGpInputDriverType
{
EGpInputDriverType_XInput,
EGpInputDriverType_SDL2_Gamepad,
EGpInputDriverType_Count,
};

View File

@@ -2,8 +2,8 @@
#define GP_BUILD_VERSION_MAJOR 1
#define GP_BUILD_VERSION_MINOR 0
#define GP_BUILD_VERSION_UPDATE 13
#define GP_BUILD_VERSION_UPDATE 16
#define GP_APPLICATION_VERSION_STRING "1.0.13"
#define GP_APPLICATION_VERSION_STRING "1.0.16"
#define GP_APPLICATION_COPYRIGHT_STRING "2019-2021 Eric Lasota"
#define GP_APPLICATION_WEBSITE_STRING "https://github.com/elasota/Aerofoil"

View File

@@ -13,9 +13,23 @@ public:
virtual bool SeekStart(GpUFilePos_t loc) = 0;
virtual bool SeekCurrent(GpFilePos_t loc) = 0;
virtual bool SeekEnd(GpUFilePos_t loc) = 0;
virtual bool Truncate(GpUFilePos_t loc) = 0;
virtual GpUFilePos_t Size() const = 0;
virtual GpUFilePos_t Tell() const = 0;
virtual void Close() = 0;
virtual void Flush() = 0;
bool ReadExact(void *bytesOut, size_t size);
bool WriteExact(const void *bytesOut, size_t size);
};
inline bool GpIOStream::ReadExact(void *bytesOut, size_t size)
{
const size_t nRead = this->Read(bytesOut, size);
return nRead == size;
}
inline bool GpIOStream::WriteExact(const void *bytes, size_t size)
{
const size_t nWritten = this->Write(bytes, size);
return nWritten == size;
}

View File

@@ -15,7 +15,7 @@ public:
typedef void(*DelayCallback_t)(uint32_t ticks);
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 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;
virtual IGpDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) = 0;
@@ -23,7 +23,6 @@ public:
virtual bool ValidateFilePath(const char *path, size_t pathLen) const = 0;
virtual bool ValidateFilePathUnicodeChar(uint32_t ch) const = 0;
virtual bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const = 0;
virtual void SetMainThreadRelay(IGpThreadRelay *relay) = 0;
virtual void SetDelayCallback(DelayCallback_t delayCallback) = 0;

View File

@@ -30,6 +30,7 @@ public:
virtual bool IsTouchscreen() const = 0;
virtual bool IsUsingMouseAsTouch() const = 0;
virtual bool IsFullscreenPreferred() const = 0;
virtual bool IsFullscreenOnStartup() const = 0;
virtual bool IsTextInputObstructive() const = 0;
virtual unsigned int GetCPUCount() const = 0;
virtual void SetTextInputEnabled(bool isEnabled) = 0;

View File

@@ -154,6 +154,7 @@ void GpInputDriverXInput::ProcessButtonStateChange(DWORD prevState, DWORD newSta
evt->m_event.m_keyboardInputEvent.m_keyIDSubset = GpKeyIDSubsets::kGamepadButton;
evt->m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_button = gamepadButton;
evt->m_event.m_keyboardInputEvent.m_key.m_gamepadKey.m_player = playerNum;
evt->m_event.m_keyboardInputEvent.m_repeatCount = 0;
}
}

View File

@@ -51,7 +51,7 @@ int main(int argc, const char **argv)
SystemTimeToTzSpecificLocalTime(&tz, &utcST, &localST);
PortabilityLayer::CombinedTimestamp ts;
ts.SetUTCTime(timeDelta);
ts.SetMacEpochTime(timeDelta);
ts.SetLocalYear(localST.wYear);
ts.m_localMonth = localST.wMonth;

388
MergeGPF/MergeGPF.cpp Normal file
View File

@@ -0,0 +1,388 @@
#include "WindowsUnicodeToolShim.h"
#include "CFileStream.h"
#include "CombinedTimestamp.h"
#include "DeflateCodec.h"
#include "MacFileInfo.h"
#include "ZipFile.h"
#include <stdio.h>
#include <string>
#include <algorithm>
int toolMain(int argc, const char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: MergeGPF <file.gpf>");
return -1;
}
std::string metaFileName = argv[1];
if (metaFileName.length() < 5)
{
fprintf(stderr, "Usage: MergeGPF <file.gpf>");
return -1;
}
std::string fnameBase = metaFileName.substr(0, metaFileName.length() - 4);
std::string resName = fnameBase + ".gpa";
std::string dataName = fnameBase + ".gpd";
PortabilityLayer::MacFilePropertiesSerialized mfps;
PortabilityLayer::ZipFileLocalHeader metaLH;
{
FILE *metaF = fopen_utf8(argv[1], "rb");
PortabilityLayer::CFileStream metaStream(metaF);
if (!mfps.ReadFromPackage(metaStream))
{
fprintf(stderr, "Error reading metadata");
return -1;
}
metaStream.SeekStart(0);
metaStream.Read(&metaLH, sizeof(metaLH));
metaStream.Close();
}
PortabilityLayer::MacFileProperties mfp;
mfps.Deserialize(mfp);
mfps.Serialize(mfp);
size_t insertedMetaFSize = sizeof(metaLH) + strlen(PortabilityLayer::MacFilePropertiesSerialized::GetPackagedName()) + sizeof(mfps.m_data);
size_t insertedDataSize = 0;
FILE *mergedF = fopen_utf8(argv[1], "wb");
if (!mergedF)
{
fprintf(stderr, "Error reopening metadata file");
return -1;
}
PortabilityLayer::CFileStream mergedStream(mergedF);
uint32_t numFiles = 0;
uint32_t cdirSize = 0;
const char *metaPackagedName = PortabilityLayer::MacFilePropertiesSerialized::GetPackagedName();
const char *dataPackagedName = "!data";
PortabilityLayer::ZipCentralDirectoryFileHeader metaCDir;
PortabilityLayer::ZipCentralDirectoryFileHeader dataCDir;
bool hasData = false;
// Write metadata
{
GpUFilePos_t metaLHStart = mergedStream.Tell();
PortabilityLayer::ZipFileLocalHeader metaCopyLH;
metaCopyLH.m_signature = PortabilityLayer::ZipFileLocalHeader::kSignature;
metaCopyLH.m_versionRequired = PortabilityLayer::ZipConstants::kStoredRequiredVersion;
metaCopyLH.m_flags = 0;
metaCopyLH.m_method = PortabilityLayer::ZipConstants::kStoredMethod;
metaCopyLH.m_modificationTime = metaLH.m_modificationTime;
metaCopyLH.m_modificationDate = metaLH.m_modificationDate;
metaCopyLH.m_crc = PortabilityLayer::DeflateContext::CRC32(0, mfps.m_data, sizeof(mfps.m_data));
metaCopyLH.m_compressedSize = sizeof(mfps.m_data);
metaCopyLH.m_uncompressedSize = sizeof(mfps.m_data);
metaCopyLH.m_fileNameLength = strlen(metaPackagedName);
metaCopyLH.m_extraFieldLength = 0;
if (!mergedStream.WriteExact(&metaCopyLH, sizeof(metaCopyLH)) || !mergedStream.WriteExact(metaPackagedName, strlen(metaPackagedName)) || !mergedStream.WriteExact(mfps.m_data, sizeof(mfps.m_data)))
{
fprintf(stderr, "Error writing metadata");
return -1;
}
numFiles++;
cdirSize += sizeof(PortabilityLayer::ZipCentralDirectoryFileHeader) + strlen(metaPackagedName);
metaCDir.m_signature = PortabilityLayer::ZipCentralDirectoryFileHeader::kSignature;
metaCDir.m_versionCreated = PortabilityLayer::ZipConstants::kCompressedRequiredVersion;
metaCDir.m_versionRequired = PortabilityLayer::ZipConstants::kStoredRequiredVersion;
metaCDir.m_flags = 0;
metaCDir.m_method = PortabilityLayer::ZipConstants::kStoredMethod;
metaCDir.m_modificationTime = metaLH.m_modificationTime;
metaCDir.m_modificationDate = metaLH.m_modificationDate;
metaCDir.m_crc = metaLH.m_crc;
metaCDir.m_compressedSize = metaLH.m_compressedSize;
metaCDir.m_uncompressedSize = metaLH.m_uncompressedSize;
metaCDir.m_fileNameLength = metaLH.m_fileNameLength;
metaCDir.m_extraFieldLength = metaLH.m_extraFieldLength;
metaCDir.m_commentLength = 0;
metaCDir.m_diskNumber = 0;
metaCDir.m_internalAttributes = 0;
metaCDir.m_externalAttributes = PortabilityLayer::ZipConstants::kArchivedAttributes;
metaCDir.m_localHeaderOffset = metaLHStart;
}
FILE *dataF = fopen_utf8(dataName.c_str(), "rb");
if (dataF)
{
GpUFilePos_t dataLHStart = mergedStream.Tell();
PortabilityLayer::ZipFileLocalHeader dataLH;
dataLH.m_signature = PortabilityLayer::ZipFileLocalHeader::kSignature;
dataLH.m_versionRequired = PortabilityLayer::ZipConstants::kCompressedRequiredVersion;
dataLH.m_flags = 0;
dataLH.m_method = PortabilityLayer::ZipConstants::kDeflatedMethod;
dataLH.m_modificationTime = metaLH.m_modificationTime;
dataLH.m_modificationDate = metaLH.m_modificationDate;
dataLH.m_crc = 0;
dataLH.m_compressedSize = 0;
dataLH.m_uncompressedSize = 0;
dataLH.m_fileNameLength = strlen(dataPackagedName);
dataLH.m_extraFieldLength = 0;
if (!mergedStream.WriteExact(&dataLH, sizeof(dataLH)) || !mergedStream.WriteExact(dataPackagedName, strlen(dataPackagedName)))
{
fprintf(stderr, "Error compressing data");
return -1;
}
PortabilityLayer::DeflateContext *ctx = PortabilityLayer::DeflateContext::Create(&mergedStream, 9);
uint8_t compressBuffer[1024];
uint32_t crc = 0;
size_t uncompressedSize = 0;
GpUFilePos_t compressedDataStart = mergedStream.Tell();
for (;;)
{
size_t dataRead = fread(compressBuffer, 1, sizeof(compressBuffer), dataF);
if (dataRead == 0)
break;
uncompressedSize += dataRead;
if (!ctx->Append(compressBuffer, dataRead))
{
fprintf(stderr, "Error compressing data");
return -1;
}
crc = PortabilityLayer::DeflateContext::CRC32(crc, compressBuffer, dataRead);
}
if (!ctx->Flush())
{
fprintf(stderr, "Error compressing data");
return -1;
}
ctx->Destroy();
GpUFilePos_t compressedDataEnd = mergedStream.Tell();
dataLH.m_crc = crc;
dataLH.m_compressedSize = (compressedDataEnd - compressedDataStart);
dataLH.m_uncompressedSize = uncompressedSize;
if (!mergedStream.SeekStart(dataLHStart) || !mergedStream.Write(&dataLH, sizeof(dataLH)) || !mergedStream.SeekStart(compressedDataEnd))
{
fprintf(stderr, "Error compressing data");
return -1;
}
numFiles++;
cdirSize += sizeof(PortabilityLayer::ZipCentralDirectoryFileHeader) + strlen(dataPackagedName);
hasData = true;
fclose(dataF);
insertedDataSize += sizeof(dataLH) + strlen(dataPackagedName) + (compressedDataEnd - compressedDataStart);
dataCDir.m_signature = PortabilityLayer::ZipCentralDirectoryFileHeader::kSignature;
dataCDir.m_versionCreated = PortabilityLayer::ZipConstants::kCompressedRequiredVersion;
dataCDir.m_versionRequired = PortabilityLayer::ZipConstants::kCompressedRequiredVersion;
dataCDir.m_flags = 0;
dataCDir.m_method = PortabilityLayer::ZipConstants::kDeflatedMethod;
dataCDir.m_modificationTime = dataLH.m_modificationTime;
dataCDir.m_modificationDate = dataLH.m_modificationDate;
dataCDir.m_crc = dataLH.m_crc;
dataCDir.m_compressedSize = dataLH.m_compressedSize;
dataCDir.m_uncompressedSize = dataLH.m_uncompressedSize;
dataCDir.m_fileNameLength = dataLH.m_fileNameLength;
dataCDir.m_extraFieldLength = dataLH.m_extraFieldLength;
dataCDir.m_commentLength = 0;
dataCDir.m_diskNumber = 0;
dataCDir.m_internalAttributes = 0;
dataCDir.m_externalAttributes = PortabilityLayer::ZipConstants::kArchivedAttributes;
dataCDir.m_localHeaderOffset = dataLHStart;
}
std::vector<PortabilityLayer::ZipCentralDirectoryFileHeader> resCentralDir;
std::vector<uint8_t> fileNameBytes;
std::vector<size_t> fileNameSizes;
FILE *resF = fopen_utf8(resName.c_str(), "rb");
{
PortabilityLayer::ZipEndOfCentralDirectoryRecord eocd;
PortabilityLayer::CFileStream resStream(resF);
if (!resStream.SeekEnd(sizeof(PortabilityLayer::ZipEndOfCentralDirectoryRecord)) || !resStream.ReadExact(&eocd, sizeof(eocd)) || !resStream.SeekStart(eocd.m_centralDirStartOffset))
{
fprintf(stderr, "Error reading res data");
return -1;
}
size_t numResFiles = eocd.m_numCentralDirRecords;
for (size_t i = 0; i < numResFiles; i++)
{
PortabilityLayer::ZipCentralDirectoryFileHeader cdirFile;
if (!resStream.ReadExact(&cdirFile, sizeof(cdirFile)))
{
fprintf(stderr, "Error reading cdir entry");
return -1;
}
size_t fileNameLength = cdirFile.m_fileNameLength;
fileNameSizes.push_back(fileNameLength);
if (fileNameLength > 0)
{
fileNameBytes.resize(fileNameBytes.size() + fileNameLength);
if (!resStream.Read(&fileNameBytes[fileNameBytes.size() - fileNameLength], fileNameLength))
{
fprintf(stderr, "Error reading cdir entry");
return -1;
}
}
if (!resStream.SeekCurrent(cdirFile.m_extraFieldLength + cdirFile.m_commentLength))
{
fprintf(stderr, "Error reading cdir entry");
return -1;
}
resCentralDir.push_back(cdirFile);
numFiles++;
cdirSize += sizeof(PortabilityLayer::ZipCentralDirectoryFileHeader) + fileNameLength;
}
for (size_t i = 0; i < resCentralDir.size(); i++)
{
PortabilityLayer::ZipCentralDirectoryFileHeader &cdirHeader = resCentralDir[i];
PortabilityLayer::ZipFileLocalHeader resLH;
if (!resStream.SeekStart(cdirHeader.m_localHeaderOffset) || !resStream.ReadExact(&resLH, sizeof(resLH)) || resLH.m_fileNameLength != cdirHeader.m_fileNameLength || resLH.m_compressedSize != cdirHeader.m_compressedSize || resLH.m_uncompressedSize != cdirHeader.m_uncompressedSize)
{
fprintf(stderr, "Error reading res");
return -1;
}
size_t chunkSizes[] = { resLH.m_fileNameLength, resLH.m_extraFieldLength, resLH.m_compressedSize };
resLH.m_extraFieldLength = 0;
cdirHeader.m_localHeaderOffset = mergedStream.Tell();
cdirHeader.m_extraFieldLength = 0;
cdirHeader.m_commentLength = 0;
if (!mergedStream.WriteExact(&resLH, sizeof(resLH)))
{
fprintf(stderr, "Error copying resource header");
return -1;
}
for (int chunk = 0; chunk < 3; chunk++)
{
size_t chunkCopySize = chunkSizes[chunk];
if (chunk == 1)
{
// Strip extra field
if (!resStream.SeekCurrent(chunkCopySize))
{
fprintf(stderr, "Error copying resource");
return -1;
}
}
else
{
uint8_t copyBuffer[1024];
while (chunkCopySize > 0)
{
size_t amountToCopy = std::min(sizeof(copyBuffer), chunkCopySize);
if (!resStream.ReadExact(copyBuffer, amountToCopy) || !mergedStream.WriteExact(copyBuffer, amountToCopy))
{
fprintf(stderr, "Error copying resource");
return -1;
}
chunkCopySize -= amountToCopy;
}
}
}
}
resStream.Close();
}
GpUFilePos_t cdirPos = mergedStream.Tell();
// Write metadata cdir
if (!mergedStream.WriteExact(&metaCDir, sizeof(metaCDir)) || !mergedStream.WriteExact(metaPackagedName, strlen(metaPackagedName)))
{
fprintf(stderr, "Error writing directory");
return -1;
}
if (hasData)
{
if (!mergedStream.WriteExact(&dataCDir, sizeof(dataCDir)) || !mergedStream.WriteExact(dataPackagedName, strlen(dataPackagedName)))
{
fprintf(stderr, "Error writing directory");
return -1;
}
}
size_t fnameBytesOffset = 0;
for (size_t i = 0; i < resCentralDir.size(); i++)
{
size_t fnameSize = fileNameSizes[i];
const PortabilityLayer::ZipCentralDirectoryFileHeader &cdir = resCentralDir[i];
if (!mergedStream.WriteExact(&cdir, sizeof(cdir)) || (fnameSize > 0 && !mergedStream.WriteExact(&fileNameBytes[fnameBytesOffset], fnameSize)))
{
fprintf(stderr, "Error writing directory");
return -1;
}
fnameBytesOffset += fnameSize;
}
PortabilityLayer::ZipEndOfCentralDirectoryRecord eocd;
eocd.m_signature = PortabilityLayer::ZipEndOfCentralDirectoryRecord::kSignature;
eocd.m_thisDiskNumber = 0;
eocd.m_centralDirDisk = 0;
eocd.m_numCentralDirRecordsThisDisk = numFiles;
eocd.m_numCentralDirRecords = numFiles;
eocd.m_centralDirectorySizeBytes = mergedStream.Tell() - cdirPos;
eocd.m_centralDirStartOffset = cdirPos;
eocd.m_commentLength = 0;
if (!mergedStream.WriteExact(&eocd, sizeof(eocd)))
{
fprintf(stderr, "Error writing EOCD");
return -1;
}
mergedStream.Close();
return 0;
}

92
MergeGPF/MergeGPF.vcxproj Normal file
View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{36DAF5FA-6ADB-4F20-9810-1610DE0AE653}</ProjectGuid>
<RootNamespace>MergeGPF</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\WindowsUnicodeToolShim.props" />
<Import Project="..\PortabilityLayer.props" />
<Import Project="..\Common.props" />
<Import Project="..\Debug.props" />
<Import Project="..\GpCommon.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\WindowsUnicodeToolShim.props" />
<Import Project="..\PortabilityLayer.props" />
<Import Project="..\Common.props" />
<Import Project="..\Release.props" />
<Import Project="..\GpCommon.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\PortabilityLayer\PortabilityLayer.vcxproj">
<Project>{6ec62b0f-9353-40a4-a510-3788f1368b33}</Project>
</ProjectReference>
<ProjectReference Include="..\WindowsUnicodeToolShim\WindowsUnicodeToolShim.vcxproj">
<Project>{15009625-1120-405e-8bba-69a16cd6713d}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MergeGPF.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="MergeGPF.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -9,6 +9,7 @@
#include "MacBinary2.h"
#include "MacFileMem.h"
#include "WindowsUnicodeToolShim.h"
// Very simplified resource compiler
@@ -117,7 +118,7 @@ void DefError()
exit(-1);
}
int main(int argc, const char **argv)
int toolMain(int argc, const char **argv)
{
if (argc != 3)
{
@@ -125,8 +126,8 @@ int main(int argc, const char **argv)
return -1;
}
FILE *f = nullptr;
if (fopen_s(&f, argv[1], "rb"))
FILE *f = fopen_utf8(argv[1], "rb");
if (!f)
{
fprintf(stderr, "Failed to open input file");
return -1;
@@ -524,8 +525,8 @@ int main(int argc, const char **argv)
printf("Writing to %s...", argv[2]);
FILE *outF = nullptr;
if (fopen_s(&outF, argv[2], "wb"))
FILE *outF = fopen_utf8(argv[2], "wb");
if (!outF)
{
fprintf(stderr, "Failed to open output file");
return -1;

View File

@@ -41,6 +41,7 @@
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\Debug.props" />
<Import Project="..\WindowsUnicodeToolShim.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -48,6 +49,7 @@
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\Release.props" />
<Import Project="..\WindowsUnicodeToolShim.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
@@ -80,6 +82,9 @@
<ProjectReference Include="..\PortabilityLayer\PortabilityLayer.vcxproj">
<Project>{6ec62b0f-9353-40a4-a510-3788f1368b33}</Project>
</ProjectReference>
<ProjectReference Include="..\WindowsUnicodeToolShim\WindowsUnicodeToolShim.vcxproj">
<Project>{15009625-1120-405e-8bba-69a16cd6713d}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -29,12 +29,14 @@ LOCAL_SRC_FILES := \
EllipsePlotter.cpp \
FileBrowserUI.cpp \
FileManager.cpp \
FileSectionStream.cpp \
FontFamily.cpp \
FontManager.cpp \
FontRenderer.cpp \
GPArchive.cpp \
HostSuspendHook.cpp \
IconLoader.cpp \
InflateStream.cpp \
InputManager.cpp \
LinePlotter.cpp \
MacBinary2.cpp \

View File

@@ -70,12 +70,7 @@ namespace PortabilityLayer
if (!m_file)
return false;
return fseek(m_file, static_cast<long>(loc), SEEK_END) == 0;
}
bool CFileStream::Truncate(GpUFilePos_t loc)
{
return false;
return fseek(m_file, -static_cast<long>(loc), SEEK_END) == 0;
}
GpUFilePos_t CFileStream::Tell() const

View File

@@ -24,7 +24,6 @@ namespace PortabilityLayer
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;

View File

@@ -6,7 +6,7 @@ namespace PortabilityLayer
{
struct CombinedTimestamp
{
uint8_t m_utcTimestamp[8];
uint8_t m_macEpochTimestamp[8];
uint8_t m_localYear[4];
uint8_t m_localMonth;
@@ -18,26 +18,30 @@ namespace PortabilityLayer
uint8_t m_padding[3];
int64_t GetUTCTime() const;
void SetUTCTime(int64_t timestamp);
static const int32_t kMacEpochToUTC = 2082844800;
int64_t GetMacEpochTime() const;
void SetMacEpochTime(int64_t timestamp);
int32_t GetLocalYear() const;
void SetLocalYear(int32_t year);
void GetAsMSDOSTimestamp(uint16_t &msdosDate, uint16_t &msdosTime) const;
};
inline int64_t CombinedTimestamp::GetUTCTime() const
inline int64_t CombinedTimestamp::GetMacEpochTime() const
{
int64_t result = 0;
for (int i = 0; i < 8; i++)
result |= static_cast<int64_t>(m_utcTimestamp[i]) << (i * 8);
result |= static_cast<int64_t>(m_macEpochTimestamp[i]) << (i * 8);
return result;
}
void CombinedTimestamp::SetUTCTime(int64_t timestamp)
inline void CombinedTimestamp::SetMacEpochTime(int64_t timestamp)
{
for (int i = 0; i < 8; i++)
m_utcTimestamp[i] = static_cast<uint8_t>((timestamp >> (i * 8)) & 0xff);
m_macEpochTimestamp[i] = static_cast<uint8_t>((timestamp >> (i * 8)) & 0xff);
}
inline int32_t CombinedTimestamp::GetLocalYear() const
@@ -49,9 +53,45 @@ namespace PortabilityLayer
return result;
}
void CombinedTimestamp::SetLocalYear(int32_t timestamp)
inline void CombinedTimestamp::SetLocalYear(int32_t timestamp)
{
for (int i = 0; i < 4; i++)
m_localYear[i] = static_cast<uint8_t>((timestamp >> (i * 8)) & 0xff);
}
inline void CombinedTimestamp::GetAsMSDOSTimestamp(uint16_t &msdosDate, uint16_t &msdosTime) const
{
int32_t localYear = this->GetLocalYear();
uint8_t month = this->m_localMonth;
uint8_t day = this->m_localDay;
uint8_t hour = this->m_localHour;
uint8_t minute = this->m_localMinute;
uint8_t second = this->m_localSecond;
int32_t yearsSince1980 = localYear - 1980;
if (localYear < 1980)
{
// Time machine
yearsSince1980 = 0;
second = 0;
minute = 0;
hour = 0;
day = 1;
month = 1;
}
else if (localYear > 1980 + 127)
{
yearsSince1980 = 127;
second = 59;
minute = 59;
hour = 23;
day = 31;
month = 12;
}
msdosTime = (second / 2) | (minute << 5) | (hour << 11);
msdosDate = day | (month << 5) | (yearsSince1980 << 9);
}
}

View File

@@ -109,6 +109,32 @@ namespace PortabilityLayer
uint8_t m_flushBuffer[1024];
};
class InflateContextImpl final : public InflateContext
{
public:
static InflateContext *Create();
void Destroy() override;
bool Append(const void *buffer, size_t size, size_t &sizeConsumed) override;
bool Read(void *buffer, size_t size, size_t &sizeRead) override;
bool Reset() override;
bool Init();
private:
InflateContextImpl();
~InflateContextImpl();
bool m_streamInitialized;
bool m_isEndOfStream;
z_stream m_zStream;
uint8_t m_flushBuffer[1024];
const uint8_t *m_readPos;
};
}
PortabilityLayer::DeflateContextImpl::DeflateContextImpl(GpIOStream *stream, int compressionLevel)
@@ -197,6 +223,131 @@ bool PortabilityLayer::DeflateContextImpl::Flush()
}
PortabilityLayer::InflateContext *PortabilityLayer::InflateContextImpl::Create()
{
void *storage = PortabilityLayer::MemoryManager::GetInstance()->Alloc(sizeof(PortabilityLayer::InflateContextImpl));
if (!storage)
return nullptr;
InflateContextImpl *obj = new (storage) InflateContextImpl();
if (!obj->Init())
{
obj->Destroy();
return nullptr;
}
return obj;
}
void PortabilityLayer::InflateContextImpl::Destroy()
{
this->~InflateContextImpl();
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
bool PortabilityLayer::InflateContextImpl::Append(const void *buffer, size_t size, size_t &sizeConsumed)
{
size_t consumed = 0;
m_zStream.avail_in = size;
m_zStream.next_in = static_cast<Bytef*>(const_cast<void*>(buffer));
for (;;)
{
if (m_isEndOfStream)
{
m_zStream.avail_in = 0;
m_zStream.next_in = nullptr;
}
if (m_zStream.avail_in == 0 || m_zStream.avail_out == 0)
{
sizeConsumed = consumed;
return true;
}
size_t lastAvailIn = m_zStream.avail_in;
int result = inflate(&m_zStream, Z_NO_FLUSH);
if (result == Z_STREAM_END)
m_isEndOfStream = true;
else if (result != Z_OK)
return false;
consumed += lastAvailIn - m_zStream.avail_in;
}
}
bool PortabilityLayer::InflateContextImpl::Read(void *buffer, size_t size, size_t &sizeRead)
{
size_t amountInOutputBuffer = static_cast<const uint8_t*>(m_zStream.next_out) - m_readPos;
if (size > amountInOutputBuffer)
size = amountInOutputBuffer;
if (size > 0)
{
if (buffer)
memcpy(buffer, m_readPos, size);
m_readPos += size;
if (m_readPos == m_zStream.next_out)
{
m_zStream.avail_out = sizeof(m_flushBuffer);
m_zStream.next_out = m_flushBuffer;
m_readPos = m_flushBuffer;
}
}
sizeRead = size;
return true;
}
bool PortabilityLayer::InflateContextImpl::Reset()
{
if (inflateReset2(&m_zStream, -15) != Z_OK)
return false;
m_isEndOfStream = false;
m_zStream.avail_out = sizeof(m_flushBuffer);
m_zStream.next_out = m_flushBuffer;
m_readPos = m_flushBuffer;
return true;
}
bool PortabilityLayer::InflateContextImpl::Init()
{
m_zStream.zalloc = ZlibAllocShim;
m_zStream.zfree = ZlibFreeShim;
m_zStream.opaque = MemoryManager::GetInstance();
if (inflateInit2(&m_zStream, -15) != Z_OK)
return false;
m_zStream.next_out = m_flushBuffer;
m_zStream.avail_out = sizeof(m_flushBuffer);
m_streamInitialized = true;
return true;
}
PortabilityLayer::InflateContextImpl::InflateContextImpl()
: m_streamInitialized(false)
, m_isEndOfStream(false)
, m_readPos(m_flushBuffer)
{
memset(&m_zStream, 0, sizeof(m_zStream));
}
PortabilityLayer::InflateContextImpl::~InflateContextImpl()
{
if (m_streamInitialized)
inflateEnd(&m_zStream);
}
PortabilityLayer::DeflateContext *PortabilityLayer::DeflateContext::Create(GpIOStream *stream, int compressionLevel)
{
void *storage = PortabilityLayer::MemoryManager::GetInstance()->Alloc(sizeof(PortabilityLayer::DeflateContextImpl));
@@ -217,3 +368,9 @@ uint32_t PortabilityLayer::DeflateContext::CRC32(uint32_t inputValue, const void
{
return crc32(inputValue, static_cast<const Bytef*>(buffer), bufferLength);
}
PortabilityLayer::InflateContext *PortabilityLayer::InflateContext::Create()
{
return InflateContextImpl::Create();
}

View File

@@ -19,6 +19,19 @@ namespace PortabilityLayer
static uint32_t CRC32(uint32_t inputValue, const void *buffer, size_t bufferLength);
};
class InflateContext
{
public:
static InflateContext *Create();
virtual void Destroy() = 0;
virtual bool Append(const void *buffer, size_t size, size_t &sizeConsumed) = 0;
virtual bool Read(void *buffer, size_t size, size_t &sizeRead) = 0;
virtual bool Reset() = 0;
};
class DeflateCodec
{
public:

View File

@@ -565,8 +565,10 @@ namespace PortabilityLayer
return hit;
}
bool FileBrowserUI::Prompt(Mode mode, VirtualDirectory_t dirID, const ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &callbackAPI)
bool FileBrowserUI::Prompt(Mode mode, 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)
{
size_t extensionLength = strlen(extension);
int dialogID = 0;
bool isObstructive = false;
int windowHeight = 272;
@@ -603,35 +605,18 @@ namespace PortabilityLayer
{
size_t nameLength = strlen(fileName);
if (nameLength < 4)
if (nameLength < extensionLength)
continue;
const char *nameExt = fileName + (nameLength - 4);
const char *nameExt = fileName + (nameLength - extensionLength);
if (!memcmp(nameExt, ".gpf", 4))
if (!memcmp(nameExt, extension, extensionLength))
{
GpIOStream *metadataStream = fs->OpenFile(dirID, fileName, false, GpFileCreationDispositions::kOpenExisting);
if (!metadataStream)
PLPasStr fnamePStr = PLPasStr(nameLength - extensionLength, fileName);
if (!callbackAPI.m_filterFileCallback(dirID, fnamePStr))
continue;
MacFilePropertiesSerialized serializedMetadata;
if (metadataStream->Read(&serializedMetadata, sizeof(serializedMetadata)) != sizeof(serializedMetadata))
{
metadataStream->Close();
continue;
}
metadataStream->Close();
MacFileProperties metadata;
serializedMetadata.Deserialize(metadata);
char ftype[4];
fileType.ExportAsChars(ftype);
if (memcmp(metadata.m_fileType, ftype, 4))
continue;
if (!uiImpl.AppendName(fileName, nameLength - 4, callbackAPI.m_loadFileDetailsCallback(dirID, PLPasStr(nameLength - 4, fileName))))
if (!uiImpl.AppendName(fileName, nameLength - extensionLength, callbackAPI.m_loadFileDetailsCallback(dirID, fnamePStr)))
{
dirCursor->Destroy();
return false;
@@ -742,15 +727,24 @@ namespace PortabilityLayer
FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIBadNameDialogTemplateID, nullptr);
hit = -1;
}
else if (PortabilityLayer::FileManager::GetInstance()->FileExists(dirID, nameStr))
else
{
DialogTextSubstitutions substitutions(nameStr);
bool fileExists = false;
if (composites)
fileExists = PortabilityLayer::FileManager::GetInstance()->CompositeFileExists(dirID, nameStr);
else
fileExists = PortabilityLayer::FileManager::GetInstance()->NonCompositeFileExists(dirID, nameStr, extension);
PLDrivers::GetSystemServices()->Beep();
int16_t subHit = FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIOverwriteDialogTemplateID, &substitutions);
if (fileExists)
{
DialogTextSubstitutions substitutions(nameStr);
if (subHit == kOverwriteNoButton)
hit = -1;
PLDrivers::GetSystemServices()->Beep();
int16_t subHit = FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIOverwriteDialogTemplateID, &substitutions);
if (subHit == kOverwriteNoButton)
hit = -1;
}
}
}
@@ -763,7 +757,11 @@ namespace PortabilityLayer
{
PLPasStr uiFileName = uiImpl.GetSelectedFileName();
PortabilityLayer::FileManager::GetInstance()->DeleteFile(dirID, uiFileName);
if (composites)
PortabilityLayer::FileManager::GetInstance()->DeleteCompositeFile(dirID, uiFileName);
else
PortabilityLayer::FileManager::GetInstance()->DeleteNonCompositeFile(dirID, uiFileName, extension);
uiImpl.RemoveSelectedFile();
dialog->GetItems()[kOkayButton - 1].GetWidget()->SetEnabled(false);
dialog->GetItems()[kDeleteButton - 1].GetWidget()->SetEnabled(false);

View File

@@ -20,6 +20,7 @@ namespace PortabilityLayer
void *(*m_loadFileDetailsCallback)(VirtualDirectory_t dirID, const PLPasStr &filename);
void(*m_freeFileDetailsCallback)(void *fileDetails);
bool(*m_filterFileCallback)(VirtualDirectory_t dirID, const PLPasStr &filename);
};
class FileBrowserUI
@@ -32,6 +33,6 @@ namespace PortabilityLayer
Mode_Open,
};
static bool Prompt(Mode mode, VirtualDirectory_t dirID, const ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &callbackAPI);
static bool Prompt(Mode mode, 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);
};
}

View File

@@ -1,5 +1,6 @@
#include "FileManager.h"
#include "CombinedTimestamp.h"
#include "FileBrowserUI.h"
#include "IGpFileSystem.h"
#include "IGpSystemServices.h"
@@ -7,6 +8,7 @@
#include "MacBinary2.h"
#include "MacFileMem.h"
#include "ResTypeID.h"
#include "ZipFileProxy.h"
#include "PLDrivers.h"
#include "PLPasStr.h"
@@ -18,68 +20,188 @@
namespace PortabilityLayer
{
class VirtualFile;
class CompositeFileImpl;
typedef char ExtendedFileName_t[64 + 4];
namespace FileManagerTools
{
bool ConstructFilename(ExtendedFileName_t& extFN, const PLPasStr &fn, const char *extension);
};
class FileManagerImpl final : public FileManager
{
public:
bool FileExists(VirtualDirectory_t dirID, const PLPasStr &filename) override;
bool FileLocked(VirtualDirectory_t dirID, const PLPasStr &filename) override;
bool DeleteFile(VirtualDirectory_t dirID, const PLPasStr &filename) override;
CompositeFile *OpenCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename) override;
PLError_t OpenNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *extension, EFilePermission filePermission, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override;
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;
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 OpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, GpIOStream *&outRefNum) override;
PLError_t OpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, GpIOStream *&outRefNum) override;
bool ReadFileProperties(VirtualDirectory_t dirID, const PLPasStr &filename, MacFileProperties &properties) 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 ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) override;
bool PromptOpenFile(VirtualDirectory_t dirID, const ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, 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) 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;
static FileManagerImpl *GetInstance();
private:
typedef char ExtendedFileName_t[64 + 4];
PLError_t OpenFileFork(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext, EFilePermission permission, GpIOStream *&outRefNum);
PLError_t RawOpenFileFork(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext, EFilePermission permission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream);
static bool ConstructFilename(ExtendedFileName_t& extFN, const PLPasStr &fn, const char *extension);
static FileManagerImpl ms_instance;
};
bool FileManagerImpl::FileExists(VirtualDirectory_t dirID, const PLPasStr &filename)
class CompositeFileImpl final : public CompositeFile
{
public:
PLError_t OpenData(EFilePermission filePermission, GpFileCreationDisposition_t disposition, GpIOStream *&outStream) override;
PLError_t OpenResources(GpIOStream *&outStream, ZipFileProxy *&outProxy, bool &outIsProxyShared) override;
const MacFileProperties &GetProperties() const override;
VirtualDirectory_t GetDirectory() const override;
PLPasStr GetFileName() const override;
bool IsDataReadOnly() const override;
void Close() override;
static CompositeFileImpl *Create(VirtualDirectory_t dirID, const PLPasStr &filename, GpIOStream *stream, ZipFileProxy *zipFile, const MacFileProperties &mfp, bool resInline, bool dataInline, size_t inlineDataIndex);
private:
CompositeFileImpl(VirtualDirectory_t dirID, const PLPasStr &filename, GpIOStream *stream, ZipFileProxy *zipFile, const MacFileProperties &mfp, bool resInline, bool dataInline, size_t inlineDataIndex);
~CompositeFileImpl();
VirtualDirectory_t m_dirID;
PascalStr<255> m_filename;
GpIOStream *m_stream;
ZipFileProxy *m_zipFile;
MacFileProperties m_mfp;
size_t m_inlineDataIndex;
bool m_resInline;
bool m_dataInline;
};
CompositeFile *FileManagerImpl::OpenCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename)
{
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, filename, ".gpf"))
if (!FileManagerTools::ConstructFilename(extFN, filename, ".gpf"))
return nullptr;
GpIOStream *stream = PLDrivers::GetFileSystem()->OpenFile(dirID, extFN, false, GpFileCreationDispositions::kOpenExisting);
if (!stream)
return nullptr;
ZipFileProxy *zipFile = ZipFileProxy::Create(stream);
if (!zipFile)
{
stream->Close();
return nullptr;
}
size_t metaIndex = 0;
if (!zipFile->IndexFile("!!meta", metaIndex))
{
stream->Close();
return nullptr;
}
MacFilePropertiesSerialized mfps;
GpIOStream *metaStream = zipFile->OpenFile(metaIndex);
if (!metaStream)
{
zipFile->Destroy();
stream->Close();
return nullptr;
}
if (!metaStream->ReadExact(mfps.m_data, sizeof(mfps.m_data)))
{
metaStream->Close();
zipFile->Destroy();
stream->Close();
return nullptr;
}
metaStream->Close();
MacFileProperties mfp;
mfps.Deserialize(mfp);
size_t dataIndex = 0;
bool hasData = zipFile->IndexFile("!data", dataIndex);
size_t nonResFiles = 1 + (hasData ? 1 : 0);
bool hasResources = (zipFile->NumFiles() > nonResFiles);
if (!hasData && !hasResources)
{
zipFile->Destroy();
zipFile = nullptr;
stream->Close();
stream = nullptr;
}
CompositeFile *compositeFile = CompositeFileImpl::Create(dirID, filename, stream, zipFile, mfp, hasResources, hasData, hasData ? dataIndex : 0);
if (!compositeFile)
{
if (zipFile)
zipFile->Destroy();
if (stream)
stream->Close();
return nullptr;
}
return compositeFile;
}
PLError_t FileManagerImpl::OpenNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *extension, EFilePermission filePermission, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream)
{
return RawOpenFileFork(dirID, filename, extension, filePermission, true, creationDisposition, outStream);
}
bool FileManagerImpl::NonCompositeFileExists(VirtualDirectory_t dirID, const PLPasStr &filename, const char *extension)
{
ExtendedFileName_t extFN;
if (!FileManagerTools::ConstructFilename(extFN, filename, extension))
return false;
return PLDrivers::GetFileSystem()->FileExists(dirID, extFN);
}
bool FileManagerImpl::FileLocked(VirtualDirectory_t dirID, const PLPasStr &filename)
bool FileManagerImpl::CompositeFileExists(VirtualDirectory_t dirID, const PLPasStr &filename)
{
const char *exts[3] = { ".gpf", ".gpa", ".gpd" };
for (int extIndex = 0; extIndex < sizeof(exts) / sizeof(exts[0]); extIndex++)
{
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, filename, exts[extIndex]))
return true;
bool exists = false;
if (PLDrivers::GetFileSystem()->FileLocked(dirID, extFN, &exists) && exists)
return true;
}
return false;
return NonCompositeFileExists(dirID, filename, ".gpf");
}
bool FileManagerImpl::DeleteFile(VirtualDirectory_t dirID, const PLPasStr &filename)
bool FileManagerImpl::DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext)
{
ExtendedFileName_t extFN;
if (!FileManagerTools::ConstructFilename(extFN, filename, ext))
return true;
bool existed = false;
if (!PLDrivers::GetFileSystem()->DeleteFile(dirID, extFN, existed))
{
if (!existed)
return false;
}
return true;
}
bool FileManagerImpl::DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename)
{
const size_t numExts = 3;
@@ -89,7 +211,7 @@ namespace PortabilityLayer
for (int extIndex = 0; extIndex < numExts; extIndex++)
{
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, filename, exts[extIndex]))
if (!FileManagerTools::ConstructFilename(extFN, filename, exts[extIndex]))
return true;
bool existed = false;
@@ -111,7 +233,7 @@ namespace PortabilityLayer
serialized.Serialize(mfp);
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, filename, ".gpf"))
if (!FileManagerTools::ConstructFilename(extFN, filename, ".gpf"))
return PLErrors::kBadFileName;
GpIOStream *stream = nullptr;
@@ -119,7 +241,9 @@ namespace PortabilityLayer
if (err)
return err;
if (stream->Write(serialized.m_data, sizeof(serialized.m_data)) != sizeof(serialized.m_data))
CombinedTimestamp ts;
if (!serialized.WriteAsPackage(*stream, ts))
{
stream->Close();
return PLErrors::kIOError;
@@ -135,38 +259,11 @@ namespace PortabilityLayer
MacFileProperties mfp;
fileCreator.ExportAsChars(mfp.m_fileCreator);
fileType.ExportAsChars(mfp.m_fileType);
mfp.m_creationDate = mfp.m_modifiedDate = PLDrivers::GetSystemServices()->GetTime();
mfp.m_createdTimeMacEpoch = mfp.m_modifiedTimeMacEpoch = PLDrivers::GetSystemServices()->GetTime();
return CreateFile(dirID, filename, mfp);
}
PLError_t FileManagerImpl::OpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission permission, GpIOStream *&outStream)
{
return OpenFileFork(dirID, filename, ".gpd", permission, outStream);
}
PLError_t FileManagerImpl::OpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission permission, GpIOStream *&outStream)
{
return OpenFileFork(dirID, filename, ".gpa", permission, outStream);
}
bool FileManagerImpl::ReadFileProperties(VirtualDirectory_t dirID, const PLPasStr &filename, MacFileProperties &properties)
{
GpIOStream *stream = nullptr;
PLError_t err = RawOpenFileFork(dirID, filename, ".gpf", EFilePermission_Read, true, GpFileCreationDispositions::kOpenExisting, stream);
if (err)
return false;
MacFilePropertiesSerialized serialized;
bool readOk = (stream->Read(serialized.m_data, MacFilePropertiesSerialized::kSize) == MacFilePropertiesSerialized::kSize);
stream->Close();
if (readOk)
serialized.Deserialize(properties);
return readOk;
}
PLError_t FileManagerImpl::RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission permission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream)
{
return RawOpenFileFork(dirID, filename, ".gpd", permission, ignoreMeta, createDisposition, outStream);
@@ -177,18 +274,18 @@ namespace PortabilityLayer
return RawOpenFileFork(dirID, filename, ".gpa", permission, ignoreMeta, createDisposition, outStream);
}
bool FileManagerImpl::PromptSaveFile(VirtualDirectory_t dirID, const ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &detailsAPI)
bool FileManagerImpl::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 &detailsAPI)
{
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, initialFileName, ""))
if (!FileManagerTools::ConstructFilename(extFN, initialFileName, ""))
return false;
return FileBrowserUI::Prompt(FileBrowserUI::Mode_Save, dirID, fileType, path, outPathLength, pathCapacity, initialFileName, promptText, detailsAPI);
return FileBrowserUI::Prompt(FileBrowserUI::Mode_Save, dirID, extension, path, outPathLength, pathCapacity, initialFileName, promptText, composites, detailsAPI);
}
bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, const ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &detailsAPI)
bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &detailsAPI)
{
return FileBrowserUI::Prompt(FileBrowserUI::Mode_Open, dirID, fileType, path, outPathLength, pathCapacity, PSTR(""), promptText, detailsAPI);
return FileBrowserUI::Prompt(FileBrowserUI::Mode_Open, dirID, extension, path, outPathLength, pathCapacity, PSTR(""), promptText, composites, detailsAPI);
}
FileManagerImpl *FileManagerImpl::GetInstance()
@@ -220,14 +317,14 @@ namespace PortabilityLayer
if (!ignoreMeta)
{
if (!ConstructFilename(gpfExtFN, filename, ".gpf"))
if (!FileManagerTools::ConstructFilename(gpfExtFN, filename, ".gpf"))
return PLErrors::kBadFileName;
if (!PLDrivers::GetFileSystem()->FileExists(dirID, gpfExtFN))
return PLErrors::kFileNotFound;
}
if (!ConstructFilename(extFN, filename, ext))
if (!FileManagerTools::ConstructFilename(extFN, filename, ext))
return PLErrors::kBadFileName;
GpIOStream *fstream = nullptr;
@@ -253,19 +350,37 @@ namespace PortabilityLayer
}
if (!fstream)
{
if (ignoreMeta)
{
if (!PLDrivers::GetFileSystem()->FileExists(dirID, extFN))
return PLErrors::kFileNotFound;
}
return PLErrors::kAccessDenied;
}
outStream = fstream;
return PLErrors::kNone;
}
bool FileManagerImpl::ConstructFilename(ExtendedFileName_t &extFN, const PLPasStr &fn, const char *extension)
FileManagerImpl FileManagerImpl::ms_instance;
FileManager *FileManager::GetInstance()
{
return FileManagerImpl::GetInstance();
}
bool FileManagerTools::ConstructFilename(ExtendedFileName_t &extFN, const PLPasStr &fn, const char *extension)
{
const size_t fnameSize = fn.Length();
if (fnameSize >= 64)
return false;
assert(strlen(extension) <= 4);
memcpy(extFN, fn.Chars(), fnameSize);
memcpy(extFN + fnameSize, extension, strlen(extension) + 1);
@@ -275,10 +390,119 @@ namespace PortabilityLayer
return true;
}
FileManagerImpl FileManagerImpl::ms_instance;
FileManager *FileManager::GetInstance()
// ==========================================================================
PLError_t CompositeFileImpl::OpenData(EFilePermission filePermission, GpFileCreationDisposition_t disposition, GpIOStream *&outStream)
{
return FileManagerImpl::GetInstance();
if (m_dataInline)
{
if (filePermission == EFilePermission_Any || filePermission == EFilePermission_Read)
{
GpIOStream *stream = m_zipFile->OpenFile(m_inlineDataIndex);
if (!stream)
return PLErrors::kIOError;
outStream = stream;
return PLErrors::kNone;
}
else
return PLErrors::kAccessDenied;
}
else
return FileManager::GetInstance()->RawOpenFileData(m_dirID, m_filename.ToShortStr(), filePermission, true, disposition, outStream);
}
PLError_t CompositeFileImpl::OpenResources(GpIOStream *&outStream, ZipFileProxy *&outProxy, bool &outIsProxyShared)
{
if (m_resInline)
{
outStream = nullptr;
outProxy = m_zipFile;
outIsProxyShared = true;
return PLErrors::kNone;
}
else
{
GpIOStream *stream = nullptr;
PLError_t err = FileManager::GetInstance()->RawOpenFileResources(m_dirID, m_filename.ToShortStr(), EFilePermission_Read, true, GpFileCreationDispositions::kOpenExisting, stream);
if (err != PLErrors::kNone)
return err;
ZipFileProxy *proxy = ZipFileProxy::Create(stream);
if (!proxy)
{
stream->Close();
return PLErrors::kIOError;
}
outStream = stream;
outProxy = proxy;
outIsProxyShared = false;
return PLErrors::kNone;
}
}
const MacFileProperties &CompositeFileImpl::GetProperties() const
{
return m_mfp;
}
VirtualDirectory_t CompositeFileImpl::GetDirectory() const
{
return m_dirID;
}
PLPasStr CompositeFileImpl::GetFileName() const
{
return m_filename.ToShortStr();
}
bool CompositeFileImpl::IsDataReadOnly() const
{
if (m_dataInline)
return true;
ExtendedFileName_t extFN;
if (!FileManagerTools::ConstructFilename(extFN, m_filename.ToShortStr(), ".gpd"))
return false;
bool exists = false;
return PLDrivers::GetFileSystem()->FileLocked(m_dirID, extFN, exists);
}
void CompositeFileImpl::Close()
{
this->~CompositeFileImpl();
free(this);
}
CompositeFileImpl *CompositeFileImpl::Create(VirtualDirectory_t dirID, const PLPasStr &filename, GpIOStream *stream, ZipFileProxy *zipFile, const MacFileProperties &mfp, bool resInline, bool dataInline, size_t inlineDataIndex)
{
void *storage = malloc(sizeof(CompositeFileImpl));
if (!storage)
return nullptr;
return new (storage) CompositeFileImpl(dirID, filename, stream, zipFile, mfp, resInline, dataInline, inlineDataIndex);
}
CompositeFileImpl::CompositeFileImpl(VirtualDirectory_t dirID, const PLPasStr &filename, GpIOStream *stream, ZipFileProxy *zipFile, const MacFileProperties &mfp, bool resInline, bool dataInline, size_t inlineDataIndex)
: m_dirID(dirID)
, m_filename(filename)
, m_stream(stream)
, m_zipFile(zipFile)
, m_mfp(mfp)
, m_resInline(resInline)
, m_dataInline(dataInline)
, m_inlineDataIndex(inlineDataIndex)
{
}
CompositeFileImpl::~CompositeFileImpl()
{
if (m_zipFile)
m_zipFile->Destroy();
if (m_stream)
m_stream->Close();
}
}

View File

@@ -17,27 +17,46 @@ namespace PortabilityLayer
class ResTypeID;
struct MacFileProperties;
struct FileBrowserUI_DetailsCallbackAPI;
class ZipFileProxy;
class CompositeFile
{
public:
virtual PLError_t OpenData(EFilePermission filePermission, GpFileCreationDisposition_t disposition, GpIOStream *&outStream) = 0;
virtual PLError_t OpenResources(GpIOStream *&outStream, ZipFileProxy *&outProxy, bool &outIsProxyShared) = 0;
virtual const MacFileProperties &GetProperties() const = 0;
virtual VirtualDirectory_t GetDirectory() const = 0;
virtual PLPasStr GetFileName() const = 0;
virtual bool IsDataReadOnly() const = 0;
virtual void Close() = 0;
protected:
inline CompositeFile() {}
inline ~CompositeFile() {}
};
class FileManager
{
public:
virtual bool FileExists(VirtualDirectory_t dirID, const PLPasStr &filename) = 0;
virtual bool FileLocked(VirtualDirectory_t dirID, const PLPasStr &filename) = 0;
virtual bool DeleteFile(VirtualDirectory_t dirID, const PLPasStr &filename) = 0;
virtual CompositeFile *OpenCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename) = 0;
virtual PLError_t OpenNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *extension, EFilePermission filePermission, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) = 0;
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;
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;
// OpenFileData + OpenFileResources require that the file already exists (i.e. has a .gpf), but the fork may not
virtual PLError_t OpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, GpIOStream *&outStream) = 0;
virtual PLError_t OpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, GpIOStream *&outStream) = 0;
virtual bool ReadFileProperties(VirtualDirectory_t dirID, const PLPasStr &filename, MacFileProperties &properties) = 0;
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 ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) = 0;
virtual bool PromptOpenFile(VirtualDirectory_t dirID, const ResTypeID &fileType, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) = 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;
static FileManager *GetInstance();
};

View File

@@ -0,0 +1,171 @@
#include "FileSectionStream.h"
#include <stdlib.h>
#include <new>
namespace PortabilityLayer
{
class FileSectionStreamImpl final : public GpIOStream
{
public:
FileSectionStreamImpl(GpIOStream *stream, GpUFilePos_t start, GpUFilePos_t size);
~FileSectionStreamImpl();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
GpIOStream *m_stream;
GpUFilePos_t m_start;
GpUFilePos_t m_size;
GpUFilePos_t m_expectedPosition;
bool m_isSeekable;
};
FileSectionStreamImpl::FileSectionStreamImpl(GpIOStream *stream, GpUFilePos_t start, GpUFilePos_t size)
: m_stream(stream)
, m_start(start)
, m_size(size)
, m_expectedPosition(start)
, m_isSeekable(stream->IsSeekable())
{
}
FileSectionStreamImpl::~FileSectionStreamImpl()
{
}
size_t FileSectionStreamImpl::Read(void *bytesOut, size_t size)
{
if (m_stream->Tell() != m_expectedPosition)
{
if (!m_stream->SeekStart(m_expectedPosition))
return 0;
}
GpUFilePos_t localPos = m_expectedPosition - m_start;
GpUFilePos_t availableBytes = m_size - localPos;
if (size > availableBytes)
size = static_cast<size_t>(availableBytes);
const size_t actuallyRead = m_stream->Read(bytesOut, size);
m_expectedPosition += actuallyRead;
return actuallyRead;
}
size_t FileSectionStreamImpl::Write(const void *bytes, size_t size)
{
return 0;
}
bool FileSectionStreamImpl::IsSeekable() const
{
return m_isSeekable;
}
bool FileSectionStreamImpl::IsReadOnly() const
{
return true;
}
bool FileSectionStreamImpl::IsWriteOnly() const
{
return false;
}
bool FileSectionStreamImpl::SeekStart(GpUFilePos_t loc)
{
if (loc == m_expectedPosition - m_start)
return true;
if (!m_isSeekable)
return false;
if (loc >= m_size)
return false;
else
{
m_expectedPosition = m_start + loc;
return true;
}
}
bool FileSectionStreamImpl::SeekCurrent(GpFilePos_t loc)
{
GpUFilePos_t localPos = m_expectedPosition - m_start;
if (loc < 0)
{
GpUFilePos_t negativePos = static_cast<GpUFilePos_t>(-loc);
if (negativePos > localPos)
return false;
m_expectedPosition -= negativePos;
return true;
}
else if (loc > 0)
{
GpUFilePos_t positivePos = static_cast<GpUFilePos_t>(loc);
if (m_size - localPos < positivePos)
return false;
m_expectedPosition += positivePos;
return true;
}
else
return true;
}
bool FileSectionStreamImpl::SeekEnd(GpUFilePos_t loc)
{
if (loc > m_size)
return false;
m_expectedPosition = m_start + (m_size - loc);
return true;
}
GpUFilePos_t FileSectionStreamImpl::Size() const
{
return m_size;
}
GpUFilePos_t FileSectionStreamImpl::Tell() const
{
return m_expectedPosition - m_start;
}
void FileSectionStreamImpl::Close()
{
this->~FileSectionStreamImpl();
free(this);
}
void FileSectionStreamImpl::Flush()
{
m_stream->Flush();
}
GpIOStream *FileSectionStream::Create(GpIOStream *stream, GpUFilePos_t start, GpUFilePos_t size)
{
void *storage = malloc(sizeof(FileSectionStreamImpl));
if (!storage)
return nullptr;
return new (storage) FileSectionStreamImpl(stream, start, size);
}
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "GpIOStream.h"
namespace PortabilityLayer
{
namespace FileSectionStream
{
GpIOStream *Create(GpIOStream *stream, GpUFilePos_t start, GpUFilePos_t size);
};
}

View File

@@ -29,7 +29,6 @@ namespace PortabilityLayer
FontFamily *GetHandwritingFont(int textSize, int variationFlags) const override;
FontFamily *GetMonospaceFont(int textSize, int variationFlags) const override;
RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) override;
RenderedFont *GetRenderedFontFromFamily(FontFamily *font, int size, bool aa, int flags) override;
RenderedFont *LoadCachedRenderedFont(int cacheID, int size, bool aa, int flags) const override;
@@ -51,7 +50,7 @@ namespace PortabilityLayer
struct CachedRenderedFont
{
RenderedFont *m_rfont;
const IGpFont *m_font;
int m_fontCacheID;
int m_size;
uint32_t m_lastUsage;
bool m_aa;
@@ -59,6 +58,9 @@ namespace PortabilityLayer
FontManagerImpl();
bool FindOrReserveCacheSlot(int cacheID, int size, bool aa, CachedRenderedFont *&outCacheSlot, RenderedFont *&outRF);
void ReplaceCachedRenderedFont(CachedRenderedFont &cacheSlot, RenderedFont *rfont, int cacheID, int size, bool aa, int flags);
void ResetUsageCounter();
static int CRFSortPredicate(const void *a, const void *b);
@@ -147,7 +149,7 @@ namespace PortabilityLayer
return m_monospaceFont;
}
RenderedFont *FontManagerImpl::GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks)
bool FontManagerImpl::FindOrReserveCacheSlot(int cacheID, int size, bool aa, CachedRenderedFont *&outCacheSlot, RenderedFont *&outRF)
{
CachedRenderedFont *newCacheSlot = &m_cachedRenderedFonts[0];
@@ -160,7 +162,7 @@ namespace PortabilityLayer
break;
}
if (crf.m_font == font && crf.m_size == size && crf.m_aa == aa)
if (crf.m_fontCacheID == cacheID && crf.m_size == size && crf.m_aa == aa)
{
crf.m_lastUsage = m_usageCounter;
RenderedFont *rf = crf.m_rfont;
@@ -169,52 +171,70 @@ namespace PortabilityLayer
else
m_usageCounter++;
return rf;
outRF = rf;
return true;
}
if (newCacheSlot->m_rfont != nullptr && crf.m_lastUsage < newCacheSlot->m_lastUsage)
newCacheSlot = &crf;
}
RenderedFont *rfont = FontRenderer::GetInstance()->RenderFont(font, size, aa, fontHacks);
if (!rfont)
return nullptr;
outCacheSlot = newCacheSlot;
return false;
}
if (newCacheSlot->m_rfont)
newCacheSlot->m_rfont->Destroy();
void FontManagerImpl::ReplaceCachedRenderedFont(CachedRenderedFont &cacheSlot, RenderedFont *rfont, int cacheID, int size, bool aa, int flags)
{
if (cacheSlot.m_rfont)
cacheSlot.m_rfont->Destroy();
newCacheSlot->m_font = font;
newCacheSlot->m_lastUsage = m_usageCounter;
newCacheSlot->m_size = size;
newCacheSlot->m_rfont = rfont;
newCacheSlot->m_aa = aa;
cacheSlot.m_fontCacheID = cacheID;
cacheSlot.m_lastUsage = m_usageCounter;
cacheSlot.m_size = size;
cacheSlot.m_rfont = rfont;
cacheSlot.m_aa = aa;
if (m_usageCounter == UINT32_MAX)
ResetUsageCounter();
else
m_usageCounter++;
return rfont;
}
RenderedFont *FontManagerImpl::GetRenderedFontFromFamily(FontFamily *fontFamily, int size, bool aa, int flags)
{
PortabilityLayer::FontManager *fm = PortabilityLayer::FontManager::GetInstance();
RenderedFont *rfont = fm->LoadCachedRenderedFont(fontFamily->GetCacheID(), size, aa, flags);
if (rfont)
RenderedFont *rfont = nullptr;
CachedRenderedFont *cacheSlot = nullptr;
int cacheID = fontFamily->GetCacheID();
if (this->FindOrReserveCacheSlot(cacheID, size, aa, cacheSlot, rfont))
return rfont;
rfont = fm->LoadCachedRenderedFont(cacheID, size, aa, flags);
if (rfont)
{
ReplaceCachedRenderedFont(*cacheSlot, rfont, cacheID, size, aa, flags);
return rfont;
}
const int variation = fontFamily->GetVariationForFlags(flags);
IGpFont *hostFont = fontFamily->GetFontForVariation(variation);
if (!hostFont)
return nullptr;
rfont = fm->GetRenderedFont(hostFont, size, aa, fontFamily->GetHacksForVariation(variation));
rfont = FontRenderer::GetInstance()->RenderFont(hostFont, size, aa, fontFamily->GetHacksForVariation(variation));
if (rfont)
{
fm->SaveCachedRenderedFont(rfont, fontFamily->GetCacheID(), size, aa, flags);
ReplaceCachedRenderedFont(*cacheSlot, rfont, cacheID, size, aa, flags);
return rfont;
}
return rfont;
}

View File

@@ -20,7 +20,6 @@ namespace PortabilityLayer
virtual FontFamily *GetHandwritingFont(int fontSize, int variationFlags) const = 0;
virtual FontFamily *GetMonospaceFont(int fontSize, int variationFlags) const = 0;
virtual RenderedFont *GetRenderedFont(IGpFont *font, int size, bool aa, FontHacks fontHacks) = 0;
virtual RenderedFont *GetRenderedFontFromFamily(FontFamily *fontFamily, int fontSize, bool aa, int flags) = 0;
virtual RenderedFont *LoadCachedRenderedFont(int cacheID, int size, bool aa, int flags) const = 0;

View File

@@ -27,7 +27,11 @@ static const char *gs_forbiddenNames[] =
static bool IsCharForbidden(char c)
{
return (c < ' ' || c == '<' || c == '>' || c == ':' || c == '\"' || c == '/' || c == '\\' || c == '|' || c == '?' || c == '*' || c > '~' || c == '$' || c == '#');
if ((c & 0x80) != 0)
return true;
// <= '$' includes space, ! " # $
return (c <= '$' || c == '<' || c == '>' || c == ':' || c == '\"' || c == '/' || c == '\\' || c == '|' || c == '?' || c == '*' || c > '~');
}
namespace PortabilityLayer

View File

@@ -0,0 +1,250 @@
#include "InflateStream.h"
#include "DeflateCodec.h"
#include <stdlib.h>
#include <new>
namespace PortabilityLayer
{
class InflateStreamImpl final : public GpIOStream
{
public:
InflateStreamImpl(GpIOStream *stream, GpUFilePos_t start, size_t compressedSize, size_t decompressedSize, InflateContext *inflateContext);
InflateStreamImpl();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
GpIOStream *m_stream;
InflateContext *m_inflateContext;
bool m_contextBroken;
GpUFilePos_t m_start;
GpUFilePos_t m_compressedSize;
GpUFilePos_t m_compressedPos;
size_t m_decompressedSize;
size_t m_decompressedPos;
uint8_t m_compressedInputBytes[1024];
size_t m_compressedInputReadOffset;
size_t m_compressedInputSize;
};
InflateStreamImpl::InflateStreamImpl(GpIOStream *stream, GpUFilePos_t start, size_t compressedSize, size_t decompressedSize, InflateContext *inflateContext)
: m_stream(stream)
, m_start(start)
, m_compressedPos(start)
, m_compressedSize(compressedSize)
, m_decompressedSize(decompressedSize)
, m_decompressedPos(0)
, m_inflateContext(inflateContext)
, m_compressedInputReadOffset(0)
, m_compressedInputSize(0)
, m_contextBroken(false)
{
}
InflateStreamImpl::InflateStreamImpl()
{
}
size_t InflateStreamImpl::Read(void *bytesOut, size_t size)
{
if (m_contextBroken)
return 0;
size_t sizeAvailable = m_decompressedSize - m_decompressedPos;
if (size > sizeAvailable)
size = sizeAvailable;
size_t totalConsumed = 0;
while (size > 0)
{
size_t sizeConsumed = 0;
if (!m_inflateContext->Read(bytesOut, size, sizeConsumed))
{
m_contextBroken = true;
return 0;
}
if (bytesOut)
bytesOut = static_cast<uint8_t*>(bytesOut) + sizeConsumed;
size -= sizeConsumed;
m_decompressedPos += sizeConsumed;
totalConsumed += sizeConsumed;
if (sizeConsumed == 0)
{
if (m_compressedInputSize == m_compressedInputReadOffset)
{
if (m_compressedPos != m_stream->Tell())
{
if (!m_stream->SeekStart(m_compressedPos))
return 0;
}
GpUFilePos_t compressedAvailable = m_compressedSize - (m_compressedPos - m_start);
if (compressedAvailable == 0)
return totalConsumed;
size_t compressedToRead = sizeof(m_compressedInputBytes);
if (compressedToRead > compressedAvailable)
compressedToRead = compressedAvailable;
if (!m_stream->ReadExact(m_compressedInputBytes, compressedToRead))
return 0;
m_compressedInputReadOffset = 0;
m_compressedInputSize = compressedToRead;
m_compressedPos += compressedToRead;
}
size_t compressedInputAvailable = m_compressedInputSize - m_compressedInputReadOffset;
size_t compressedInputConsumed = 0;
if (!m_inflateContext->Append(m_compressedInputBytes + m_compressedInputReadOffset, compressedInputAvailable, compressedInputConsumed))
{
m_contextBroken = true;
return 0;
}
if (compressedInputConsumed == 0)
return 0; // This should never happen
m_compressedInputReadOffset += compressedInputConsumed;
}
}
return totalConsumed;
}
size_t InflateStreamImpl::Write(const void *bytes, size_t size)
{
return 0;
}
bool InflateStreamImpl::IsSeekable() const
{
return true;
}
bool InflateStreamImpl::IsReadOnly() const
{
return true;
}
bool InflateStreamImpl::IsWriteOnly() const
{
return false;
}
bool InflateStreamImpl::SeekStart(GpUFilePos_t loc)
{
if (m_contextBroken)
return false;
if (loc > m_decompressedSize)
return false;
if (loc < m_decompressedPos)
{
if (!m_inflateContext->Reset())
{
m_contextBroken = true;
return false;
}
m_decompressedPos = 0;
m_compressedInputReadOffset = 0;
m_compressedInputSize = 0;
m_compressedPos = m_start;
}
size_t skipAhead = static_cast<size_t>(loc) - m_decompressedPos;
return this->Read(nullptr, skipAhead) == skipAhead;
}
bool InflateStreamImpl::SeekCurrent(GpFilePos_t loc)
{
if (m_contextBroken)
return false;
if (loc < 0)
{
GpUFilePos_t negativePos = static_cast<GpUFilePos_t>(-loc);
if (negativePos > m_decompressedPos)
return false;
return SeekStart(m_decompressedPos - negativePos);
}
else if (loc > 0)
{
GpUFilePos_t positivePos = static_cast<GpUFilePos_t>(-loc);
if (positivePos > m_decompressedSize - m_decompressedPos)
return false;
return this->Read(nullptr, static_cast<size_t>(positivePos));
}
else
return true;
}
bool InflateStreamImpl::SeekEnd(GpUFilePos_t loc)
{
if (loc > m_decompressedSize)
return false;
return this->SeekStart(m_decompressedSize - loc);
}
GpUFilePos_t InflateStreamImpl::Size() const
{
return m_decompressedSize;
}
GpUFilePos_t InflateStreamImpl::Tell() const
{
return m_decompressedPos;
}
void InflateStreamImpl::Close()
{
this->~InflateStreamImpl();
free(this);
}
void InflateStreamImpl::Flush()
{
}
GpIOStream *InflateStream::Create(GpIOStream *stream, GpUFilePos_t start, size_t compressedSize, size_t decompressedSize)
{
InflateContext *inflateContext = InflateContext::Create();
if (!inflateContext)
return nullptr;
void *storage = malloc(sizeof(InflateStreamImpl));
if (!storage)
{
inflateContext->Destroy();
return nullptr;
}
return new (storage) InflateStreamImpl(stream, start, compressedSize, decompressedSize, inflateContext);
}
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "GpIOStream.h"
namespace PortabilityLayer
{
namespace InflateStream
{
GpIOStream *Create(GpIOStream *stream, GpUFilePos_t start, size_t compressedSize, size_t decompressedSize);
};
}

View File

@@ -24,7 +24,7 @@ namespace
const unsigned int Protected = 81;
const unsigned int DataForkSize = 83;
const unsigned int ResourceForkSize = 87;
const unsigned int CreationDate = 91;
const unsigned int CreatedDate = 91;
const unsigned int ModifiedDate = 95;
const unsigned int CommentLength = 99;
const unsigned int FinderFlagsLow = 101;
@@ -75,8 +75,8 @@ namespace PortabilityLayer
mb2Header[MB2FileOffsets::Protected] = fileInfo.m_properties.m_protected;
BytePack::BigUInt32(mb2Header + MB2FileOffsets::DataForkSize, fileInfo.m_dataForkSize);
BytePack::BigUInt32(mb2Header + MB2FileOffsets::ResourceForkSize, fileInfo.m_resourceForkSize);
BytePack::BigUInt32(mb2Header + MB2FileOffsets::CreationDate, static_cast<uint32_t>(fileInfo.m_properties.m_creationDate));
BytePack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate, static_cast<uint32_t>(fileInfo.m_properties.m_modifiedDate));
BytePack::BigUInt32(mb2Header + MB2FileOffsets::CreatedDate, static_cast<uint32_t>(fileInfo.m_properties.m_createdTimeMacEpoch));
BytePack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate, static_cast<uint32_t>(fileInfo.m_properties.m_modifiedTimeMacEpoch));
BytePack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength, fileInfo.m_commentSize);
mb2Header[MB2FileOffsets::FinderFlagsLow] = static_cast<uint8_t>(fileInfo.m_properties.m_finderFlags & 0xff);
@@ -130,8 +130,8 @@ namespace PortabilityLayer
fileInfo.m_properties.m_protected = mb2Header[MB2FileOffsets::Protected];
fileInfo.m_dataForkSize = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::DataForkSize);
fileInfo.m_resourceForkSize = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::ResourceForkSize);
fileInfo.m_properties.m_creationDate = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::CreationDate);
fileInfo.m_properties.m_modifiedDate = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate);
fileInfo.m_properties.m_createdTimeMacEpoch = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::CreatedDate);
fileInfo.m_properties.m_modifiedTimeMacEpoch = ByteUnpack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate);
fileInfo.m_commentSize = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength);
fileInfo.m_properties.m_finderFlags |= mb2Header[MB2FileOffsets::FinderFlagsLow];

View File

@@ -1,63 +1,185 @@
#include "MacFileInfo.h"
#include "PLBigEndian.h"
#include <string.h>
namespace PortabilityLayer
{
static const unsigned int kOffsetFileType = 0;
static const unsigned int kOffsetFileCreator = 4;
static const unsigned int kOffsetXPos = 8;
static const unsigned int kOffsetYPos = 10;
static const unsigned int kOffsetFinderFlags = 12;
static const unsigned int kProtected = 14;
static const unsigned int kCreationDate = 15;
static const unsigned int kModifiedDate = 19;
static const unsigned int kSize = 23;
uint8_t m_data[kSize];
void MacFilePropertiesSerialized::Deserialize(MacFileProperties &props) const
{
memcpy(props.m_fileType, m_data + kOffsetFileType, 4);
memcpy(props.m_fileCreator, m_data + kOffsetFileCreator, 4);
memcpy(&props.m_xPos, m_data + kOffsetXPos, 2);
memcpy(&props.m_yPos, m_data + kOffsetYPos, 2);
memcpy(&props.m_finderFlags, m_data + kOffsetFinderFlags, 2);
memcpy(&props.m_protected, m_data + kProtected, 1);
memcpy(&props.m_creationDate, m_data + kCreationDate, 8);
memcpy(&props.m_modifiedDate, m_data + kModifiedDate, 8);
PortabilityLayer::ByteSwap::BigInt16(props.m_xPos);
PortabilityLayer::ByteSwap::BigInt16(props.m_yPos);
PortabilityLayer::ByteSwap::BigUInt16(props.m_finderFlags);
PortabilityLayer::ByteSwap::BigInt64(props.m_creationDate);
PortabilityLayer::ByteSwap::BigInt64(props.m_modifiedDate);
}
void MacFilePropertiesSerialized::Serialize(const MacFileProperties &props)
{
int16_t xPos = props.m_xPos;
int16_t yPos = props.m_yPos;
uint16_t finderFlags = props.m_finderFlags;
uint64_t creationDate = props.m_creationDate;
uint64_t modifiedDate = props.m_modifiedDate;
PortabilityLayer::ByteSwap::BigInt16(xPos);
PortabilityLayer::ByteSwap::BigInt16(yPos);
PortabilityLayer::ByteSwap::BigUInt16(finderFlags);
PortabilityLayer::ByteSwap::BigUInt64(creationDate);
PortabilityLayer::ByteSwap::BigUInt64(modifiedDate);
memcpy(m_data + kOffsetFileType, props.m_fileType, 4);
memcpy(m_data + kOffsetFileCreator, props.m_fileCreator, 4);
memcpy(m_data + kOffsetXPos, &xPos, 2);
memcpy(m_data + kOffsetYPos, &yPos, 2);
memcpy(m_data + kOffsetFinderFlags, &finderFlags, 2);
memcpy(m_data + kProtected, &props.m_protected, 1);
memcpy(m_data + kCreationDate, &creationDate, 8);
memcpy(m_data + kModifiedDate, &modifiedDate, 8);
}
}
#include "MacFileInfo.h"
#include "DeflateCodec.h"
#include "GpIOStream.h"
#include "ZipFile.h"
#include "PLBigEndian.h"
#include "CombinedTimestamp.h"
#include <string.h>
namespace PortabilityLayer
{
void MacFilePropertiesSerialized::Deserialize(MacFileProperties &props) const
{
memcpy(props.m_fileType, m_data + kOffsetFileType, 4);
memcpy(props.m_fileCreator, m_data + kOffsetFileCreator, 4);
memcpy(&props.m_xPos, m_data + kOffsetXPos, 2);
memcpy(&props.m_yPos, m_data + kOffsetYPos, 2);
memcpy(&props.m_finderFlags, m_data + kOffsetFinderFlags, 2);
memcpy(&props.m_protected, m_data + kOffsetProtected, 1);
memcpy(&props.m_createdTimeMacEpoch, m_data + kOffsetCreatedDate, 8);
memcpy(&props.m_modifiedTimeMacEpoch, m_data + kOffsetModifiedDate, 8);
PortabilityLayer::ByteSwap::BigInt16(props.m_xPos);
PortabilityLayer::ByteSwap::BigInt16(props.m_yPos);
PortabilityLayer::ByteSwap::BigUInt16(props.m_finderFlags);
PortabilityLayer::ByteSwap::BigInt64(props.m_createdTimeMacEpoch);
PortabilityLayer::ByteSwap::BigInt64(props.m_modifiedTimeMacEpoch);
}
void MacFilePropertiesSerialized::Serialize(const MacFileProperties &props)
{
int16_t xPos = props.m_xPos;
int16_t yPos = props.m_yPos;
uint16_t finderFlags = props.m_finderFlags;
uint64_t createdDate = props.m_createdTimeMacEpoch;
uint64_t modifiedDate = props.m_modifiedTimeMacEpoch;
PortabilityLayer::ByteSwap::BigInt16(xPos);
PortabilityLayer::ByteSwap::BigInt16(yPos);
PortabilityLayer::ByteSwap::BigUInt16(finderFlags);
PortabilityLayer::ByteSwap::BigUInt64(createdDate);
PortabilityLayer::ByteSwap::BigUInt64(modifiedDate);
memcpy(m_data + kOffsetFileType, props.m_fileType, 4);
memcpy(m_data + kOffsetFileCreator, props.m_fileCreator, 4);
memcpy(m_data + kOffsetXPos, &xPos, 2);
memcpy(m_data + kOffsetYPos, &yPos, 2);
memcpy(m_data + kOffsetFinderFlags, &finderFlags, 2);
memcpy(m_data + kOffsetProtected, &props.m_protected, 1);
memcpy(m_data + kOffsetCreatedDate, &createdDate, 8);
memcpy(m_data + kOffsetModifiedDate, &modifiedDate, 8);
}
bool MacFilePropertiesSerialized::WriteAsPackage(GpIOStream &stream, const CombinedTimestamp &ts) const
{
if (!WriteIsolated(stream, ts))
return false;
const char *packagedName = GetPackagedName();
uint16_t msdosDate, msdosTime;
ts.GetAsMSDOSTimestamp(msdosDate, msdosTime);
ZipCentralDirectoryFileHeader cdh;
cdh.m_signature = ZipCentralDirectoryFileHeader::kSignature;
cdh.m_versionCreated = ZipConstants::kCompressedRequiredVersion;
cdh.m_versionRequired = ZipConstants::kStoredRequiredVersion;
cdh.m_flags = 0;
cdh.m_method = ZipConstants::kStoredMethod;
cdh.m_modificationTime = msdosTime;
cdh.m_modificationDate = msdosDate;
cdh.m_crc = PortabilityLayer::DeflateContext::CRC32(0, m_data, sizeof(m_data));
cdh.m_compressedSize = sizeof(m_data);
cdh.m_uncompressedSize = sizeof(m_data);
cdh.m_fileNameLength = strlen(packagedName);
cdh.m_extraFieldLength = 0;
cdh.m_commentLength = 0;
cdh.m_diskNumber = 0;
cdh.m_internalAttributes = ZipConstants::kArchivedAttributes;
cdh.m_externalAttributes = PortabilityLayer::ZipConstants::kArchivedAttributes;
cdh.m_localHeaderOffset = 0;
if (!stream.WriteExact(&cdh, sizeof(cdh)))
return false;
if (!stream.WriteExact(packagedName, strlen(packagedName)))
return false;
ZipEndOfCentralDirectoryRecord eod;
eod.m_signature = ZipEndOfCentralDirectoryRecord::kSignature;
eod.m_thisDiskNumber = 0;
eod.m_centralDirDisk = 0;
eod.m_numCentralDirRecordsThisDisk = 1;
eod.m_numCentralDirRecords = 1;
eod.m_centralDirectorySizeBytes = sizeof(ZipCentralDirectoryFileHeader) + strlen(packagedName);
eod.m_centralDirStartOffset = sizeof(ZipFileLocalHeader) + strlen(packagedName) + sizeof(m_data);
eod.m_commentLength = 0;
if (stream.Write(&eod, sizeof(eod)) != sizeof(eod))
return false;
return true;
}
bool MacFilePropertiesSerialized::WriteIsolated(GpIOStream &stream, const CombinedTimestamp &ts) const
{
static const char *packagedName = GetPackagedName();
ZipFileLocalHeader lh;
static const uint32_t kSignature = 0x04034b50;
uint16_t msdosDate, msdosTime;
ts.GetAsMSDOSTimestamp(msdosDate, msdosTime);
lh.m_signature = ZipFileLocalHeader::kSignature;
lh.m_versionRequired = ZipConstants::kStoredRequiredVersion;
lh.m_flags = 0;
lh.m_method = ZipConstants::kStoredMethod;
lh.m_modificationTime = msdosTime;
lh.m_modificationDate = msdosDate;
lh.m_crc = DeflateContext::CRC32(0, m_data, sizeof(m_data));
lh.m_compressedSize = sizeof(m_data);
lh.m_uncompressedSize = sizeof(m_data);
lh.m_fileNameLength = strlen(packagedName);
lh.m_extraFieldLength = 0;
if (stream.Write(&lh, sizeof(lh)) != sizeof(lh))
return false;
if (stream.Write(packagedName, strlen(packagedName)) != strlen(packagedName))
return false;
if (stream.Write(m_data, sizeof(m_data)) != sizeof(m_data))
return false;
return true;
}
bool MacFilePropertiesSerialized::ReadFromPackage(GpIOStream &stream)
{
const char *packagedName = GetPackagedName();
ZipFileLocalHeader lh;
if (stream.Read(&lh, sizeof(lh)) != sizeof(lh))
return false;
if (lh.m_signature != ZipFileLocalHeader::kSignature)
return false;
if (lh.m_versionRequired != ZipConstants::kStoredRequiredVersion)
return false;
if (lh.m_flags != 0)
return false;
if (lh.m_method != ZipConstants::kStoredMethod)
return false;
if (lh.m_compressedSize != sizeof(m_data))
return false;
if (lh.m_uncompressedSize != sizeof(m_data))
return false;
if (lh.m_fileNameLength != strlen(packagedName))
return false;
if (lh.m_extraFieldLength != 0)
return false;
if (!stream.SeekCurrent(lh.m_fileNameLength))
return false;
if (stream.Read(m_data, sizeof(m_data)) != sizeof(m_data))
return false;
if (lh.m_crc != DeflateContext::CRC32(0, m_data, sizeof(m_data)))
return false;
return true;
}
const char *MacFilePropertiesSerialized::GetPackagedName()
{
return "!!meta";
}
}

View File

@@ -1,86 +1,96 @@
#pragma once
#include "DataTypes.h"
#include "PascalStr.h"
namespace PortabilityLayer
{
enum FinderFileFlags
{
FINDER_FILE_FLAG_LOCKED = (1 << 15),
FINDER_FILE_FLAG_INVISIBLE = (1 << 14),
FINDER_FILE_FLAG_BUNDLE = (1 << 13),
FINDER_FILE_FLAG_SYSTEM = (1 << 12),
FINDER_FILE_FLAG_COPY_PROTECTED = (1 << 11),
FINDER_FILE_FLAG_BUSY = (1 << 10),
FINDER_FILE_FLAG_CHANGED = (1 << 9),
FINDER_FILE_FLAG_INITED = (1 << 8),
};
struct MacFileProperties
{
MacFileProperties();
char m_fileType[4];
char m_fileCreator[4];
int16_t m_xPos;
int16_t m_yPos;
uint16_t m_finderFlags;
uint8_t m_protected;
int64_t m_creationDate;
int64_t m_modifiedDate;
};
struct MacFilePropertiesSerialized
{
static const unsigned int kOffsetFileType = 0;
static const unsigned int kOffsetFileCreator = 4;
static const unsigned int kOffsetXPos = 8;
static const unsigned int kOffsetYPos = 10;
static const unsigned int kOffsetFinderFlags = 12;
static const unsigned int kProtected = 14;
static const unsigned int kCreationDate = 15;
static const unsigned int kModifiedDate = 23;
static const unsigned int kSize = 31;
uint8_t m_data[kSize];
void Deserialize(MacFileProperties &props) const;
void Serialize(const MacFileProperties &props);
};
struct MacFileInfo
{
MacFileInfo();
PascalStr<64> m_fileName;
uint16_t m_commentSize;
uint32_t m_dataForkSize;
uint32_t m_resourceForkSize;
MacFileProperties m_properties;
};
}
namespace PortabilityLayer
{
inline MacFileProperties::MacFileProperties()
: m_xPos(0)
, m_yPos(0)
, m_finderFlags(0)
, m_protected(0)
, m_creationDate(0)
, m_modifiedDate(0)
{
m_fileType[0] = m_fileType[1] = m_fileType[2] = m_fileType[3] = '\0';
m_fileCreator[0] = m_fileCreator[1] = m_fileCreator[2] = m_fileCreator[3] = '\0';
}
inline MacFileInfo::MacFileInfo()
: m_dataForkSize(0)
, m_resourceForkSize(0)
, m_commentSize(0)
{
}
}
#pragma once
#include "DataTypes.h"
#include "PascalStr.h"
class GpIOStream;
namespace PortabilityLayer
{
struct CombinedTimestamp;
enum FinderFileFlags
{
FINDER_FILE_FLAG_LOCKED = (1 << 15),
FINDER_FILE_FLAG_INVISIBLE = (1 << 14),
FINDER_FILE_FLAG_BUNDLE = (1 << 13),
FINDER_FILE_FLAG_SYSTEM = (1 << 12),
FINDER_FILE_FLAG_COPY_PROTECTED = (1 << 11),
FINDER_FILE_FLAG_BUSY = (1 << 10),
FINDER_FILE_FLAG_CHANGED = (1 << 9),
FINDER_FILE_FLAG_INITED = (1 << 8),
};
struct MacFileProperties
{
MacFileProperties();
char m_fileType[4];
char m_fileCreator[4];
int16_t m_xPos;
int16_t m_yPos;
uint16_t m_finderFlags;
uint8_t m_protected;
int64_t m_createdTimeMacEpoch;
int64_t m_modifiedTimeMacEpoch;
};
struct MacFilePropertiesSerialized
{
static const unsigned int kOffsetFileType = 0;
static const unsigned int kOffsetFileCreator = 4;
static const unsigned int kOffsetXPos = 8;
static const unsigned int kOffsetYPos = 10;
static const unsigned int kOffsetFinderFlags = 12;
static const unsigned int kOffsetProtected = 14;
static const unsigned int kOffsetCreatedDate = 15;
static const unsigned int kOffsetModifiedDate = 23;
static const unsigned int kSize = 31;
uint8_t m_data[kSize];
void Deserialize(MacFileProperties &props) const;
void Serialize(const MacFileProperties &props);
bool WriteAsPackage(GpIOStream &stream, const CombinedTimestamp &ts) const;
bool WriteIsolated(GpIOStream &stream, const CombinedTimestamp &ts) const;
bool ReadFromPackage(GpIOStream &stream);
static const char *GetPackagedName();
};
struct MacFileInfo
{
MacFileInfo();
PascalStr<64> m_fileName;
uint16_t m_commentSize;
uint32_t m_dataForkSize;
uint32_t m_resourceForkSize;
MacFileProperties m_properties;
};
}
namespace PortabilityLayer
{
inline MacFileProperties::MacFileProperties()
: m_xPos(0)
, m_yPos(0)
, m_finderFlags(0)
, m_protected(0)
, m_createdTimeMacEpoch(0)
, m_modifiedTimeMacEpoch(0)
{
m_fileType[0] = m_fileType[1] = m_fileType[2] = m_fileType[3] = '\0';
m_fileCreator[0] = m_fileCreator[1] = m_fileCreator[2] = m_fileCreator[3] = '\0';
}
inline MacFileInfo::MacFileInfo()
: m_dataForkSize(0)
, m_resourceForkSize(0)
, m_commentSize(0)
{
}
}

View File

@@ -1,125 +1,120 @@
#include "MemReaderStream.h"
#include "MemoryManager.h"
#include <string.h>
namespace PortabilityLayer
{
MemReaderStream::MemReaderStream(const void *memStream, size_t size)
: m_bytes(static_cast<const uint8_t*>(memStream))
, m_size(size)
, m_loc(0)
{
#include "MemoryManager.h"
#include <string.h>
namespace PortabilityLayer
{
MemReaderStream::MemReaderStream(const void *memStream, size_t size)
: m_bytes(static_cast<const uint8_t*>(memStream))
, m_size(size)
, m_loc(0)
{
}
MemReaderStream::~MemReaderStream()
{
}
size_t MemReaderStream::Read(void *bytesOut, size_t size)
{
size_t available = m_size - m_loc;
if (size > available)
size = available;
memcpy(bytesOut, m_bytes + m_loc, size);
m_loc += size;
return size;
}
size_t MemReaderStream::Write(const void *bytes, size_t size)
{
return 0;
}
bool IsSeekable()
{
return true;
}
bool MemReaderStream::IsSeekable() const
{
return true;
}
bool MemReaderStream::IsReadOnly() const
{
return true;
}
bool MemReaderStream::IsWriteOnly() const
{
return false;
}
bool MemReaderStream::SeekStart(GpUFilePos_t loc)
{
if (loc > m_size)
m_loc = m_size;
else
m_loc = static_cast<size_t>(loc);
return true;
}
bool MemReaderStream::SeekCurrent(GpFilePos_t loc)
{
if (loc < 0)
{
if (static_cast<GpFilePos_t>(m_loc) + loc < 0)
m_loc = 0;
else
m_loc = static_cast<size_t>(static_cast<GpFilePos_t>(m_loc) + loc);
}
else
{
const size_t available = m_size - m_loc;
if (static_cast<GpUFilePos_t>(loc) > available)
m_loc = m_size;
else
m_loc = static_cast<size_t>(static_cast<GpFilePos_t>(m_loc) + loc);
}
return true;
}
bool MemReaderStream::SeekEnd(GpUFilePos_t loc)
{
if (m_size < loc)
m_loc = 0;
else
m_loc = m_size - static_cast<size_t>(loc);
return true;
}
bool MemReaderStream::Truncate(GpUFilePos_t loc)
{
return false;
}
GpUFilePos_t MemReaderStream::Size() const
{
return m_size;
}
GpUFilePos_t MemReaderStream::Tell() const
{
return static_cast<GpUFilePos_t>(m_loc);
}
void MemReaderStream::Close()
{
}
void MemReaderStream::Flush()
{
{
}
size_t MemReaderStream::Read(void *bytesOut, size_t size)
{
size_t available = m_size - m_loc;
if (size > available)
size = available;
memcpy(bytesOut, m_bytes + m_loc, size);
m_loc += size;
return size;
}
size_t MemReaderStream::Write(const void *bytes, size_t size)
{
return 0;
}
bool IsSeekable()
{
return true;
}
bool MemReaderStream::IsSeekable() const
{
return true;
}
bool MemReaderStream::IsReadOnly() const
{
return true;
}
bool MemReaderStream::IsWriteOnly() const
{
return false;
}
bool MemReaderStream::SeekStart(GpUFilePos_t loc)
{
if (loc > m_size)
m_loc = m_size;
else
m_loc = static_cast<size_t>(loc);
return true;
}
bool MemReaderStream::SeekCurrent(GpFilePos_t loc)
{
if (loc < 0)
{
if (static_cast<GpFilePos_t>(m_loc) + loc < 0)
m_loc = 0;
else
m_loc = static_cast<size_t>(static_cast<GpFilePos_t>(m_loc) + loc);
}
else
{
const size_t available = m_size - m_loc;
if (static_cast<GpUFilePos_t>(loc) > available)
m_loc = m_size;
else
m_loc = static_cast<size_t>(static_cast<GpFilePos_t>(m_loc) + loc);
}
return true;
}
bool MemReaderStream::SeekEnd(GpUFilePos_t loc)
{
if (m_size < loc)
m_loc = 0;
else
m_loc = m_size - static_cast<size_t>(loc);
return true;
}
GpUFilePos_t MemReaderStream::Size() const
{
return m_size;
}
GpUFilePos_t MemReaderStream::Tell() const
{
return static_cast<GpUFilePos_t>(m_loc);
}
void MemReaderStream::Close()
{
}
void MemReaderStream::Flush()
{
}
MemBufferReaderStream::~MemBufferReaderStream()
{
{
if (m_buffer)
MemoryManager::GetInstance()->Release(m_buffer);
}
@@ -132,7 +127,7 @@ namespace PortabilityLayer
return new (storage) MemBufferReaderStream(buffer, size);
}
void MemBufferReaderStream::Close()
{
this->~MemBufferReaderStream();
@@ -144,4 +139,4 @@ namespace PortabilityLayer
, m_buffer(buffer)
{
}
}
}

View File

@@ -1,55 +1,54 @@
#pragma once
#ifndef __PL_MEM_READER_STREAM_H__
#define __PL_MEM_READER_STREAM_H__
#include "CoreDefs.h"
#include "GpIOStream.h"
namespace PortabilityLayer
{
class MemReaderStream : public GpIOStream
{
public:
#pragma once
#ifndef __PL_MEM_READER_STREAM_H__
#define __PL_MEM_READER_STREAM_H__
#include "CoreDefs.h"
#include "GpIOStream.h"
namespace PortabilityLayer
{
class MemReaderStream : public GpIOStream
{
public:
MemReaderStream(const void *memStream, size_t size);
virtual ~MemReaderStream();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
MemReaderStream() GP_DELETED;
const uint8_t *m_bytes;
size_t m_size;
size_t m_loc;
virtual ~MemReaderStream();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
MemReaderStream() GP_DELETED;
const uint8_t *m_bytes;
size_t m_size;
size_t m_loc;
};
class MemBufferReaderStream final : public MemReaderStream
{
public:
~MemBufferReaderStream() override;
static MemBufferReaderStream *Create(void *buffer, size_t size);
void Close() override;
private:
MemBufferReaderStream() GP_DELETED;
MemBufferReaderStream(void *buffer, size_t size);
void *m_buffer;
};
}
#endif
void *m_buffer;
};
}
#endif

View File

@@ -81,7 +81,7 @@ static bool ConvertFilenameToSafePStr(const char *str, uint8_t *pstr)
{
const char c = *str++;
if (c == '.' || c == ' ' || c == '_' || c == '\'' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
if (c == '.' || c == ' ' || c == '_' || c == '!' || c == '\'' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
continue;
else
return false;
@@ -425,18 +425,6 @@ VFileSpec MakeVFileSpec(PortabilityLayer::VirtualDirectory_t dir, const PLPasStr
return spec;
}
PLError_t FSpGetFInfo(const VFileSpec &spec, VFileInfo &finfo)
{
PortabilityLayer::MacFileProperties mfp;
if (!PortabilityLayer::FileManager::GetInstance()->ReadFileProperties(spec.m_dir, spec.m_name, mfp))
return PLErrors::kFileNotFound;
finfo.m_type = PortabilityLayer::ResTypeID(mfp.m_fileType);
finfo.m_creator = PortabilityLayer::ResTypeID(mfp.m_fileCreator);
return PLErrors::kNone;
}
DirectoryFileListEntry *GetDirectoryFiles(PortabilityLayer::VirtualDirectory_t dirID)
{
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
@@ -469,10 +457,10 @@ DirectoryFileListEntry *GetDirectoryFiles(PortabilityLayer::VirtualDirectory_t d
PortabilityLayer::MacFileProperties mfp;
PortabilityLayer::MacFilePropertiesSerialized mfs;
const size_t gpfSize = stream->Read(mfs.m_data, PortabilityLayer::MacFilePropertiesSerialized::kSize);
bool deserializedOK = mfs.ReadFromPackage(*stream);
stream->Close();
if (gpfSize != PortabilityLayer::MacFilePropertiesSerialized::kSize)
if (!deserializedOK)
continue;
mfs.Deserialize(mfp);

View File

@@ -243,13 +243,10 @@ void GetIndString(unsigned char *str, int stringsID, int fnameIndex); // Fetches
VFileSpec MakeVFileSpec(PortabilityLayer::VirtualDirectory_t dir, const PLPasStr &fileName);
PLError_t FSpGetFInfo(const VFileSpec &spec, VFileInfo &finfoOut);
DirectoryFileListEntry *GetDirectoryFiles(PortabilityLayer::VirtualDirectory_t dirID);
void DisposeDirectoryFiles(DirectoryFileListEntry *firstDFL);
void GetMouse(Window *window, Point *point);
Boolean Button(); // Returns true if there's a mouse down event in the queue
Boolean StillDown();
Boolean WaitMouseUp();

View File

@@ -15,6 +15,7 @@ namespace PLErrors
kBadFileName,
kFileNotFound,
kAccessDenied,
kFileIsBusy,
kOutOfMemory,
@@ -23,8 +24,6 @@ namespace PLErrors
kIOError,
kResourceError,
kUserCancelled_TEMP,
};
}

View File

@@ -1,6 +1,7 @@
#include "PLMovies.h"
#include "BitmapImage.h"
#include "FileManager.h"
#include "MemoryManager.h"
#include "PLQDraw.h"
#include "PLResources.h"
@@ -56,15 +57,19 @@ void AnimationPackage::Destroy()
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
bool AnimationPackage::Load(PortabilityLayer::VirtualDirectory_t virtualDir, const PLPasStr &path)
PLError_t AnimationPackage::Load(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &name)
{
m_resArchive = PortabilityLayer::ResourceManager::GetInstance()->LoadResFile(virtualDir, path);
m_compositeFile = PortabilityLayer::FileManager::GetInstance()->OpenCompositeFile(dirID, name);
if (!m_compositeFile)
return PLErrors::kFileNotFound;
m_resArchive = PortabilityLayer::ResourceManager::GetInstance()->LoadResFile(m_compositeFile);
if (!m_resArchive)
return false;
return PLErrors::kResourceError;
THandle<void> movieMetadataRes = m_resArchive->LoadResource('muvi', 0);
if (!movieMetadataRes)
return false;
return PLErrors::kResourceError;
const void *movieMetadata = *movieMetadataRes;
@@ -74,25 +79,25 @@ bool AnimationPackage::Load(PortabilityLayer::VirtualDirectory_t virtualDir, con
movieMetadataRes.Dispose();
if (document.HasParseError() || !document.IsObject())
return false;
return PLErrors::kResourceError;
if (!document.HasMember("frameRateNumerator") || !document.HasMember("frameRateDenominator"))
return false;
return PLErrors::kResourceError;
const rapidjson::Value &frameRateNumeratorJSON = document["frameRateNumerator"];
const rapidjson::Value &frameRateDenominatorJSON = document["frameRateDenominator"];
if (!frameRateNumeratorJSON.IsInt() && !frameRateDenominatorJSON.IsInt())
return false;
return PLErrors::kResourceError;
const int frameRateNumerator = frameRateNumeratorJSON.GetInt();
const int frameRateDenominator = frameRateDenominatorJSON.GetInt();
if (frameRateNumerator < 1 || frameRateDenominator < 1)
return false;
return PLErrors::kResourceError;
if (frameRateDenominator > INT_MAX / 60 || frameRateDenominator * 60 < frameRateNumerator)
return false; // We only support up to 60fps
return PLErrors::kResourceError; // We only support up to 60fps
m_frameRateNumerator = frameRateNumerator;
m_frameRateDenominator = frameRateDenominator;
@@ -101,7 +106,7 @@ bool AnimationPackage::Load(PortabilityLayer::VirtualDirectory_t virtualDir, con
for (;;)
{
if (numFrames + 1 > 0x7fff)
return false;
return PLErrors::kResourceError;
THandle<void> frameRes = m_resArchive->LoadResource('PICT', numFrames + 1);
if (!frameRes)
@@ -109,18 +114,18 @@ bool AnimationPackage::Load(PortabilityLayer::VirtualDirectory_t virtualDir, con
else
{
if (frameRes.MMBlock()->m_size < sizeof(BitmapImage))
return false;
return PLErrors::kResourceError;
numFrames++;
}
}
if (numFrames == 0)
return false;
return PLErrors::kResourceError;
void *imageListStorage = PortabilityLayer::MemoryManager::GetInstance()->Alloc(sizeof(THandle<BitmapImage>) * numFrames);
if (!imageListStorage)
return false;
return PLErrors::kResourceError;
m_images = static_cast<THandle<BitmapImage>*>(imageListStorage);
@@ -132,7 +137,7 @@ bool AnimationPackage::Load(PortabilityLayer::VirtualDirectory_t virtualDir, con
m_numImages = numFrames;
return true;
return PLErrors::kNone;
}
const THandle<BitmapImage> &AnimationPackage::GetFrame(size_t index) const
@@ -159,6 +164,7 @@ uint32_t AnimationPackage::GetFrameRateDenominator() const
AnimationPackage::AnimationPackage()
: m_images(nullptr)
, m_resArchive(nullptr)
, m_compositeFile(nullptr)
, m_numImages(0)
{
}
@@ -167,6 +173,10 @@ AnimationPackage::~AnimationPackage()
{
if (m_resArchive)
m_resArchive->Destroy();
if (m_compositeFile)
m_compositeFile->Close();
PortabilityLayer::MemoryManager::GetInstance()->Release(m_images);
}

View File

@@ -8,6 +8,8 @@
namespace PortabilityLayer
{
struct IResourceArchive;
class MultiStreamFile;
class CompositeFile;
}
struct DrawSurface;
@@ -40,7 +42,7 @@ public:
static AnimationPackage *Create();
void Destroy();
bool Load(PortabilityLayer::VirtualDirectory_t virtualDir, const PLPasStr &path);
PLError_t Load(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &name);
const THandle<BitmapImage> &GetFrame(size_t index) const;
size_t NumFrames() const;
@@ -53,6 +55,7 @@ private:
THandle<BitmapImage> *m_images;
PortabilityLayer::IResourceArchive *m_resArchive;
PortabilityLayer::CompositeFile *m_compositeFile;
size_t m_numImages;
uint32_t m_frameRateNumerator;

View File

@@ -100,6 +100,7 @@ namespace
namespace PortabilityLayer
{
class CompositeFile;
struct MMHandleBlock;
struct IResourceArchive;
@@ -114,7 +115,7 @@ namespace PortabilityLayer
THandle<void> GetAppResource(const ResTypeID &resTypeID, int16_t resID) const override;
IResourceArchive *GetAppResourceArchive() const override;
IResourceArchive *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const override;
IResourceArchive *LoadResFile(CompositeFile *file) const override;
PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) override;
void DissociateHandle(MMHandleBlock *hdl) const override;
@@ -125,21 +126,23 @@ namespace PortabilityLayer
private:
void UnloadAndDestroyResourceFile(IResourceArchive *rf);
IResourceArchive *LoadResDirectory(VirtualDirectory_t virtualDir, const PLPasStr &filename) const;
IResourceArchive *m_appResArchive;
CompositeFile *m_appResFile;
static ResourceManagerImpl ms_instance;
};
ResourceManagerImpl::ResourceManagerImpl()
: m_appResArchive(nullptr)
, m_appResFile(nullptr)
{
}
void ResourceManagerImpl::Init()
{
m_appResArchive = LoadResFile(VirtualDirectories::kApplicationData, PSTR("ApplicationResources"));
m_appResFile = PortabilityLayer::FileManager::GetInstance()->OpenCompositeFile(VirtualDirectories::kApplicationData, PSTR("ApplicationResources"));
if (m_appResFile)
m_appResArchive = LoadResFile(m_appResFile);
}
void ResourceManagerImpl::Shutdown()
@@ -147,6 +150,9 @@ namespace PortabilityLayer
if (m_appResArchive)
m_appResArchive->Destroy();
if (m_appResFile)
m_appResFile->Close();
m_appResArchive = nullptr;
}
@@ -168,47 +174,25 @@ namespace PortabilityLayer
rf->Destroy();
}
IResourceArchive *ResourceManagerImpl::LoadResDirectory(VirtualDirectory_t virtualDir, const PLPasStr &filename) const
{
ResourceArchiveDirectory *archive = ResourceArchiveDirectory::Create(virtualDir, filename);
if (!archive)
return nullptr;
if (!archive->Init())
{
archive->Destroy();
return nullptr;
}
return archive;
}
ResourceManagerImpl *ResourceManagerImpl::GetInstance()
{
return &ms_instance;
}
IResourceArchive *ResourceManagerImpl::LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const
IResourceArchive *ResourceManagerImpl::LoadResFile(CompositeFile *file) const
{
if (PLDrivers::GetFileSystem()->IsVirtualDirectoryLooseResources(virtualDir))
return LoadResDirectory(virtualDir, filename);
GpIOStream *fStream = nullptr;
if (FileManager::GetInstance()->RawOpenFileResources(virtualDir, filename, EFilePermission_Read, true, GpFileCreationDispositions::kOpenExisting, fStream) != PLErrors::kNone)
ZipFileProxy *proxy = nullptr;
bool proxyIsShared = false;
if (file->OpenResources(fStream, proxy, proxyIsShared) != PLErrors::kNone)
return nullptr;
ZipFileProxy *proxy = ZipFileProxy::Create(fStream);
if (!proxy)
{
fStream->Close();
return nullptr;
}
IResourceArchive *archive = ResourceArchiveZipFile::Create(proxy, fStream);
IResourceArchive *archive = ResourceArchiveZipFile::Create(proxy, proxyIsShared, fStream);
if (!archive)
{
proxy->Destroy();
fStream->Close();
if (fStream)
fStream->Close();
return nullptr;
}
@@ -296,7 +280,7 @@ namespace PortabilityLayer
// ===========================================================================================
ResourceArchiveZipFile *ResourceArchiveZipFile::Create(ZipFileProxy *zipFileProxy, GpIOStream *stream)
ResourceArchiveZipFile *ResourceArchiveZipFile::Create(ZipFileProxy *zipFileProxy, bool proxyIsShared, GpIOStream *stream)
{
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
@@ -320,7 +304,7 @@ namespace PortabilityLayer
return nullptr;
}
return new (storage) ResourceArchiveZipFile(zipFileProxy, stream, refs);
return new (storage) ResourceArchiveZipFile(zipFileProxy, proxyIsShared, stream, refs);
}
void ResourceArchiveZipFile::Destroy()
@@ -509,8 +493,9 @@ namespace PortabilityLayer
return THandle<void>(handle);
}
ResourceArchiveZipFile::ResourceArchiveZipFile(ZipFileProxy *zipFileProxy, GpIOStream *stream, ResourceArchiveRef *resourceHandles)
ResourceArchiveZipFile::ResourceArchiveZipFile(ZipFileProxy *zipFileProxy, bool proxyIsShared, GpIOStream *stream, ResourceArchiveRef *resourceHandles)
: m_zipFileProxy(zipFileProxy)
, m_proxyIsShared(proxyIsShared)
, m_stream(stream)
, m_resourceHandles(resourceHandles)
{
@@ -532,336 +517,10 @@ namespace PortabilityLayer
mm->Release(m_resourceHandles);
m_zipFileProxy->Destroy();
m_stream->Close();
}
if (!m_proxyIsShared)
m_zipFileProxy->Destroy();
// ========================================================================================
ResourceArchiveDirectory *ResourceArchiveDirectory::Create(VirtualDirectory_t directory, const PLPasStr &subdirectory)
{
void *storage = PortabilityLayer::MemoryManager::GetInstance()->Alloc(sizeof(ResourceArchiveDirectory));
if (!storage)
return nullptr;
return new (storage) ResourceArchiveDirectory(directory, subdirectory);
}
void ResourceArchiveDirectory::Destroy()
{
this->~ResourceArchiveDirectory();
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
THandle<void> ResourceArchiveDirectory::LoadResource(const ResTypeID &resTypeID, int id)
{
return GetResource(resTypeID, id, true);
}
bool ResourceArchiveDirectory::HasAnyResourcesOfType(const ResTypeID &resTypeID) const
{
int16_t scratch;
return FindFirstResourceOfType(resTypeID, scratch);
}
bool ResourceArchiveDirectory::FindFirstResourceOfType(const ResTypeID &resTypeID, int16_t &outID) const
{
int32_t resID32 = resTypeID.ExportAsInt32();
const ResTypeEntry *firstTypeEntry = *m_resTypes;
const ResTypeEntry *lastTypeEntry = firstTypeEntry + m_numResourceTypes;
const ResTypeEntry *entry = BinarySearch(firstTypeEntry, lastTypeEntry, resID32, ResourceArchiveDirectory::ResTypeSearchPredicate);
if (entry == lastTypeEntry)
return false;
outID = (*m_resIDs)[entry->m_firstRes];
return true;
}
bool ResourceArchiveDirectory::Init()
{
IGpFileSystem *fs = PLDrivers::GetFileSystem();
const char *typePaths[1] = { this->m_subdirectory };
IGpDirectoryCursor *typeDirCursor = fs->ScanDirectoryNested(m_directory, typePaths, 1);
if (!typeDirCursor)
return false;
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
m_resTypes = THandle<ResTypeEntry>(mm->AllocHandle(0));
if (!m_resTypes)
return false;
m_resIDs = THandle<int16_t>(mm->AllocHandle(0));
if (!m_resIDs)
return false;
size_t resTypeCapacity = 0;
size_t resIDCapacity = 0;
const char *typeScanFilename = nullptr;
while (typeDirCursor->GetNext(typeScanFilename))
{
GpArcResourceTypeTag resourceTypeTag;
if (!resourceTypeTag.Load(typeScanFilename))
continue;
ResTypeID resTypeID;
if (!resourceTypeTag.Decode(resTypeID))
continue;
int32_t dirResType = resTypeID.ExportAsInt32();
ResTypeEntry rte;
rte.m_resTypeID = dirResType;
rte.m_firstRes = m_numResources;
rte.m_lastRes = m_numResources;
const char *idScanFilenames[2] = { this->m_subdirectory, typeScanFilename };
IGpDirectoryCursor *typeIDCursor = fs->ScanDirectoryNested(m_directory, idScanFilenames, 2);
if (!typeIDCursor)
continue;
const char *idScanFilename = nullptr;
while (typeIDCursor->GetNext(idScanFilename))
{
int resID = 0;
bool isNegative = false;
for (size_t chi = 0; idScanFilename[chi] != '.' && idScanFilename[chi] != '\0'; chi++)
{
char ch = idScanFilename[chi];
if (ch == '-')
isNegative = true;
else if (ch >= '0' && ch <= '9')
{
resID *= 10;
int digit = ch - '0';
if (isNegative)
resID -= digit;
else
resID += digit;
}
else
break;
}
if (m_numResources == resIDCapacity)
{
const size_t oldCapacity = resIDCapacity;
resIDCapacity *= 2;
if (resIDCapacity == 0)
resIDCapacity = 1;
if (!mm->ResizeHandle(m_resIDs.MMBlock(), sizeof(int16_t) * resIDCapacity))
{
typeIDCursor->Destroy();
typeDirCursor->Destroy();
return false;
}
}
(*m_resIDs)[m_numResources] = resID;
m_numResources++;
}
typeIDCursor->Destroy();
rte.m_lastRes = m_numResources;
if (m_numResourceTypes == resTypeCapacity)
{
const size_t oldCapacity = resTypeCapacity;
resTypeCapacity *= 2;
if (resTypeCapacity == 0)
resTypeCapacity = 1;
if (!mm->ResizeHandle(m_resTypes.MMBlock(), sizeof(ResTypeEntry) * resTypeCapacity))
{
typeDirCursor->Destroy();
return false;
}
}
(*m_resTypes)[m_numResourceTypes] = rte;
m_numResourceTypes++;
}
mm->ResizeHandle(m_resTypes.MMBlock(), sizeof(ResTypeEntry) * m_numResourceTypes);
mm->ResizeHandle(m_resIDs.MMBlock(), sizeof(int16_t) * m_numResources);
ResTypeEntry *resTypes = *m_resTypes;
int16_t *resIDs = *m_resIDs;
std::sort(resTypes, resTypes + m_numResourceTypes, ResourceArchiveDirectory::ResTypeEntrySortPredicate);
for (size_t i = 0; i < m_numResourceTypes; i++)
{
int16_t *resIDStart = resIDs + resTypes[i].m_firstRes;
int16_t *resIDEnd = resIDs + resTypes[i].m_lastRes;
std::sort(resIDStart, resIDEnd);
}
m_resourceHandles = static_cast<ResourceArchiveRef*>(mm->Alloc(sizeof(ResourceArchiveRef) * m_numResources));
if (!m_resourceHandles)
return false;
for (size_t i = 0; i < m_numResources; i++)
new (m_resourceHandles + i) ResourceArchiveRef();
return true;
}
bool ResourceArchiveDirectory::IndexResource(const ResTypeID &resTypeID, int id, size_t &outIndex) const
{
int32_t resID32 = resTypeID.ExportAsInt32();
const ResTypeEntry *firstTypeEntry = *m_resTypes;
const ResTypeEntry *lastTypeEntry = firstTypeEntry + m_numResourceTypes;
const ResTypeEntry *entry = BinarySearch(firstTypeEntry, lastTypeEntry, resID32, ResourceArchiveDirectory::ResTypeSearchPredicate);
if (entry == lastTypeEntry)
return false;
const int16_t *resIDs = *m_resIDs;
const int16_t *firstRes = resIDs + entry->m_firstRes;
const int16_t *lastRes = resIDs + entry->m_lastRes;
const int16_t *idLoc = BinarySearch(firstRes, lastRes, static_cast<int16_t>(id), ResourceArchiveDirectory::ResIDSearchPredicate);
if (idLoc == lastRes)
return false;
outIndex = static_cast<size_t>(idLoc - resIDs);
return true;
}
THandle<void> ResourceArchiveDirectory::GetResource(const ResTypeID &resTypeID, int id, bool load)
{
int validationRule = 0;
size_t index = 0;
if (!IndexResource(resTypeID, id, index))
return THandle<void>();
ResourceArchiveRef *ref = m_resourceHandles + index;
MMHandleBlock *handle = nullptr;
if (ref->m_handle != nullptr)
handle = ref->m_handle;
else
{
handle = MemoryManager::GetInstance()->AllocHandle(0);
if (!handle)
return THandle<void>();
handle->m_rmSelfRef = ref;
ref->m_handle = handle;
ref->m_resID = static_cast<int16_t>(id);
ref->m_size = 0;
}
if (handle->m_contents == nullptr && load)
{
int validationRule = 0;
const char *extension = GetFileExtensionForResType(resTypeID, validationRule);
GpArcResourceTypeTag resTypeTag = GpArcResourceTypeTag::Encode(resTypeID);
char fileName[32];
snprintf(fileName, sizeof(fileName) - 1, "%i%s", id, extension);
const char *paths[3] = { m_subdirectory, resTypeTag.m_id, fileName };
GpIOStream *ioStream = PLDrivers::GetFileSystem()->OpenFileNested(m_directory, paths, 3, false, GpFileCreationDispositions::kOpenExisting);
if (!ioStream)
return THandle<void>();
size_t size = ioStream->Size();
void *contents = MemoryManager::GetInstance()->Alloc(size);
handle->m_contents = contents;
handle->m_size = size;
ref->m_size = size;
bool readOK = (ioStream->Read(contents, size));
ioStream->Close();
if (!readOK || (validationRule != ResourceValidationRules::kNone && !ValidateResource(contents, ref->m_size, static_cast<ResourceValidationRule_t>(validationRule))))
{
MemoryManager::GetInstance()->Release(contents);
handle->m_contents = nullptr;
handle->m_size = 0;
ref->m_size = 0;
return THandle<void>();
}
}
return THandle<void>(handle);
}
int ResourceArchiveDirectory::ResTypeSearchPredicate(int32_t resTypeID, const ResTypeEntry &entry)
{
if (resTypeID < entry.m_resTypeID)
return -1;
if (resTypeID > entry.m_resTypeID)
return 1;
return 0;
}
int ResourceArchiveDirectory::ResIDSearchPredicate(int16_t resTypeID, int16_t entry)
{
if (resTypeID < entry)
return -1;
if (resTypeID > entry)
return 1;
return 0;
}
bool ResourceArchiveDirectory::ResTypeEntrySortPredicate(const ResTypeEntry &a, const ResTypeEntry &b)
{
return a.m_resTypeID < b.m_resTypeID;
}
ResourceArchiveDirectory::ResourceArchiveDirectory(VirtualDirectory_t directory, const PLPasStr &subdirectory)
: m_directory(directory)
, m_numResourceTypes(0)
, m_resourceHandles(nullptr)
, m_numResources(0)
{
memcpy(m_subdirectory, subdirectory.UChars(), subdirectory.Length());
m_subdirectory[subdirectory.Length()] = '\0';
}
ResourceArchiveDirectory::~ResourceArchiveDirectory()
{
MemoryManager *mm = MemoryManager::GetInstance();
const size_t numHandles = m_numResources;
if (m_resourceHandles)
{
for (size_t i = 0; i < numHandles; i++)
{
ResourceArchiveRef &ref = m_resourceHandles[numHandles - 1 - i];
if (ref.m_handle)
mm->ReleaseHandle(ref.m_handle);
ref.~ResourceArchiveRef();
}
}
mm->Release(m_resourceHandles);
m_resIDs.Dispose();
m_resTypes.Dispose();
if (m_stream)
m_stream->Close();
}
}

View File

@@ -47,7 +47,7 @@ namespace StrCmp
const uint8_t *chars2 = string2.UChars();
const size_t len1 = string1.Length();
const size_t len2 = string1.Length();
const size_t len2 = string2.Length();
const size_t shorterLen = std::min(len1, len2);

View File

@@ -1,20 +1,20 @@
#pragma once
#include "PLCore.h"
#include "PLPasStr.h"
#pragma once
#include "PLCore.h"
#include "PLPasStr.h"
namespace StrCmp
{
{
int CompareCaseInsensitive(const PLPasStr &string1, const PLPasStr &string2);
int Compare(const PLPasStr &string1, const PLPasStr &string2);
inline bool EqualCaseInsensitive(const PLPasStr &string1, const PLPasStr &string2)
{
return CompareCaseInsensitive(string1, string2) == 0;
{
return CompareCaseInsensitive(string1, string2) == 0;
}
inline bool Equal(const PLPasStr &string1, const PLPasStr &string2)
{
return Compare(string1, string2) == 0;
}
{
return Compare(string1, string2) == 0;
}
}

View File

@@ -101,6 +101,7 @@
<ClInclude Include="FileBrowserUI.h" />
<ClInclude Include="FileManager.h" />
<ClInclude Include="FilePermission.h" />
<ClInclude Include="FileSectionStream.h" />
<ClInclude Include="FontFamily.h" />
<ClInclude Include="FontManager.h" />
<ClInclude Include="FontRenderer.h" />
@@ -110,6 +111,7 @@
<ClInclude Include="HostSuspendCallID.h" />
<ClInclude Include="HostSuspendHook.h" />
<ClInclude Include="IconLoader.h" />
<ClInclude Include="InflateStream.h" />
<ClInclude Include="InputManager.h" />
<ClInclude Include="IPlotter.h" />
<ClInclude Include="LinePlotter.h" />
@@ -230,12 +232,14 @@
<ClCompile Include="EllipsePlotter.cpp" />
<ClCompile Include="FileBrowserUI.cpp" />
<ClCompile Include="FileManager.cpp" />
<ClCompile Include="FileSectionStream.cpp" />
<ClCompile Include="FontFamily.cpp" />
<ClCompile Include="FontManager.cpp" />
<ClCompile Include="FontRenderer.cpp" />
<ClCompile Include="GPArchive.cpp" />
<ClCompile Include="HostSuspendHook.cpp" />
<ClCompile Include="IconLoader.cpp" />
<ClCompile Include="InflateStream.cpp" />
<ClCompile Include="InputManager.cpp" />
<ClCompile Include="LinePlotter.cpp" />
<ClCompile Include="MacBinary2.cpp" />

View File

@@ -420,6 +420,12 @@
<ClInclude Include="PLDrivers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FileSectionStream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="InflateStream.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CFileStream.cpp">
@@ -677,5 +683,11 @@
<ClCompile Include="PLDrivers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="FileSectionStream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="InflateStream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -16,6 +16,7 @@ namespace PortabilityLayer
class ResourceFile;
class ResTypeID;
class ZipFileProxy;
class CompositeFile;
struct ResourceArchiveRef
{
@@ -42,52 +43,10 @@ namespace PortabilityLayer
static const char *GetFileExtensionForResType(const ResTypeID &resTypeID, int &outValidationRule);
};
class ResourceArchiveDirectory final : public ResourceArchiveBase
{
public:
static ResourceArchiveDirectory *Create(VirtualDirectory_t directory, const PLPasStr &subdirectory);
void Destroy() override;
THandle<void> LoadResource(const ResTypeID &resTypeID, int id) override;
bool HasAnyResourcesOfType(const ResTypeID &resTypeID) const override;
bool FindFirstResourceOfType(const ResTypeID &resTypeID, int16_t &outID) const override;
bool Init();
private:
ResourceArchiveDirectory(VirtualDirectory_t directory, const PLPasStr &subdirectory);
~ResourceArchiveDirectory();
struct ResTypeEntry
{
int32_t m_resTypeID;
size_t m_firstRes;
size_t m_lastRes;
};
bool IndexResource(const ResTypeID &resTypeID, int id, size_t &outIndex) const;
THandle<void> GetResource(const ResTypeID &resTypeID, int id, bool load);
static int ResTypeSearchPredicate(int32_t resTypeID, const ResTypeEntry &entry);
static int ResIDSearchPredicate(int16_t resTypeID, int16_t entry);
static bool ResTypeEntrySortPredicate(const ResTypeEntry &a, const ResTypeEntry &b);
VirtualDirectory_t m_directory;
char m_subdirectory[256];
THandle<ResTypeEntry> m_resTypes;
size_t m_numResourceTypes;
THandle<int16_t> m_resIDs;
ResourceArchiveRef *m_resourceHandles;
size_t m_numResources;
};
class ResourceArchiveZipFile final : public ResourceArchiveBase
{
public:
static ResourceArchiveZipFile *Create(ZipFileProxy *zipFileProxy, GpIOStream *stream);
static ResourceArchiveZipFile *Create(ZipFileProxy *zipFileProxy, bool proxyIsShared, GpIOStream *stream);
void Destroy() override;
THandle<void> LoadResource(const ResTypeID &resTypeID, int id) override;
@@ -96,7 +55,7 @@ namespace PortabilityLayer
bool FindFirstResourceOfType(const ResTypeID &resTypeID, int16_t &outID) const override;
private:
ResourceArchiveZipFile(ZipFileProxy *zipFileProxy, GpIOStream *stream, ResourceArchiveRef *resourceHandles);
ResourceArchiveZipFile(ZipFileProxy *zipFileProxy, bool proxyIsShared, GpIOStream *stream, ResourceArchiveRef *resourceHandles);
~ResourceArchiveZipFile();
bool IndexResource(const ResTypeID &resTypeID, int id, size_t &outIndex, int &outValidationRule) const;
@@ -104,8 +63,9 @@ namespace PortabilityLayer
THandle<void> GetResource(const ResTypeID &resTypeID, int id, bool load);
ZipFileProxy *m_zipFileProxy;
GpIOStream *m_stream;
GpIOStream *m_stream; // This may be null, i.e. a composite file may own it instead
ResourceArchiveRef *m_resourceHandles;
bool m_proxyIsShared;
};
class ResourceManager
@@ -117,7 +77,7 @@ namespace PortabilityLayer
virtual THandle<void> GetAppResource(const ResTypeID &resTypeID, int16_t resID) const = 0;
virtual IResourceArchive *GetAppResourceArchive() const = 0;
virtual IResourceArchive *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const = 0;
virtual IResourceArchive *LoadResFile(CompositeFile *file) const = 0;
virtual PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) = 0;
virtual void DissociateHandle(MMHandleBlock *hdl) const = 0;

View File

@@ -1,7 +1,9 @@
#include "ZipFileProxy.h"
#include "BinarySearch.h"
#include "FileSectionStream.h"
#include "GpIOStream.h"
#include "InflateStream.h"
#include "MemoryManager.h"
#include "ZipFile.h"
@@ -227,6 +229,38 @@ namespace PortabilityLayer
return false;
}
GpIOStream *ZipFileProxy::OpenFile(size_t index) const
{
ZipCentralDirectoryFileHeader centralDirHeader = m_sortedFiles[index].Get();
if (!m_stream->SeekStart(centralDirHeader.m_localHeaderOffset))
return nullptr;
ZipFileLocalHeader localHeader;
if (m_stream->Read(&localHeader, sizeof(ZipFileLocalHeader)) != sizeof(ZipFileLocalHeader))
return nullptr;
if (!m_stream->SeekCurrent(localHeader.m_fileNameLength + localHeader.m_extraFieldLength))
return nullptr;
if (localHeader.m_compressedSize != centralDirHeader.m_compressedSize || localHeader.m_uncompressedSize != centralDirHeader.m_uncompressedSize || localHeader.m_method != centralDirHeader.m_method)
return nullptr;
const size_t compressedSize = centralDirHeader.m_compressedSize;
const size_t uncompressedSize = centralDirHeader.m_uncompressedSize;
if (localHeader.m_method == PortabilityLayer::ZipConstants::kStoredMethod)
{
if (uncompressedSize != compressedSize)
return nullptr;
return FileSectionStream::Create(m_stream, m_stream->Tell(), uncompressedSize);
}
else if (localHeader.m_method == PortabilityLayer::ZipConstants::kDeflatedMethod)
return InflateStream::Create(m_stream, m_stream->Tell(), compressedSize, uncompressedSize);
else
return nullptr;
}
size_t ZipFileProxy::NumFiles() const
{
return m_numFiles;

View File

@@ -16,6 +16,8 @@ namespace PortabilityLayer
bool IndexFile(const char *path, size_t &outIndex) const;
bool LoadFile(size_t index, void *outBuffer);
GpIOStream *OpenFile(size_t index) const;
bool HasPrefix(const char *path) const;
bool FindFirstWithPrefix(const char *resPrefix, size_t &outFileIndex) const;
@@ -23,7 +25,6 @@ namespace PortabilityLayer
size_t GetFileSize(size_t index) const;
void GetFileName(size_t index, const char *&outName, size_t &outLength) const;
static ZipFileProxy *Create(GpIOStream *stream);
private:

Some files were not shown because too many files have changed in this diff Show More