Add project restore files and NuGet cache for GsaViewer
- Created project.nuget.cache to store NuGet package cache information. - Added project.packagespec.json to define project restore settings and dependencies. - Included rider.project.restore.info for Rider IDE integration.
This commit is contained in:
114
GsaEditor.Core/IO/GsaWriter.cs
Normal file
114
GsaEditor.Core/IO/GsaWriter.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System.Text;
|
||||
using GsaEditor.Core.Models;
|
||||
|
||||
namespace GsaEditor.Core.IO;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="GsaArchive"/> to a binary .gsa stream or file.
|
||||
/// Supports both NARC (legacy) and NARD (enhanced with padding) format variants.
|
||||
/// </summary>
|
||||
public static class GsaWriter
|
||||
{
|
||||
/// <summary>Magic word for the NARC (legacy) format.</summary>
|
||||
private const uint MAGIC_NARC = 0x4E415243;
|
||||
|
||||
/// <summary>Magic word for the NARD (enhanced) format.</summary>
|
||||
private const uint MAGIC_NARD = 0x4E415244;
|
||||
|
||||
/// <summary>
|
||||
/// Writes the archive to the specified file path.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to write.</param>
|
||||
/// <param name="filePath">The output file path.</param>
|
||||
public static void Write(GsaArchive archive, string filePath)
|
||||
{
|
||||
using var stream = File.Create(filePath);
|
||||
Write(archive, stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the archive to the given stream.
|
||||
/// Each entry's <see cref="GsaEntry.DataOffset"/> is updated to reflect the new position in the output.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to write.</param>
|
||||
/// <param name="stream">A writable stream.</param>
|
||||
public static void Write(GsaArchive archive, Stream stream)
|
||||
{
|
||||
using var writer = new BinaryWriter(stream, Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Write global header
|
||||
if (archive.Format == GsaFormat.NARC)
|
||||
{
|
||||
writer.Write(MAGIC_NARC);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(MAGIC_NARD);
|
||||
writer.Write(archive.OffsetPadding);
|
||||
writer.Write(archive.SizePadding);
|
||||
}
|
||||
|
||||
// Write each entry sequentially
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
WriteEntry(writer, entry, archive);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a single file entry at the current stream position.
|
||||
/// </summary>
|
||||
/// <param name="writer">The binary writer.</param>
|
||||
/// <param name="entry">The entry to write.</param>
|
||||
/// <param name="archive">The parent archive (used for NARD padding alignment).</param>
|
||||
private static void WriteEntry(BinaryWriter writer, GsaEntry entry, GsaArchive archive)
|
||||
{
|
||||
// NARD: align stream position before writing entry header
|
||||
if (archive.Format == GsaFormat.NARD && archive.OffsetPadding > 0)
|
||||
WritePadding(writer, archive.OffsetPadding);
|
||||
|
||||
// Write alias
|
||||
byte[] aliasBytes = Encoding.ASCII.GetBytes(entry.Alias);
|
||||
writer.Write((uint)aliasBytes.Length);
|
||||
writer.Write(aliasBytes);
|
||||
|
||||
// Write compression flag
|
||||
writer.Write((byte)(entry.IsCompressed ? 1 : 0));
|
||||
|
||||
// Write original (decompressed) length
|
||||
writer.Write(entry.OriginalLength);
|
||||
|
||||
// Write compressed length (only if compressed)
|
||||
if (entry.IsCompressed)
|
||||
{
|
||||
writer.Write(entry.CompressedLength);
|
||||
}
|
||||
|
||||
// NARD: align stream position before writing the data block
|
||||
if (archive.Format == GsaFormat.NARD && archive.OffsetPadding > 0)
|
||||
WritePadding(writer, archive.OffsetPadding);
|
||||
|
||||
// Update the entry's data offset to reflect the new position
|
||||
entry.DataOffset = writer.BaseStream.Position;
|
||||
|
||||
// Write raw data
|
||||
writer.Write(entry.RawData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes zero-bytes to pad the stream to the next aligned boundary.
|
||||
/// </summary>
|
||||
/// <param name="writer">The binary writer.</param>
|
||||
/// <param name="alignment">The alignment boundary in bytes.</param>
|
||||
private static void WritePadding(BinaryWriter writer, int alignment)
|
||||
{
|
||||
if (alignment <= 1) return;
|
||||
long pos = writer.BaseStream.Position;
|
||||
long remainder = pos % alignment;
|
||||
if (remainder != 0)
|
||||
{
|
||||
int paddingBytes = (int)(alignment - remainder);
|
||||
writer.Write(new byte[paddingBytes]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user