Switch to zip archive format for resource data, prep work for moving from PICT/snd to BMP/WAV

This commit is contained in:
elasota
2020-01-18 08:37:57 -05:00
parent e01cd4ef2e
commit d8331eaeb7
298 changed files with 79115 additions and 231 deletions

View File

@@ -0,0 +1,44 @@
#pragma once
#include "PLLittleEndian.h"
namespace PortabilityLayer
{
namespace BitmapConstants
{
static const uint32_t kCompressionRGB = 0;
static const uint32_t kCompressionBitfields = 3;
}
struct BitmapFileHeader
{
char m_id[2]; // Normally "BM"
LEUInt32_t m_fileSize;
LEUInt16_t m_reserved1;
LEUInt16_t m_reserved2;
LEUInt32_t m_imageDataStart;
};
struct BitmapInfoHeader
{
LEUInt32_t m_thisStructureSize;
LEUInt32_t m_width;
LEUInt32_t m_height;
LEUInt16_t m_planes; // Must be 1
LEUInt16_t m_bitsPerPixel;
LEUInt32_t m_compression; // In V1 format, when using bitfields mode, the color table contains three DWORD color masks
LEUInt32_t m_imageSize;
LEUInt32_t m_xPixelsPerMeter;
LEUInt32_t m_yPixelsPerMeter;
LEUInt32_t m_numColors;
LEUInt32_t m_importantColorCount; // First N colors are important. If 0, all are important.
};
struct BitmapColorTableEntry
{
uint8_t m_b;
uint8_t m_g;
uint8_t m_r;
uint8_t m_reserved;
};
}

View File

@@ -1,76 +1,127 @@
#pragma once
#ifndef __PL_BYTEPACK_H__
#define __PL_BYTEPACK_H__
#include "DataTypes.h"
namespace PortabilityLayer
{
namespace BytePack
{
void BigUInt64(uint8_t *bytes, uint64_t value);
void BigUInt32(uint8_t *bytes, uint32_t value);
void BigUInt16(uint8_t *bytes, uint16_t value);
}
}
namespace PortabilityLayer
{
namespace BytePack
{
inline void BigUInt64(uint8_t *bytes, uint64_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 56) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 48) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 40) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 32) & 0xff);
bytes[4] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[5] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[6] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[7] = static_cast<uint8_t>(value & 0xff);
}
inline void BigUInt32(uint8_t *bytes, uint32_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[3] = static_cast<uint8_t>(value & 0xff);
}
inline void BigUInt16(uint8_t *bytes, uint16_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[1] = static_cast<uint8_t>(value & 0xff);
}
inline void BigInt64(uint8_t *bytes, int64_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 56) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 48) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 40) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 32) & 0xff);
bytes[4] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[5] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[6] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[7] = static_cast<uint8_t>(value & 0xff);
}
inline void BigInt32(uint8_t *bytes, uint32_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[3] = static_cast<uint8_t>(value & 0xff);
}
inline void BigInt16(uint8_t *bytes, uint16_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[1] = static_cast<uint8_t>(value & 0xff);
}
}
}
#endif
#pragma once
#include "DataTypes.h"
namespace PortabilityLayer
{
namespace BytePack
{
void BigUInt64(uint8_t *bytes, uint64_t value);
void BigUInt32(uint8_t *bytes, uint32_t value);
void BigUInt16(uint8_t *bytes, uint16_t value);
void LittleUInt64(uint8_t *bytes, uint64_t value);
void LittleUInt32(uint8_t *bytes, uint32_t value);
void LittleUInt16(uint8_t *bytes, uint16_t value);
}
}
namespace PortabilityLayer
{
namespace BytePack
{
inline void BigUInt64(uint8_t *bytes, uint64_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 56) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 48) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 40) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 32) & 0xff);
bytes[4] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[5] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[6] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[7] = static_cast<uint8_t>(value & 0xff);
}
inline void BigUInt32(uint8_t *bytes, uint32_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[3] = static_cast<uint8_t>(value & 0xff);
}
inline void BigUInt16(uint8_t *bytes, uint16_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[1] = static_cast<uint8_t>(value & 0xff);
}
inline void BigInt64(uint8_t *bytes, int64_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 56) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 48) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 40) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 32) & 0xff);
bytes[4] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[5] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[6] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[7] = static_cast<uint8_t>(value & 0xff);
}
inline void BigInt32(uint8_t *bytes, uint32_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[3] = static_cast<uint8_t>(value & 0xff);
}
inline void BigInt16(uint8_t *bytes, uint16_t value)
{
bytes[0] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[1] = static_cast<uint8_t>(value & 0xff);
}
inline void LittleUInt64(uint8_t *bytes, uint64_t value)
{
bytes[0] = static_cast<uint8_t>(value & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[4] = static_cast<uint8_t>((value >> 32) & 0xff);
bytes[5] = static_cast<uint8_t>((value >> 40) & 0xff);
bytes[6] = static_cast<uint8_t>((value >> 48) & 0xff);
bytes[7] = static_cast<uint8_t>((value >> 56) & 0xff);
}
inline void LittleUInt32(uint8_t *bytes, uint32_t value)
{
bytes[0] = static_cast<uint8_t>(value & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 24) & 0xff);
}
inline void LittleUInt16(uint8_t *bytes, uint16_t value)
{
bytes[0] = static_cast<uint8_t>(value & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 8) & 0xff);
}
inline void LittleInt64(uint8_t *bytes, int64_t value)
{
bytes[0] = static_cast<uint8_t>(value & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 24) & 0xff);
bytes[4] = static_cast<uint8_t>((value >> 32) & 0xff);
bytes[5] = static_cast<uint8_t>((value >> 40) & 0xff);
bytes[6] = static_cast<uint8_t>((value >> 48) & 0xff);
bytes[7] = static_cast<uint8_t>((value >> 56) & 0xff);
}
inline void LittleInt32(uint8_t *bytes, uint32_t value)
{
bytes[0] = static_cast<uint8_t>(value & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 8) & 0xff);
bytes[2] = static_cast<uint8_t>((value >> 16) & 0xff);
bytes[3] = static_cast<uint8_t>((value >> 24) & 0xff);
}
inline void LittleInt16(uint8_t *bytes, uint16_t value)
{
bytes[0] = static_cast<uint8_t>(value & 0xff);
bytes[1] = static_cast<uint8_t>((value >> 8) & 0xff);
}
}
}

View File

