File system refactor, bug fixes

This commit is contained in:
elasota
2021-03-07 04:24:13 -05:00
parent 6715bcb030
commit 3917e1a370
70 changed files with 2417 additions and 1242 deletions

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;
@@ -763,7 +748,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,180 @@
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:
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 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;
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;
};
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;
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 (!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::FileExists(VirtualDirectory_t dirID, const PLPasStr &filename)
{
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, filename, ".gpf"))
if (!FileManagerTools::ConstructFilename(extFN, filename, ".gpf"))
return false;
return PLDrivers::GetFileSystem()->FileExists(dirID, extFN);
}
bool FileManagerImpl::FileLocked(VirtualDirectory_t dirID, const PLPasStr &filename)
bool FileManagerImpl::DeleteNonCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename, const char *ext)
{
const char *exts[3] = { ".gpf", ".gpa", ".gpd" };
ExtendedFileName_t extFN;
if (!FileManagerTools::ConstructFilename(extFN, filename, ext))
return true;
for (int extIndex = 0; extIndex < sizeof(exts) / sizeof(exts[0]); extIndex++)
bool existed = false;
if (!PLDrivers::GetFileSystem()->DeleteFile(dirID, extFN, existed))
{
ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, filename, exts[extIndex]))
return true;
bool exists = false;
if (PLDrivers::GetFileSystem()->FileLocked(dirID, extFN, &exists) && exists)
return true;
if (!existed)
return false;
}
return false;
return true;
}
bool FileManagerImpl::DeleteFile(VirtualDirectory_t dirID, const PLPasStr &filename)
bool FileManagerImpl::DeleteCompositeFile(VirtualDirectory_t dirID, const PLPasStr &filename)
{
const size_t numExts = 3;
@@ -89,7 +203,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 +225,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 +233,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 +251,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 +266,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 +309,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,14 +342,30 @@ 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)
@@ -275,10 +380,109 @@ 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;
}
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,43 @@ 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 bool IsDataReadOnly() const = 0;
virtual void Close() = 0;
protected:
inline CompositeFile() {}
inline ~CompositeFile() {}
};
class FileManager
{
public:
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 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 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

@@ -23,8 +23,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

@@ -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: