From b1cc4eddf3b0ea96b21bc63bb2ae690f910f6c89 Mon Sep 17 00:00:00 2001 From: ManicSteiner Date: Thu, 14 Dec 2023 22:07:58 +0800 Subject: [PATCH] feat: KID DATRAW archive (failed) --- ArcFormats/ArcFormats.csproj | 1 + ArcFormats/Kid/ArcDATRAW.cs | 148 +++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 ArcFormats/Kid/ArcDATRAW.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 28bc40b1..211acb36 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -131,6 +131,7 @@ + diff --git a/ArcFormats/Kid/ArcDATRAW.cs b/ArcFormats/Kid/ArcDATRAW.cs new file mode 100644 index 00000000..3ce1f311 --- /dev/null +++ b/ArcFormats/Kid/ArcDATRAW.cs @@ -0,0 +1,148 @@ +using GameRes.Utility; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace GameRes.Formats.Kid +{ + [Export(typeof(ArchiveFormat))] + public class DATRAWOpener : ArchiveFormat + { + public override string Tag { get { return "DAT/KID & MAGES PS2 DAT RAW"; } } + public override string Description { get { return "DAT/KID & MAGES PS2 DAT RAW"; } } + public override uint Signature { get { return 0; } } //actually zero + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + private static readonly uint dataEntryCount = 4096; + + public override ArcFile TryOpen(ArcView file) + { + var archivename = Path.GetFileNameWithoutExtension(file.Name); + var dir = new List(); + for (int i = 0; i < dataEntryCount; i++) + { + uint offset = file.View.ReadUInt32(i * 8); + uint size = file.View.ReadUInt32(i * 8 + 4); + offset = offset * 2048 + 0x8000; + size *= 1024; + if (offset > file.MaxOffset || size > file.MaxOffset) + { + throw new InvalidFormatException(); + } + if (size == 0) continue; + + var entry = Create(archivename + i.ToString("D5")); + entry.Offset = offset; + entry.Size = size; + dir.Add(entry); + } + return new ArcFile(file, this, dir); + } + + /*public override Stream OpenEntry(ArcFile arc, Entry entry) + { + IBinaryStream input = arc.File.CreateStream(entry.Offset, entry.Size, entry.Name); + if (input.Signature == 0x535043) // 'CPS' + { + using (input) + return UnpackCps(input); + } + return input.AsStream; + }*/ + Stream UnpackCps(IBinaryStream input) + { + var header = input.ReadHeader(0x10); + int packed_size = header.ToInt32(4); + int compression = header.ToUInt16(0xA); + int unpacked_size = header.ToInt32(0xC); + + //input.Seek(-4, SeekOrigin.End); + input.Seek(packed_size - 4, SeekOrigin.Begin); + uint key_offset = input.ReadUInt32() - 0x7534682; + input.Position = key_offset; + uint key = input.ReadUInt32() + key_offset + 0x3786425; + + var decryptor = new CpsTransform(packed_size, (int)key_offset, key); + using (var decoded = new InputCryptoStream(input.AsStream, decryptor)) + using (var cps = new BinaryStream(decoded, input.Name)) + { + var output = new byte[unpacked_size]; + if ((compression & 1) != 0) + { + cps.ReadInt32(); + UnpackLnd(cps, output); + } + else if ((compression & 2) != 0) + { + UnpackLnd16(cps, output); + } + else + { + cps.ReadInt32(); + cps.Read(output, 0, unpacked_size); + } + return new BinMemoryStream(output); + } + } + internal static void UnpackLnd(IBinaryStream input, byte[] output) + { + int unpacked_size = output.Length; + int dst = 0; + while (dst < unpacked_size) + { + int ctl = input.ReadByte(); + if (-1 == ctl) + break; + if ((ctl & 0x80) != 0) + { + if ((ctl & 0x40) != 0) + { + int count = (ctl & 0x1F) + 2; + if ((ctl & 0x20) != 0) + count += input.ReadUInt8() << 5; + count = Math.Min(count, unpacked_size - dst); + byte v = input.ReadUInt8(); + for (int i = 0; i < count; ++i) + output[dst++] = v; + } + else + { + int count = ((ctl >> 2) & 0xF) + 2; + int offset = ((ctl & 3) << 8) + input.ReadUInt8() + 1; + count = Math.Min(count, unpacked_size - dst); + Binary.CopyOverlapped(output, dst - offset, dst, count); + dst += count; + } + } + else if ((ctl & 0x40) != 0) + { + int length = Math.Min((ctl & 0x3F) + 2, unpacked_size - dst); + int count = input.ReadUInt8(); + input.Read(output, dst, length); + dst += length; + count = Math.Min(count * length, unpacked_size - dst); + if (count > 0) + { + Binary.CopyOverlapped(output, dst - length, dst, count); + dst += count; + } + } + else + { + int count = (ctl & 0x1F) + 1; + if ((ctl & 0x20) != 0) + count += input.ReadUInt8() << 5; + count = Math.Min(count, unpacked_size - dst); + input.Read(output, dst, count); + dst += count; + } + } + } + static void UnpackLnd16(IBinaryStream input, byte[] output) + { + throw new NotImplementedException("KID Lnd16 compression not implemented."); + } + } +}