void ae3d::FileSystem::LoadPakFile( const char* path ) { if (path == nullptr) { System::Print( "LoadPakFile: path is null\n" ); } Global::pakFiles.emplace_back( PakFile() ); unsigned entryCount = 0; std::ifstream ifs( path ); if (!ifs.is_open()) { System::Print( "LoadPakFile: Could not open %s\n", path ); } ifs.read( (char*)&entryCount, 4 ); auto& pakFile = Global::pakFiles.back(); pakFile.entries.resize( entryCount ); pakFile.path = path; for (unsigned i = 0; i < entryCount; ++i) { auto& entry = pakFile.entries[i]; char entryPath[ 128 ]; ifs.read( entryPath, 128 ); entry.path = entryPath; unsigned entrySize = 0; ifs.read( (char*)&entrySize, 4 ); entry.contents.resize( entrySize ); ifs.read( (char*)entry.contents.data(), entrySize ); } }
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; } }
bool ListFilesInPak(const TCHAR * InPakFilename) { FPakFile PakFile(InPakFilename, FParse::Param(FCommandLine::Get(), TEXT("signed"))); int32 FileCount = 0; int64 FileSize = 0; if (PakFile.IsValid()) { TArray<FPakFile::FFileIterator> Records; for (FPakFile::FFileIterator It(PakFile); It; ++It) { Records.Add(It); } struct FOffsetSort { FORCEINLINE bool operator()(const FPakFile::FFileIterator& A, const FPakFile::FFileIterator& B) const { return A.Info().Offset < B.Info().Offset; } }; Records.Sort(FOffsetSort()); for (auto It : Records) { const FPakEntry& Entry = It.Info(); UE_LOG(LogPakFile, Display, TEXT("\"%s\" offset: %lld, size: %d bytes."), *It.Filename(), Entry.Offset, Entry.Size); FileSize += Entry.Size; FileCount++; } UE_LOG(LogPakFile, Display, TEXT("%d files (%lld bytes)."), FileCount, FileSize); return true; } else { UE_LOG(LogPakFile, Error, TEXT("Unable to open pak file \"%s\"."), InPakFilename); return false; } }
libPak::libPak(QIODevice *dev):_dev(dev), _type(PakUnknown) { // Store IODevice original position QIODevice::Offset lastOffset = _dev->at(); /* Get type */ _dev->reset(); _dev->readBlock(_magic, 8); if (qstrncmp(_magic, "SceeWhPk", 8) == 0) { _type = PakPK; } else if (qstrncmp(_magic, "SceeWhPC", 8) == 0) // This type has CRC information along with files _type = PakPC; if (_type != PakUnknown) { /* Get date and time */ char dateTime[20]; _dev->readBlock(dateTime, 20); // TODO: Parse date and time //_dateTime.fromString(dateTime, /* Get files header size and number of files */ _dev->readBlock((char*)&_headSize, 4); _dev->readBlock((char*)&_nFiles, 4); /* Get extensions */ _dev->at(0x0114); char exts[0x84]; _dev->readBlock(exts, 0x84); QStringList extsList; for (int j = 0; j < 0x84; j += 4) { if (exts[j]) extsList.append(QCString(exts+j)); } /* Get files */ char filesBuf[_headSize]; _dev->readBlock(filesBuf, _headSize); register int offset = 0; // TODO: Find a better way to reserve space on the list! for (unsigned int j = 0; j < _nFiles; j++) { _files.push_back(PakFile()); } QString last(""); for (unsigned int j = 0; j < _nFiles; j++) { _files[j].offset = (*(unsigned int *)(filesBuf+offset) & 0x00FFFFFF) * 0x800; offset += 3; unsigned int save = *(unsigned char *)(filesBuf+offset); unsigned int strLen = filesBuf[offset + 1] - 1; // Unknown use! unsigned int dir = *(unsigned short *)(filesBuf+offset + 2); offset += 4; _files[j].size = *(unsigned int *)(filesBuf+offset); offset += 4; if (_type == PakPC) { _files[j].CRC = *(unsigned int *)(filesBuf+offset); offset += 4; } last = _files[j].filename = last.left(save).append(QCString(filesBuf+offset, strLen + 1)); offset += strLen; _files[j].filename.append("." + extsList[*(unsigned char*)(filesBuf + offset++) - 1]).prepend("\\"); _filenamesOnly.push_back(_files[j].filename); } } // Restore original position _dev->at(lastOffset); }
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; } }
bool FAssetStreamer::StreamPackage(const FString& PakFileName, IAssetStreamerListener* AssetStreamerListener, EAssetStreamingMode::Type DesiredMode, const TCHAR* CmdLine) { Lock(); Listener = NULL; const bool bRemote = (DesiredMode == EAssetStreamingMode::Remote); if (!(bRemote && UseRemote(CmdLine) || !bRemote && UseLocal(CmdLine))) { Unlock(); return false; } CurrentMode = DesiredMode; FPlatformFileManager::Get().SetPlatformFile(*PakPlatform); // Now Get the path and start the streaming const FString FilePath = bRemote ? ResolveRemotePath(PakFileName) : ResolveLocalPath(PakFileName); // Make sure the Pak file is actually there FPakFile PakFile(*FilePath, bSigned); if (!PakFile.IsValid()) { Unlock(); UE_LOG(LogAsyncPackageStreamer, Error, TEXT("Invalid pak file: %s"), *FilePath); return false; } // TODO: Do we need to mount it into the engine dir? Creare a DLC dir instead? PakFile.SetMountPoint(*FPaths::EngineContentDir()); const int32 PakOrder = 0; if (!PakPlatform->Mount(*FilePath, PakOrder, *FPaths::EngineContentDir())) { Unlock(); UE_LOG(LogAsyncPackageStreamer, Error, TEXT("Failed to mount pak file: %s"), *FilePath); return false; } // Load all assets contained in this Pak file TSet<FString> FileList; PakFile.FindFilesAtPath(FileList, *PakFile.GetMountPoint(), true, false, true); // Discover assets within the PakFile StreamedAssets.Empty(); for (TSet<FString>::TConstIterator FileItem(FileList); FileItem; ++FileItem) { FString AssetName = *FileItem; if (AssetName.EndsWith(FPackageName::GetAssetPackageExtension()) || AssetName.EndsWith(FPackageName::GetMapPackageExtension())) { // TODO: Set path relative to mountpoint for remote streaming? StreamedAssets.Add(AssetName); } } // Once we started the async work assign listener Listener = AssetStreamerListener; // Tell the listener which assets we are about to stream if (Listener) { Listener->OnPrepareAssetStreaming(StreamedAssets); } // IF we have not yet a StreamableManager setup (Arrr...) abort if (StreamableManager == nullptr) { Unlock(); UE_LOG(LogAsyncPackageStreamer, Error, TEXT("No StreamableManager registered, did you missed to call initialize?")); return false; } StreamableManager->RequestAsyncLoad(StreamedAssets, FStreamableDelegate::CreateRaw(this, &FAssetStreamer::OnStreamingCompleteDelegate)); return true; }