mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-30 17:05:37 +08:00
(Legacy): CGD images and ASD archives.
This commit is contained in:
parent
8f9cc46dba
commit
ae7630b5be
125
Legacy/KApp/ArcASD.cs
Normal file
125
Legacy/KApp/ArcASD.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
//! \file ArcASD.cs
|
||||||
|
//! \date 2019 Jan 11
|
||||||
|
//! \brief Spiel resource archive.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 by morkt
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.KApp
|
||||||
|
{
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class AsdOpener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "ASD/KTOOL"; } }
|
||||||
|
public override string Description { get { return "KApp engine resource archive"; } }
|
||||||
|
public override uint Signature { get { return 0x6F6F746B; } } // 'ktool210'
|
||||||
|
public override bool IsHierarchic { get { return false; } }
|
||||||
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
{
|
||||||
|
int count = file.View.ReadInt32 (8);
|
||||||
|
if (!IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||||
|
uint index_pos = 0x10;
|
||||||
|
uint next_offset = file.View.ReadUInt32 (index_pos);
|
||||||
|
var dir = new List<Entry> (count);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
index_pos += 4;
|
||||||
|
var entry = new Entry {
|
||||||
|
Name = string.Format ("{0}#{1:D4}", base_name, i),
|
||||||
|
Offset = next_offset,
|
||||||
|
};
|
||||||
|
next_offset = file.View.ReadUInt32 (index_pos);
|
||||||
|
entry.Size = (uint)(next_offset - entry.Offset);
|
||||||
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
dir.Add (entry);
|
||||||
|
}
|
||||||
|
DetectFileTypes (file, dir);
|
||||||
|
return new ArcFile (file, this, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetectFileTypes (ArcView file, List<Entry> dir)
|
||||||
|
{
|
||||||
|
foreach (var entry in dir)
|
||||||
|
{
|
||||||
|
var type = file.View.ReadUInt32 (entry.Offset+0xC);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case 0xB713E4: entry.Type = "audio"; break;
|
||||||
|
case 0xB29EA4:
|
||||||
|
case 0x973768: entry.Type = "image"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
uint id = arc.File.View.ReadUInt32 (entry.Offset+0xC);
|
||||||
|
if (id != 0xB713E4)
|
||||||
|
return base.OpenEntry (arc, entry);
|
||||||
|
return OpenAudio (arc, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||||
|
var info = CgdMetaData.FromStream (input, 0);
|
||||||
|
input.Position = 0;
|
||||||
|
if (null == info)
|
||||||
|
return ImageFormatDecoder.Create (input);
|
||||||
|
return new CgdDecoder (input, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream OpenAudio (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
using (var input = arc.File.CreateStream (entry.Offset, entry.Size))
|
||||||
|
{
|
||||||
|
var header = input.ReadHeader (0x20);
|
||||||
|
int header_size = header.ToUInt16 (10);
|
||||||
|
var format = new WaveFormat {
|
||||||
|
FormatTag = header.ToUInt16 (0x10),
|
||||||
|
Channels = header.ToUInt16 (0x12),
|
||||||
|
SamplesPerSecond = header.ToUInt32 (0x14),
|
||||||
|
AverageBytesPerSecond = header.ToUInt32 (0x18),
|
||||||
|
BlockAlign = header.ToUInt16 (0x1C),
|
||||||
|
BitsPerSample = header.ToUInt16 (0x1E),
|
||||||
|
};
|
||||||
|
input.Position = header_size + 0x10;
|
||||||
|
var data = new byte[header.ToInt32 (0)];
|
||||||
|
KTool.Unpack (input, data, header[8]);
|
||||||
|
var output = new MemoryStream (data.Length);
|
||||||
|
WaveAudio.WriteRiffHeader (output, format, (uint)data.Length);
|
||||||
|
output.Write (data, 0, data.Length);
|
||||||
|
output.Position = 0;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
261
Legacy/KApp/ImageCGD.cs
Normal file
261
Legacy/KApp/ImageCGD.cs
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
//! \file ImageCGD.cs
|
||||||
|
//! \date 2019 Jan 10
|
||||||
|
//! \brief Spiel compressed image.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 by morkt
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
// [030228][spiel] The Black Box
|
||||||
|
|
||||||
|
namespace GameRes.Formats.KApp
|
||||||
|
{
|
||||||
|
[Export(typeof(ImageFormat))]
|
||||||
|
public class CgdFormat : ImageFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "CGD/KTOOL"; } }
|
||||||
|
public override string Description { get { return "KApp compressed image format"; } }
|
||||||
|
public override uint Signature { get { return 0x6F6F746B; } } // 'ktool210'
|
||||||
|
|
||||||
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
|
{
|
||||||
|
var header = file.ReadHeader (0x18);
|
||||||
|
if (!header.AsciiEqual ("ktool210") || header.ToInt32 (8) != 1)
|
||||||
|
return null;
|
||||||
|
uint offset = header.ToUInt32 (0x10) & 0x7FFFFFFF;
|
||||||
|
return CgdMetaData.FromStream (file, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||||
|
{
|
||||||
|
var reader = new CgdDecoder (file, (CgdMetaData)info);
|
||||||
|
return reader.Image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write (Stream file, ImageData image)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException ("CgdFormat.Write not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CgdMetaData : ImageMetaData
|
||||||
|
{
|
||||||
|
public uint DataOffset;
|
||||||
|
public int UnpackedSize;
|
||||||
|
public byte Compression;
|
||||||
|
|
||||||
|
internal static CgdMetaData FromStream (IBinaryStream file, uint offset)
|
||||||
|
{
|
||||||
|
file.Position = offset;
|
||||||
|
int unpacked_size = file.ReadInt32();
|
||||||
|
file.ReadInt32();
|
||||||
|
byte compression = (byte)file.ReadUInt16();
|
||||||
|
uint header_size = file.ReadUInt16();
|
||||||
|
uint id = file.ReadUInt32();
|
||||||
|
if (header_size < 0x10 || (id != 0x973768 && id != 0xB29EA4))
|
||||||
|
return null;
|
||||||
|
ushort width = file.ReadUInt16();
|
||||||
|
ushort height = file.ReadUInt16();
|
||||||
|
ushort bpp = file.ReadUInt16();
|
||||||
|
return new CgdMetaData {
|
||||||
|
Width = width,
|
||||||
|
Height = height,
|
||||||
|
BPP = bpp,
|
||||||
|
DataOffset = offset + 0x10 + header_size,
|
||||||
|
UnpackedSize = unpacked_size,
|
||||||
|
Compression = compression,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class KTool
|
||||||
|
{
|
||||||
|
public static void Unpack (IBinaryStream input, byte[] output, byte method)
|
||||||
|
{
|
||||||
|
switch (method)
|
||||||
|
{
|
||||||
|
case 0: input.Read (output, 0, output.Length); break;
|
||||||
|
case 1: DecompressRle (input, output, 1); break;
|
||||||
|
case 2: DecompressRle (input, output, 2); break;
|
||||||
|
case 3: DecompressRle (input, output, 3); break;
|
||||||
|
case 4: DecompressRle (input, output, 4); break;
|
||||||
|
case 0x10: DecompressHuffman (input, output); break;
|
||||||
|
default:
|
||||||
|
throw new InvalidFormatException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void DecompressRle (IBinaryStream input, byte[] output, int step)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < step; ++i)
|
||||||
|
{
|
||||||
|
sbyte ctl = input.ReadInt8();
|
||||||
|
int dst = i;
|
||||||
|
while (ctl != 0)
|
||||||
|
{
|
||||||
|
if (ctl < 0)
|
||||||
|
{
|
||||||
|
int count = -ctl;
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
output[dst] = input.ReadUInt8();
|
||||||
|
dst += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte v = input.ReadUInt8();
|
||||||
|
int count = ctl;
|
||||||
|
while (count --> 0)
|
||||||
|
{
|
||||||
|
output[dst] = v;
|
||||||
|
dst += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctl = input.ReadInt8();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void DecompressHuffman (IBinaryStream input, byte[] output)
|
||||||
|
{
|
||||||
|
var decomp = new HuffmanDecoder (input);
|
||||||
|
decomp.Unpack (output);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HuffmanNode
|
||||||
|
{
|
||||||
|
public ushort Code;
|
||||||
|
public ushort LNode;
|
||||||
|
public ushort RNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HuffmanDecoder
|
||||||
|
{
|
||||||
|
IBinaryStream m_input;
|
||||||
|
HuffmanNode[] m_tree = new HuffmanNode[514];
|
||||||
|
|
||||||
|
public HuffmanDecoder (IBinaryStream input)
|
||||||
|
{
|
||||||
|
m_input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unpack (byte[] output)
|
||||||
|
{
|
||||||
|
ReadDict();
|
||||||
|
var root = BuildTree();
|
||||||
|
int dst = 0;
|
||||||
|
int bits = 0;
|
||||||
|
byte mask = 0;
|
||||||
|
while (dst < output.Length)
|
||||||
|
{
|
||||||
|
var token = root;
|
||||||
|
while (token > 0x100)
|
||||||
|
{
|
||||||
|
if (0 == mask)
|
||||||
|
{
|
||||||
|
bits = m_input.ReadByte();
|
||||||
|
if (-1 == bits)
|
||||||
|
return;
|
||||||
|
mask = 0x80;
|
||||||
|
}
|
||||||
|
if ((bits & mask) != 0)
|
||||||
|
token = m_tree[token].RNode;
|
||||||
|
else
|
||||||
|
token = m_tree[token].LNode;
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
output[dst++] = (byte)token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadDict ()
|
||||||
|
{
|
||||||
|
var dict = new byte[256];
|
||||||
|
DecompressRle (m_input, dict, 1);
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
m_tree[i].Code = dict[i];
|
||||||
|
}
|
||||||
|
m_tree[256].Code = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort BuildTree ()
|
||||||
|
{
|
||||||
|
m_tree[513].Code = ushort.MaxValue;
|
||||||
|
ushort root = 257;
|
||||||
|
while (root > 0)
|
||||||
|
{
|
||||||
|
ushort rhs = 513;
|
||||||
|
ushort lhs = 513;
|
||||||
|
ushort node = 0;
|
||||||
|
for (ushort i = 0; i < root; ++i)
|
||||||
|
{
|
||||||
|
var code = m_tree[node].Code;
|
||||||
|
if (code != 0)
|
||||||
|
{
|
||||||
|
if (code < m_tree[lhs].Code)
|
||||||
|
{
|
||||||
|
rhs = lhs;
|
||||||
|
lhs = i;
|
||||||
|
}
|
||||||
|
else if (code < m_tree[rhs].Code)
|
||||||
|
{
|
||||||
|
rhs = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++node;
|
||||||
|
}
|
||||||
|
if (rhs == 513)
|
||||||
|
break;
|
||||||
|
m_tree[root].Code = (ushort)(m_tree[rhs].Code + m_tree[lhs].Code);
|
||||||
|
m_tree[root].LNode = lhs;
|
||||||
|
m_tree[root].RNode = rhs;
|
||||||
|
m_tree[lhs].Code = 0;
|
||||||
|
m_tree[rhs].Code = 0;
|
||||||
|
++root;
|
||||||
|
}
|
||||||
|
return (ushort)(root - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CgdDecoder : BinaryImageDecoder
|
||||||
|
{
|
||||||
|
public CgdDecoder (IBinaryStream input, CgdMetaData info) : base (input, info)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ImageData GetImageData ()
|
||||||
|
{
|
||||||
|
var meta = (CgdMetaData)Info;
|
||||||
|
m_input.Position = meta.DataOffset;
|
||||||
|
var pixels = new byte[meta.UnpackedSize];
|
||||||
|
KTool.Unpack (m_input, pixels, meta.Compression);
|
||||||
|
PixelFormat format = 24 == meta.BPP ? PixelFormats.Rgb24 : PixelFormats.Bgra32;
|
||||||
|
return ImageData.Create (meta, format, null, pixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -44,9 +44,9 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="ICSharpCode.SharpZipLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
<Reference Include="ICSharpCode.SharpZipLib, Version=1.0.0.999, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\SharpZipLib.1.0.0\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
<HintPath>..\packages\SharpZipLib.1.1.0\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
@ -89,6 +89,8 @@
|
|||||||
<Compile Include="DigitalMonkey\ArcDM.cs" />
|
<Compile Include="DigitalMonkey\ArcDM.cs" />
|
||||||
<Compile Include="DigitalMonkey\ImagePKT.cs" />
|
<Compile Include="DigitalMonkey\ImagePKT.cs" />
|
||||||
<Compile Include="Electriciteit\ArcPKK.cs" />
|
<Compile Include="Electriciteit\ArcPKK.cs" />
|
||||||
|
<Compile Include="KApp\ArcASD.cs" />
|
||||||
|
<Compile Include="KApp\ImageCGD.cs" />
|
||||||
<Compile Include="Kasane\ArcAR2.cs" />
|
<Compile Include="Kasane\ArcAR2.cs" />
|
||||||
<Compile Include="KeroQ\ArcDAT.cs" />
|
<Compile Include="KeroQ\ArcDAT.cs" />
|
||||||
<Compile Include="KeroQ\ImageCBM.cs" />
|
<Compile Include="KeroQ\ImageCBM.cs" />
|
||||||
@ -97,6 +99,8 @@
|
|||||||
<Compile Include="Lazycrew\ArcDAT.cs" />
|
<Compile Include="Lazycrew\ArcDAT.cs" />
|
||||||
<Compile Include="Lazycrew\ImageDAT.cs" />
|
<Compile Include="Lazycrew\ImageDAT.cs" />
|
||||||
<Compile Include="Melonpan\ArcTTD.cs" />
|
<Compile Include="Melonpan\ArcTTD.cs" />
|
||||||
|
<Compile Include="Mermaid\AudioPWV.cs" />
|
||||||
|
<Compile Include="Mermaid\ImageGP1.cs" />
|
||||||
<Compile Include="Mmfass\ArcSDA.cs" />
|
<Compile Include="Mmfass\ArcSDA.cs" />
|
||||||
<Compile Include="Nyoken\ArcZLK.cs" />
|
<Compile Include="Nyoken\ArcZLK.cs" />
|
||||||
<Compile Include="PenguinWorks\ArcPAC.cs" />
|
<Compile Include="PenguinWorks\ArcPAC.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user