mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 14:53:52 +00:00
214 lines
5.2 KiB
C++
214 lines
5.2 KiB
C++
#include "CompactProParser.h"
|
|
|
|
#include "IFileReader.h"
|
|
#include "UPByteSwap.h"
|
|
#include "PLBigEndian.h"
|
|
#include "CRC.h"
|
|
|
|
#include "ArchiveDescription.h"
|
|
#include "StringCommon.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
bool CompactProParser::Check(IFileReader &reader)
|
|
{
|
|
uint8_t bytes[8];
|
|
|
|
if (!reader.SeekStart(0))
|
|
return false;
|
|
|
|
if (!reader.ReadExact(bytes, sizeof(bytes)))
|
|
return false;
|
|
|
|
if (bytes[0] != 1)
|
|
return false;
|
|
|
|
uint32_t offset = ParseUInt32BE(bytes + 4);
|
|
|
|
if (offset > reader.FileSize() - 7)
|
|
return false;
|
|
|
|
if (!reader.SeekStart(offset))
|
|
return false;
|
|
|
|
uint8_t buf[256];
|
|
|
|
if (!reader.ReadExact(buf, 4))
|
|
return false;
|
|
|
|
uint32_t correctcrc = ParseUInt32BE(buf);
|
|
|
|
uint32_t crc = 0xffffffff;
|
|
if (!reader.ReadExact(buf, 3))
|
|
return false;
|
|
|
|
crc = XADCalculateCRC(crc, buf, 3, XADCRCTable_edb88320);
|
|
|
|
int numentries = ParseUInt16BE(buf);
|
|
int commentsize = buf[2];
|
|
|
|
if (!reader.ReadExact(buf, commentsize))
|
|
return false;
|
|
|
|
crc = XADCalculateCRC(crc, buf, commentsize, XADCRCTable_edb88320);
|
|
|
|
for (int i = 0; i < numentries; i++)
|
|
{
|
|
uint8_t namelen;
|
|
if (!reader.ReadExact(&namelen, 1))
|
|
return false;
|
|
|
|
crc = XADCRC(crc, namelen, XADCRCTable_edb88320);
|
|
|
|
if (!reader.ReadExact(buf, namelen & 0x7f))
|
|
return false;
|
|
|
|
crc = XADCalculateCRC(crc, buf, namelen & 0x7f, XADCRCTable_edb88320);
|
|
|
|
int metadatasize;
|
|
if (namelen & 0x80)
|
|
metadatasize = 2;
|
|
else
|
|
metadatasize = 45;
|
|
|
|
if (!reader.ReadExact(buf, metadatasize))
|
|
return false;
|
|
|
|
crc = XADCalculateCRC(crc, buf, metadatasize, XADCRCTable_edb88320);
|
|
}
|
|
|
|
if (crc == correctcrc)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
struct CompactProArchiveHeader
|
|
{
|
|
uint8_t m_marker;
|
|
uint8_t m_volume;
|
|
BEUInt16_t m_xmagic;
|
|
BEUInt32_t m_catalogOffset;
|
|
};
|
|
|
|
struct CompactProCatalogHeader
|
|
{
|
|
BEUInt32_t m_headerCRC;
|
|
BEUInt16_t m_numEntries;
|
|
uint8_t m_commentLength;
|
|
};
|
|
|
|
struct CompactProCatalogFileEntry
|
|
{
|
|
uint8_t m_volume;
|
|
BEUInt32_t m_fileOffset;
|
|
uint8_t m_fileType[4];
|
|
uint8_t m_fileCreator[4];
|
|
BEUInt32_t m_creationDate;
|
|
BEUInt32_t m_modificationDate;
|
|
BEUInt16_t m_finderFlags;
|
|
BEUInt32_t m_crc;
|
|
BEUInt16_t m_flags;
|
|
|
|
BEUInt32_t m_resUncompressedSize;
|
|
BEUInt32_t m_dataUncompressedSize;
|
|
BEUInt32_t m_resCompressedSize;
|
|
BEUInt32_t m_dataCompressedSize;
|
|
};
|
|
|
|
ArchiveItemList *CompactProParser::Parse(IFileReader &reader)
|
|
{
|
|
if (!reader.SeekStart(0))
|
|
return nullptr;
|
|
|
|
CompactProArchiveHeader arcHeader;
|
|
if (!reader.ReadExact(&arcHeader, sizeof(arcHeader)))
|
|
return nullptr;
|
|
|
|
if (!reader.SeekStart(arcHeader.m_catalogOffset))
|
|
return nullptr;
|
|
|
|
CompactProCatalogHeader catHeader;
|
|
if (!reader.ReadExact(&catHeader, sizeof(catHeader)))
|
|
return nullptr;
|
|
|
|
if (!reader.SeekCurrent(catHeader.m_commentLength))
|
|
return nullptr;
|
|
|
|
return ParseDirectory(catHeader.m_numEntries, reader);
|
|
}
|
|
|
|
ArchiveItemList *CompactProParser::ParseDirectory(uint32_t numEntries, IFileReader &reader)
|
|
{
|
|
ArchiveItemList itemList;
|
|
|
|
for (uint32_t itemIndex = 0; itemIndex < numEntries; itemIndex++)
|
|
{
|
|
itemList.m_items.push_back(ArchiveItem());
|
|
ArchiveItem &item = itemList.m_items.back();
|
|
|
|
uint8_t nameLengthAndDirFlag;
|
|
if (!reader.ReadExact(&nameLengthAndDirFlag, 1))
|
|
return nullptr;
|
|
|
|
uint8_t nameLength = (nameLengthAndDirFlag & 0x7f);
|
|
|
|
uint8_t fname[127];
|
|
if (!reader.ReadExact(fname, nameLength))
|
|
return nullptr;
|
|
|
|
StringCommon::ConvertMacRomanFileName(item.m_fileNameUTF8, fname, nameLength);
|
|
|
|
if (nameLengthAndDirFlag & 0x80)
|
|
{
|
|
BEUInt16_t numChildrenBE;
|
|
if (!reader.ReadExact(&numChildrenBE, sizeof(numChildrenBE)))
|
|
return nullptr;
|
|
|
|
uint16_t numChildren = numChildrenBE;
|
|
|
|
if (numChildren > numEntries - itemIndex)
|
|
return nullptr;
|
|
|
|
item.m_isDirectory = true;
|
|
|
|
ArchiveItemList *children = ParseDirectory(numChildren, reader);
|
|
if (!children)
|
|
return nullptr;
|
|
|
|
item.m_children = children;
|
|
numEntries -= numChildren;
|
|
}
|
|
else
|
|
{
|
|
CompactProCatalogFileEntry fileEntry;
|
|
if (!reader.ReadExact(&fileEntry, sizeof(fileEntry)))
|
|
return nullptr;
|
|
|
|
if (fileEntry.m_resUncompressedSize)
|
|
{
|
|
item.m_resourceForkDesc.m_compressedSize = fileEntry.m_resCompressedSize;
|
|
item.m_resourceForkDesc.m_uncompressedSize = fileEntry.m_resUncompressedSize;
|
|
item.m_resourceForkDesc.m_filePosition = fileEntry.m_fileOffset;
|
|
item.m_resourceForkDesc.m_compressionMethod = (fileEntry.m_flags & 2) ? CompressionMethods::kCompactProLZHRLE : CompressionMethods::kCompactProRLE;
|
|
}
|
|
|
|
if (fileEntry.m_dataUncompressedSize)
|
|
{
|
|
item.m_dataForkDesc.m_compressedSize = fileEntry.m_dataCompressedSize;
|
|
item.m_dataForkDesc.m_uncompressedSize = fileEntry.m_dataUncompressedSize;
|
|
item.m_dataForkDesc.m_filePosition = fileEntry.m_fileOffset + fileEntry.m_resCompressedSize;
|
|
item.m_dataForkDesc.m_compressionMethod = (fileEntry.m_flags & 4) ? CompressionMethods::kCompactProLZHRLE : CompressionMethods::kCompactProRLE;
|
|
}
|
|
|
|
item.m_macProperties.m_creationDate = fileEntry.m_creationDate;
|
|
item.m_macProperties.m_modifiedDate = fileEntry.m_modificationDate;
|
|
memcpy(item.m_macProperties.m_fileCreator, fileEntry.m_fileCreator, 4);
|
|
memcpy(item.m_macProperties.m_fileType, fileEntry.m_fileType, 4);
|
|
item.m_macProperties.m_finderFlags = fileEntry.m_finderFlags;
|
|
}
|
|
}
|
|
|
|
return new ArchiveItemList(std::move(itemList));
|
|
}
|