Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "StdAfx.h"
- #include "PackArchive.h"
- PackArchive::PackArchive(BinFilePtr file) {
- mFile = file;
- }
- void PackArchive::validate() {
- uint32 sig = mFile->read<uint32>();
- if(sig != FileMagic) {
- throw std::exception("Invalid file signature");
- }
- uint32 version = mFile->read<uint32>();
- if(version != 1) {
- throw std::exception("Invalid file version");
- }
- uint8 sizeData[548];
- mFile->read(sizeData, 548);
- uint8* start = sizeData;
- uint8* ptr = sizeData;
- for(uint32 i = 0; i < 0x40; ++i) {
- uint64 mask = *(uint64*)ptr;
- uint32 low = *(uint32*)(ptr);
- uint32 high = *(uint32*)(ptr + 4);
- uint32 upperLow = *(uint32*)(start + 512);
- uint32 upperHigh = *(uint32*)(start + 516);
- if(mask != 0) {
- uint8 overflow = low >= 0xFFFFFFE8;
- uint32 sizeLow = low + 24;
- uint32 sizeHigh = high + overflow;
- if(low & 0xF || (high == 0 && low < 0x240) || sizeHigh > upperHigh
- || (sizeHigh >= upperHigh && sizeLow > upperLow)) {
- throw std::exception("First validation failed");
- }
- }
- ptr += 8;
- }
- uint32 maskSecond = *(uint32*)(sizeData + 536);
- if(maskSecond != 0) {
- uint32 low = *(uint32*)(sizeData + 528);
- uint32 high = *(uint32*)(sizeData + 532);
- uint32 upperLow = *(uint32*)(start + 512);
- uint32 upperHigh = *(uint32*)(start + 516);
- uint8 overflow = low >= 0xFFFFFFE8;
- uint32 sizeLow = low + 24;
- uint32 sizeHigh = high + overflow;
- if(low & 0xF || (high == 0 && low < 0x240) || sizeHigh > upperHigh
- || (sizeHigh >= upperHigh && sizeLow > upperLow)) {
- throw std::exception("second validation failed");
- }
- } else {
- uint32 checkVal = *(uint32*)(sizeData + 532) | *(uint32*)(sizeData + 528);
- if(*(uint64*)(sizeData + 528) != 0 || *(uint32*)(sizeData + 540) != checkVal || *(uint32*)(sizeData + 544) != checkVal) {
- throw std::exception("third validation failed");
- }
- }
- mDirectoryCount = *(uint32*)(sizeData + 536);
- mDirectoryTableStart = *(uint64*)(sizeData + 528);
- mDirectoryHeaders.resize(mDirectoryCount);
- mFile->seek(mDirectoryTableStart);
- mFile->read(mDirectoryHeaders.data(), (uint64)mDirectoryHeaders.size() * 16);
- }
- void PackArchive::loadDirectoryTree() {
- bool aidxFound = false;
- for(auto entry : mDirectoryHeaders) {
- if(entry.blockSize < sizeof(AIDX)) {
- continue;
- }
- mFile->seek(entry.directoryOffset);
- AIDX idx = mFile->read<AIDX>();
- if(idx.magic == IndexMagic) {
- aidxFound = true;
- mIndexHeader = idx;
- break;
- }
- }
- if(aidxFound == false) {
- throw std::exception("File misses AIDX block");
- }
- mFileRoot = std::make_shared<DirectoryEntry>(std::shared_ptr<IFileSystemEntry>(), L"", mIndexHeader.rootBlock, shared_from_this());
- mFileRoot->parseChildren();
- }
- void DirectoryEntry::getFiles(std::vector<IFileSystemEntryPtr>& files) {
- for(auto entry : mChildren) {
- if(entry->isDirectory() == false) {
- files.push_back(entry);
- } else {
- std::dynamic_pointer_cast<DirectoryEntry>(entry)->getFiles(files);
- }
- }
- }
- DirectoryEntry::DirectoryEntry(IFileSystemEntryPtr parent, const std::wstring& name, uint32 nextBlock, PackArchivePtr archive) {
- mArchive = archive;
- mEntryName = name;
- mNextBlock = nextBlock;
- mParent = parent;
- }
- IFileSystemEntryPtr DirectoryEntry::getFile(std::wstring path) {
- std::wstring::size_type t = path.find(L'\\');
- if(t == std::wstring::npos) {
- for(auto child : mChildren) {
- if(child->getEntryName() == path) {
- return child;
- }
- }
- return nullptr;
- }
- std::wstring dir = path.substr(0, t);
- std::wstring remain = path.substr(t + 1);
- for(auto child : mChildren) {
- if(child->getEntryName() == dir && child->isDirectory())
- return std::dynamic_pointer_cast<DirectoryEntry>(child)->getFile(remain);
- }
- return nullptr;
- }
- void DirectoryEntry::dumpFiles(std::wstring basePath, std::wostream& strm) {
- std::wstringstream newPath;
- newPath << basePath << mEntryName;
- if(mParent != nullptr) {
- newPath << L"\\";
- }
- for(auto child : mChildren) {
- child->dumpFiles(newPath.str(), strm);
- }
- }
- void DirectoryEntry::parseChildren() {
- auto& blockTable = mArchive->getBlockTable();
- auto file = mArchive->getFile();
- auto nextBlock = blockTable[mNextBlock];
- file->seek(nextBlock.directoryOffset);
- uint32 numDirectories = file->read<uint32>();
- uint32 numFiles = file->read<uint32>();
- uint64 curPos = file->tell();
- int64 dataSize = numDirectories * 8 + numFiles * 56;
- file->seekMod(dataSize);
- uint64 stringSize = nextBlock.blockSize - 8 - dataSize;
- std::vector<char> nameData((uint32)stringSize);
- file->read(nameData.data(), nameData.size());
- file->seek(curPos);
- std::list<DirectoryEntryPtr> dirEntries;
- for(uint32 i = 0; i < numDirectories; ++i) {
- uint32 nameOffset = file->read<uint32>();
- uint32 nextBlock = file->read<uint32>();
- DirectoryEntryPtr dirEnt = std::make_shared<DirectoryEntry>(shared_from_this(), toUnicode(nameData.data() + nameOffset), nextBlock, mArchive);
- dirEntries.push_back(dirEnt);
- mChildren.push_back(dirEnt);
- }
- for(uint32 i = 0; i < numFiles; ++i) {
- uint32 nameOffset = file->read<uint32>();
- std::vector<uint8> junk(52);
- file->read(junk.data(), junk.size());
- FileEntryPtr fe = std::make_shared<FileEntry>(shared_from_this(), toUnicode(nameData.data() + nameOffset), junk);
- mChildren.push_back(fe);
- }
- for(auto dirEnt : dirEntries) {
- dirEnt->parseChildren();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment