mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-12-13 19:49:36 +00:00
More Android stub-outs and bug fixes. Fix broken SDL fiber sync.
This commit is contained in:
112
PortabilityLayer/Android.mk
Normal file
112
PortabilityLayer/Android.mk
Normal 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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "VirtualDirectory.h"
|
||||
|
||||
class PLPasStr;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct IGpInputDriver;
|
||||
|
||||
namespace PortabilityLayer
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -139,6 +139,11 @@ namespace PortabilityLayer
|
||||
return m_rect;
|
||||
}
|
||||
|
||||
void Widget::SetWindow(Window *window)
|
||||
{
|
||||
m_window = window;
|
||||
}
|
||||
|
||||
Window *Widget::GetWindow() const
|
||||
{
|
||||
return m_window;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user