mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-12-14 03:59:36 +00:00
File system refactor, bug fixes
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
171
PortabilityLayer/FileSectionStream.cpp
Normal file
171
PortabilityLayer/FileSectionStream.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
11
PortabilityLayer/FileSectionStream.h
Normal file
11
PortabilityLayer/FileSectionStream.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "GpIOStream.h"
|
||||
|
||||
namespace PortabilityLayer
|
||||
{
|
||||
namespace FileSectionStream
|
||||
{
|
||||
GpIOStream *Create(GpIOStream *stream, GpUFilePos_t start, GpUFilePos_t size);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
250
PortabilityLayer/InflateStream.cpp
Normal file
250
PortabilityLayer/InflateStream.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
11
PortabilityLayer/InflateStream.h
Normal file
11
PortabilityLayer/InflateStream.h
Normal 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);
|
||||
};
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace PLErrors
|
||||
kIOError,
|
||||
|
||||
kResourceError,
|
||||
|
||||
kUserCancelled_TEMP,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user