@@ -6,7 +6,7 @@ namespace PortabilityLayer
namespace ByteSwap
{
template<class TNumberType, class TUnsignedType>
void SwapArbitrary(TNumberType &v)
void SwapArbitraryBig(TNumberType &v)
{
GP_STATIC_ASSERT(sizeof(TNumberType) == sizeof(TUnsignedType));
@@ -21,34 +21,80 @@ namespace PortabilityLayer
v = static_cast<TNumberType>(result);
}
template<class TNumberType, class TUnsignedType>
void SwapArbitraryLittle(TNumberType &v)
{
GP_STATIC_ASSERT(sizeof(TNumberType) == sizeof(TUnsignedType));
uint8_t bytes[sizeof(TNumberType)];
for (size_t i = 0; i < sizeof(TNumberType); i++)
bytes[i] = reinterpret_cast<const uint8_t*>(&v)[i];
TUnsignedType result = 0;
for (size_t i = 0; i < sizeof(TNumberType); i++)
result |= static_cast<TUnsignedType>(bytes[i]) << (i * 8);
v = static_cast<TNumberType>(result);
}
void BigInt16(int16_t &v)
{
SwapArbitrary<int16_t, uint16_t>(v);
SwapArbitraryBig<int16_t, uint16_t>(v);
}
void BigInt32(int32_t &v)
{
SwapArbitrary<int32_t, uint32_t>(v);
SwapArbitraryBig<int32_t, uint32_t>(v);
}
void BigInt64(int64_t &v)
{
SwapArbitrary<int64_t, uint64_t>(v);
SwapArbitraryBig<int64_t, uint64_t>(v);
}
void BigUInt16(uint16_t &v)
{
SwapArbitrary<uint16_t, uint16_t>(v);
SwapArbitraryBig<uint16_t, uint16_t>(v);
}
void BigUInt32(uint32_t &v)
{
SwapArbitrary<uint32_t, uint32_t>(v);
SwapArbitraryBig<uint32_t, uint32_t>(v);
}
void BigUInt64(uint64_t &v)
{
SwapArbitrary<uint64_t, uint64_t>(v);
SwapArbitraryBig<uint64_t, uint64_t>(v);
}
void LittleInt16(int16_t &v)
{
SwapArbitraryLittle<int16_t, uint16_t>(v);
}
void LittleInt32(int32_t &v)
{
SwapArbitraryLittle<int32_t, uint32_t>(v);
}
void LittleInt64(int64_t &v)
{
SwapArbitraryLittle<int64_t, uint64_t>(v);
}
void LittleUInt16(uint16_t &v)
{
SwapArbitraryLittle<uint16_t, uint16_t>(v);
}
void LittleUInt32(uint32_t &v)
{
SwapArbitraryLittle<uint32_t, uint32_t>(v);
}
void LittleUInt64(uint64_t &v)
{
SwapArbitraryLittle<uint64_t, uint64_t>(v);
}
}
}

View File

@@ -1,20 +1,23 @@
#pragma once
#ifndef __PL_BYTESWAP_H__
#define __PL_BYTESWAP_H__
#include <stdint.h>
namespace PortabilityLayer
{
namespace ByteSwap
{
void BigInt16(int16_t &v);
void BigInt32(int32_t &v);
void BigInt64(int64_t &v);
void BigUInt16(uint16_t &v);
void BigUInt32(uint32_t &v);
void BigUInt64(uint64_t &v);
}
}
#endif
#pragma once
#include <stdint.h>
namespace PortabilityLayer
{
namespace ByteSwap
{
void BigInt16(int16_t &v);
void BigInt32(int32_t &v);
void BigInt64(int64_t &v);
void BigUInt16(uint16_t &v);
void BigUInt32(uint32_t &v);
void BigUInt64(uint64_t &v);
void LittleInt16(int16_t &v);
void LittleInt32(int32_t &v);
void LittleInt64(int64_t &v);
void LittleUInt16(uint16_t &v);
void LittleUInt32(uint32_t &v);
void LittleUInt64(uint64_t &v);
}
}

View File

