mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 13:45:34 +08:00
implemented CGF and IAF image sets.
This commit is contained in:
parent
0fe5d01ed7
commit
f502e9578c
@ -230,6 +230,8 @@
|
||||
<Compile Include="Tmr-Hiro\ImageGRD.cs" />
|
||||
<Compile Include="TopCat\ArcTCD3.cs" />
|
||||
<Compile Include="TopCat\ImageSPD.cs" />
|
||||
<Compile Include="Triangle\ArcCGF.cs" />
|
||||
<Compile Include="Triangle\ArcIAF.cs" />
|
||||
<Compile Include="uGOS\ArcDET.cs" />
|
||||
<Compile Include="uGOS\ImageBMP.cs" />
|
||||
<Compile Include="UMeSoft\ArcPK.cs" />
|
||||
|
119
ArcFormats/Triangle/ArcCGF.cs
Normal file
119
ArcFormats/Triangle/ArcCGF.cs
Normal file
@ -0,0 +1,119 @@
|
||||
//! \file ArcCGF.cs
|
||||
//! \date Tue Feb 02 00:47:55 2016
|
||||
//! \brief route2 engine CG archive.
|
||||
//
|
||||
// Copyright (C) 2016 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;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Triangle
|
||||
{
|
||||
internal class CgfEntry : Entry
|
||||
{
|
||||
public uint Flags;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class CgfOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "CGF"; } }
|
||||
public override string Description { get { return "route2 engine CG archive"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return false; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (0);
|
||||
if (!IsSaneCount (count) || file.MaxOffset >= ~0xC0000000)
|
||||
return null;
|
||||
uint offset1 = file.View.ReadUInt32 (0x14);
|
||||
uint offset2 = file.View.ReadUInt32 (0x20);
|
||||
uint entry_size, next_offset;
|
||||
if (4+(uint)count*0x14 == (offset1 & ~0xC0000000))
|
||||
{
|
||||
entry_size = 0x14;
|
||||
next_offset = offset1;
|
||||
}
|
||||
else if (4+(uint)count*0x20 == (offset2 & ~0xC0000000))
|
||||
{
|
||||
entry_size = 0x20;
|
||||
next_offset = offset2;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
|
||||
uint index_size = entry_size * (uint)count;
|
||||
if (index_size > file.View.Reserve (4, index_size))
|
||||
return null;
|
||||
|
||||
uint index_offset = 4;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = file.View.ReadString (index_offset, entry_size-4);
|
||||
uint flags = next_offset >> 30;
|
||||
Entry entry;
|
||||
if (1 == flags || name.EndsWith (".iaf", StringComparison.InvariantCultureIgnoreCase))
|
||||
entry = new Entry();
|
||||
else
|
||||
entry = new CgfEntry { Flags = flags };
|
||||
entry.Name = name;
|
||||
entry.Type = "image";
|
||||
entry.Offset = next_offset & ~0xC0000000;
|
||||
|
||||
index_offset += entry_size;
|
||||
next_offset = i+1 == count ? (uint)file.MaxOffset : file.View.ReadUInt32 (index_offset+entry_size-4);
|
||||
if (next_offset < entry.Offset)
|
||||
return null;
|
||||
entry.Size = (next_offset & ~0xC0000000) - (uint)entry.Offset;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var cent = entry as CgfEntry;
|
||||
if (null == cent)
|
||||
return base.OpenEntry (arc, entry);
|
||||
var offset = entry.Offset;
|
||||
var header = new byte[12];
|
||||
if (2 == cent.Flags)
|
||||
{
|
||||
arc.File.View.Read (offset, header, 0, 8);
|
||||
offset += 0x10;
|
||||
}
|
||||
uint packed_size = arc.File.View.ReadUInt32 (offset);
|
||||
arc.File.View.Read (offset+4, header, 8, 4);
|
||||
var input = arc.File.CreateStream (offset+8, packed_size);
|
||||
return new PrefixStream (header, input);
|
||||
}
|
||||
}
|
||||
}
|
76
ArcFormats/Triangle/ArcIAF.cs
Normal file
76
ArcFormats/Triangle/ArcIAF.cs
Normal file
@ -0,0 +1,76 @@
|
||||
//! \file ArcIAF.cs
|
||||
//! \date Thu Feb 04 03:18:26 2016
|
||||
//! \brief route2 engine multi-frame image.
|
||||
//
|
||||
// Copyright (C) 2016 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.Triangle
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class IafOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "IAF/MULTI"; } }
|
||||
public override string Description { get { return "route2 engine multi-frame image"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return false; } }
|
||||
|
||||
public IafOpener ()
|
||||
{
|
||||
Extensions = new string[] { "iaf" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.Name.EndsWith (".iaf", StringComparison.InvariantCultureIgnoreCase)
|
||||
|| file.MaxOffset < 0x20)
|
||||
return null;
|
||||
uint size = file.View.ReadUInt32 (1);
|
||||
if (size >= file.MaxOffset || size+0x19 >= file.MaxOffset)
|
||||
return null;
|
||||
|
||||
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
long current_offset = 0;
|
||||
var dir = new List<Entry>();
|
||||
while (current_offset < file.MaxOffset)
|
||||
{
|
||||
uint packed_size = file.View.ReadUInt32 (current_offset+1);
|
||||
if (0 == packed_size || current_offset+packed_size+0x19 > file.MaxOffset)
|
||||
return null;
|
||||
var entry = new Entry {
|
||||
Name = string.Format ("{0}#{1:D3}.IAF", base_name, dir.Count),
|
||||
Type = "image",
|
||||
Offset = current_offset,
|
||||
Size = packed_size + 0x19,
|
||||
};
|
||||
dir.Add (entry);
|
||||
current_offset += entry.Size;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
}
|
@ -76,46 +76,20 @@ namespace GameRes.Formats.Triangle
|
||||
if (Math.Abs (x) > 4096 || Math.Abs (y) > 4096)
|
||||
return null;
|
||||
int pack_type = (unpacked_size >> 30) & 3;
|
||||
if (3 == pack_type)
|
||||
return null;
|
||||
unpacked_size &= (int)~0xC0000000;
|
||||
stream.Position = data_offset;
|
||||
byte[] bmp;
|
||||
if (0 == pack_type)
|
||||
{
|
||||
using (var reader = new LzssReader (stream, (int)stream.Length-12, 0x26))
|
||||
{
|
||||
reader.Unpack();
|
||||
bmp = reader.Data;
|
||||
}
|
||||
}
|
||||
else if (2 == pack_type)
|
||||
{
|
||||
using (var reader = new RleReader (stream, (int)stream.Length-12, 0x26))
|
||||
{
|
||||
reader.Unpack();
|
||||
bmp = reader.Data;
|
||||
}
|
||||
}
|
||||
else if (1 == pack_type)
|
||||
{
|
||||
bmp = new byte[0x26];
|
||||
stream.Read (bmp, 0, bmp.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] bmp = UnpackBitmap (stream, pack_type, packed_size, 0x26);
|
||||
if (bmp[0] != 'B' && bmp[0] != 'C' || bmp[1] != 'M')
|
||||
return null;
|
||||
int width = LittleEndian.ToInt32 (bmp, 0x12);
|
||||
int height = LittleEndian.ToInt32 (bmp, 0x16);
|
||||
int bpp = LittleEndian.ToInt16 (bmp, 0x1c);
|
||||
return new IafMetaData
|
||||
{
|
||||
Width = (uint)width,
|
||||
Height = (uint)height,
|
||||
Width = LittleEndian.ToUInt32 (bmp, 0x12),
|
||||
Height = LittleEndian.ToUInt32 (bmp, 0x16),
|
||||
OffsetX = x,
|
||||
OffsetY = y,
|
||||
BPP = bpp,
|
||||
BPP = LittleEndian.ToInt16 (bmp, 0x1c),
|
||||
DataOffset = data_offset,
|
||||
PackedSize = packed_size,
|
||||
UnpackedSize = unpacked_size,
|
||||
@ -125,41 +99,16 @@ namespace GameRes.Formats.Triangle
|
||||
|
||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||
{
|
||||
var meta = info as IafMetaData;
|
||||
if (null == meta)
|
||||
throw new ArgumentException ("IafFormat.Read should be supplied with IafMetaData", "info");
|
||||
|
||||
var meta = (IafMetaData)info;
|
||||
stream.Position = meta.DataOffset;
|
||||
byte[] bitmap;
|
||||
if (2 == meta.PackType)
|
||||
{
|
||||
using (var reader = new RleReader (stream, meta.PackedSize, meta.UnpackedSize))
|
||||
{
|
||||
reader.Unpack();
|
||||
bitmap = reader.Data;
|
||||
}
|
||||
}
|
||||
else if (0 == meta.PackType)
|
||||
{
|
||||
using (var reader = new LzssReader (stream, meta.PackedSize, meta.UnpackedSize))
|
||||
{
|
||||
reader.Unpack();
|
||||
bitmap = reader.Data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap = new byte[meta.UnpackedSize];
|
||||
if (bitmap.Length != stream.Read (bitmap, 0, bitmap.Length))
|
||||
throw new InvalidFormatException ("Unexpected end of file");
|
||||
}
|
||||
var bitmap = UnpackBitmap (stream, meta.PackType, meta.PackedSize, meta.UnpackedSize);
|
||||
if ('C' == bitmap[0])
|
||||
{
|
||||
bitmap[0] = (byte)'B';
|
||||
if (info.BPP > 8)
|
||||
bitmap = ConvertCM (bitmap, (int)info.Width, (int)info.Height, info.BPP);
|
||||
}
|
||||
if (meta.BPP >= 24) // currently alpha channel could be applied to 24+bpp bitmaps only
|
||||
if (info.BPP >= 24) // currently alpha channel could be applied to 24+bpp bitmaps only
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -172,7 +121,7 @@ namespace GameRes.Formats.Triangle
|
||||
uint alpha_width = LittleEndian.ToUInt32 (bitmap, bmp_size+0x12);
|
||||
uint alpha_height = LittleEndian.ToUInt32 (bitmap, bmp_size+0x16);
|
||||
if (info.Width == alpha_width && info.Height == alpha_height)
|
||||
return BitmapWithAlphaChannel (meta, bitmap, bmp_size);
|
||||
return BitmapWithAlphaChannel (info, bitmap, bmp_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,6 +135,35 @@ namespace GameRes.Formats.Triangle
|
||||
return base.Read (bmp, info);
|
||||
}
|
||||
|
||||
internal static byte[] UnpackBitmap (Stream stream, int pack_type, int packed_size, int unpacked_size)
|
||||
{
|
||||
if (2 == pack_type)
|
||||
{
|
||||
using (var reader = new RleReader (stream, packed_size, unpacked_size))
|
||||
{
|
||||
reader.Unpack();
|
||||
return reader.Data;
|
||||
}
|
||||
}
|
||||
else if (0 == pack_type)
|
||||
{
|
||||
using (var reader = new LzssReader (stream, packed_size, unpacked_size))
|
||||
{
|
||||
reader.Unpack();
|
||||
return reader.Data;
|
||||
}
|
||||
}
|
||||
else if (1 == pack_type)
|
||||
{
|
||||
var bitmap = new byte[unpacked_size];
|
||||
if (bitmap.Length != stream.Read (bitmap, 0, bitmap.Length))
|
||||
throw new InvalidFormatException ("Unexpected end of file");
|
||||
return bitmap;
|
||||
}
|
||||
else
|
||||
throw new InvalidFormatException();
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new System.NotImplementedException ("IafFormat.Write not implemented");
|
||||
|
@ -122,9 +122,10 @@ Sweet Pool<br/>
|
||||
Zoku Satsuriku no Django<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.npa</td><td>-</td><td>Yes</td><td>Nitro+</td><td>Steins;Gate</td></tr>
|
||||
<tr><td>*.pak</td><td><tt>\002\000\000\000</tt><br/><tt>\003\000\000\000</tt></td><td>No</td><td>Nitro+</td><td>
|
||||
<tr><td>*.pak</td><td><tt>\002\000\000\000</tt><br/><tt>\003\000\000\000</tt></td><td>No</td><td>Nitro+<br/>CoreMoreco</td><td>
|
||||
Hanachirasu<br/>
|
||||
Jingai Makyou<br/>
|
||||
Chibi Mama<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.nsa<br/>*.sar</td><td>-</td><td>Yes<a href="#note-1" class="footnote">1</a></td><td>NScripter</td><td>
|
||||
Binary Pot<br/>
|
||||
@ -452,11 +453,13 @@ Gokudou no Hanayome<br/>
|
||||
Knight Carnival!<br/>
|
||||
Seal Princess<br/>
|
||||
</td></tr>
|
||||
<tr><td>*.sud</td><td>-</td><td>No</td><td rowspan="2">Triangle</td><td rowspan="2">
|
||||
<tr><td>*.sud</td><td>-</td><td>No</td><td rowspan="3">Triangle</td><td rowspan="3">
|
||||
Kourin Tenshi En Ciel Rena<br/>
|
||||
Mamagoto<br/>
|
||||
Vampire Crusaders<br/>
|
||||
</td></tr>
|
||||
<tr><td>*.iaf</td><td>-</td><td>No</td></tr>
|
||||
<tr><td>*.cgf</td><td>-</td><td>No</td></tr>
|
||||
<tr class="odd"><td>*.bin+*.pak</td><td><tt>hed</tt></td><td>No</td><td rowspan="2">elf</td><td rowspan="2">Adult Video King</td></tr>
|
||||
<tr class="odd"><td>*.hip<br/>*.hiz<br/></td><td><tt>hip</tt><br/><tt>hiz</tt></td><td>No</td></tr>
|
||||
<tr><td>*.gpk+*.gtb<br/>*.vpk+*.vtb</td><td>-</td><td>No</td><td rowspan="3">Black Cyc</td><td rowspan="3">
|
||||
@ -612,6 +615,7 @@ AstralAir no Shiroki Towa<br/>
|
||||
<tr><td>*.hzc</td><td><tt>hzc1</tt></td><td>No</td></tr>
|
||||
<tr class="odd"><td>*.bin</td><td><tt>ESC-ARC1</tt><br/><tt>ESC-ARC2</tt></td><td>No</td><td>Escu:de</td><td>
|
||||
Otome Renshin Prister<br/>
|
||||
Suisei Tenshi Primaveil Zwei<br/>
|
||||
Wondering Repair!<br/>
|
||||
</td></tr>
|
||||
<tr><td>*.pac</td><td>-</td><td>No</td><td>Tmr-Hiro ADV System</td><td>
|
||||
@ -637,6 +641,7 @@ Ayakashi H<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.arc</td><td><tt>LINK3</tt></td><td>No</td><td rowspan="3">KaGuYa</td><td rowspan="3">
|
||||
Dokidoki Onee-san<br/>
|
||||
Mahokoi ~Ecchi na Mahou de Koi x Koi Shichau~<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.alp</td><td><tt>AP-2</tt></td><td>No</td></tr>
|
||||
<tr class="odd"><td>*.anm</td><td><tt>AN00</tt></td><td>No</td></tr>
|
||||
|
Loading…
Reference in New Issue
Block a user