More Android stub-outs and bug fixes. Fix broken SDL fiber sync.

This commit is contained in:
elasota
2020-10-10 02:42:06 -04:00
parent a2f19f5ccb
commit 5c98783bbb
63 changed files with 1445 additions and 635 deletions

112
PortabilityLayer/Android.mk Normal file
View File

@@ -0,0 +1,112 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := PortabilityLayer
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../GpCommon \
$(LOCAL_PATH)/../Common \
$(LOCAL_PATH)/../rapidjson/include \
$(LOCAL_PATH)/../MacRomanConversion \
$(LOCAL_PATH)/../stb
LOCAL_CFLAGS := -DGP_DEBUG_CONFIG=0
# Add your application source files here...
LOCAL_SRC_FILES := \
AntiAliasTable.cpp \
AppEventHandler.cpp \
BinHex4.cpp \
BitmapImage.cpp \
ByteSwap.cpp \
CFileStream.cpp \
DeflateCodec.cpp \
DialogManager.cpp \
DisplayDeviceManager.cpp \
EllipsePlotter.cpp \
FileBrowserUI.cpp \
FileManager.cpp \
FontFamily.cpp \
FontManager.cpp \
FontRenderer.cpp \
GPArchive.cpp \
HostAudioDriver.cpp \
HostDisplayDriver.cpp \
HostFileSystem.cpp \
HostFontHandler.cpp \
HostInputDriver.cpp \
HostLogDriver.cpp \
HostSuspendHook.cpp \
HostSystemServices.cpp \
HostVOSEventQueue.cpp \
IconLoader.cpp \
InputManager.cpp \
LinePlotter.cpp \
MacBinary2.cpp \
MacFileInfo.cpp \
MacFileMem.cpp \
MemoryManager.cpp \
MemReaderStream.cpp \
MenuManager.cpp \
MMBlock.cpp \
MMHandleBlock.cpp \
PLApplication.cpp \
PLButtonWidget.cpp \
PLControlDefinitions.cpp \
PLCore.cpp \
PLCTabReducer.cpp \
PLDialogs.cpp \
PLEditboxWidget.cpp \
PLEventQueue.cpp \
PLHacks.cpp \
PLHandle.cpp \
PLIconWidget.cpp \
PLImageWidget.cpp \
PLInvisibleWidget.cpp \
PLKeyEncoding.cpp \
PLLabelWidget.cpp \
PLMenus.cpp \
PLMovies.cpp \
PLNumberFormatting.cpp \
PLPopupMenuWidget.cpp \
PLQDOffscreen.cpp \
PLQDraw.cpp \
PLResourceManager.cpp \
PLResources.cpp \
PLScrollBarWidget.cpp \
PLSound.cpp \
PLStandardColors.cpp \
PLStringCompare.cpp \
PLSysCalls.cpp \
PLTimeTaggedVOSEvent.cpp \
PLWidgets.cpp \
QDGraf.cpp \
QDManager.cpp \
QDPictDecoder.cpp \
QDPictEmitContext.cpp \
QDPictHeader.cpp \
QDPixMap.cpp \
QDPort.cpp \
QDStandardPalette.cpp \
RandomNumberGenerator.cpp \
ResolveCachingColor.cpp \
ResourceCompiledRef.cpp \
ResourceFile.cpp \
ScanlineMask.cpp \
ScanlineMaskBuilder.cpp \
ScanlineMaskConverter.cpp \
ScanlineMaskIterator.cpp \
SimpleGraphic.cpp \
TextPlacer.cpp \
UTF8.cpp \
UTF16.cpp \
WindowDef.cpp \
WindowManager.cpp \
XModemCRC.cpp \
ZipFileProxy.cpp
LOCAL_STATIC_LIBRARIES := zlib MacRomanConversion stb
include $(BUILD_SHARED_LIBRARY)

View File

