mirror of
https://github.com/crskycode/GARbro.git
synced 2026-06-07 06:08:47 +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="CsWare\AudioWAV.cs" />
|
||||
<Compile Include="CsWare\ImageGDT.cs" />
|
||||
<Compile Include="DigitalWorks\ArcPACPS2.cs" />
|
||||
<Compile Include="DxLib\HuffmanDecoder.cs" />
|
||||
<Compile Include="DxLib\WidgetDXA.xaml.cs">
|
||||
<DependentUpon>WidgetDXA.xaml</DependentUpon>
|
||||
@@ -191,6 +192,7 @@
|
||||
<Compile Include="MAGES\ArcLoveOnce.cs" />
|
||||
<Compile Include="MAGES\ImageBIN.cs" />
|
||||
<Compile Include="Mugi\ArcBIN.cs" />
|
||||
<Compile Include="Musica\ArcPAK.cs" />
|
||||
<Compile Include="NipponIchi\ArcCASN.cs" />
|
||||
<Compile Include="NipponIchi\ArcPSFS.cs" />
|
||||
<Compile Include="NipponIchi\ImageNMT.cs" />
|
||||
@@ -1335,4 +1337,4 @@ xcopy "$(ProjectDir)\Resources\Formats.dat" "$(TargetDir)\GameData\" /D /Y >N
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,53 +1,53 @@
|
||||
//! \file ArcGXP.cs
|
||||
//! \date Thu Jun 30 08:17:12 2016
|
||||
//! \brief Astronauts resource 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 System.Text;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Astronauts
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class PakOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "GXP"; } }
|
||||
public override string Description { get { return "Astronauts resource archive"; } }
|
||||
public override uint Signature { get { return 0x505847; } } // 'GXP'
|
||||
public override bool IsHierarchic { get { return true; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
private bool UseNameAsKey = false;
|
||||
|
||||
static readonly byte[] KnownKey = {
|
||||
0x40, 0x21, 0x28, 0x38, 0xA6, 0x6E, 0x43, 0xA5, 0x40, 0x21, 0x28, 0x38, 0xA6, 0x43, 0xA5, 0x64,
|
||||
0x3E, 0x65, 0x24, 0x20, 0x46, 0x6E, 0x74,
|
||||
};
|
||||
|
||||
//! \file ArcGXP.cs
|
||||
//! \date Thu Jun 30 08:17:12 2016
|
||||
//! \brief Astronauts resource 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 System.Text;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Astronauts
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class PakOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "GXP"; } }
|
||||
public override string Description { get { return "Astronauts resource archive"; } }
|
||||
public override uint Signature { get { return 0x505847; } } // 'GXP'
|
||||
public override bool IsHierarchic { get { return true; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
private bool UseNameAsKey = false;
|
||||
|
||||
static readonly byte[] KnownKey = {
|
||||
0x40, 0x21, 0x28, 0x38, 0xA6, 0x6E, 0x43, 0xA5, 0x40, 0x21, 0x28, 0x38, 0xA6, 0x43, 0xA5, 0x64,
|
||||
0x3E, 0x65, 0x24, 0x20, 0x46, 0x6E, 0x74,
|
||||
};
|
||||
|
||||
public override ArcFile TryOpen(ArcView file)
|
||||
{
|
||||
UseNameAsKey = false;
|
||||
@@ -58,76 +58,76 @@ namespace GameRes.Formats.Astronauts
|
||||
arc = TryOpenGxpFile(file);
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
private ArcFile TryOpenGxpFile (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (0x18);
|
||||
if (!IsSaneCount (count))
|
||||
}
|
||||
|
||||
private ArcFile TryOpenGxpFile (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (0x18);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
string arcname = Path.GetFileName(file.Name);
|
||||
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
||||
long base_offset = file.View.ReadInt64 (0x28);
|
||||
uint entry_key = KnownKey[0] | (1u ^ KnownKey[1]) << 8 | (2u ^ KnownKey[2]) << 16 | (3u ^ KnownKey[3]) << 24;
|
||||
string arcname = Path.GetFileName(file.Name);
|
||||
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
||||
long base_offset = file.View.ReadInt64 (0x28);
|
||||
uint entry_key = KnownKey[0] | (1u ^ KnownKey[1]) << 8 | (2u ^ KnownKey[2]) << 16 | (3u ^ KnownKey[3]) << 24;
|
||||
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);
|
||||
entry_key ^= arcname_key;
|
||||
}
|
||||
uint index_offset = 0x30;
|
||||
var entry_buffer = new byte[0x100];
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry_length = file.View.ReadUInt32 (index_offset) ^ entry_key;
|
||||
if (entry_length < 0x20 || entry_length > 0x1000)
|
||||
return null;
|
||||
if (entry_length > entry_buffer.Length)
|
||||
entry_buffer = new byte[entry_length];
|
||||
if (entry_length != file.View.Read (index_offset, entry_buffer, 0, entry_length))
|
||||
return null;
|
||||
}
|
||||
uint index_offset = 0x30;
|
||||
var entry_buffer = new byte[0x100];
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry_length = file.View.ReadUInt32 (index_offset) ^ entry_key;
|
||||
if (entry_length < 0x20 || entry_length > 0x1000)
|
||||
return null;
|
||||
if (entry_length > entry_buffer.Length)
|
||||
entry_buffer = new byte[entry_length];
|
||||
if (entry_length != file.View.Read (index_offset, entry_buffer, 0, entry_length))
|
||||
return null;
|
||||
if (UseNameAsKey)
|
||||
Decrypt(entry_buffer, entry_length, arcname_bytes);
|
||||
else
|
||||
Decrypt(entry_buffer, entry_length);
|
||||
int name_length = LittleEndian.ToInt32 (entry_buffer, 0xC) * 2; // length in characters
|
||||
if (name_length >= entry_length)
|
||||
return null;
|
||||
var name = Encoding.Unicode.GetString (entry_buffer, 0x20, name_length);
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||
entry.Offset = base_offset + LittleEndian.ToInt64 (entry_buffer, 0x18);
|
||||
entry.Size = LittleEndian.ToUInt32 (entry_buffer, 4); // length is 64-bit actually
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
index_offset += entry_length;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
Decrypt(entry_buffer, entry_length);
|
||||
int name_length = LittleEndian.ToInt32 (entry_buffer, 0xC) * 2; // length in characters
|
||||
if (name_length >= entry_length)
|
||||
return null;
|
||||
var name = Encoding.Unicode.GetString (entry_buffer, 0x20, name_length);
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||
entry.Offset = base_offset + LittleEndian.ToInt64 (entry_buffer, 0x18);
|
||||
entry.Size = LittleEndian.ToUInt32 (entry_buffer, 4); // length is 64-bit actually
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
index_offset += entry_length;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
if (UseNameAsKey)
|
||||
{
|
||||
string arcname = Path.GetFileName(arc.File.Name);
|
||||
byte[] arcname_bytes = Encoding.ASCII.GetBytes(arcname);
|
||||
Decrypt(data, entry.Size, arcname_bytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
Decrypt(data, entry.Size);
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
|
||||
static void Decrypt (byte[] data, uint length, byte[] key=null)
|
||||
{
|
||||
for (uint i = 0; i < length; ++i)
|
||||
{
|
||||
byte xorkey = (byte)(i ^ KnownKey[i % KnownKey.Length]);
|
||||
Decrypt(data, entry.Size);
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
|
||||
static void Decrypt (byte[] data, uint length, byte[] key=null)
|
||||
{
|
||||
for (uint i = 0; i < length; ++i)
|
||||
{
|
||||
byte xorkey = (byte)(i ^ KnownKey[i % KnownKey.Length]);
|
||||
if(null != key)
|
||||
xorkey ^= key[i % key.Length];
|
||||
data[i] ^= xorkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xorkey ^= key[i % key.Length];
|
||||
data[i] ^= xorkey;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,20 +35,20 @@ namespace GameRes.Formats.DigitalWorks
|
||||
{
|
||||
public override string Tag { get { return "PAC/HED"; } }
|
||||
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 CanWrite { get { return false; } }
|
||||
|
||||
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;
|
||||
var hed_name = Path.ChangeExtension (file.Name, "hed");
|
||||
if (!VFS.FileExists (hed_name))
|
||||
return null;
|
||||
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;
|
||||
uint index_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)
|
||||
{
|
||||
if (!file.View.AsciiEqual (4, "ARCHIVED"))
|
||||
if (!file.View.AsciiEqual (4, "ARCHIVED") && !file.View.AsciiEqual(4, "ENGLISH "))
|
||||
return null;
|
||||
int count = file.View.ReadInt16 (0x0C);
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
Info = info;
|
||||
FPS = fps;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ namespace GameRes.Formats.Musica
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (0x10) * 2;
|
||||
int count = file.View.ReadInt32 (4);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
|
||||
@@ -62,8 +64,8 @@ namespace GameRes.Formats.Musica
|
||||
Width = file.View.ReadUInt32 (8),
|
||||
Height = file.View.ReadUInt32 (0xC),
|
||||
BPP = 32,
|
||||
// BPP = file.View.ReadInt32 (4),
|
||||
};
|
||||
int fps = file.View.ReadInt32(0x10);
|
||||
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
uint index_offset = 0x14;
|
||||
var dir = new List<Entry> (count);
|
||||
@@ -80,7 +82,7 @@ namespace GameRes.Formats.Musica
|
||||
dir.Add (entry);
|
||||
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)
|
||||
|
||||
Binary file not shown.
@@ -54,7 +54,8 @@ namespace GameRes.Formats.Seraphim
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
||||
{
|
||||
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;
|
||||
int packed_size = header.ToInt32 (12);
|
||||
if (packed_size <= 0 || packed_size > stream.Length-0x10)
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace GameRes.Formats.Valkyria
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -52,17 +52,17 @@ namespace GameRes.Formats.Valkyria
|
||||
public override string Description { get { return "Valkyria image format"; } }
|
||||
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)
|
||||
{
|
||||
var header = file.ReadHeader (0x10);
|
||||
if (!header.AsciiEqual (4, "CG01"))
|
||||
if (!header.AsciiEqual (4, "CG01") && !header.AsciiEqual (4, "CG02"))
|
||||
return null;
|
||||
int length = header.ToInt32 (8);
|
||||
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))
|
||||
{
|
||||
ImageFormat format;
|
||||
@@ -102,7 +102,7 @@ namespace GameRes.Formats.Valkyria
|
||||
BitmapSource ReadBitmapSource (Stream file, Mg2MetaData meta)
|
||||
{
|
||||
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))
|
||||
{
|
||||
var image = meta.Format.Read (img, meta);
|
||||
@@ -116,7 +116,7 @@ namespace GameRes.Formats.Valkyria
|
||||
var pixels = new byte[stride * (int)meta.Height];
|
||||
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);
|
||||
BitmapSource alpha_frame = decoder.Frames[0];
|
||||
@@ -148,32 +148,53 @@ namespace GameRes.Formats.Valkyria
|
||||
|
||||
internal class Mg2EncryptedStream : StreamRegion
|
||||
{
|
||||
readonly byte m_version;
|
||||
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)
|
||||
{
|
||||
m_version = version;
|
||||
m_threshold = threshold;
|
||||
m_key = key;
|
||||
m_key0 = key0;
|
||||
m_key1 = key1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int pos = (int)Position;
|
||||
int read = base.Read (buffer, offset, count);
|
||||
for (int i = 0; i < read && pos < m_threshold; ++i)
|
||||
buffer[offset+i] ^= (byte)(m_key + pos++);
|
||||
long pos = Position;
|
||||
int read = base.Read(buffer, offset, count);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -181,15 +202,24 @@ namespace GameRes.Formats.Valkyria
|
||||
{
|
||||
long pos = Position;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -203,7 +233,7 @@ namespace GameRes.Formats.Valkyria
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -215,4 +245,19 @@ namespace GameRes.Formats.Valkyria
|
||||
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