0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-07-01 12:40:25 +03:00
Files
ParkanPlayground/NResLib/NResPacker.cs

151 lines
5.4 KiB
C#
Raw Normal View History

2025-06-22 18:47:21 +03:00
using System.Buffers.Binary;
using System.Text;
namespace NResLib;
public class NResPacker
{
public static string Pack(NResArchive archive, string srcNresPath, string contentDirectoryPath, string targetFileDirectoryPath)
{
var diskFiles = Directory.GetFiles(contentDirectoryPath)
.Select(Path.GetFileName)
.ToList();
var fileOffset = 16; // 16 по умолчанию, т.к. есть заголовок в 16 байт.
var metadataItems = new List<ListMetadataItem>();
foreach (var archiveFile in archive.Files)
{
var extension = Path.GetExtension(archiveFile.FileName);
var fileName = Path.GetFileNameWithoutExtension(archiveFile.FileName);
if (extension == "")
{
extension = ".bin";
}
var targetFileName = $"{archiveFile.Index}_{archiveFile.FileType}_{fileName}{extension}";
if (diskFiles.All(x => x != targetFileName))
{
return $"Не найдён файл {targetFileName}";
}
var filePath = Path.Combine(contentDirectoryPath, targetFileName);
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
{
throw new Exception();
}
var newFileLength = (int)fileInfo.Length;
var listItem = new ListMetadataItem(
archiveFile.FileType,
archiveFile.ElementCount,
archiveFile.Magic1,
newFileLength,
archiveFile.ElementSize,
archiveFile.FileName,
archiveFile.Magic3,
archiveFile.Magic4,
archiveFile.Magic5,
archiveFile.Magic6,
fileOffset,
archiveFile.Index
);
fileOffset += newFileLength;
metadataItems.Add(listItem);
}
var totalFileLength =
16 + // заголовок
metadataItems.Sum(x => x.FileLength) + // сумма длин всех файлов
metadataItems.Count * 64; // длина всех метаданных
var header = new NResArchiveHeader(archive.Header.NRes, archive.Header.Version, archive.Header.FileCount, totalFileLength);
var targetArchive = new NResArchive(header, metadataItems);
// имя архива = имени папки в которую архив распаковывали
string targetArchiveFileName = Path.GetFileName(srcNresPath)!;
var targetArchivePath = Path.Combine(targetFileDirectoryPath, targetArchiveFileName);
using var fs = new FileStream(targetArchivePath, FileMode.CreateNew);
Span<byte> span = stackalloc byte[4];
span.Clear();
Encoding.ASCII.GetBytes(header.NRes, span);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, header.Version);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, header.FileCount);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, header.TotalFileLengthBytes);
fs.Write(span);
foreach (var archiveFile in targetArchive.Files)
{
var extension = Path.GetExtension(archiveFile.FileName);
var fileName = Path.GetFileNameWithoutExtension(archiveFile.FileName);
if (extension == "")
{
extension = ".bin";
}
var targetFileName = $"{archiveFile.Index}_{archiveFile.FileType}_{fileName}{extension}";
var filePath = Path.Combine(contentDirectoryPath, targetFileName);
using var srcFs = new FileStream(filePath, FileMode.Open);
srcFs.CopyTo(fs);
}
Span<byte> fileNameSpan = stackalloc byte[20];
foreach (var archiveFile in targetArchive.Files)
{
span.Clear();
Encoding.ASCII.GetBytes(archiveFile.FileType, span);
fs.Write(span);
BinaryPrimitives.WriteUInt32LittleEndian(span, archiveFile.ElementCount);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic1);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.FileLength);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.ElementSize);
fs.Write(span);
fileNameSpan.Clear();
Encoding.ASCII.GetBytes(archiveFile.FileName, fileNameSpan);
fs.Write(fileNameSpan);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic3);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic4);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic5);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Magic6);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.OffsetInFile);
fs.Write(span);
BinaryPrimitives.WriteInt32LittleEndian(span, archiveFile.Index);
fs.Write(span);
}
fs.Flush();
return "Запакован архив";
}
}