@@ -1,302 +1,302 @@
#include "BinHex4.h"
#include "GpIOStream.h"
#include <string.h>
#include <vector>
#include <assert.h>
// See: https://files.stairways.com/other/binhex-40-specs-info.txt
// Unfortunately, while the spec specifies that decoding is to be done high-to-low,
// it doesn't specify how the encoded 6-bit value is split.
#include "MacFileInfo.h"
#include "ByteUnpack.h"
#include "XModemCRC.h"
#include "MacFileMem.h"
namespace
{
static bool IsEOL(char c)
{
return c == '\r' || c == '\n';
}
static bool IsWhitespaceChar(char c)
{
return c == '\r' || c == '\n' || c == ' ' || c == '\t';
}
uint16_t BinHexCRCNoPadding(const uint8_t *bytes, size_t size, int initialValue)
{
uint16_t crc = initialValue;
for (size_t b = 0; b < size; b++)
{
uint8_t v = bytes[b];
for (int i = 0; i < 8; i++)
{
int temp = (crc & 0x8000);
crc = (crc << 1) | (v >> 7);
if (temp)
crc = crc ^ 0x1021;
v = (v << 1) & 0xff;
}
}
return static_cast<uint16_t>(crc);
}
uint16_t BinHexCRC(const uint8_t *bytes, size_t size)
{
const uint8_t zeroBytes[] = { 0, 0 };
uint16_t crc = BinHexCRCNoPadding(bytes, size, 0);
return BinHexCRCNoPadding(zeroBytes, 2, crc);
}
}
namespace PortabilityLayer
{
MacFileMem *BinHex4::LoadHQX(GpIOStream *stream)
{
const uint8_t errCodeChar = 64;
uint8_t charMap[128];
for (int i = 0; i < 128; i++)
charMap[i] = errCodeChar;
const char binHexCharacters[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
for (int i = 0; i < 64; i++)
charMap[binHexCharacters[i]] = static_cast<uint8_t>(i);
const char expectedPrefix[] = "(This file must be converted with BinHex";
const size_t prefixSizeChars = sizeof(expectedPrefix) - 1;
char prefix[prefixSizeChars];
if (stream->Read(prefix, prefixSizeChars) != prefixSizeChars)
return nullptr;
if (memcmp(prefix, expectedPrefix, prefixSizeChars))
return nullptr;
// Find end char
for (;;)
{
char nextChar;
if (!stream->Read(&nextChar, 1))
return nullptr;
if (IsEOL(nextChar))
break;
}
// Find start colon
for (;;)
{
char nextChar;
if (!stream->Read(&nextChar, 1))
return nullptr;
if (IsWhitespaceChar(nextChar))
continue;
else if (nextChar == ':')
break;
else
return nullptr;
}
std::vector<uint8_t> bytesAfter6To8;
if (stream->IsSeekable())
{
GpUFilePos_t filePos = stream->Tell();
if (stream->SeekEnd(0))
{
GpUFilePos_t endPos = stream->Tell();
if (!stream->SeekStart(filePos))
return nullptr;
if (endPos > filePos && (endPos - filePos) < SIZE_MAX / 6)
bytesAfter6To8.reserve(static_cast<size_t>(endPos - filePos) * 6 / 8);
}
}
// Undo 8-to-6 coding
const size_t bufferCapacity = 128;
size_t bufferReadPos = 0;
size_t bufferSize = 0;
char buffer[bufferCapacity];
bool isEOF = false;
int decodedByte = 0;
int decodedByteBitPos = 8;
for (;;)
{
if (bufferReadPos == bufferSize)
{
const size_t numRead = stream->Read(buffer, bufferCapacity);
if (numRead == 0)
return nullptr; // Missing terminator
bufferSize = numRead;
bufferReadPos = 0;
}
char nextChar = buffer[bufferReadPos++];
if (nextChar == ':')
break;
if (IsWhitespaceChar(nextChar))
continue;
if (nextChar < 0 || nextChar > 127)
return nullptr;
uint8_t value6Bit = charMap[nextChar];
if (value6Bit == errCodeChar)
return nullptr;
switch (decodedByteBitPos)
{
case 8:
decodedByte = value6Bit << 2;
decodedByteBitPos = 2;
break;
case 6:
decodedByte |= value6Bit;
bytesAfter6To8.push_back(decodedByte);
decodedByte = 0;
decodedByteBitPos = 8;
break;
case 4:
decodedByte |= (value6Bit >> 2);
bytesAfter6To8.push_back(decodedByte);
decodedByte = (value6Bit << 6) & 0xff;
decodedByteBitPos = 6;
break;
case 2:
decodedByte |= (value6Bit >> 4);
bytesAfter6To8.push_back(decodedByte);
decodedByte = (value6Bit << 4) & 0xff;
decodedByteBitPos = 4;
break;
default:
return nullptr;
}
}
const size_t bytesBeforeRLEDec = bytesAfter6To8.size();
size_t decodedDataSize = 0;
for (size_t i = 0; i < bytesBeforeRLEDec; i++)
{
const uint8_t b = bytesAfter6To8[i];
if (b == 0x90)
{
if (i == bytesBeforeRLEDec - 1)
return nullptr;
const uint8_t runLength = bytesAfter6To8[++i];
if (runLength == 0)
decodedDataSize++; // 0x90 literal
else
decodedDataSize += runLength - 1; // RLE, runs of length 1 are permitted
}
else
decodedDataSize++;
}
std::vector<uint8_t> decodedBytes;
decodedBytes.reserve(decodedDataSize);
for (size_t i = 0; i < bytesBeforeRLEDec; i++)
{
const uint8_t b = bytesAfter6To8[i];
if (b == 0x90)
{
const uint8_t runLength = bytesAfter6To8[++i];
if (runLength == 0)
decodedBytes.push_back(0x90);
else
{
if (decodedBytes.size() == 0)
return nullptr;
const uint8_t lastByte = *(decodedBytes.end() - 1);
for (size_t r = 1; r < runLength; r++)
decodedBytes.push_back(lastByte);
}
}
else
decodedBytes.push_back(b);
}
assert(decodedBytes.size() == decodedDataSize);
if (decodedBytes.size() == 0)
return nullptr;
const uint8_t nameLength = decodedBytes[0];
if (decodedBytes.size() < 22 + nameLength || nameLength > 63)
return nullptr;
// Header format:
// uint8_t nameLength
// char name[nameLength]
// char <null>
// char fileType[4]
// char fileCreator[4]
// word flags
// dword dataLength
// dword resourceLength
// word headerCRC
const size_t headerStartLoc = 2 + nameLength;
if (decodedBytes[nameLength + 1] != 0)
return nullptr;
MacFileInfo mfi;
mfi.m_fileName.Set(nameLength, reinterpret_cast<const char*>(&decodedBytes[1]));
memcpy(mfi.m_properties.m_fileType, &decodedBytes[headerStartLoc + 0], 4);
memcpy(mfi.m_properties.m_fileCreator, &decodedBytes[headerStartLoc + 4], 4);
mfi.m_properties.m_finderFlags = ByteUnpack::BigUInt16(&decodedBytes[headerStartLoc + 8]);
mfi.m_dataForkSize = ByteUnpack::BigUInt32(&decodedBytes[headerStartLoc + 10]);
mfi.m_resourceForkSize = ByteUnpack::BigUInt32(&decodedBytes[headerStartLoc + 14]);
const size_t availableDataSize = decodedBytes.size() - 26 - nameLength; // +4 bytes for CRCs
if (mfi.m_dataForkSize > availableDataSize || availableDataSize - mfi.m_dataForkSize < mfi.m_resourceForkSize)
return nullptr;
const uint16_t expectedHeaderCRC = ByteUnpack::BigUInt16(&decodedBytes[headerStartLoc + 18]);
const uint16_t actualHeaderCRC = BinHexCRC(&decodedBytes[0], headerStartLoc + 18);
if (expectedHeaderCRC != actualHeaderCRC)
return nullptr;
const size_t dataForkStart = headerStartLoc + 20;
const size_t dataForkCRCLoc = dataForkStart + mfi.m_dataForkSize;
const size_t resourceForkStart = dataForkCRCLoc + 2;
const size_t resourceForkCRCLoc = resourceForkStart + mfi.m_resourceForkSize;
const uint16_t expectedDataCRC = ByteUnpack::BigUInt16(&decodedBytes[dataForkCRCLoc]);
const uint16_t expectedResCRC = ByteUnpack::BigUInt16(&decodedBytes[resourceForkCRCLoc]);
if (expectedDataCRC != BinHexCRC(&decodedBytes[dataForkStart], mfi.m_dataForkSize))
return false;
if (expectedResCRC != BinHexCRC(&decodedBytes[resourceForkStart], mfi.m_resourceForkSize))
return false;
return new MacFileMem(&decodedBytes[dataForkStart], &decodedBytes[resourceForkStart], nullptr, mfi);
}
}
#include "BinHex4.h"
#include "GpIOStream.h"
#include <string.h>
#include <vector>
#include <assert.h>
// See: https://files.stairways.com/other/binhex-40-specs-info.txt
// Unfortunately, while the spec specifies that decoding is to be done high-to-low,
// it doesn't specify how the encoded 6-bit value is split.
#include "MacFileInfo.h"
#include "ByteUnpack.h"
#include "XModemCRC.h"
#include "MacFileMem.h"
namespace
{
static bool IsEOL(char c)
{
return c == '\r' || c == '\n';
}
static bool IsWhitespaceChar(char c)
{
return c == '\r' || c == '\n' || c == ' ' || c == '\t';
}
uint16_t BinHexCRCNoPadding(const uint8_t *bytes, size_t size, int initialValue)
{
uint16_t crc = initialValue;
for (size_t b = 0; b < size; b++)
{
uint8_t v = bytes[b];
for (int i = 0; i < 8; i++)
{
int temp = (crc & 0x8000);
crc = (crc << 1) | (v >> 7);
if (temp)
crc = crc ^ 0x1021;
v = (v << 1) & 0xff;
}
}
return static_cast<uint16_t>(crc);
}
uint16_t BinHexCRC(const uint8_t *bytes, size_t size)
{
const uint8_t zeroBytes[] = { 0, 0 };
uint16_t crc = BinHexCRCNoPadding(bytes, size, 0);
return BinHexCRCNoPadding(zeroBytes, 2, crc);
}
}
namespace PortabilityLayer
{
MacFileMem *BinHex4::LoadHQX(GpIOStream *stream)
{
const uint8_t errCodeChar = 64;
uint8_t charMap[128];
for (int i = 0; i < 128; i++)
charMap[i] = errCodeChar;
const char binHexCharacters[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
for (int i = 0; i < 64; i++)
charMap[binHexCharacters[i]] = static_cast<uint8_t>(i);
const char expectedPrefix[] = "(This file must be converted with BinHex";
const size_t prefixSizeChars = sizeof(expectedPrefix) - 1;
char prefix[prefixSizeChars];
if (stream->Read(prefix, prefixSizeChars) != prefixSizeChars)
return nullptr;
if (memcmp(prefix, expectedPrefix, prefixSizeChars))
return nullptr;
// Find end char
for (;;)
{
char nextChar;
if (!stream->Read(&nextChar, 1))
return nullptr;
if (IsEOL(nextChar))
break;
}
// Find start colon
for (;;)
{
char nextChar;
if (!stream->Read(&nextChar, 1))
return nullptr;
if (IsWhitespaceChar(nextChar))
continue;
else if (nextChar == ':')
break;
else
return nullptr;
}
std::vector<uint8_t> bytesAfter6To8;
if (stream->IsSeekable())
{
GpUFilePos_t filePos = stream->Tell();
if (stream->SeekEnd(0))
{
GpUFilePos_t endPos = stream->Tell();
if (!stream->SeekStart(filePos))
return nullptr;
if (endPos > filePos && (endPos - filePos) < SIZE_MAX / 6)
bytesAfter6To8.reserve(static_cast<size_t>(endPos - filePos) * 6 / 8);
}
}
// Undo 8-to-6 coding
const size_t bufferCapacity = 128;
size_t bufferReadPos = 0;
size_t bufferSize = 0;
char buffer[bufferCapacity];
bool isEOF = false;
int decodedByte = 0;
int decodedByteBitPos = 8;
for (;;)
{
if (bufferReadPos == bufferSize)
{
const size_t numRead = stream->Read(buffer, bufferCapacity);
if (numRead == 0)
return nullptr; // Missing terminator
bufferSize = numRead;
bufferReadPos = 0;
}
char nextChar = buffer[bufferReadPos++];
if (nextChar == ':')
break;
if (IsWhitespaceChar(nextChar))
continue;
if (nextChar < 0 || nextChar > 127)
return nullptr;
uint8_t value6Bit = charMap[nextChar];
if (value6Bit == errCodeChar)
return nullptr;
switch (decodedByteBitPos)
{
case 8:
decodedByte = value6Bit << 2;
decodedByteBitPos = 2;
break;
case 6:
decodedByte |= value6Bit;
bytesAfter6To8.push_back(decodedByte);
decodedByte = 0;
decodedByteBitPos = 8;
break;
case 4:
decodedByte |= (value6Bit >> 2);
bytesAfter6To8.push_back(decodedByte);
decodedByte = (value6Bit << 6) & 0xff;
decodedByteBitPos = 6;
break;
case 2:
decodedByte |= (value6Bit >> 4);
bytesAfter6To8.push_back(decodedByte);
decodedByte = (value6Bit << 4) & 0xff;
decodedByteBitPos = 4;
break;
default:
return nullptr;
}
}
const size_t bytesBeforeRLEDec = bytesAfter6To8.size();
size_t decodedDataSize = 0;
for (size_t i = 0; i < bytesBeforeRLEDec; i++)
{
const uint8_t b = bytesAfter6To8[i];
if (b == 0x90)
{
if (i == bytesBeforeRLEDec - 1)
return nullptr;
const uint8_t runLength = bytesAfter6To8[++i];
if (runLength == 0)
decodedDataSize++; // 0x90 literal
else
decodedDataSize += runLength - 1; // RLE, runs of length 1 are permitted
}
else
decodedDataSize++;
}
std::vector<uint8_t> decodedBytes;
decodedBytes.reserve(decodedDataSize);
for (size_t i = 0; i < bytesBeforeRLEDec; i++)
{
const uint8_t b = bytesAfter6To8[i];
if (b == 0x90)
{
const uint8_t runLength = bytesAfter6To8[++i];
if (runLength == 0)
decodedBytes.push_back(0x90);
else
{
if (decodedBytes.size() == 0)
return nullptr;
const uint8_t lastByte = *(decodedBytes.end() - 1);
for (size_t r = 1; r < runLength; r++)
decodedBytes.push_back(lastByte);
}
}
else
decodedBytes.push_back(b);
}
assert(decodedBytes.size() == decodedDataSize);
if (decodedBytes.size() == 0)
return nullptr;
const uint8_t nameLength = decodedBytes[0];
if (decodedBytes.size() < 22 + nameLength || nameLength > 63)
return nullptr;
// Header format:
// uint8_t nameLength
// char name[nameLength]
// char <null>
// char fileType[4]
// char fileCreator[4]
// word flags
// dword dataLength
// dword resourceLength
// word headerCRC
const size_t headerStartLoc = 2 + nameLength;
if (decodedBytes[nameLength + 1] != 0)
return nullptr;
MacFileInfo mfi;
mfi.m_fileName.Set(nameLength, reinterpret_cast<const char*>(&decodedBytes[1]));
memcpy(mfi.m_properties.m_fileType, &decodedBytes[headerStartLoc + 0], 4);
memcpy(mfi.m_properties.m_fileCreator, &decodedBytes[headerStartLoc + 4], 4);
mfi.m_properties.m_finderFlags = ByteUnpack::BigUInt16(&decodedBytes[headerStartLoc + 8]);
mfi.m_dataForkSize = ByteUnpack::BigUInt32(&decodedBytes[headerStartLoc + 10]);
mfi.m_resourceForkSize = ByteUnpack::BigUInt32(&decodedBytes[headerStartLoc + 14]);
const size_t availableDataSize = decodedBytes.size() - 26 - nameLength; // +4 bytes for CRCs
if (mfi.m_dataForkSize > availableDataSize || availableDataSize - mfi.m_dataForkSize < mfi.m_resourceForkSize)
return nullptr;
const uint16_t expectedHeaderCRC = ByteUnpack::BigUInt16(&decodedBytes[headerStartLoc + 18]);
const uint16_t actualHeaderCRC = BinHexCRC(&decodedBytes[0], headerStartLoc + 18);
if (expectedHeaderCRC != actualHeaderCRC)
return nullptr;
const size_t dataForkStart = headerStartLoc + 20;
const size_t dataForkCRCLoc = dataForkStart + mfi.m_dataForkSize;
const size_t resourceForkStart = dataForkCRCLoc + 2;
const size_t resourceForkCRCLoc = resourceForkStart + mfi.m_resourceForkSize;
const uint16_t expectedDataCRC = ByteUnpack::BigUInt16(&decodedBytes[dataForkCRCLoc]);
const uint16_t expectedResCRC = ByteUnpack::BigUInt16(&decodedBytes[resourceForkCRCLoc]);
if (expectedDataCRC != BinHexCRC(&decodedBytes[dataForkStart], mfi.m_dataForkSize))
return nullptr;
if (expectedResCRC != BinHexCRC(&decodedBytes[resourceForkStart], mfi.m_resourceForkSize))
return nullptr;
return new MacFileMem(&decodedBytes[dataForkStart], &decodedBytes[resourceForkStart], nullptr, mfi);
}
}

View File

@@ -1,5 +1,7 @@
#pragma once
#include <stdint.h>
#include "VirtualDirectory.h"
class PLPasStr;

View File

@@ -1,5 +1,7 @@
#pragma once
#include <stdint.h>
struct IGpInputDriver;
namespace PortabilityLayer

View File

@@ -21,7 +21,7 @@ namespace PortabilityLayer
virtual HostMutex *CreateMutex() = 0;
virtual HostMutex *CreateRecursiveMutex() = 0;
virtual HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) = 0;
virtual size_t GetFreeMemoryCosmetic() const = 0; // Returns free memory in bytes, does not have to be accurate
virtual uint64_t GetFreeMemoryCosmetic() const = 0; // Returns free memory in bytes, does not have to be accurate
virtual void Beep() const = 0;
static void SetInstance(HostSystemServices *instance);

View File

@@ -8,7 +8,7 @@ namespace PortabilityLayer
{
public:
virtual void Wait() = 0;
virtual void WaitTimed(uint32_t msec) = 0;
virtual bool WaitTimed(uint32_t msec) = 0;
virtual void Signal() = 0;
virtual void Destroy() = 0;
};

View File

@@ -1,185 +1,185 @@
#include "MacBinary2.h"
#include "BytePack.h"
#include "ByteUnpack.h"
#include "DataTypes.h"
#include "GpIOStream.h"
#include "MacFileMem.h"
#include "XModemCRC.h"
// See: https://files.stairways.com/other/macbinaryii-standard-info.txt
namespace
{
namespace MB2FileOffsets
{
const unsigned int Version = 0;
const unsigned int FileNameLength = 1;
const unsigned int FileName = 2;
const unsigned int FileType = 65;
const unsigned int FileCreator = 69;
const unsigned int FinderFlagsHigh = 73;
const unsigned int YPos = 75;
const unsigned int XPos = 77;
const unsigned int Protected = 81;
const unsigned int DataForkSize = 83;
const unsigned int ResourceForkSize = 87;
const unsigned int CreationDate = 91;
const unsigned int ModifiedDate = 95;
const unsigned int CommentLength = 99;
const unsigned int FinderFlagsLow = 101;
const unsigned int DecompressedSize = 116;
const unsigned int SecondaryHeaderLength = 120;
const unsigned int WriterVersion = 122;
const unsigned int MinVersion = 123;
const unsigned int Checksum = 124;
const unsigned int ContentStart = 128;
};
}
namespace PortabilityLayer
{
void MacBinary2::WriteBin(const MacFileMem *file, GpIOStream *stream)
{
const MacFileInfo &fileInfo = file->FileInfo();
uint8_t mb2Header[128];
memset(mb2Header, 0, sizeof(mb2Header));
mb2Header[MB2FileOffsets::Version] = 0;
size_t fileNameLength = fileInfo.m_fileName.Length();
if (fileNameLength == 0)
{
mb2Header[MB2FileOffsets::FileNameLength] = 1;
mb2Header[MB2FileOffsets::FileName] = '?';
}
else
{
if (fileNameLength > 63)
fileNameLength = 63;
mb2Header[MB2FileOffsets::FileNameLength] = static_cast<uint8_t>(fileNameLength);
memcpy(mb2Header + MB2FileOffsets::FileName, &fileInfo.m_fileName[0], fileNameLength);
}
memcpy(mb2Header + MB2FileOffsets::FileType, fileInfo.m_properties.m_fileType, 4);
memcpy(mb2Header + MB2FileOffsets::FileCreator, fileInfo.m_properties.m_fileCreator, 4);
mb2Header[MB2FileOffsets::FinderFlagsHigh] = static_cast<uint8_t>((fileInfo.m_properties.m_finderFlags >> 8) & 0xff);
BytePack::BigInt16(mb2Header + MB2FileOffsets::YPos, fileInfo.m_properties.m_yPos);
BytePack::BigInt16(mb2Header + MB2FileOffsets::XPos, fileInfo.m_properties.m_xPos);
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, fileInfo.m_properties.m_creationDate);
BytePack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate, fileInfo.m_properties.m_modifiedDate);
BytePack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength, fileInfo.m_commentSize);
mb2Header[MB2FileOffsets::FinderFlagsLow] = static_cast<uint8_t>(fileInfo.m_properties.m_finderFlags & 0xff);
// DecompressedSize is unused
// SecondaryHeaderLength is zero
mb2Header[MB2FileOffsets::WriterVersion] = 129;
mb2Header[MB2FileOffsets::MinVersion] = 129;
BytePack::BigUInt16(mb2Header + MB2FileOffsets::Checksum, XModemCRC(mb2Header, 124, 0));
stream->Write(mb2Header, 128);
uint8_t *padding = mb2Header;
memset(padding, 0, 128);
const size_t dataForkPadding = 127 - ((fileInfo.m_dataForkSize + 127) % 128);
const size_t resourceForkPadding = 127 - ((fileInfo.m_resourceForkSize + 127) % 128);
stream->Write(file->DataFork(), fileInfo.m_dataForkSize);
stream->Write(padding, dataForkPadding);
stream->Write(file->ResourceFork(), fileInfo.m_resourceForkSize);
stream->Write(padding, resourceForkPadding);
}
MacFileMem *MacBinary2::ReadBin(GpIOStream *stream)
{
MacFileInfo fileInfo;
uint8_t mb2Header[128];
if (stream->Read(mb2Header, 128) != 128)
return nullptr;
if (mb2Header[MB2FileOffsets::Version] != 0)
return nullptr;
const uint8_t fileNameLength = mb2Header[MB2FileOffsets::FileNameLength];
if (fileNameLength < 1 || fileNameLength > 63)
return nullptr;
fileInfo.m_fileName.Set(fileNameLength, reinterpret_cast<const char*>(mb2Header + MB2FileOffsets::FileName));
memcpy(fileInfo.m_properties.m_fileType, mb2Header + MB2FileOffsets::FileType, 4);
memcpy(fileInfo.m_properties.m_fileCreator, mb2Header + MB2FileOffsets::FileCreator, 4);
fileInfo.m_properties.m_finderFlags = mb2Header[MB2FileOffsets::FinderFlagsHigh] << 8;
fileInfo.m_properties.m_yPos = ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::YPos);
fileInfo.m_properties.m_xPos = ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::XPos);
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_commentSize = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength);
fileInfo.m_properties.m_finderFlags |= mb2Header[MB2FileOffsets::FinderFlagsLow];
if (ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::SecondaryHeaderLength) != 0)
return nullptr;
uint16_t crc = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::Checksum);
uint16_t expectedCRC = XModemCRC(mb2Header, 124, 0);
if (fileInfo.m_dataForkSize > SIZE_MAX)
return nullptr;
if (fileInfo.m_resourceForkSize > SIZE_MAX)
return nullptr;
uint8_t *dataBuffer = nullptr;
uint8_t *rsrcBuffer = nullptr;
if (fileInfo.m_dataForkSize != 0)
dataBuffer = new uint8_t[fileInfo.m_dataForkSize];
if (fileInfo.m_resourceForkSize != 0)
rsrcBuffer = new uint8_t[fileInfo.m_resourceForkSize];
ScopedArray<uint8_t> dataContents = dataBuffer;
ScopedArray<uint8_t> rsrcContents = rsrcBuffer;
uint8_t *padding = mb2Header;
const size_t dataForkPadding = 127 - ((fileInfo.m_dataForkSize + 127) % 128);
const size_t resourceForkPadding = 127 - ((fileInfo.m_resourceForkSize + 127) % 128);
if (stream->Read(dataBuffer, fileInfo.m_dataForkSize) != fileInfo.m_dataForkSize)
return nullptr;
if (stream->Read(padding, dataForkPadding) != dataForkPadding)
return nullptr;
if (stream->Read(rsrcBuffer, fileInfo.m_resourceForkSize) != fileInfo.m_resourceForkSize)
return nullptr;
if (stream->Read(padding, resourceForkPadding) != resourceForkPadding)
return nullptr;
// Ignore comment for now
return new MacFileMem(dataBuffer, rsrcBuffer, nullptr, fileInfo);
}
}
#include "MacBinary2.h"
#include "BytePack.h"
#include "ByteUnpack.h"
#include "DataTypes.h"
#include "GpIOStream.h"
#include "MacFileMem.h"
#include "XModemCRC.h"
// See: https://files.stairways.com/other/macbinaryii-standard-info.txt
namespace
{
namespace MB2FileOffsets
{
const unsigned int Version = 0;
const unsigned int FileNameLength = 1;
const unsigned int FileName = 2;
const unsigned int FileType = 65;
const unsigned int FileCreator = 69;
const unsigned int FinderFlagsHigh = 73;
const unsigned int YPos = 75;
const unsigned int XPos = 77;
const unsigned int Protected = 81;
const unsigned int DataForkSize = 83;
const unsigned int ResourceForkSize = 87;
const unsigned int CreationDate = 91;
const unsigned int ModifiedDate = 95;
const unsigned int CommentLength = 99;
const unsigned int FinderFlagsLow = 101;
const unsigned int DecompressedSize = 116;
const unsigned int SecondaryHeaderLength = 120;
const unsigned int WriterVersion = 122;
const unsigned int MinVersion = 123;
const unsigned int Checksum = 124;
const unsigned int ContentStart = 128;
};
}
namespace PortabilityLayer
{
void MacBinary2::WriteBin(const MacFileMem *file, GpIOStream *stream)
{
const MacFileInfo &fileInfo = file->FileInfo();
uint8_t mb2Header[128];
memset(mb2Header, 0, sizeof(mb2Header));
mb2Header[MB2FileOffsets::Version] = 0;
size_t fileNameLength = fileInfo.m_fileName.Length();
if (fileNameLength == 0)
{
mb2Header[MB2FileOffsets::FileNameLength] = 1;
mb2Header[MB2FileOffsets::FileName] = '?';
}
else
{
if (fileNameLength > 63)
fileNameLength = 63;
mb2Header[MB2FileOffsets::FileNameLength] = static_cast<uint8_t>(fileNameLength);
memcpy(mb2Header + MB2FileOffsets::FileName, &fileInfo.m_fileName[0], fileNameLength);
}
memcpy(mb2Header + MB2FileOffsets::FileType, fileInfo.m_properties.m_fileType, 4);
memcpy(mb2Header + MB2FileOffsets::FileCreator, fileInfo.m_properties.m_fileCreator, 4);
mb2Header[MB2FileOffsets::FinderFlagsHigh] = static_cast<uint8_t>((fileInfo.m_properties.m_finderFlags >> 8) & 0xff);
BytePack::BigInt16(mb2Header + MB2FileOffsets::YPos, fileInfo.m_properties.m_yPos);
BytePack::BigInt16(mb2Header + MB2FileOffsets::XPos, fileInfo.m_properties.m_xPos);
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, fileInfo.m_properties.m_creationDate);
BytePack::BigUInt32(mb2Header + MB2FileOffsets::ModifiedDate, fileInfo.m_properties.m_modifiedDate);
BytePack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength, fileInfo.m_commentSize);
mb2Header[MB2FileOffsets::FinderFlagsLow] = static_cast<uint8_t>(fileInfo.m_properties.m_finderFlags & 0xff);
// DecompressedSize is unused
// SecondaryHeaderLength is zero
mb2Header[MB2FileOffsets::WriterVersion] = 129;
mb2Header[MB2FileOffsets::MinVersion] = 129;
BytePack::BigUInt16(mb2Header + MB2FileOffsets::Checksum, XModemCRC(mb2Header, 124, 0));
stream->Write(mb2Header, 128);
uint8_t *padding = mb2Header;
memset(padding, 0, 128);
const size_t dataForkPadding = 127 - ((fileInfo.m_dataForkSize + 127) % 128);
const size_t resourceForkPadding = 127 - ((fileInfo.m_resourceForkSize + 127) % 128);
stream->Write(file->DataFork(), fileInfo.m_dataForkSize);
stream->Write(padding, dataForkPadding);
stream->Write(file->ResourceFork(), fileInfo.m_resourceForkSize);
stream->Write(padding, resourceForkPadding);
}
MacFileMem *MacBinary2::ReadBin(GpIOStream *stream)
{
MacFileInfo fileInfo;
uint8_t mb2Header[128];
if (stream->Read(mb2Header, 128) != 128)
return nullptr;
if (mb2Header[MB2FileOffsets::Version] != 0)
return nullptr;
const uint8_t fileNameLength = mb2Header[MB2FileOffsets::FileNameLength];
if (fileNameLength < 1 || fileNameLength > 63)
return nullptr;
fileInfo.m_fileName.Set(fileNameLength, reinterpret_cast<const char*>(mb2Header + MB2FileOffsets::FileName));
memcpy(fileInfo.m_properties.m_fileType, mb2Header + MB2FileOffsets::FileType, 4);
memcpy(fileInfo.m_properties.m_fileCreator, mb2Header + MB2FileOffsets::FileCreator, 4);
fileInfo.m_properties.m_finderFlags = mb2Header[MB2FileOffsets::FinderFlagsHigh] << 8;
fileInfo.m_properties.m_yPos = ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::YPos);
fileInfo.m_properties.m_xPos = ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::XPos);
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_commentSize = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::CommentLength);
fileInfo.m_properties.m_finderFlags |= mb2Header[MB2FileOffsets::FinderFlagsLow];
if (ByteUnpack::BigInt16(mb2Header + MB2FileOffsets::SecondaryHeaderLength) != 0)
return nullptr;
uint16_t crc = ByteUnpack::BigUInt16(mb2Header + MB2FileOffsets::Checksum);
uint16_t expectedCRC = XModemCRC(mb2Header, 124, 0);
if (fileInfo.m_dataForkSize > SIZE_MAX)
return nullptr;
if (fileInfo.m_resourceForkSize > SIZE_MAX)
return nullptr;
uint8_t *dataBuffer = nullptr;
uint8_t *rsrcBuffer = nullptr;
if (fileInfo.m_dataForkSize != 0)
dataBuffer = new uint8_t[fileInfo.m_dataForkSize];
if (fileInfo.m_resourceForkSize != 0)
rsrcBuffer = new uint8_t[fileInfo.m_resourceForkSize];
ScopedArray<uint8_t> dataContents(dataBuffer);
ScopedArray<uint8_t> rsrcContents(rsrcBuffer);
uint8_t *padding = mb2Header;
const size_t dataForkPadding = 127 - ((fileInfo.m_dataForkSize + 127) % 128);
const size_t resourceForkPadding = 127 - ((fileInfo.m_resourceForkSize + 127) % 128);
if (stream->Read(dataBuffer, fileInfo.m_dataForkSize) != fileInfo.m_dataForkSize)
return nullptr;
if (stream->Read(padding, dataForkPadding) != dataForkPadding)
return nullptr;
if (stream->Read(rsrcBuffer, fileInfo.m_resourceForkSize) != fileInfo.m_resourceForkSize)
return nullptr;
if (stream->Read(padding, resourceForkPadding) != resourceForkPadding)
return nullptr;
// Ignore comment for now
return new MacFileMem(dataBuffer, rsrcBuffer, nullptr, fileInfo);
}
}

