mirror of
https://github.com/crskycode/GARbro.git
synced 2026-07-08 01:30:18 +08:00
Compare commits
19 Commits
GARbro-Mod
...
GARbro-Mod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f63834c4bf | ||
|
|
8f96a1bccd | ||
|
|
f9def97321 | ||
|
|
301b795de6 | ||
|
|
cd8fcea992 | ||
|
|
ddbeddd862 | ||
|
|
82d44aeae2 | ||
|
|
a7021686e9 | ||
|
|
cdd4e0161c | ||
|
|
8424d75eab | ||
|
|
9cb5ec89b3 | ||
|
|
ac063d7eb5 | ||
|
|
7210ff5ff3 | ||
|
|
ccc7c8032b | ||
|
|
499ac02c64 | ||
|
|
a20aa9434c | ||
|
|
b967d505ec | ||
|
|
4554b82be5 | ||
|
|
e642644845 |
@@ -131,6 +131,7 @@
|
|||||||
<Compile Include="Artemis\ImageNekoPNG.cs" />
|
<Compile Include="Artemis\ImageNekoPNG.cs" />
|
||||||
<Compile Include="CsWare\AudioWAV.cs" />
|
<Compile Include="CsWare\AudioWAV.cs" />
|
||||||
<Compile Include="CsWare\ImageGDT.cs" />
|
<Compile Include="CsWare\ImageGDT.cs" />
|
||||||
|
<Compile Include="DigitalWorks\ArcPACPS2.cs" />
|
||||||
<Compile Include="DxLib\HuffmanDecoder.cs" />
|
<Compile Include="DxLib\HuffmanDecoder.cs" />
|
||||||
<Compile Include="DxLib\WidgetDXA.xaml.cs">
|
<Compile Include="DxLib\WidgetDXA.xaml.cs">
|
||||||
<DependentUpon>WidgetDXA.xaml</DependentUpon>
|
<DependentUpon>WidgetDXA.xaml</DependentUpon>
|
||||||
@@ -191,6 +192,7 @@
|
|||||||
<Compile Include="MAGES\ArcLoveOnce.cs" />
|
<Compile Include="MAGES\ArcLoveOnce.cs" />
|
||||||
<Compile Include="MAGES\ImageBIN.cs" />
|
<Compile Include="MAGES\ImageBIN.cs" />
|
||||||
<Compile Include="Mugi\ArcBIN.cs" />
|
<Compile Include="Mugi\ArcBIN.cs" />
|
||||||
|
<Compile Include="Musica\ArcPAK.cs" />
|
||||||
<Compile Include="NipponIchi\ArcCASN.cs" />
|
<Compile Include="NipponIchi\ArcCASN.cs" />
|
||||||
<Compile Include="NipponIchi\ArcPSFS.cs" />
|
<Compile Include="NipponIchi\ArcPSFS.cs" />
|
||||||
<Compile Include="NipponIchi\ImageNMT.cs" />
|
<Compile Include="NipponIchi\ImageNMT.cs" />
|
||||||
@@ -1335,4 +1337,4 @@ xcopy "$(ProjectDir)\Resources\Formats.dat" "$(TargetDir)\GameData\" /D /Y >N
|
|||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,53 +1,53 @@
|
|||||||
//! \file ArcGXP.cs
|
//! \file ArcGXP.cs
|
||||||
//! \date Thu Jun 30 08:17:12 2016
|
//! \date Thu Jun 30 08:17:12 2016
|
||||||
//! \brief Astronauts resource archive.
|
//! \brief Astronauts resource archive.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2016 by morkt
|
// Copyright (C) 2016 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
// deal in the Software without restriction, including without limitation the
|
// deal in the Software without restriction, including without limitation the
|
||||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
// 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
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
// furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be included in
|
// The above copyright notice and this permission notice shall be included in
|
||||||
// all copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
// 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
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GameRes.Utility;
|
using GameRes.Utility;
|
||||||
|
|
||||||
namespace GameRes.Formats.Astronauts
|
namespace GameRes.Formats.Astronauts
|
||||||
{
|
{
|
||||||
[Export(typeof(ArchiveFormat))]
|
[Export(typeof(ArchiveFormat))]
|
||||||
public class PakOpener : ArchiveFormat
|
public class PakOpener : ArchiveFormat
|
||||||
{
|
{
|
||||||
public override string Tag { get { return "GXP"; } }
|
public override string Tag { get { return "GXP"; } }
|
||||||
public override string Description { get { return "Astronauts resource archive"; } }
|
public override string Description { get { return "Astronauts resource archive"; } }
|
||||||
public override uint Signature { get { return 0x505847; } } // 'GXP'
|
public override uint Signature { get { return 0x505847; } } // 'GXP'
|
||||||
public override bool IsHierarchic { get { return true; } }
|
public override bool IsHierarchic { get { return true; } }
|
||||||
public override bool CanWrite { get { return false; } }
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
private bool UseNameAsKey = false;
|
private bool UseNameAsKey = false;
|
||||||
|
|
||||||
static readonly byte[] KnownKey = {
|
static readonly byte[] KnownKey = {
|
||||||
0x40, 0x21, 0x28, 0x38, 0xA6, 0x6E, 0x43, 0xA5, 0x40, 0x21, 0x28, 0x38, 0xA6, 0x43, 0xA5, 0x64,
|
0x40, 0x21, 0x28, 0x38, 0xA6, 0x6E, 0x43, 0xA5, 0x40, 0x21, 0x28, 0x38, 0xA6, 0x43, 0xA5, 0x64,
|
||||||
0x3E, 0x65, 0x24, 0x20, 0x46, 0x6E, 0x74,
|
0x3E, 0x65, 0x24, 0x20, 0x46, 0x6E, 0x74,
|
||||||
};
|
};
|
||||||
|
|
||||||
public override ArcFile TryOpen(ArcView file)
|
public override ArcFile TryOpen(ArcView file)
|
||||||
{
|
{
|
||||||
UseNameAsKey = false;
|
UseNameAsKey = false;
|
||||||
@@ -58,76 +58,76 @@ namespace GameRes.Formats.Astronauts
|
|||||||
arc = TryOpenGxpFile(file);
|
arc = TryOpenGxpFile(file);
|
||||||
}
|
}
|
||||||
return arc;
|
return arc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArcFile TryOpenGxpFile (ArcView file)
|
private ArcFile TryOpenGxpFile (ArcView file)
|
||||||
{
|
{
|
||||||
int count = file.View.ReadInt32 (0x18);
|
int count = file.View.ReadInt32 (0x18);
|
||||||
if (!IsSaneCount (count))
|
if (!IsSaneCount (count))
|
||||||
return null;
|
return null;
|
||||||
string arcname = Path.GetFileName(file.Name);
|
string arcname = Path.GetFileName(file.Name);
|
||||||
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
||||||
long base_offset = file.View.ReadInt64 (0x28);
|
long base_offset = file.View.ReadInt64 (0x28);
|
||||||
uint entry_key = KnownKey[0] | (1u ^ KnownKey[1]) << 8 | (2u ^ KnownKey[2]) << 16 | (3u ^ KnownKey[3]) << 24;
|
uint entry_key = KnownKey[0] | (1u ^ KnownKey[1]) << 8 | (2u ^ KnownKey[2]) << 16 | (3u ^ KnownKey[3]) << 24;
|
||||||
if (UseNameAsKey)
|
if (UseNameAsKey)
|
||||||
{
|
{
|
||||||
uint arcname_key = (uint)(arcname_bytes[0] | (arcname_bytes[1 % arcname_bytes.Length]) << 8 | (arcname_bytes[2 % arcname_bytes.Length]) << 16 | (arcname_bytes[3 % arcname_bytes.Length]) << 24);
|
uint arcname_key = (uint)(arcname_bytes[0] | (arcname_bytes[1 % arcname_bytes.Length]) << 8 | (arcname_bytes[2 % arcname_bytes.Length]) << 16 | (arcname_bytes[3 % arcname_bytes.Length]) << 24);
|
||||||
entry_key ^= arcname_key;
|
entry_key ^= arcname_key;
|
||||||
}
|
}
|
||||||
uint index_offset = 0x30;
|
uint index_offset = 0x30;
|
||||||
var entry_buffer = new byte[0x100];
|
var entry_buffer = new byte[0x100];
|
||||||
var dir = new List<Entry> (count);
|
var dir = new List<Entry> (count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
var entry_length = file.View.ReadUInt32 (index_offset) ^ entry_key;
|
var entry_length = file.View.ReadUInt32 (index_offset) ^ entry_key;
|
||||||
if (entry_length < 0x20 || entry_length > 0x1000)
|
if (entry_length < 0x20 || entry_length > 0x1000)
|
||||||
return null;
|
return null;
|
||||||
if (entry_length > entry_buffer.Length)
|
if (entry_length > entry_buffer.Length)
|
||||||
entry_buffer = new byte[entry_length];
|
entry_buffer = new byte[entry_length];
|
||||||
if (entry_length != file.View.Read (index_offset, entry_buffer, 0, entry_length))
|
if (entry_length != file.View.Read (index_offset, entry_buffer, 0, entry_length))
|
||||||
return null;
|
return null;
|
||||||
if (UseNameAsKey)
|
if (UseNameAsKey)
|
||||||
Decrypt(entry_buffer, entry_length, arcname_bytes);
|
Decrypt(entry_buffer, entry_length, arcname_bytes);
|
||||||
else
|
else
|
||||||
Decrypt(entry_buffer, entry_length);
|
Decrypt(entry_buffer, entry_length);
|
||||||
int name_length = LittleEndian.ToInt32 (entry_buffer, 0xC) * 2; // length in characters
|
int name_length = LittleEndian.ToInt32 (entry_buffer, 0xC) * 2; // length in characters
|
||||||
if (name_length >= entry_length)
|
if (name_length >= entry_length)
|
||||||
return null;
|
return null;
|
||||||
var name = Encoding.Unicode.GetString (entry_buffer, 0x20, name_length);
|
var name = Encoding.Unicode.GetString (entry_buffer, 0x20, name_length);
|
||||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||||
entry.Offset = base_offset + LittleEndian.ToInt64 (entry_buffer, 0x18);
|
entry.Offset = base_offset + LittleEndian.ToInt64 (entry_buffer, 0x18);
|
||||||
entry.Size = LittleEndian.ToUInt32 (entry_buffer, 4); // length is 64-bit actually
|
entry.Size = LittleEndian.ToUInt32 (entry_buffer, 4); // length is 64-bit actually
|
||||||
if (!entry.CheckPlacement (file.MaxOffset))
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
return null;
|
return null;
|
||||||
dir.Add (entry);
|
dir.Add (entry);
|
||||||
index_offset += entry_length;
|
index_offset += entry_length;
|
||||||
}
|
}
|
||||||
return new ArcFile (file, this, dir);
|
return new ArcFile (file, this, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
{
|
{
|
||||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||||
if (UseNameAsKey)
|
if (UseNameAsKey)
|
||||||
{
|
{
|
||||||
string arcname = Path.GetFileName(arc.File.Name);
|
string arcname = Path.GetFileName(arc.File.Name);
|
||||||
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
||||||
Decrypt(data, entry.Size, arcname_bytes);
|
Decrypt(data, entry.Size, arcname_bytes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Decrypt(data, entry.Size);
|
Decrypt(data, entry.Size);
|
||||||
return new BinMemoryStream (data, entry.Name);
|
return new BinMemoryStream (data, entry.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Decrypt (byte[] data, uint length, byte[] key=null)
|
static void Decrypt (byte[] data, uint length, byte[] key=null)
|
||||||
{
|
{
|
||||||
for (uint i = 0; i < length; ++i)
|
for (uint i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
byte xorkey = (byte)(i ^ KnownKey[i % KnownKey.Length]);
|
byte xorkey = (byte)(i ^ KnownKey[i % KnownKey.Length]);
|
||||||
if(null != key)
|
if(null != key)
|
||||||
xorkey ^= key[i % key.Length];
|
xorkey ^= key[i % key.Length];
|
||||||
data[i] ^= xorkey;
|
data[i] ^= xorkey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,20 +35,20 @@ namespace GameRes.Formats.DigitalWorks
|
|||||||
{
|
{
|
||||||
public override string Tag { get { return "PAC/HED"; } }
|
public override string Tag { get { return "PAC/HED"; } }
|
||||||
public override string Description { get { return "Digital Works resource archive"; } }
|
public override string Description { get { return "Digital Works resource archive"; } }
|
||||||
public override uint Signature { get { return 0x43415050; } } // 'PPAC-PAC'
|
public override uint Signature { get { return 0; } } // 'PPAC-PAC'
|
||||||
public override bool IsHierarchic { get { return false; } }
|
public override bool IsHierarchic { get { return false; } }
|
||||||
public override bool CanWrite { get { return false; } }
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
{
|
{
|
||||||
if (!file.View.AsciiEqual (4, "-PAC"))
|
if (!file.View.AsciiEqual (0, "PPAC-PAC") && !file.View.AsciiEqual(0, "FANA_V1.0.0.0"))
|
||||||
return null;
|
return null;
|
||||||
var hed_name = Path.ChangeExtension (file.Name, "hed");
|
var hed_name = Path.ChangeExtension (file.Name, "hed");
|
||||||
if (!VFS.FileExists (hed_name))
|
if (!VFS.FileExists (hed_name))
|
||||||
return null;
|
return null;
|
||||||
using (var hed = VFS.OpenView (hed_name))
|
using (var hed = VFS.OpenView (hed_name))
|
||||||
{
|
{
|
||||||
if (!hed.View.AsciiEqual (0, "PPAC-HED"))
|
if (!hed.View.AsciiEqual (0, "PPAC-HED") && !hed.View.AsciiEqual(0, "FANA_V1.0.0.0"))
|
||||||
return null;
|
return null;
|
||||||
uint index_offset = 0x10;
|
uint index_offset = 0x10;
|
||||||
const uint data_offset = 0x10;
|
const uint data_offset = 0x10;
|
||||||
|
|||||||
98
ArcFormats/DigitalWorks/ArcPACPS2.cs
Normal file
98
ArcFormats/DigitalWorks/ArcPACPS2.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
//! \file ArcPACPS2.cs
|
||||||
|
//! \date 2018 Sep 18
|
||||||
|
//! \brief Digital Works PS2 resource archive.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 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.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using GameRes.Compression;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.DigitalWorks
|
||||||
|
{
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class PacPS2Opener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get { return "PAC/PS2"; } }
|
||||||
|
public override string Description { get { return "Digital Works PS2 resource archive"; } }
|
||||||
|
public override uint Signature { get { return 0x434150; } } // 'PAC'
|
||||||
|
public override bool IsHierarchic { get { return false; } }
|
||||||
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Target games:
|
||||||
|
Cafe Little Wish SLPM-65294
|
||||||
|
F Fanatic SLPM-65296
|
||||||
|
*/
|
||||||
|
|
||||||
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
{
|
||||||
|
uint filename_index = file.View.ReadUInt32(4);
|
||||||
|
int count = file.View.ReadInt32(8);
|
||||||
|
uint index_offset = 0x0C;
|
||||||
|
|
||||||
|
if (!IsSaneCount (count))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var dir = new List<Entry> (count);
|
||||||
|
int i = 0;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
var name = file.View.ReadString (filename_index + i * 0x40, 0x40);
|
||||||
|
var entry = FormatCatalog.Instance.Create<PackedEntry> (name);
|
||||||
|
entry.Offset = file.View.ReadUInt32 (index_offset + i * 8);
|
||||||
|
entry.Size = file.View.ReadUInt32 (index_offset + i * 8 + 4);
|
||||||
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
|
return null;
|
||||||
|
dir.Add (entry);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return new ArcFile (file, this, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
var pent = entry as PackedEntry;
|
||||||
|
if (null == pent)
|
||||||
|
return base.OpenEntry (arc, entry);
|
||||||
|
if (!pent.IsPacked)
|
||||||
|
{
|
||||||
|
if (!arc.File.View.AsciiEqual (entry.Offset, "LZS\0"))
|
||||||
|
return base.OpenEntry (arc, entry);
|
||||||
|
pent.IsPacked = true;
|
||||||
|
pent.UnpackedSize = arc.File.View.ReadUInt32 (entry.Offset+4);
|
||||||
|
}
|
||||||
|
var input = arc.File.CreateStream (entry.Offset+8, entry.Size-8);
|
||||||
|
bool embedded_lzs = (input.Signature & ~0xF0u) == 0x535A4C0F; // 'LZS'
|
||||||
|
var lzs = new LzssStream (input);
|
||||||
|
if (embedded_lzs)
|
||||||
|
{
|
||||||
|
var header = new byte[8];
|
||||||
|
lzs.Read (header, 0, 8);
|
||||||
|
pent.UnpackedSize = header.ToUInt32 (4);
|
||||||
|
lzs = new LzssStream (lzs);
|
||||||
|
}
|
||||||
|
return lzs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ namespace GameRes.Formats.ISM
|
|||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
{
|
{
|
||||||
if (!file.View.AsciiEqual (4, "ARCHIVED"))
|
if (!file.View.AsciiEqual (4, "ARCHIVED") && !file.View.AsciiEqual(4, "ENGLISH "))
|
||||||
return null;
|
return null;
|
||||||
int count = file.View.ReadInt16 (0x0C);
|
int count = file.View.ReadInt16 (0x0C);
|
||||||
if (!IsSaneCount (count))
|
if (!IsSaneCount (count))
|
||||||
|
|||||||
173
ArcFormats/Musica/ArcPAK.cs
Normal file
173
ArcFormats/Musica/ArcPAK.cs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.Musica
|
||||||
|
{
|
||||||
|
[Export(typeof(ArchiveFormat))]
|
||||||
|
public class PakOpener : ArchiveFormat
|
||||||
|
{
|
||||||
|
public override string Tag { get; } = "PAK";
|
||||||
|
public override string Description { get; } = "Musica engine legacy resource archive";
|
||||||
|
public override uint Signature { get; } = 0;
|
||||||
|
public override bool IsHierarchic { get; } = true;
|
||||||
|
public override bool CanWrite { get; } = false;
|
||||||
|
|
||||||
|
public PakOpener()
|
||||||
|
{
|
||||||
|
Extensions = new[] { "pak" };
|
||||||
|
ContainedFormats = new string[] { "PNG", "OGG" };
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly HashSet<string> PakImageNames = new HashSet<string>()
|
||||||
|
{
|
||||||
|
"bg", "st",
|
||||||
|
};
|
||||||
|
|
||||||
|
static readonly HashSet<string> PakAudioNames = new HashSet<string>()
|
||||||
|
{
|
||||||
|
"bgm", "se", "voice",
|
||||||
|
};
|
||||||
|
|
||||||
|
private string GetType(string pakName, string entryName)
|
||||||
|
{
|
||||||
|
if (PakImageNames.Contains(pakName))
|
||||||
|
{
|
||||||
|
return "image";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PakAudioNames.Contains(pakName))
|
||||||
|
{
|
||||||
|
return "audio";
|
||||||
|
}
|
||||||
|
|
||||||
|
return FormatCatalog.Instance.GetTypeFromName(entryName, ContainedFormats);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ArcFile TryOpen(ArcView view)
|
||||||
|
{
|
||||||
|
Stream input = view.CreateStream();
|
||||||
|
using(input = new NegStream(input))
|
||||||
|
{
|
||||||
|
using(ArcView.Reader reader = new ArcView.Reader(input))
|
||||||
|
{
|
||||||
|
int count = reader.ReadInt32();
|
||||||
|
if (count <= 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Entry> entries = new List<Entry>(count);
|
||||||
|
for(int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
uint indexLen = reader.ReadUInt32();
|
||||||
|
long indexStart = input.Position;
|
||||||
|
|
||||||
|
string name = input.ReadCString();
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
uint size = reader.ReadUInt32();
|
||||||
|
uint offset = reader.ReadUInt32();
|
||||||
|
|
||||||
|
Entry entry = new Entry() { Name = name, Offset = offset, Size = size };
|
||||||
|
if (!entry.CheckPlacement(view.MaxOffset))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
entry.Type = this.GetType(Path.GetFileNameWithoutExtension(view.Name), entry.Name);
|
||||||
|
entries.Add(entry);
|
||||||
|
|
||||||
|
input.Position = indexStart + indexLen;
|
||||||
|
}
|
||||||
|
return new PakArchive(view, this, entries, input.Position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream OpenEntry(ArcFile arc, Entry entry)
|
||||||
|
{
|
||||||
|
if (!(arc is PakArchive pakArc))
|
||||||
|
{
|
||||||
|
return base.OpenEntry(arc, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NegStream(base.OpenEntry(arc, pakArc.GetEntry(entry)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PakArchive : ArcFile
|
||||||
|
{
|
||||||
|
private long m_IndexSize;
|
||||||
|
public PakArchive(ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, long indexSize) : base(arc, impl, dir)
|
||||||
|
{
|
||||||
|
m_IndexSize = indexSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry GetEntry(Entry e)
|
||||||
|
{
|
||||||
|
return new Entry
|
||||||
|
{
|
||||||
|
Name = e.Name,
|
||||||
|
Offset = e.Offset + m_IndexSize,
|
||||||
|
Size = e.Size,
|
||||||
|
Type = e.Type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//neg reg8
|
||||||
|
public class NegStream : ProxyStream
|
||||||
|
{
|
||||||
|
public NegStream(Stream stream, bool leave_open = false) : base(stream, leave_open)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
int read = BaseStream.Read(buffer, offset, count);
|
||||||
|
for (int i = 0; i < read; ++i)
|
||||||
|
{
|
||||||
|
buffer[offset + i] = (byte)-buffer[offset + i];
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int ReadByte()
|
||||||
|
{
|
||||||
|
int b = BaseStream.ReadByte();
|
||||||
|
if (-1 != b)
|
||||||
|
{
|
||||||
|
b = (byte)-b;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] write_buf;
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (null == write_buf)
|
||||||
|
write_buf = new byte[81920];
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
int chunk = Math.Min(write_buf.Length, count);
|
||||||
|
for (int i = 0; i < chunk; ++i)
|
||||||
|
{
|
||||||
|
write_buf[i] = (byte)-buffer[offset + i];
|
||||||
|
}
|
||||||
|
BaseStream.Write(write_buf, 0, chunk);
|
||||||
|
offset += chunk;
|
||||||
|
count -= chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteByte(byte value)
|
||||||
|
{
|
||||||
|
BaseStream.WriteByte((byte)-value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,11 +34,13 @@ namespace GameRes.Formats.Musica
|
|||||||
internal class SqzArchive : ArcFile
|
internal class SqzArchive : ArcFile
|
||||||
{
|
{
|
||||||
public readonly ImageMetaData Info;
|
public readonly ImageMetaData Info;
|
||||||
|
public readonly int FPS;
|
||||||
|
|
||||||
public SqzArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, ImageMetaData info)
|
public SqzArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, ImageMetaData info, int fps)
|
||||||
: base (arc, impl, dir)
|
: base (arc, impl, dir)
|
||||||
{
|
{
|
||||||
Info = info;
|
Info = info;
|
||||||
|
FPS = fps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ namespace GameRes.Formats.Musica
|
|||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
{
|
{
|
||||||
int count = file.View.ReadInt32 (0x10) * 2;
|
int count = file.View.ReadInt32 (4);
|
||||||
if (!IsSaneCount (count))
|
if (!IsSaneCount (count))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -62,8 +64,8 @@ namespace GameRes.Formats.Musica
|
|||||||
Width = file.View.ReadUInt32 (8),
|
Width = file.View.ReadUInt32 (8),
|
||||||
Height = file.View.ReadUInt32 (0xC),
|
Height = file.View.ReadUInt32 (0xC),
|
||||||
BPP = 32,
|
BPP = 32,
|
||||||
// BPP = file.View.ReadInt32 (4),
|
|
||||||
};
|
};
|
||||||
|
int fps = file.View.ReadInt32(0x10);
|
||||||
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||||
uint index_offset = 0x14;
|
uint index_offset = 0x14;
|
||||||
var dir = new List<Entry> (count);
|
var dir = new List<Entry> (count);
|
||||||
@@ -80,7 +82,7 @@ namespace GameRes.Formats.Musica
|
|||||||
dir.Add (entry);
|
dir.Add (entry);
|
||||||
index_offset += 8;
|
index_offset += 8;
|
||||||
}
|
}
|
||||||
return new SqzArchive (file, this, dir, info);
|
return new SqzArchive (file, this, dir, info, fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
public override IImageDecoder OpenImage (ArcFile arc, Entry entry)
|
||||||
|
|||||||
Binary file not shown.
@@ -54,7 +54,8 @@ namespace GameRes.Formats.Seraphim
|
|||||||
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
||||||
{
|
{
|
||||||
var header = stream.ReadHeader (0x10);
|
var header = stream.ReadHeader (0x10);
|
||||||
if ('C' != header[0] || 'F' != header[1] || 0 != header[3])
|
uint sig = header.ToUInt16(0);
|
||||||
|
if (sig != Signature)
|
||||||
return null;
|
return null;
|
||||||
int packed_size = header.ToInt32 (12);
|
int packed_size = header.ToInt32 (12);
|
||||||
if (packed_size <= 0 || packed_size > stream.Length-0x10)
|
if (packed_size <= 0 || packed_size > stream.Length-0x10)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace GameRes.Formats.Valkyria
|
|||||||
|
|
||||||
internal interface IMg2Scheme
|
internal interface IMg2Scheme
|
||||||
{
|
{
|
||||||
Mg2EncryptedStream CreateStream (Stream main, int offset, int length);
|
Mg2EncryptedStream CreateStream (Stream main, int offset, int length, int key);
|
||||||
ImageData CreateImage (BitmapSource bitmap, ImageMetaData info);
|
ImageData CreateImage (BitmapSource bitmap, ImageMetaData info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,17 +52,17 @@ namespace GameRes.Formats.Valkyria
|
|||||||
public override string Description { get { return "Valkyria image format"; } }
|
public override string Description { get { return "Valkyria image format"; } }
|
||||||
public override uint Signature { get { return 0x4F43494D; } } // 'MICO'
|
public override uint Signature { get { return 0x4F43494D; } } // 'MICO'
|
||||||
|
|
||||||
static readonly IMg2Scheme[] KnownSchemes = { new Mg2SchemeV1(), new Mg2SchemeV2() };
|
static readonly IMg2Scheme[] KnownSchemes = { new Mg2SchemeV1(), new Mg2SchemeV2(), new Mg2SchemeV3() };
|
||||||
|
|
||||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
{
|
{
|
||||||
var header = file.ReadHeader (0x10);
|
var header = file.ReadHeader (0x10);
|
||||||
if (!header.AsciiEqual (4, "CG01"))
|
if (!header.AsciiEqual (4, "CG01") && !header.AsciiEqual (4, "CG02"))
|
||||||
return null;
|
return null;
|
||||||
int length = header.ToInt32 (8);
|
int length = header.ToInt32 (8);
|
||||||
foreach (var scheme in KnownSchemes)
|
foreach (var scheme in KnownSchemes)
|
||||||
{
|
{
|
||||||
using (var input = scheme.CreateStream (file.AsStream, 0x10, length))
|
using (var input = scheme.CreateStream (file.AsStream, 0x10, length, length))
|
||||||
using (var img = new BinaryStream (input, file.Name))
|
using (var img = new BinaryStream (input, file.Name))
|
||||||
{
|
{
|
||||||
ImageFormat format;
|
ImageFormat format;
|
||||||
@@ -102,7 +102,7 @@ namespace GameRes.Formats.Valkyria
|
|||||||
BitmapSource ReadBitmapSource (Stream file, Mg2MetaData meta)
|
BitmapSource ReadBitmapSource (Stream file, Mg2MetaData meta)
|
||||||
{
|
{
|
||||||
BitmapSource frame;
|
BitmapSource frame;
|
||||||
using (var input = meta.Scheme.CreateStream (file, 0x10, meta.ImageLength))
|
using (var input = meta.Scheme.CreateStream (file, 0x10, meta.ImageLength, meta.ImageLength))
|
||||||
using (var img = new BinaryStream (input, meta.FileName))
|
using (var img = new BinaryStream (input, meta.FileName))
|
||||||
{
|
{
|
||||||
var image = meta.Format.Read (img, meta);
|
var image = meta.Format.Read (img, meta);
|
||||||
@@ -116,7 +116,7 @@ namespace GameRes.Formats.Valkyria
|
|||||||
var pixels = new byte[stride * (int)meta.Height];
|
var pixels = new byte[stride * (int)meta.Height];
|
||||||
frame.CopyPixels (pixels, stride, 0);
|
frame.CopyPixels (pixels, stride, 0);
|
||||||
|
|
||||||
using (var input = meta.Scheme.CreateStream (file, 0x10+meta.ImageLength, meta.AlphaLength))
|
using (var input = meta.Scheme.CreateStream (file, 0x10+meta.ImageLength, meta.AlphaLength, meta.ImageLength))
|
||||||
{
|
{
|
||||||
var decoder = BitmapDecoder.Create (input, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
var decoder = BitmapDecoder.Create (input, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||||
BitmapSource alpha_frame = decoder.Frames[0];
|
BitmapSource alpha_frame = decoder.Frames[0];
|
||||||
@@ -148,32 +148,53 @@ namespace GameRes.Formats.Valkyria
|
|||||||
|
|
||||||
internal class Mg2EncryptedStream : StreamRegion
|
internal class Mg2EncryptedStream : StreamRegion
|
||||||
{
|
{
|
||||||
|
readonly byte m_version;
|
||||||
readonly int m_threshold;
|
readonly int m_threshold;
|
||||||
readonly byte m_key;
|
readonly byte m_key0;
|
||||||
|
readonly byte m_key1;
|
||||||
|
|
||||||
protected Mg2EncryptedStream (Stream main, int offset, int length, int threshold, byte key)
|
protected Mg2EncryptedStream (Stream main, int offset, int length, byte version, int threshold, byte key0, byte key1)
|
||||||
: base (main, offset, length, true)
|
: base (main, offset, length, true)
|
||||||
{
|
{
|
||||||
|
m_version = version;
|
||||||
m_threshold = threshold;
|
m_threshold = threshold;
|
||||||
m_key = key;
|
m_key0 = key0;
|
||||||
|
m_key1 = key1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mg2EncryptedStream CreateV1 (Stream main, int offset, int length)
|
public static Mg2EncryptedStream CreateV1 (Stream main, int offset, int length)
|
||||||
{
|
{
|
||||||
return new Mg2EncryptedStream (main, offset, length, length / 5, 0);
|
return new Mg2EncryptedStream(main, offset, length, 1, length / 5, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mg2EncryptedStream CreateV2 (Stream main, int offset, int length)
|
public static Mg2EncryptedStream CreateV2 (Stream main, int offset, int length)
|
||||||
{
|
{
|
||||||
return new Mg2EncryptedStream (main, offset, length, Math.Min (25, length), (byte)length);
|
return new Mg2EncryptedStream( main, offset, length, 2, Math.Min(25, length), (byte)length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Mg2EncryptedStream CreateV3 (Stream main, int offset, int length, int key)
|
||||||
|
{
|
||||||
|
return new Mg2EncryptedStream(main, offset, length, 3, 0, (byte)(key >> 1), (byte)((key & 1) + (key >> 3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read (byte[] buffer, int offset, int count)
|
public override int Read (byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
int pos = (int)Position;
|
long pos = Position;
|
||||||
int read = base.Read (buffer, offset, count);
|
int read = base.Read(buffer, offset, count);
|
||||||
for (int i = 0; i < read && pos < m_threshold; ++i)
|
|
||||||
buffer[offset+i] ^= (byte)(m_key + pos++);
|
if (m_version == 3)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < read; ++i)
|
||||||
|
{
|
||||||
|
buffer[offset+i] ^= (byte)((pos >> 4) ^ (pos + m_key0) ^ m_key1);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < read && pos < m_threshold; ++i)
|
||||||
|
buffer[offset+i] ^= (byte)(m_key0 + pos++);
|
||||||
|
}
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,15 +202,24 @@ namespace GameRes.Formats.Valkyria
|
|||||||
{
|
{
|
||||||
long pos = Position;
|
long pos = Position;
|
||||||
int b = base.ReadByte();
|
int b = base.ReadByte();
|
||||||
if (b != -1 && pos < m_threshold)
|
|
||||||
b ^= (byte)(m_key + pos);
|
if (m_version == 3)
|
||||||
|
{
|
||||||
|
b ^= (byte)((pos >> 4) ^ (pos + m_key0) ^ m_key1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (b != -1 && pos < m_threshold)
|
||||||
|
b ^= (byte)(m_key0 + pos);
|
||||||
|
}
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Mg2SchemeV1 : IMg2Scheme
|
internal class Mg2SchemeV1 : IMg2Scheme
|
||||||
{
|
{
|
||||||
public Mg2EncryptedStream CreateStream (Stream main, int offset, int length)
|
public Mg2EncryptedStream CreateStream (Stream main, int offset, int length, int key)
|
||||||
{
|
{
|
||||||
return Mg2EncryptedStream.CreateV1 (main, offset, length);
|
return Mg2EncryptedStream.CreateV1 (main, offset, length);
|
||||||
}
|
}
|
||||||
@@ -203,7 +233,7 @@ namespace GameRes.Formats.Valkyria
|
|||||||
|
|
||||||
internal class Mg2SchemeV2 : IMg2Scheme
|
internal class Mg2SchemeV2 : IMg2Scheme
|
||||||
{
|
{
|
||||||
public Mg2EncryptedStream CreateStream (Stream main, int offset, int length)
|
public Mg2EncryptedStream CreateStream (Stream main, int offset, int length, int key)
|
||||||
{
|
{
|
||||||
return Mg2EncryptedStream.CreateV2 (main, offset, length);
|
return Mg2EncryptedStream.CreateV2 (main, offset, length);
|
||||||
}
|
}
|
||||||
@@ -215,4 +245,19 @@ namespace GameRes.Formats.Valkyria
|
|||||||
return new ImageData (frame, info);
|
return new ImageData (frame, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Mg2SchemeV3 : IMg2Scheme
|
||||||
|
{
|
||||||
|
public Mg2EncryptedStream CreateStream (Stream main, int offset, int length, int key)
|
||||||
|
{
|
||||||
|
return Mg2EncryptedStream.CreateV3 (main, offset, length, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageData CreateImage (BitmapSource frame, ImageMetaData info)
|
||||||
|
{
|
||||||
|
frame = new TransformedBitmap(frame, new ScaleTransform { ScaleY = -1 });
|
||||||
|
frame.Freeze();
|
||||||
|
return new ImageData(frame, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user