0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-08-02 17:36:32 +03:00

create NResUI

This commit is contained in:
bird_egop
2024-11-15 19:06:44 +03:00
parent 0c39485188
commit 1091605e2d
22 changed files with 869 additions and 100 deletions

45
NResLib/NResArchive.cs Normal file
View File

@@ -0,0 +1,45 @@
namespace NResLib;
/// <summary>
/// Архив NRes (файл NRes)
/// </summary>
public record NResArchive(NResArchiveHeader Header, List<ListMetadataItem> Files);
/// <summary>
/// Заголовок файла
/// </summary>
/// <param name="NRes">[0..4] ASCII NRes</param>
/// <param name="Version">[4..8] Версия кодировщика (должно быть всегда 0x100)</param>
/// <param name="FileCount">[8..12] Количество файлов </param>
/// <param name="TotalFileLengthBytes">[12..16] Длина всего архива</param>
public record NResArchiveHeader(string NRes, int Version, int FileCount, int TotalFileLengthBytes);
/// <summary>
/// В конце файла есть список метаданных,
/// каждый элемент это 64 байта,
/// найти начало можно как (Header.TotalFileLengthBytes - Header.FileCount * 64)
/// </summary>
/// <param name="FileType">[0..8] ASCII описание типа файла, например TEXM или MAT0</param>
/// <param name="Magic1">[8..12] Неизвестное число</param>
/// <param name="FileLength">[12..16] Длина файла в байтах</param>
/// <param name="Magic2">[16..20] Неизвестное число</param>
/// <param name="FileName">[20..40] ASCII имя файла</param>
/// <param name="Magic3">[40..44] Неизвестное число</param>
/// <param name="Magic4">[44..48] Неизвестное число</param>
/// <param name="Magic5">[48..52] Неизвестное число</param>
/// <param name="Magic6">[52..56] Неизвестное число</param>
/// <param name="OffsetInFile">[56..60] Смещение подфайла от начала NRes (именно самого NRes) в байтах</param>
/// <param name="Index">[60..64] Индекс в файле (от 0, не больше чем кол-во файлов)</param>
public record ListMetadataItem(
string FileType,
int Magic1,
int FileLength,
int Magic2,
string FileName,
int Magic3,
int Magic4,
int Magic5,
int Magic6,
int OffsetInFile,
int Index
);

9
NResLib/NResLib.csproj Normal file
View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,3 @@
namespace NResLib;
public record NResParseResult(NResArchive? Archive = null, string? Error = null);

78
NResLib/NResParser.cs Normal file
View File

@@ -0,0 +1,78 @@
using System.Buffers.Binary;
using System.Text;
namespace NResLib;
public static class NResParser
{
public static NResParseResult ReadFile(string path)
{
using FileStream nResFs = new FileStream(path, FileMode.Open);
if (nResFs.Length < 16)
{
return new NResParseResult(null, "Файл не может быть NRes, менее 16 байт");
}
Span<byte> buffer = stackalloc byte[16];
nResFs.ReadExactly(buffer);
if (buffer[0] != 'N' || buffer[1] != 'R' || buffer[2] != 'e' || buffer[3] != 's')
{
return new NResParseResult(null, "Файл не начинается с NRes");
}
var header = new NResArchiveHeader(
NRes: Encoding.ASCII.GetString(buffer[0..4]),
Version: BinaryPrimitives.ReadInt32LittleEndian(buffer[4..8]),
FileCount: BinaryPrimitives.ReadInt32LittleEndian(buffer[8..12]),
TotalFileLengthBytes: BinaryPrimitives.ReadInt32LittleEndian(buffer[12..16])
);
if (header.TotalFileLengthBytes != nResFs.Length)
{
return new NResParseResult(
null,
$"Длина файла не совпадает с заявленным в заголовке.\n" +
$"Заявлено: {header.TotalFileLengthBytes}\n" +
$"Фактически: {nResFs.Length}"
);
}
nResFs.Seek(-header.FileCount * 64, SeekOrigin.End);
var elements = new List<ListMetadataItem>(header.FileCount);
Span<byte> metaDataBuffer = stackalloc byte[64];
for (int i = 0; i < header.FileCount; i++)
{
nResFs.ReadExactly(metaDataBuffer);
elements.Add(
new ListMetadataItem(
FileType: Encoding.ASCII.GetString(metaDataBuffer[..8]),
Magic1: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[8..12]),
FileLength: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[12..16]),
Magic2: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[16..20]),
FileName: Encoding.ASCII.GetString(metaDataBuffer[20..40]),
Magic3: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[40..44]),
Magic4: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[44..48]),
Magic5: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[48..52]),
Magic6: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[52..56]),
OffsetInFile: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[56..60]),
Index: BinaryPrimitives.ReadInt32LittleEndian(metaDataBuffer[60..64])
)
);
metaDataBuffer.Clear();
}
return new NResParseResult(
new NResArchive(
Header: header,
Files: elements
)
);
}
}