View File

@@ -706,6 +706,8 @@ namespace PortabilityLayer
if (evt.m_vosEvent.m_event.m_mouseInputEvent.m_button == GpMouseButtons::kLeft)
canDismiss = true;
break;
default:
break;
}
}
}
@@ -764,6 +766,8 @@ namespace PortabilityLayer
if (evt.m_vosEvent.m_event.m_mouseInputEvent.m_button == GpMouseButtons::kLeft)
canDismiss = true;
break;
default:
break;
}
}
}

View File

@@ -298,7 +298,7 @@ void NumToString(long number, unsigned char *str)
number /= 10;
*outChar = '0' + digit;
*outChar++;
outChar++;
}
const ptrdiff_t strLength = outChar - firstChar;
@@ -753,7 +753,7 @@ bool Window::ReplaceWidget(PortabilityLayer::Widget *oldWidget, PortabilityLayer
oldWidget->Destroy();
m_widgets[i] = newWidget;
newWidget->m_window = this;
newWidget->SetWindow(this);
newWidget->DrawControl(&m_surface);
m_surface.m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents);

View File

@@ -29,7 +29,7 @@ namespace PortabilityLayer
Rect GetExpandedRect() const override;
bool HandlesTickEvents() const;
bool HandlesTickEvents() const override;
void SetSelection(size_t startChar, size_t endChar);
@@ -87,7 +87,7 @@ namespace PortabilityLayer
CaratSelectionAnchor m_caratSelectionAnchor; // Where the carat is attached to the selection range
Vec2i m_caratScrollPosition; // Ideal position of the carat in the editbox, but not necessarily its actual location (i.e. may be in the middle of a glyph)
bool m_caratScrollLocked; // If true, the vertical position
bool m_caratScrollLocked; // If true, the vertical position
Vec2i m_scrollOffset;

