bool TestPakFile(const TCHAR* Filename) { FPakFile PakFile(Filename, FParse::Param(FCommandLine::Get(), TEXT("signed"))); if (PakFile.IsValid()) { UE_LOG(LogPakFile, Display, TEXT("Checking pak file \"%s\". This may take a while..."), Filename); FArchive& PakReader = *PakFile.GetSharedReader(NULL); int32 ErrorCount = 0; int32 FileCount = 0; for (FPakFile::FFileIterator It(PakFile); It; ++It, ++FileCount) { const FPakEntry& Entry = It.Info(); void* FileContents = FMemory::Malloc(Entry.Size); PakReader.Seek(Entry.Offset); uint32 SerializedCrcTest = 0; FPakEntry EntryInfo; EntryInfo.Serialize(PakReader, PakFile.GetInfo().Version); if (EntryInfo != Entry) { UE_LOG(LogPakFile, Error, TEXT("Serialized hash mismatch for \"%s\"."), *It.Filename()); ErrorCount++; } PakReader.Serialize(FileContents, Entry.Size); uint8 TestHash[20]; FSHA1::HashBuffer(FileContents, Entry.Size, TestHash); if (FMemory::Memcmp(TestHash, Entry.Hash, sizeof(TestHash)) != 0) { UE_LOG(LogPakFile, Error, TEXT("Hash mismatch for \"%s\"."), *It.Filename()); ErrorCount++; } else { UE_LOG(LogPakFile, Display, TEXT("\"%s\" OK."), *It.Filename()); } FMemory::Free(FileContents); } if (ErrorCount == 0) { UE_LOG(LogPakFile, Display, TEXT("Pak file \"%s\" healthy, %d files checked."), Filename, FileCount); } else { UE_LOG(LogPakFile, Display, TEXT("Pak file \"%s\" corrupted (%d errors ouf of %d files checked.)."), Filename, ErrorCount, FileCount); } return (ErrorCount == 0); } else { UE_LOG(LogPakFile, Error, TEXT("Unable to open pak file \"%s\"."), Filename); return false; } }
void FPakFile::LoadIndex(FArchive* Reader) { if (Reader->TotalSize() < (Info.IndexOffset + Info.IndexSize)) { UE_LOG(LogPakFile, Fatal, TEXT("Corrupted index offset in pak file.")); } else { // Load index into memory first. Reader->Seek(Info.IndexOffset); TArray<uint8> IndexData; IndexData.AddUninitialized(Info.IndexSize); Reader->Serialize(IndexData.GetData(), Info.IndexSize); FMemoryReader IndexReader(IndexData); // Check SHA1 value. uint8 IndexHash[20]; FSHA1::HashBuffer(IndexData.GetData(), IndexData.Num(), IndexHash); if (FMemory::Memcmp(IndexHash, Info.IndexHash, sizeof(IndexHash)) != 0) { UE_LOG(LogPakFile, Fatal, TEXT("Corrupted index in pak file (CRC mismatch).")); } // Read the default mount point and all entries. int32 NumEntries = 0; IndexReader << MountPoint; IndexReader << NumEntries; MakeDirectoryFromPath(MountPoint); // Allocate enough memory to hold all entries (and not reallocate while they're being added to it). Files.Empty(NumEntries); for (int32 EntryIndex = 0; EntryIndex < NumEntries; EntryIndex++) { // Serialize from memory. FPakEntry Entry; FString Filename; IndexReader << Filename; Entry.Serialize(IndexReader, Info.Version); // Add new file info. Files.Add(Entry); // Construct Index of all directories in pak file. FString Path = FPaths::GetPath(Filename); MakeDirectoryFromPath(Path); FPakDirectory* Directory = Index.Find(Path); if (Directory != NULL) { Directory->Add(Filename, &Files.Last()); } else { FPakDirectory NewDirectory; NewDirectory.Add(Filename, &Files.Last()); Index.Add(Path, NewDirectory); // add the parent directories up to the mount point while (MountPoint != Path) { Path = Path.Left(Path.Len()-1); int32 Offset = 0; if (Path.FindLastChar('/', Offset)) { Path = Path.Left(Offset); MakeDirectoryFromPath(Path); if (Index.Find(Path) == NULL) { FPakDirectory ParentDirectory; Index.Add(Path, ParentDirectory); } } else { Path = MountPoint; } } } } } }
bool ExtractFilesFromPak(const TCHAR* InPakFilename, const TCHAR* InDestPath, bool bUseMountPoint = false) { FPakFile PakFile(InPakFilename, FParse::Param(FCommandLine::Get(), TEXT("signed"))); if (PakFile.IsValid()) { FString DestPath(InDestPath); FArchive& PakReader = *PakFile.GetSharedReader(NULL); const int64 BufferSize = 8 * 1024 * 1024; // 8MB buffer for extracting void* Buffer = FMemory::Malloc(BufferSize); int64 CompressionBufferSize = 0; uint8* PersistantCompressionBuffer = NULL; int32 ErrorCount = 0; int32 FileCount = 0; FString PakMountPoint = bUseMountPoint ? PakFile.GetMountPoint().Replace( TEXT("../../../"), TEXT("")) : TEXT(""); for (FPakFile::FFileIterator It(PakFile); It; ++It, ++FileCount) { const FPakEntry& Entry = It.Info(); PakReader.Seek(Entry.Offset); uint32 SerializedCrcTest = 0; FPakEntry EntryInfo; EntryInfo.Serialize(PakReader, PakFile.GetInfo().Version); if (EntryInfo == Entry) { FString DestFilename(DestPath / PakMountPoint / It.Filename()); TAutoPtr<FArchive> FileHandle(IFileManager::Get().CreateFileWriter(*DestFilename)); if (FileHandle.IsValid()) { if (Entry.CompressionMethod == COMPRESS_None) { BufferedCopyFile(*FileHandle, PakReader, Entry, Buffer, BufferSize); } else { UncompressCopyFile(*FileHandle, PakReader, Entry, PersistantCompressionBuffer, CompressionBufferSize); } UE_LOG(LogPakFile, Display, TEXT("Extracted \"%s\" to \"%s\"."), *It.Filename(), *DestFilename); } else { UE_LOG(LogPakFile, Error, TEXT("Unable to create file \"%s\"."), *DestFilename); ErrorCount++; } } else { UE_LOG(LogPakFile, Error, TEXT("Serialized hash mismatch for \"%s\"."), *It.Filename()); ErrorCount++; } } FMemory::Free(Buffer); FMemory::Free(PersistantCompressionBuffer); UE_LOG(LogPakFile, Error, TEXT("Finished extracting %d files (including %d errors)."), FileCount, ErrorCount); return true; } else { UE_LOG(LogPakFile, Error, TEXT("Unable to open pak file \"%s\"."), InPakFilename); return false; } }