@@ -0,0 +1,83 @@
#include "DeflateCodec.h"
#include "IOStream.h"
#include "MemoryManager.h"
#include "zlib.h"
namespace
{
static voidpf ZlibAllocShim(voidpf opaque, uInt items, uInt size)
{
return static_cast<PortabilityLayer::MemoryManager*>(opaque)->Alloc(items * size);
}
void ZlibFreeShim(voidpf opaque, voidpf address)
{
static_cast<PortabilityLayer::MemoryManager*>(opaque)->Release(address);
}
}
namespace PortabilityLayer
{
bool DeflateCodec::DecompressStream(IOStream *stream, size_t inSize, void *outBuffer, size_t outSize)
{
z_stream zstream;
zstream.zalloc = ZlibAllocShim;
zstream.zfree = ZlibFreeShim;
zstream.opaque = MemoryManager::GetInstance();
if (inflateInit2(&zstream, -15) != Z_OK)
return false;
const size_t bufferSize = 1024;
uint8_t buffer[1024];
zstream.avail_out = outSize;
zstream.next_out = static_cast<Bytef*>(outBuffer);
zstream.avail_in = 0;
zstream.next_in = buffer;
bool failed = false;
for (;;)
{
if (zstream.avail_in == 0)
{
const size_t sizeToRead = (bufferSize < inSize) ? bufferSize : inSize;
if (sizeToRead == 0)
{
// Ran out of input
failed = true;
break;
}
if (stream->Read(buffer, sizeToRead) != sizeToRead)
{
failed = true;
break;
}
zstream.avail_in = sizeToRead;
zstream.next_in = buffer;
}
int result = inflate(&zstream, Z_NO_FLUSH);
if (result == Z_STREAM_END)
{
failed = (zstream.avail_out != 0);
break;
}
if (result != Z_OK)
{
failed = true;
break;
}
}
inflateEnd(&zstream);
return !failed;
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
namespace PortabilityLayer
{
class IOStream;
class DeflateCodec
{
public:
static bool DecompressStream(IOStream *stream, size_t inSize, void *outBuffer, size_t outSize);
};
}

View File

@@ -59,7 +59,7 @@ namespace PortabilityLayer
bool FileManagerImpl::FileLocked(VirtualDirectory_t dirID, const PLPasStr &filename)
{
const char *exts[3] = { ".gpf", ".gpr", ".gpd" };
const char *exts[3] = { ".gpf", ".gpa", ".gpd" };
for (int extIndex = 0; extIndex < sizeof(exts) / sizeof(exts[0]); extIndex++)
{
@@ -79,7 +79,7 @@ namespace PortabilityLayer
{
const size_t numExts = 3;
const char *exts[numExts] = { ".gpr", ".gpd", ".gpf" };
const char *exts[numExts] = { ".gpa", ".gpd", ".gpf" };
const bool extMayNotExist[numExts] = { true, true, false };
for (int extIndex = 0; extIndex < numExts; extIndex++)
@@ -143,7 +143,7 @@ namespace PortabilityLayer
PLError_t FileManagerImpl::OpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission permission, IOStream *&outStream)
{
return OpenFileFork(dirID, filename, ".gpr", permission, outStream);
return OpenFileFork(dirID, filename, ".gpa", permission, outStream);
}
bool FileManagerImpl::ReadFileProperties(VirtualDirectory_t dirID, const PLPasStr &filename, MacFileProperties &properties)
@@ -170,7 +170,7 @@ namespace PortabilityLayer
PLError_t FileManagerImpl::RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission permission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, IOStream *&outStream)
{
return RawOpenFileFork(dirID, filename, ".gpr", permission, ignoreMeta, createDisposition, outStream);
return RawOpenFileFork(dirID, filename, ".gpa", permission, ignoreMeta, createDisposition, outStream);
}
bool FileManagerImpl::PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName)

View File

@@ -0,0 +1,84 @@
#include "GPArchive.h"
#include "ResTypeID.h"
#include <string.h>
static const char *gs_forbiddenNames[] =
{
"COM1",
"COM2",
"COM3",
"COM4",
"COM5",
"COM6",
"COM7",
"COM8",
"COM9",
"LPT1",
"LPT2",
"LPT3",
"LPT4",
"LPT5",
"LPT6",
"LPT7",
"LPT8",
"LPT9",
};
namespace PortabilityLayer
{
GpArcResourceTypeTag GpArcResourceTypeTag::Encode(const ResTypeID &tag)
{
static const char *nibbles = "0123456789abcdef";
char chars[4];
tag.ExportAsChars(chars);
GpArcResourceTypeTag output;
memset(&output, 0, sizeof(output));
char *outChar = output.m_id;
for (int i = 0; i < 4; i++)
{
char c = chars[i];
bool isForbidden = (c < ' ' || c == '<' || c == '>' || c == ':' || c == '\"' || c == '/' || c == '\\' || c == '|' || c == '?' || c == '*' || c > '~' || c == '$');
if (i == 3)
{
if (c == ' ' || c == '.')
isForbidden = true;
else
{
for (int fi = 0; fi < sizeof(gs_forbiddenNames) / sizeof(gs_forbiddenNames[0]); fi++)
{
if (!memcmp(chars, gs_forbiddenNames[fi], 4))
{
isForbidden = true;
break;
}
}
}
}
if (isForbidden)
{
uint8_t byteValue;
memcpy(&byteValue, &c, 1);
*outChar++ = '$';
int highNibble = (byteValue >> 4) & 0xf;
int lowNibble = (byteValue & 0xf);
*outChar++ = nibbles[highNibble];
*outChar++ = nibbles[lowNibble];
}
else
{
*outChar++ = c;
}
}
return output;
}
}

View File

@@ -0,0 +1,13 @@
#pragma once
namespace PortabilityLayer
{
class ResTypeID;
struct GpArcResourceTypeTag
{
char m_id[13];
static GpArcResourceTypeTag Encode(const ResTypeID &tag);
};
}

View File

@@ -1,29 +1,30 @@
#pragma once
#ifndef __PL_MM_HANDLE_BLOCK_H__
#define __PL_MM_HANDLE_BLOCK_H__
#include <stdint.h>
#include "CoreDefs.h"
namespace PortabilityLayer
{
struct ResourceCompiledRef;
struct MMHandleBlock
{
explicit MMHandleBlock(void *contents, size_t size);
void **AsHandle();
void *m_contents; // This must be the first field
ResourceCompiledRef *m_rmSelfRef;
size_t m_size;
private:
MMHandleBlock() GP_DELETED;
};
}
#endif
#pragma once
#ifndef __PL_MM_HANDLE_BLOCK_H__
#define __PL_MM_HANDLE_BLOCK_H__
#include <stdint.h>
#include "CoreDefs.h"
namespace PortabilityLayer
{
struct ResourceArchiveRef;
struct ResourceCompiledRef;
struct MMHandleBlock
{
explicit MMHandleBlock(void *contents, size_t size);
void **AsHandle();
void *m_contents; // This must be the first field
ResourceArchiveRef *m_rmSelfRef;
size_t m_size;
private:
MMHandleBlock() GP_DELETED;
};
}
#endif

View File

@@ -515,6 +515,8 @@ namespace PortabilityLayer
PortabilityLayer::MemoryManager::GetInstance()->ReleaseHandle(menuPtr->stringBlobHandle);
menuPtr->stringBlobHandle = newHandle.MMBlock();
return true;
}
bool MenuManagerImpl::IsPointInMenuBar(const Vec2i &point) const

View File

@@ -1,6 +1,4 @@
#pragma once
#ifndef __PL_BIG_ENDIAN_H__
#define __PL_BIG_ENDIAN_H__
#include <stdint.h>
@@ -251,5 +249,3 @@ struct BEFixed32_t
BEInt16_t m_intPart;
BEUInt16_t m_fracPart;
};
#endif

View File