View File

@@ -14,8 +14,8 @@ namespace PortabilityLayer
bool Init(const WidgetBasicState &state, const void *additionalData) override;
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt);
int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) override;
void DrawControl(DrawSurface *surface) override;
void OnStateChanged() override;

View File

@@ -1783,6 +1783,7 @@ static void CopyBitsComplete(const BitMap *srcBitmap, const BitMap *maskBitmap8,
{
case GpPixelFormats::k8BitCustom:
case GpPixelFormats::k8BitStandard:
case GpPixelFormats::kBW1:
pixelSizeBytes = 1;
break;
case GpPixelFormats::kRGB555:
@@ -1794,6 +1795,8 @@ static void CopyBitsComplete(const BitMap *srcBitmap, const BitMap *maskBitmap8,
case GpPixelFormats::kRGB32:
pixelSizeBytes = 4;
break;
default:
return;
};
const uint8_t *srcBytes = static_cast<const uint8_t*>(srcBitmap->m_data);
@@ -2029,8 +2032,8 @@ void DebugPixMap(PixMap **pixMapH, const char *outName)
{
PixMap *pixMap = *pixMapH;
char outPath[1024];
strcpy_s(outPath, outName);
strcat_s(outPath, ".png");
strcpy(outPath, outName);
strcat(outPath, ".png");
stbi_write_png(outPath, pixMap->m_rect.right - pixMap->m_rect.left, pixMap->m_rect.bottom - pixMap->m_rect.top, 1, pixMap->m_data, pixMap->m_pitch);
}

View File

@@ -179,7 +179,7 @@ namespace PortabilityLayer
{
AudioCommand cmd;
cmd.m_commandType = AudioCommandTypes::kCallback;
cmd.m_param.m_ptr = callback;
cmd.m_param.m_ptr = reinterpret_cast<void*>(callback);
return this->PushCommand(cmd, blocking);
}

View File

@@ -71,7 +71,7 @@ static void TranslateKeyboardInputEvent(const GpVOSEvent &vosEventBase, uint32_t
inputManager->ApplyKeyboardEvent(vosEvent);
// Special handling of alt-enter, redirect to display driver
if (vosEventBase.m_eventType == GpKeyboardInputEventTypes::kDown &&
if (vosEventBase.m_event.m_keyboardInputEvent.m_eventType == GpKeyboardInputEventTypes::kDown &&
vosEventBase.m_event.m_keyboardInputEvent.m_keyIDSubset == GpKeyIDSubsets::kSpecial &&
vosEventBase.m_event.m_keyboardInputEvent.m_key.m_specialKey == GpKeySpecials::kEnter)
{

View File

@@ -139,6 +139,11 @@ namespace PortabilityLayer
return m_rect;
}
void Widget::SetWindow(Window *window)
{
m_window = window;
}
Window *Widget::GetWindow() const
{
return m_window;

View File

@@ -80,21 +80,23 @@ namespace PortabilityLayer
virtual int ResolvePart(const Point &point) const;
const Rect &GetRect() const;
Window *GetWindow() const;
protected:
friend struct Window;
void SetWindow(Window *window);
Window *GetWindow() const;
virtual void GainFocus();
virtual void LoseFocus();
explicit Widget(const WidgetBasicState &state);
virtual ~Widget();
virtual void OnEnabledChanged();
virtual void OnStateChanged();
virtual void OnTick();
protected:
friend struct Window;
explicit Widget(const WidgetBasicState &state);
virtual ~Widget();
static void BaseRelease(void *storage);
static void *BaseAlloc(size_t sz);