Files
UnrealEngine/Engine/Source/Developer/PakFileUtilities/Private/SignedArchiveWriter.cpp
2025-05-18 13:04:45 +08:00

99 lines
2.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SignedArchiveWriter.h"
#include "IPlatformFilePak.h"
#include "Misc/SecureHash.h"
#include "HAL/FileManager.h"
FSignedArchiveWriter::FSignedArchiveWriter(FArchive& InPak, const FString& InPakFilename, const FRSAKeyHandle InSigningKey)
: FArchive(InPak)
, BufferArchive(Buffer)
, PakWriter(InPak)
, PakSignaturesFilename(FPaths::ChangeExtension(InPakFilename, TEXT("sig")))
, SizeOnDisk(0)
, PakSize(0)
, SigningKey(InSigningKey)
{
check(IsSaving());
Buffer.Reserve(FPakInfo::MaxChunkDataSize);
}
FSignedArchiveWriter::~FSignedArchiveWriter()
{
if (BufferArchive.Tell() > 0)
{
SerializeBufferAndSign();
}
delete &PakWriter;
}
void FSignedArchiveWriter::SerializeBufferAndSign()
{
// Compute a hash for this buffer data
ChunkHashes.Add(ComputePakChunkHash(&Buffer[0], Buffer.Num()));
// Flush the buffer
PakWriter.Serialize(&Buffer[0], Buffer.Num());
BufferArchive.Seek(0);
Buffer.Empty(FPakInfo::MaxChunkDataSize);
}
bool FSignedArchiveWriter::Close()
{
if (BufferArchive.Tell() > 0)
{
SerializeBufferAndSign();
}
FArchive* SignatureWriter = IFileManager::Get().CreateFileWriter(*PakSignaturesFilename);
FPakSignatureFile SignatureFile;
SignatureFile.SetChunkHashesAndSign(ChunkHashes, SignatureData, SigningKey);
SignatureFile.Serialize(*SignatureWriter);
delete SignatureWriter;
return FArchive::Close();
}
void FSignedArchiveWriter::Serialize(void* Data, int64 Length)
{
// Serialize data to a buffer. When the max buffer size is reached, the buffer is signed and
// serialized to disk with its signature
uint8* DataToWrite = (uint8*)Data;
int64 RemainingSize = Length;
while (RemainingSize > 0)
{
int64 BufferPos = BufferArchive.Tell();
int64 SizeToWrite = RemainingSize;
if (BufferPos + SizeToWrite > FPakInfo::MaxChunkDataSize)
{
SizeToWrite = FPakInfo::MaxChunkDataSize - BufferPos;
}
BufferArchive.Serialize(DataToWrite, SizeToWrite);
if (BufferArchive.Tell() == FPakInfo::MaxChunkDataSize)
{
SerializeBufferAndSign();
}
SizeOnDisk += SizeToWrite;
PakSize += SizeToWrite;
RemainingSize -= SizeToWrite;
DataToWrite += SizeToWrite;
}
}
int64 FSignedArchiveWriter::Tell()
{
return PakSize;
}
int64 FSignedArchiveWriter::TotalSize()
{
return PakSize;
}
void FSignedArchiveWriter::Seek(int64 InPos)
{
UE_LOG(LogPakFile, Fatal, TEXT("Seek is not supported in FSignedArchiveWriter."));
}