@@ -0,0 +1,245 @@
#pragma once
#include <stdint.h>
template<class T>
struct LEInteger
{
public:
LEInteger();
LEInteger(const LEInteger<T> &other);
explicit LEInteger(T i);
operator T() const;
LEInteger<T> &operator=(T value);
template<class TOther>
LEInteger<T> &operator+=(TOther value);
template<class TOther>
LEInteger<T> &operator-=(TOther value);
template<class TOther>
LEInteger<T> &operator*=(TOther value);
template<class TOther>
LEInteger<T> &operator/=(TOther value);
template<class TOther>
LEInteger<T> &operator%=(TOther value);
LEInteger<T>& operator--();
LEInteger<T> operator--(int);
LEInteger<T>& operator++();
LEInteger<T> operator++(int);
private:
uint8_t m_leValueBytes[sizeof(T)];
};
template<class T>
struct LEInteger_SwapHelper
{
};
#include "ByteSwap.h"
template<>
struct LEInteger_SwapHelper<int16_t>
{
inline static void Swap(int16_t &v)
{
PortabilityLayer::ByteSwap::LittleInt16(v);
}
};
template<>
struct LEInteger_SwapHelper<int32_t>
{
inline static void Swap(int32_t &v)
{
PortabilityLayer::ByteSwap::LittleInt32(v);
}
};
template<>
struct LEInteger_SwapHelper<uint16_t>
{
inline static void Swap(uint16_t &v)
{
PortabilityLayer::ByteSwap::LittleUInt16(v);
}
};
template<>
struct LEInteger_SwapHelper<uint32_t>
{
inline static void Swap(uint32_t &v)
{
PortabilityLayer::ByteSwap::LittleUInt32(v);
}
};
#include <string.h>
template<class T>
inline LEInteger<T>::LEInteger()
{
memset(m_leValueBytes, 0, sizeof(T));
}
template<class T>
inline LEInteger<T>::LEInteger(const LEInteger<T> &other)
{
memcpy(m_leValueBytes, other.m_leValueBytes, sizeof(T));
}
template<class T>
inline LEInteger<T>::LEInteger(T i)
{
LEInteger_SwapHelper<T>::Swap(i);
memcpy(m_leValueBytes, &i, sizeof(T));
}
template<class T>
inline LEInteger<T>::operator T() const
{
T result;
memcpy(&result, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(result);
return result;
}
template<class T>
inline LEInteger<T> &LEInteger<T>::operator=(T value)
{
LEInteger_SwapHelper<T>::Swap(value);
memcpy(m_leValueBytes, &value, sizeof(T));
return *this;
}
template<class T>
template<class TOther>
LEInteger<T> &LEInteger<T>::operator+=(TOther value)
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue += value;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
template<class TOther>
LEInteger<T> &LEInteger<T>::operator-=(TOther value)
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue -= value;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
template<class TOther>
LEInteger<T> &LEInteger<T>::operator*=(TOther value)
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue *= value;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
template<class TOther>
LEInteger<T> &LEInteger<T>::operator/=(TOther value)
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue /= value;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
template<class TOther>
LEInteger<T> &LEInteger<T>::operator%=(TOther value)
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue %= value;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
LEInteger<T>& LEInteger<T>::operator--()
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue--;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
LEInteger<T> LEInteger<T>::operator--(int)
{
LEInteger<T> orig(*this);
--(*this);
return orig;
}
template<class T>
LEInteger<T>& LEInteger<T>::operator++()
{
T storedValue;
memcpy(&storedValue, m_leValueBytes, sizeof(T));
LEInteger_SwapHelper<T>::Swap(storedValue);
storedValue++;
LEInteger_SwapHelper<T>::Swap(storedValue);
memcpy(m_leValueBytes, &storedValue, sizeof(T));
return *this;
}
template<class T>
LEInteger<T> LEInteger<T>::operator++(int)
{
LEInteger<T> orig(*this);
++(*this);
return orig;
}
typedef LEInteger<int16_t> LEInt16_t;
typedef LEInteger<int32_t> LEInt32_t;
typedef LEInteger<uint16_t> LEUInt16_t;
typedef LEInteger<uint32_t> LEUInt32_t;

View File

@@ -1,6 +1,7 @@
#include "ResourceManager.h"
#include "VirtualDirectory.h"
#include "FileManager.h"
#include "GPArchive.h"
#include "HostFileSystem.h"
#include "HostMemoryBuffer.h"
#include "IOStream.h"
@@ -13,12 +14,14 @@
#include "ResourceFile.h"
#include "PLPasStr.h"
#include "PLErrorCodes.h"
#include "ZipFileProxy.h"
#include <vector>
namespace PortabilityLayer
{
struct MMHandleBlock;
class ResourceArchive;
class ResourceManagerImpl final : public ResourceManager
{
@@ -30,7 +33,7 @@ namespace PortabilityLayer
void SetResLoad(bool load) override;
ResourceFile *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const override;
ResourceArchive *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const override;
short OpenResFork(VirtualDirectory_t virtualDir, const PLPasStr &filename) override;
void CloseResFile(short ref) override;
PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) override;
@@ -41,7 +44,7 @@ namespace PortabilityLayer
void SetCurrentResFile(short ref) override;
void DissociateHandle(MMHandleBlock *hdl) const override;
const ResourceCompiledRef *ResourceForHandle(MMHandleBlock *hdl) const override;
const ResourceArchiveRef *ResourceForHandle(MMHandleBlock *hdl) const override;
static ResourceManagerImpl *GetInstance();
@@ -50,10 +53,10 @@ namespace PortabilityLayer
{
short m_prevFile;
short m_nextFile;
ResourceFile *m_resourceFile;
ResourceArchive *m_resourceArchive;
};
void UnloadAndDestroyResourceFile(ResourceFile *rf);
void UnloadAndDestroyResourceFile(ResourceArchive *rf);
std::vector<ResFileSlot> m_resFiles;
short m_firstResFile;
@@ -81,8 +84,8 @@ namespace PortabilityLayer
{
for (std::vector<ResFileSlot>::iterator it = m_resFiles.begin(), itEnd = m_resFiles.end(); it != itEnd; ++it)
{
if (it->m_resourceFile)
UnloadAndDestroyResourceFile(it->m_resourceFile);
if (it->m_resourceArchive)
UnloadAndDestroyResourceFile(it->m_resourceArchive);
}
m_resFiles.clear();
@@ -106,32 +109,13 @@ namespace PortabilityLayer
hdl->m_rmSelfRef = nullptr;
}
const ResourceCompiledRef *ResourceManagerImpl::ResourceForHandle(MMHandleBlock *hdl) const
const ResourceArchiveRef *ResourceManagerImpl::ResourceForHandle(MMHandleBlock *hdl) const
{
return hdl->m_rmSelfRef;
}
void ResourceManagerImpl::UnloadAndDestroyResourceFile(ResourceFile *rf)
void ResourceManagerImpl::UnloadAndDestroyResourceFile(ResourceArchive *rf)
{
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
ResourceCompiledTypeList *rtls = nullptr;
size_t numRTLs = 0;
rf->GetAllResourceTypeLists(rtls, numRTLs);
for (size_t i = 0; i < numRTLs; i++)
{
const ResourceCompiledTypeList &rtl = rtls[i];
const size_t numRefs = rtl.m_numRefs;
for (size_t r = 0; r < numRefs; r++)
{
const ResourceCompiledRef &ref = rtl.m_firstRef[r];
if (MMHandleBlock *hdl = ref.m_handle)
mm->ReleaseHandle(hdl);
}
}
rf->Destroy();
}
@@ -145,26 +129,28 @@ namespace PortabilityLayer
m_load = load;
}
ResourceFile *ResourceManagerImpl::LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const
ResourceArchive *ResourceManagerImpl::LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const
{
IOStream *fStream = nullptr;
if (FileManager::GetInstance()->RawOpenFileResources(virtualDir, filename, EFilePermission_Read, true, GpFileCreationDispositions::kOpenExisting, fStream) != PLErrors::kNone)
return nullptr;
ResourceFile *resFile = ResourceFile::Create();
if (!resFile)
return nullptr;
bool loaded = resFile->Load(fStream);
fStream->Close();
if (!loaded)
ZipFileProxy *proxy = ZipFileProxy::Create(fStream);
if (!proxy)
{
resFile->Destroy();
fStream->Close();
return nullptr;
}
return resFile;
ResourceArchive *archive = ResourceArchive::Create(proxy, fStream);
if (!archive)
{
proxy->Destroy();
fStream->Close();
return nullptr;
}
return archive;
}
short ResourceManagerImpl::OpenResFork(VirtualDirectory_t virtualDir, const PLPasStr &filename)
@@ -174,7 +160,7 @@ namespace PortabilityLayer
for (size_t i = 0; i < numSlots; i++)
{
if (m_resFiles[i].m_resourceFile == nullptr)
if (m_resFiles[i].m_resourceArchive == nullptr)
{
resFileIndex = i;
break;
@@ -185,13 +171,13 @@ namespace PortabilityLayer
return -1;
ResourceFile *resFile = LoadResFile(virtualDir, filename);
ResourceArchive *resFile = LoadResFile(virtualDir, filename);
if (!resFile)
return -1;
ResFileSlot slot;
slot.m_resourceFile = resFile;
slot.m_resourceArchive = resFile;
slot.m_prevFile = m_lastResFile;
slot.m_nextFile = -1;
@@ -218,10 +204,10 @@ namespace PortabilityLayer
{
ResFileSlot &slot = m_resFiles[ref];
assert(slot.m_resourceFile != nullptr);
assert(slot.m_resourceArchive != nullptr);
slot.m_resourceFile->Destroy();
slot.m_resourceFile = nullptr;
slot.m_resourceArchive->Destroy();
slot.m_resourceArchive = nullptr;
if (m_lastResFile == ref)
m_lastResFile = slot.m_prevFile;
@@ -272,9 +258,9 @@ namespace PortabilityLayer
while (searchIndex >= 0)
{
const ResFileSlot& slot = m_resFiles[searchIndex];
assert(slot.m_resourceFile);
assert(slot.m_resourceArchive);
THandle<void> resHdl = slot.m_resourceFile->GetResource(resType, id, m_load);
THandle<void> resHdl = slot.m_resourceArchive->GetResource(resType, id, m_load);
if (resHdl != nullptr)
return resHdl;
@@ -284,8 +270,122 @@ namespace PortabilityLayer
return nullptr;
}
ResourceManagerImpl ResourceManagerImpl::ms_instance;
ResourceManager *ResourceManager::GetInstance() { return ResourceManagerImpl::GetInstance(); }
// ===========================================================================================
ResourceArchiveRef::ResourceArchiveRef()
: m_handle(nullptr)
, m_size(0)
, m_resID(0)
{
}
ResourceArchive *ResourceArchive::Create(ZipFileProxy *zipFileProxy, IOStream *stream)
{
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
size_t numFiles = zipFileProxy->NumFiles();
ResourceArchiveRef *refs = static_cast<ResourceArchiveRef*>(mm->Alloc(sizeof(ResourceArchiveRef) * numFiles));
if (!refs)
return nullptr;
for (size_t i = 0; i < numFiles; i++)
new (refs + i) ResourceArchiveRef();
void *storage = mm->Alloc(sizeof(ResourceArchive));
if (!storage)
{
mm->Release(refs);
return nullptr;
}
return new (storage) ResourceArchive(zipFileProxy, stream, refs);
}
void ResourceArchive::Destroy()
{
this->~ResourceArchive();
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
THandle<void> ResourceArchive::GetResource(const ResTypeID &resTypeID, int id, bool load)
{
const char *extension = ".bin";
char resourceFile[64];
GpArcResourceTypeTag resTag = GpArcResourceTypeTag::Encode(resTypeID);
snprintf(resourceFile, sizeof(resourceFile) - 1, "%s/%i%s", resTag.m_id, id, extension);
size_t index = 0;
if (!m_zipFileProxy->IndexFile(resourceFile, 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 = m_zipFileProxy->GetFileSize(index);
}
if (handle->m_contents == nullptr && load)
{
if (ref->m_size > 0)
{
void *contents = MemoryManager::GetInstance()->Alloc(ref->m_size);
handle->m_contents = contents;
handle->m_size = ref->m_size;
if (!m_zipFileProxy->LoadFile(index, contents))
{
MemoryManager::GetInstance()->Release(contents);
handle->m_contents = nullptr;
handle->m_size = 0;
}
}
}
return THandle<void>(handle);
}
ResourceArchive::ResourceArchive(ZipFileProxy *zipFileProxy, IOStream *stream, ResourceArchiveRef *resourceHandles)
: m_zipFileProxy(zipFileProxy)
, m_stream(stream)
, m_resourceHandles(resourceHandles)
{
}
ResourceArchive::~ResourceArchive()
{
MemoryManager *mm = MemoryManager::GetInstance();
const size_t numFiles = m_zipFileProxy->NumFiles();
for (size_t i = 0; i < numFiles; i++)
{
ResourceArchiveRef &ref = m_resourceHandles[numFiles - 1 - i];
if (ref.m_handle)
mm->ReleaseHandle(ref.m_handle);
ref.~ResourceArchiveRef();
}
mm->Release(m_resourceHandles);
m_zipFileProxy->Destroy();
m_stream->Close();
}
}

View File

@@ -53,8 +53,8 @@ void SetResLoad(Boolean load)
long GetMaxResourceSize(Handle res)
{
const PortabilityLayer::MMHandleBlock *hBlock = res.MMBlock();
const PortabilityLayer::ResourceCompiledRef *resRef = hBlock->m_rmSelfRef;
return resRef->GetSize();
const PortabilityLayer::ResourceArchiveRef *resRef = hBlock->m_rmSelfRef;
return resRef->m_size;
}
short HOpenResFile(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &name, int permissions)

View File

@@ -62,6 +62,7 @@
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
<Import Project="..\MacRomanConversion.props" />
<Import Project="..\zlib.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -69,6 +70,7 @@
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
<Import Project="..\MacRomanConversion.props" />
<Import Project="..\zlib.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -76,6 +78,7 @@
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
<Import Project="..\MacRomanConversion.props" />
<Import Project="..\zlib.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
@@ -83,6 +86,7 @@
<Import Project="..\GpCommon.props" />
<Import Project="..\stb.props" />
<Import Project="..\MacRomanConversion.props" />
<Import Project="..\zlib.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
@@ -136,12 +140,14 @@
<ClInclude Include="AEManager.h" />
<ClInclude Include="BinarySearch.h" />
<ClInclude Include="BinHex4.h" />
<ClInclude Include="BMPFormat.h" />
<ClInclude Include="BytePack.h" />
<ClInclude Include="ByteSwap.h" />
<ClInclude Include="ByteUnpack.h" />
<ClInclude Include="CFileStream.h" />
<ClInclude Include="ClientAudioChannelContext.h" />
<ClInclude Include="DataTypes.h" />
<ClInclude Include="DeflateCodec.h" />
<ClInclude Include="DialogManager.h" />
<ClInclude Include="DisplayDeviceManager.h" />
<ClInclude Include="EllipsePlotter.h" />
@@ -152,6 +158,7 @@
<ClInclude Include="FontManager.h" />
<ClInclude Include="FontRenderer.h" />
<ClInclude Include="GpAppInterface.h" />
<ClInclude Include="GPArchive.h" />
<ClInclude Include="HostAudioChannel.h" />
<ClInclude Include="HostAudioDriver.h" />
<ClInclude Include="HostDirectoryCursor.h" />
@@ -206,10 +213,12 @@
<ClInclude Include="PLImageWidget.h" />
<ClInclude Include="PLInvisibleWidget.h" />
<ClInclude Include="PLLabelWidget.h" />
<ClInclude Include="PLLittleEndian.h" />
<ClInclude Include="PLPopupMenuWidget.h" />
<ClInclude Include="PLRadioButtonWidget.h" />
<ClInclude Include="PLScrollBarWidget.h" />
<ClInclude Include="PLWidgets.h" />
<ClInclude Include="ZipFileProxy.h" />
<ClInclude Include="SimpleImage.h" />
<ClInclude Include="PLKeyEncoding.h" />
<ClInclude Include="PLMacTypes.h" />
@@ -271,9 +280,11 @@
<ClInclude Include="ScopedPtr.h" />
<ClInclude Include="SmallestInt.h" />
<ClInclude Include="UnsafePascalStr.h" />
<ClInclude Include="WaveFormat.h" />
<ClInclude Include="WindowDef.h" />
<ClInclude Include="WindowManager.h" />
<ClInclude Include="XModemCRC.h" />
<ClInclude Include="ZipFile.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\stb\stb_image_write.c" />
@@ -281,6 +292,7 @@
<ClCompile Include="BinHex4.cpp" />
<ClCompile Include="ByteSwap.cpp" />
<ClCompile Include="CFileStream.cpp" />
<ClCompile Include="DeflateCodec.cpp" />
<ClCompile Include="DialogManager.cpp" />
<ClCompile Include="DisplayDeviceManager.cpp" />
<ClCompile Include="EllipsePlotter.cpp" />
@@ -288,6 +300,7 @@
<ClCompile Include="FontFamily.cpp" />
<ClCompile Include="FontManager.cpp" />
<ClCompile Include="FontRenderer.cpp" />
<ClCompile Include="GPArchive.cpp" />
<ClCompile Include="HostAudioDriver.cpp" />
<ClCompile Include="HostDisplayDriver.cpp" />
<ClCompile Include="HostFileSystem.cpp" />
@@ -359,11 +372,15 @@
<ClCompile Include="WindowDef.cpp" />
<ClCompile Include="WindowManager.cpp" />
<ClCompile Include="XModemCRC.cpp" />
<ClCompile Include="ZipFileProxy.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MacRomanConversion\MacRomanConversion.vcxproj">
<Project>{07351a8e-1f79-42c9-bbab-31f071eaa99e}</Project>
</ProjectReference>
<ProjectReference Include="..\zlib\zlib.vcxproj">
<Project>{6ae5c85e-6631-4a12-97a0-a05f812fe9ca}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -444,6 +444,27 @@
<ClInclude Include="PLRadioButtonWidget.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ZipFile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PLLittleEndian.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GPArchive.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BMPFormat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WaveFormat.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ZipFileProxy.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DeflateCodec.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CFileStream.cpp">
@@ -695,5 +716,14 @@
<ClCompile Include="PLKeyEncoding.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GPArchive.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ZipFileProxy.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DeflateCodec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -9,7 +9,6 @@ namespace PortabilityLayer
struct ResourceCompiledRef
{
const uint8_t *m_resData;
MMHandleBlock *m_handle;
int16_t m_resID;
int16_t m_resNameOffset;
uint8_t m_attributes;

View File

@@ -233,7 +233,6 @@ namespace PortabilityLayer
refToCompile->m_resData = m_resDataBlob + dataOffset;
refToCompile->m_resID = refListEntry.m_resID;
refToCompile->m_resNameOffset = refListEntry.m_resourceNameOffset;
refToCompile->m_handle = nullptr;
uint32_t resSize;
memcpy(&resSize, m_resDataBlob + dataSizeOffset, 4);
@@ -356,7 +355,7 @@ namespace PortabilityLayer
return tl;
}
THandle<void> ResourceFile::GetResource(const ResTypeID &resType, int id, bool load)
THandle<void> ResourceFile::LoadResource(const ResTypeID &resType, int id)
{
const ResourceCompiledTypeList *tl = GetResourceTypeList(resType);
if (tl == nullptr)
@@ -369,26 +368,15 @@ namespace PortabilityLayer
if (ref == refEnd)
return THandle<void>();
MMHandleBlock *handle = nullptr;
if (ref->m_handle != nullptr)
handle = ref->m_handle;
else
{
handle = MemoryManager::GetInstance()->AllocHandle(0);
handle->m_rmSelfRef = ref;
ref->m_handle = handle;
}
MMHandleBlock *handle = MemoryManager::GetInstance()->AllocHandle(0);
if (handle->m_contents == nullptr && load)
const uint32_t resSize = ref->GetSize();
if (resSize > 0)
{
const uint32_t resSize = ref->GetSize();
if (resSize > 0)
{
void *contents = MemoryManager::GetInstance()->Alloc(resSize);
handle->m_contents = contents;
handle->m_size = resSize;
memcpy(handle->m_contents, ref->m_resData, resSize);
}
void *contents = MemoryManager::GetInstance()->Alloc(resSize);
handle->m_contents = contents;
handle->m_size = resSize;
memcpy(handle->m_contents, ref->m_resData, resSize);
}
return THandle<void>(handle);

View File

@@ -13,7 +13,7 @@ namespace PortabilityLayer
struct ResourceCompiledTypeList;
class ResTypeID;
class ResourceFile
class ResourceFile final
{
public:
bool Load(IOStream *stream);
@@ -21,7 +21,7 @@ namespace PortabilityLayer
void GetAllResourceTypeLists(ResourceCompiledTypeList *&outTypeLists, size_t &outCount) const;
const ResourceCompiledTypeList *GetResourceTypeList(const ResTypeID &resType);
THandle<void> GetResource(const ResTypeID &resType, int id, bool load);
THandle<void> LoadResource(const ResTypeID &resType, int id);
static ResourceFile *Create();
void Destroy();

View File

@@ -8,10 +8,38 @@ class PLPasStr;
namespace PortabilityLayer
{
class IOStream;
struct MMHandleBlock;
struct ResourceCompiledRef;
class ResourceFile;
class ResTypeID;
class ZipFileProxy;
struct ResourceArchiveRef
{
ResourceArchiveRef();
MMHandleBlock *m_handle;
size_t m_size;
int16_t m_resID;
};
class ResourceArchive final
{
public:
static ResourceArchive *Create(ZipFileProxy *zipFileProxy, IOStream *stream);
void Destroy();
THandle<void> GetResource(const ResTypeID &resTypeID, int id, bool load);
private:
ResourceArchive(ZipFileProxy *zipFileProxy, IOStream *stream, ResourceArchiveRef *resourceHandles);
~ResourceArchive();
ZipFileProxy *m_zipFileProxy;
IOStream *m_stream;
ResourceArchiveRef *m_resourceHandles;
};
class ResourceManager
{
@@ -21,7 +49,7 @@ namespace PortabilityLayer
virtual void SetResLoad(bool load) = 0;
virtual ResourceFile *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const = 0;
virtual ResourceArchive *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const = 0;
virtual short OpenResFork(VirtualDirectory_t virtualDir, const PLPasStr &filename) = 0;
virtual void CloseResFile(short ref) = 0;
virtual PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) = 0;
@@ -32,7 +60,7 @@ namespace PortabilityLayer
virtual void SetCurrentResFile(short ref) = 0;
virtual void DissociateHandle(MMHandleBlock *hdl) const = 0;
virtual const ResourceCompiledRef *ResourceForHandle(MMHandleBlock *hdl) const = 0;
virtual const ResourceArchiveRef *ResourceForHandle(MMHandleBlock *hdl) const = 0;
static ResourceManager *GetInstance();
};

View File

@@ -0,0 +1,46 @@
#pragma once
#include "PLLittleEndian.h"
namespace PortabilityLayer
{
namespace WaveConstants
{
static const uint16_t kFormatPCM = 1;
static const uint32_t kRiffChunkID = 0x46464952;
static const uint32_t kWaveChunkID = 0x45564157;
static const uint32_t kFormatChunkID = 0x20746d66;
static const uint32_t kDataChunkID = 0x61746164;
}
struct RIFFTag
{
LEUInt32_t m_tag;
LEUInt32_t m_chunkSize; // Actual size is padded to 2-byte alignment
};
struct WaveFormatChunkV1
{
LEUInt16_t m_formatCode;
LEUInt16_t m_numChannels;
LEUInt32_t m_sampleRate;
LEUInt32_t m_bytesPerSecond;
LEUInt16_t m_blockAlignmentBytes;
LEUInt16_t m_bitsPerSample;
};
struct WaveFormatChunkV2
{
WaveFormatChunkV1 m_v1;
LEUInt16_t m_extSize;
};
struct WaveFormatChunkV3
{
WaveFormatChunkV2 m_v2;
LEUInt16_t m_validBitsPerSample;
LEUInt32_t m_channelMask;
uint8_t m_subFormatGUID[16];
};
}

View File

@@ -0,0 +1,81 @@
#pragma once
#include "PLLittleEndian.h"
#include <stdint.h>
namespace PortabilityLayer
{
namespace ZipConstants
{
static const uint16_t kStoredRequiredVersion = 10;
static const uint16_t kDirectoryRequiredVersion = 20;
static const uint16_t kCompressedRequiredVersion = 20;
static const uint32_t kDirectoryAttributes = 0x0010;
static const uint32_t kArchivedAttributes = 0x0020;
static const uint16_t kStoredMethod = 0x0000;
static const uint16_t kDeflatedMethod = 0x0008;
}
struct ZipFileLocalHeader
{
static const uint32_t kSignature = 0x04034b50;
LEUInt32_t m_signature;
LEUInt16_t m_versionRequired;
LEUInt16_t m_flags;
LEUInt16_t m_method;
LEUInt16_t m_modificationTime;
LEUInt16_t m_modificationDate;
LEUInt32_t m_crc;
LEUInt32_t m_compressedSize;
LEUInt32_t m_uncompressedSize;
LEUInt16_t m_fileNameLength;
LEUInt16_t m_extraFieldLength;
};
struct ZipCentralDirectoryFileHeader
{
static const uint32_t kSignature = 0x02014b50;
LEUInt32_t m_signature;
LEUInt16_t m_versionCreated;
LEUInt16_t m_versionRequired;
LEUInt16_t m_flags;
LEUInt16_t m_method;
LEUInt16_t m_modificationTime;
LEUInt16_t m_modificationDate;
LEUInt32_t m_crc;
LEUInt32_t m_compressedSize;
LEUInt32_t m_uncompressedSize;
LEUInt16_t m_fileNameLength;
LEUInt16_t m_extraFieldLength;
LEUInt16_t m_commentLength;
LEUInt16_t m_diskNumber;
LEUInt16_t m_internalAttributes;
LEUInt32_t m_externalAttributes;
LEUInt32_t m_localHeaderOffset;
// File name
// Extra field
// File comment
};
struct ZipEndOfCentralDirectoryRecord
{
static const uint32_t kSignature = 0x06054b50;
LEUInt32_t m_signature;
LEUInt16_t m_thisDiskNumber;
LEUInt16_t m_centralDirDisk;
LEUInt16_t m_numCentralDirRecordsThisDisk;
LEUInt16_t m_numCentralDirRecords;
LEUInt32_t m_centralDirectorySizeBytes;
LEUInt32_t m_centralDirStartOffset;
LEUInt16_t m_commentLength;
// Comment
};
}

View File

@@ -0,0 +1,287 @@
#include "ZipFileProxy.h"
#include "BinarySearch.h"
#include "IOStream.h"
#include "MemoryManager.h"
#include "ZipFile.h"
#include "DeflateCodec.h"
namespace
{
static int ZipDirectorySearchPredicate(const char *path, PortabilityLayer::ZipCentralDirectoryFileHeader *item)
{
const uint16_t fnameLength = item->m_fileNameLength;
const char *itemPath = reinterpret_cast<const char*>(item) + sizeof(PortabilityLayer::ZipCentralDirectoryFileHeader);
for (size_t i = 0; i < fnameLength; i++)
{
const uint8_t pathC = static_cast<uint8_t>(path[i] & 0xff);
if (pathC == 0)
return -1;
const uint8_t itemC = static_cast<uint8_t>(itemPath[i] & 0xff);
if (pathC < itemC)
return -1;
if (pathC > itemC)
return 1;
}
if (path[fnameLength] == 0)
return 0;
else
return 1;
}
static int ZipDirectorySortPredicate(const void *a, const void *b)
{
const PortabilityLayer::ZipCentralDirectoryFileHeader *typedA = *static_cast<PortabilityLayer::ZipCentralDirectoryFileHeader *const*>(a);
const PortabilityLayer::ZipCentralDirectoryFileHeader *typedB = *static_cast<PortabilityLayer::ZipCentralDirectoryFileHeader *const*>(b);
const uint16_t lenA = typedA->m_fileNameLength;
const uint16_t lenB = typedB->m_fileNameLength;
const char *pathA = reinterpret_cast<const char*>(typedA) + sizeof(PortabilityLayer::ZipCentralDirectoryFileHeader);
const char *pathB = reinterpret_cast<const char*>(typedB) + sizeof(PortabilityLayer::ZipCentralDirectoryFileHeader);
const size_t shorterLength = (lenA < lenB) ? lenA : lenB;
for (size_t i = 0; i < shorterLength; i++)
{
const uint8_t ca = static_cast<uint8_t>(pathA[i] & 0xff);
const uint8_t cb = static_cast<uint8_t>(pathB[i] & 0xff);
if (ca < cb)
return -1;
if (ca > cb)
return 1;
}
if (lenA < lenB)
return -1;
if (lenA > lenB)
return 1;
return 0;
}
static bool CheckAndFixFileName(uint8_t *fname, size_t length)
{
for (size_t i = 0; i < length; i++)
{
if (fname[i] == '\\')
fname[i] = '/';
else if (fname[i] == 0)
return false; // Illegal null in file path, illegal
}
return true;
}
}
namespace PortabilityLayer
{
void ZipFileProxy::Destroy()
{
MemoryManager *mm = MemoryManager::GetInstance();
this->~ZipFileProxy();
mm->Release(this);
}
bool ZipFileProxy::IndexFile(const char *path, size_t &outIndex) const
{
PortabilityLayer::ZipCentralDirectoryFileHeader **indexLoc = BinarySearch(m_sortedFiles, m_sortedFiles + m_numFiles, path, ZipDirectorySearchPredicate);
const size_t index = static_cast<size_t>(indexLoc - m_sortedFiles);
if (index == m_numFiles)
return false;
else
{
outIndex = index;
return true;
}
}
bool ZipFileProxy::LoadFile(size_t index, void *outBuffer)
{
ZipCentralDirectoryFileHeader *centralDirHeader = m_sortedFiles[index];
if (!m_stream->SeekStart(centralDirHeader->m_localHeaderOffset))
return false;
ZipFileLocalHeader localHeader;
if (m_stream->Read(&localHeader, sizeof(ZipFileLocalHeader)) != sizeof(ZipFileLocalHeader))
return false;
if (!m_stream->SeekCurrent(localHeader.m_fileNameLength + localHeader.m_extraFieldLength))
return false;
if (localHeader.m_compressedSize != centralDirHeader->m_compressedSize || localHeader.m_uncompressedSize != centralDirHeader->m_uncompressedSize || localHeader.m_method != centralDirHeader->m_method)
return false;
const size_t uncompressedSize = centralDirHeader->m_uncompressedSize;
if (localHeader.m_method == PortabilityLayer::ZipConstants::kStoredMethod)
return m_stream->Read(outBuffer, uncompressedSize) == uncompressedSize;
else if (localHeader.m_method == PortabilityLayer::ZipConstants::kDeflatedMethod)
{
const size_t compressedSize = centralDirHeader->m_compressedSize;
return DeflateCodec::DecompressStream(m_stream, compressedSize, outBuffer, uncompressedSize);
}
else
return false;
}
size_t ZipFileProxy::NumFiles() const
{
return m_numFiles;
}
size_t ZipFileProxy::GetFileSize(size_t index) const
{
return m_sortedFiles[index]->m_uncompressedSize;
}
ZipFileProxy *ZipFileProxy::Create(IOStream *stream)
{
MemoryManager *mm = MemoryManager::GetInstance();
if (!stream->SeekEnd(sizeof(ZipEndOfCentralDirectoryRecord)))
return nullptr;
ZipEndOfCentralDirectoryRecord eocd;
if (stream->Read(&eocd, sizeof(eocd)) != sizeof(eocd))
return nullptr;
if (eocd.m_signature != ZipEndOfCentralDirectoryRecord::kSignature)
return nullptr;
if (!stream->SeekStart(eocd.m_centralDirStartOffset))
return nullptr;
const size_t centralDirSize = eocd.m_centralDirectorySizeBytes;
void *centralDirImage = mm->Alloc(centralDirSize);
if (!centralDirImage)
return nullptr;
const size_t numFiles = eocd.m_numCentralDirRecords;
ZipCentralDirectoryFileHeader **centralDirFiles = static_cast<ZipCentralDirectoryFileHeader **>(mm->Alloc(sizeof(ZipCentralDirectoryFileHeader*) * numFiles));
if (!centralDirFiles)
{
mm->Release(centralDirImage);
return nullptr;
}
if (stream->Read(centralDirImage, centralDirSize) != centralDirSize)
{
mm->Release(centralDirFiles);
mm->Release(centralDirImage);
return nullptr;
}
bool failed = false;
uint8_t *const centralDirStart = static_cast<uint8_t*>(centralDirImage);
uint8_t *const centralDirEnd = centralDirStart + centralDirSize;
uint8_t *centralDirCursor = centralDirStart;
for (size_t i = 0; i < numFiles; i++)
{
if (centralDirEnd - centralDirCursor < sizeof(ZipCentralDirectoryFileHeader))
{
failed = true;
break;
}
ZipCentralDirectoryFileHeader *centralDirHeader = reinterpret_cast<ZipCentralDirectoryFileHeader*>(centralDirCursor);
centralDirCursor += sizeof(ZipCentralDirectoryFileHeader);
if (centralDirHeader->m_signature != ZipCentralDirectoryFileHeader::kSignature)
{
failed = true;
break;
}
if (centralDirEnd - centralDirCursor < centralDirHeader->m_fileNameLength)
{
failed = true;
break;
}
if (!CheckAndFixFileName(centralDirCursor, centralDirHeader->m_fileNameLength))
{
failed = true;
break;
}
centralDirCursor += centralDirHeader->m_fileNameLength;
if (centralDirEnd - centralDirCursor < centralDirHeader->m_extraFieldLength)
{
failed = true;
break;
}
centralDirCursor += centralDirHeader->m_extraFieldLength;
if (centralDirEnd - centralDirCursor < centralDirHeader->m_commentLength)
{
failed = true;
break;
}
centralDirCursor += centralDirHeader->m_commentLength;
centralDirFiles[i] = centralDirHeader;
}
if (failed)
{
mm->Release(centralDirFiles);
mm->Release(centralDirImage);
return nullptr;
}
qsort(centralDirFiles, numFiles, sizeof(ZipCentralDirectoryFileHeader*), ZipDirectorySortPredicate);
for (size_t i = 1; i < numFiles; i++)
{
if (ZipDirectorySortPredicate(centralDirFiles + (i - 1), centralDirFiles + i) == 0)
{
// Duplicate file names
mm->Release(centralDirFiles);
mm->Release(centralDirImage);
return nullptr;
}
}
void *storage = mm->Alloc(sizeof(ZipFileProxy));
if (!storage)
{
mm->Release(centralDirFiles);
mm->Release(centralDirImage);
return nullptr;
}
return new (storage) ZipFileProxy(stream, centralDirImage, centralDirFiles, numFiles);
}
ZipFileProxy::ZipFileProxy(IOStream *stream, void *centralDirImage, ZipCentralDirectoryFileHeader **sortedFiles, size_t numFiles)
: m_stream(stream)
, m_centralDirImage(centralDirImage)
, m_sortedFiles(sortedFiles)
, m_numFiles(numFiles)
{
}
ZipFileProxy::~ZipFileProxy()
{
MemoryManager *mm = MemoryManager::GetInstance();
mm->Release(m_centralDirImage);
mm->Release(m_sortedFiles);
}
}

View File

@@ -0,0 +1,30 @@
#pragma once
namespace PortabilityLayer
{
class IOStream;
struct ZipCentralDirectoryFileHeader;
class ZipFileProxy
{
public:
void Destroy();
bool IndexFile(const char *path, size_t &outIndex) const;
bool LoadFile(size_t index, void *outBuffer);
size_t NumFiles() const;
size_t GetFileSize(size_t index) const;
static ZipFileProxy *Create(IOStream *stream);
private:
ZipFileProxy(IOStream *stream, void *centralDirImage, ZipCentralDirectoryFileHeader **sortedFiles, size_t numFiles);
~ZipFileProxy();
IOStream *m_stream;
void *m_centralDirImage;
ZipCentralDirectoryFileHeader **m_sortedFiles;
size_t m_numFiles;
};
}