#include "Pack.h" #include "BinaryIO.h" #include "ZCompression.h" Pack::Pack(const std::filesystem::path& filePath) { m_FilePath = filePath; if (!std::filesystem::exists(filePath)) { return; } m_FileStream = std::ifstream(filePath, std::ios::in | std::ios::binary); m_FileStream.read(m_Version, 7); m_FileStream.seekg(-8, std::ios::end); // move file pointer to 8 bytes before the end (location of the address of the record count) uint32_t recordCountPos = 0; BinaryIO::BinaryRead(m_FileStream, recordCountPos); m_FileStream.seekg(recordCountPos, std::ios::beg); BinaryIO::BinaryRead(m_FileStream, m_RecordCount); for (int i = 0; i < m_RecordCount; i++) { PackRecord record; BinaryIO::BinaryRead(m_FileStream, record); m_Records.push_back(record); } m_FileStream.close(); } bool Pack::HasFile(uint32_t crc) { for (const auto& record : m_Records) { if (record.m_Crc == crc) { return true; } } return false; } bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) { // Time for some wacky C file reading for speed reasons PackRecord pkRecord{}; for (const auto& record : m_Records) { if (record.m_Crc == crc) { pkRecord = record; break; } } if (pkRecord.m_Crc == 0) return false; size_t pos = 0; pos += pkRecord.m_FilePointer; bool isCompressed = (pkRecord.m_IsCompressed & 0xff) > 0; auto inPackSize = isCompressed ? pkRecord.m_CompressedSize : pkRecord.m_UncompressedSize; FILE* file; #ifdef _WIN32 fopen_s(&file, m_FilePath.string().c_str(), "rb"); #elif __APPLE__ // macOS has 64bit file IO by default file = fopen(m_FilePath.string().c_str(), "rb"); #else file = fopen64(m_FilePath.string().c_str(), "rb"); #endif fseek(file, pos, SEEK_SET); if (!isCompressed) { char* tempData = (char*)malloc(pkRecord.m_UncompressedSize); fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file); *data = tempData; *len = pkRecord.m_UncompressedSize; fclose(file); return true; } pos += 5; // skip header fseek(file, pos, SEEK_SET); char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize); uint32_t currentReadPos = 0; while (true) { if (currentReadPos >= pkRecord.m_UncompressedSize) break; uint32_t size; fread(&size, sizeof(uint32_t), 1, file); pos += 4; // Move pointer position 4 to the right char* chunk = (char*)malloc(size); fread(chunk, sizeof(int8_t), size, file); pos += size; // Move pointer position the amount of bytes read to the right int32_t err; currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err); free(chunk); } *data = decompressedData; *len = pkRecord.m_UncompressedSize; fclose(file); return true; }