Merge pull request #187 from YeLikesss/master

[NekoNovel] 新增支持
This commit is contained in:
Crsky
2026-04-23 00:40:10 +08:00
committed by GitHub
2 changed files with 95 additions and 0 deletions

View File

@@ -265,6 +265,7 @@
<Compile Include="MAGES\ImageBIN.cs" />
<Compile Include="Mugi\ArcBIN.cs" />
<Compile Include="Musica\ArcPAK.cs" />
<Compile Include="NekoNovel\ArcNKPACK.cs" />
<Compile Include="NEKOWORKs\ArcPACK.cs" />
<Compile Include="NipponIchi\ArcCASN.cs" />
<Compile Include="NipponIchi\ArcPSFS.cs" />

View File

@@ -0,0 +1,94 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using GameRes.Compression;
using System.ComponentModel.Composition;
using CommunityToolkit.HighPerformance;
namespace GameRes.Formats.NekoNovel
{
[Export(typeof(ArchiveFormat))]
public class NkpackOpener : ArchiveFormat
{
public override string Tag => "NKPACK/NekoNovel";
public override string Description => "NekoNovel resource archive";
public override uint Signature => 0u;
public override bool IsHierarchic => true;
public override bool CanWrite => false;
public NkpackOpener()
{
Extensions = new string[] { "nkpack" };
}
private static readonly byte[] s_mHeader = new byte[]
{
0x0F, 0x00, 0x00, 0x00, 0x4E, 0x4B, 0x4E, 0x4F, 0x45, 0x56, 0x4C, 0x20, 0x50, 0x41, 0x43, 0x4B,
0x41, 0x47, 0x45
};
public override ArcFile TryOpen(ArcView file)
{
if (!file.View.BytesEqual(0L, s_mHeader))
{
return null;
}
using (ArcViewStream stream = file.CreateStream())
{
stream.Seek(-4L, SeekOrigin.End);
uint entryOffset = ~stream.ReadUInt32();
stream.Seek(entryOffset, SeekOrigin.Begin);
string signature = ReadString(stream);
int count = stream.ReadInt32();
List<Entry> entries = new List<Entry>(count);
for (int i = 0; i < count; ++i)
{
string name = ReadString(stream);
PackedEntry entry = Create<PackedEntry>(name);
entry.Offset = ~stream.ReadUInt32();
entry.UnpackedSize = stream.ReadUInt32();
entry.Size = ~stream.ReadUInt32();
entry.IsPacked = true;
if (!entry.CheckPlacement(file.MaxOffset))
{
return null;
}
entries.Add(entry);
}
return new ArcFile(file, this, entries);
}
}
public override Stream OpenEntry(ArcFile arc, Entry entry)
{
if (!(entry is PackedEntry e))
{
return arc.File.CreateStream(entry.Offset, entry.Size);
}
return new ZLibStream(arc.File.CreateStream(e.Offset, e.Size), CompressionMode.Decompress);
}
private unsafe static string ReadString(Stream stream)
{
uint length = 0u;
stream.Read(new Span<byte>(&length, 4));
if (length == 0u)
{
return string.Empty;
}
byte[] data = new byte[length];
stream.Read(data, 0, data.Length);
return Encoding.UTF8.GetString(data);
}
}
}