mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-30 08:55:39 +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>
|
||||
</PropertyGroup>
|
||||
<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>
|
||||
<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 Include="PresentationCore" />
|
||||
<Reference Include="System" />
|
||||
@ -89,6 +89,8 @@
|
||||
<Compile Include="DigitalMonkey\ArcDM.cs" />
|
||||
<Compile Include="DigitalMonkey\ImagePKT.cs" />
|
||||
<Compile Include="Electriciteit\ArcPKK.cs" />
|
||||
<Compile Include="KApp\ArcASD.cs" />
|
||||
<Compile Include="KApp\ImageCGD.cs" />
|
||||
<Compile Include="Kasane\ArcAR2.cs" />
|
||||
<Compile Include="KeroQ\ArcDAT.cs" />
|
||||
<Compile Include="KeroQ\ImageCBM.cs" />
|
||||
@ -97,6 +99,8 @@
|
||||
<Compile Include="Lazycrew\ArcDAT.cs" />
|
||||
<Compile Include="Lazycrew\ImageDAT.cs" />
|
||||
<Compile Include="Melonpan\ArcTTD.cs" />
|
||||
<Compile Include="Mermaid\AudioPWV.cs" />
|
||||
<Compile Include="Mermaid\ImageGP1.cs" />
|
||||
<Compile Include="Mmfass\ArcSDA.cs" />
|
||||
<Compile Include="Nyoken\ArcZLK.cs" />
|
||||
<Compile Include="PenguinWorks\ArcPAC.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user