mirror of
https://github.com/crskycode/GARbro.git
synced 2026-06-06 21:58:53 +08:00
Compare commits
15 Commits
v1.5.43-pr
...
v1.5.43
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c609792416 | ||
|
|
e3ddab124a | ||
|
|
1c26c0a856 | ||
|
|
5fd5a9a44c | ||
|
|
87fa5a3024 | ||
|
|
26eb42ee1d | ||
|
|
e70251d304 | ||
|
|
72452d664a | ||
|
|
aadb48a7dc | ||
|
|
f79be94cde | ||
|
|
006004f170 | ||
|
|
91390fb69c | ||
|
|
69c60b0202 | ||
|
|
f452605e54 | ||
|
|
96d113115b |
@@ -162,6 +162,7 @@
|
||||
<Compile Include="DigitalWorks\ImageTX.cs" />
|
||||
<Compile Include="DirectDraw\DxtDecoder.cs" />
|
||||
<Compile Include="DjSystem\ArcDAT.cs" />
|
||||
<Compile Include="DxLib\DxKey.cs" />
|
||||
<Compile Include="elf\ArcAi5DAT.cs" />
|
||||
<Compile Include="elf\ImageRMT.cs" />
|
||||
<Compile Include="EmbeddedResource.cs" />
|
||||
@@ -243,6 +244,7 @@
|
||||
<Compile Include="Nekopunch\ImagePBM.cs" />
|
||||
<Compile Include="Nexas\ArcTPF.cs" />
|
||||
<Compile Include="LiveMaker\ImageGALX.cs" />
|
||||
<Compile Include="Nonono\ArcNPF.cs" />
|
||||
<Compile Include="Origin\ArcDAT.cs" />
|
||||
<Compile Include="Otemoto\ArcTLZ.cs" />
|
||||
<Compile Include="Otemoto\ImageMAG.cs" />
|
||||
@@ -747,6 +749,7 @@
|
||||
<Compile Include="Rits\ArcSAF.cs" />
|
||||
<Compile Include="BlackCyc\ArcVPK.cs" />
|
||||
<Compile Include="Unity\ArcASSET.cs" />
|
||||
<Compile Include="Unity\ArcBIN.cs" />
|
||||
<Compile Include="Unity\ArcSpVM.cs" />
|
||||
<Compile Include="Unity\ArcUnityFS.cs" />
|
||||
<Compile Include="Unity\Asset.cs" />
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace GameRes.Formats.Artemis
|
||||
public PfsOpener ()
|
||||
{
|
||||
Extensions = new string[] { "pfs", "000", "001", "002", "003", "004", "005" };
|
||||
ContainedFormats = new string[] { "PNG", "JPEG", "IPT", "OGG", "TXT", "SCR" };
|
||||
Settings = new[] { PfsEncoding };
|
||||
}
|
||||
|
||||
|
||||
@@ -166,12 +166,12 @@ namespace GameRes.Formats.Cyberworks
|
||||
|
||||
internal class InKyouParser : ArchiveNameParser
|
||||
{
|
||||
public InKyouParser () : base (@"^inyoukyou_kuon\.app$") { }
|
||||
public InKyouParser () : base (@"^(inyoukyou_kuon|mugen.*)\.app$") { }
|
||||
|
||||
protected override string ParseMatch (Match match, out int arc_idx)
|
||||
{
|
||||
arc_idx = 0;
|
||||
return "inyoukyou_kuon.dat";
|
||||
return match.Groups[1].Value + ".dat";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using GameRes.Utility;
|
||||
|
||||
@@ -36,13 +35,13 @@ namespace GameRes.Formats.DxLib
|
||||
{
|
||||
internal class DxArchive : ArcFile
|
||||
{
|
||||
public readonly byte[] Key;
|
||||
public readonly IDxKey Encryption;
|
||||
public readonly int Version;
|
||||
|
||||
public DxArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, byte[] key, int version)
|
||||
public DxArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, IDxKey enc, int version)
|
||||
: base (arc, impl, dir)
|
||||
{
|
||||
Key = key;
|
||||
Encryption = enc;
|
||||
Version = version;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +49,7 @@ namespace GameRes.Formats.DxLib
|
||||
[Serializable]
|
||||
public class DxScheme : ResourceScheme
|
||||
{
|
||||
public IList<byte[]> KnownKeys;
|
||||
public IList<IDxKey> KnownKeys;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
@@ -67,36 +66,37 @@ namespace GameRes.Formats.DxLib
|
||||
Extensions = new string[] { "dxa", "hud", "usi", "med", "dat", "bin", "bcx", "wolf" };
|
||||
Signatures = new uint[] {
|
||||
0x19EF8ED4, 0xA9FCCEDD, 0x0AEE0FD3, 0x5523F211, 0x5524F211, 0x69FC5FE4, 0x09E19ED9, 0x7DCC5D83,
|
||||
0
|
||||
0xC55D4473, 0
|
||||
};
|
||||
}
|
||||
|
||||
DxScheme DefaultScheme = new DxScheme { KnownKeys = new List<byte[]>() };
|
||||
DxScheme DefaultScheme = new DxScheme { KnownKeys = new List<IDxKey>() };
|
||||
|
||||
public IList<byte[]> KnownKeys { get { return DefaultScheme.KnownKeys; } }
|
||||
public IList<IDxKey> KnownKeys { get { return DefaultScheme.KnownKeys; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (file.MaxOffset < 0x1C)
|
||||
return null;
|
||||
uint signature = file.View.ReadUInt32 (0);
|
||||
foreach (var key in KnownKeys)
|
||||
foreach (var enc in KnownKeys)
|
||||
{
|
||||
var key = enc.Key;
|
||||
uint sig_key = LittleEndian.ToUInt32 (key, 0);
|
||||
uint sig_test = signature ^ sig_key;
|
||||
int version = (int)(sig_test >> 16);
|
||||
if (0x5844 == (sig_test & 0xFFFF) && version <= 6) // 'DX'
|
||||
if (0x5844 == (sig_test & 0xFFFF) && version <= 7) // 'DX'
|
||||
{
|
||||
var dir = ReadIndex (file, version, key);
|
||||
if (null != dir)
|
||||
{
|
||||
if (KnownKeys[0] != key)
|
||||
if (KnownKeys[0] != enc)
|
||||
{
|
||||
// move last used key to the top of the known keys list
|
||||
KnownKeys.Remove (key);
|
||||
KnownKeys.Insert (0, key);
|
||||
KnownKeys.Remove (enc);
|
||||
KnownKeys.Insert (0, enc);
|
||||
}
|
||||
return new DxArchive (file, this, dir, key, version);
|
||||
return new DxArchive (file, this, dir, enc, version);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -104,8 +104,9 @@ namespace GameRes.Formats.DxLib
|
||||
var arc = GuessKey (file);
|
||||
if (arc != null)
|
||||
{
|
||||
KnownKeys.Insert (0, arc.Key);
|
||||
Trace.WriteLine (string.Format ("Restored key '{0}'", RestoreKey (arc.Key)), "[DXA]");
|
||||
var encryption = arc.Encryption;
|
||||
KnownKeys.Insert (0, encryption);
|
||||
Trace.WriteLine (string.Format ("Restored key '{0}'", encryption.Password, "[DXA]"));
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
@@ -119,7 +120,7 @@ namespace GameRes.Formats.DxLib
|
||||
{
|
||||
var dir = ReadIndex (file, 6, key);
|
||||
if (dir != null)
|
||||
return new DxArchive (file, this, dir, key, 6);
|
||||
return new DxArchive (file, this, dir, new DxKey (key), 6);
|
||||
}
|
||||
key = new byte[12];
|
||||
for (short version = 4; version >= 1; --version)
|
||||
@@ -144,7 +145,7 @@ namespace GameRes.Formats.DxLib
|
||||
{
|
||||
var dir = ReadIndex (file, version, key);
|
||||
if (null != dir)
|
||||
return new DxArchive (file, this, dir, key, version);
|
||||
return new DxArchive (file, this, dir, new DxKey (key), version);
|
||||
}
|
||||
catch { /* ignore parse errors */ }
|
||||
}
|
||||
@@ -186,7 +187,8 @@ namespace GameRes.Formats.DxLib
|
||||
{
|
||||
dec_offset = dx_ent.UnpackedSize;
|
||||
}
|
||||
input = new EncryptedStream (input, dec_offset, dx_arc.Key);
|
||||
var key = dx_arc.Encryption.GetEntryKey (dx_ent.Name);
|
||||
input = new EncryptedStream (input, dec_offset, key);
|
||||
if (!dx_ent.IsPacked)
|
||||
return input;
|
||||
using (input)
|
||||
@@ -265,12 +267,12 @@ namespace GameRes.Formats.DxLib
|
||||
DxHeader dx = null;
|
||||
if (version <= 4)
|
||||
dx = ReadArcHeaderV4 (file, version, key);
|
||||
else if (6 == version)
|
||||
else if (version >= 6)
|
||||
dx = ReadArcHeaderV6 (file, version, key);
|
||||
if (null == dx || dx.DirTable >= dx.IndexSize || dx.FileTable >= dx.IndexSize)
|
||||
return null;
|
||||
using (var encrypted = file.CreateStream (dx.IndexOffset, dx.IndexSize))
|
||||
using (var index = new EncryptedStream (encrypted, 6 == version ? 0 : dx.IndexOffset, key))
|
||||
using (var index = new EncryptedStream (encrypted, version >= 6 ? 0 : dx.IndexOffset, key))
|
||||
using (var reader = IndexReader.Create (dx, version, index))
|
||||
{
|
||||
return reader.Read();
|
||||
@@ -320,54 +322,6 @@ namespace GameRes.Formats.DxLib
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] CreateKey (string keyword)
|
||||
{
|
||||
byte[] key;
|
||||
if (string.IsNullOrEmpty (keyword))
|
||||
{
|
||||
key = Enumerable.Repeat<byte> (0xAA, 12).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = new byte[12];
|
||||
int char_count = Math.Min (keyword.Length, 12);
|
||||
int length = Encodings.cp932.GetBytes (keyword, 0, char_count, key, 0);
|
||||
if (length < 12)
|
||||
Binary.CopyOverlapped (key, 0, length, 12-length);
|
||||
}
|
||||
key[0] ^= 0xFF;
|
||||
key[1] = Binary.RotByteR (key[1], 4);
|
||||
key[2] ^= 0x8A;
|
||||
key[3] = (byte)~Binary.RotByteR (key[3], 4);
|
||||
key[4] ^= 0xFF;
|
||||
key[5] ^= 0xAC;
|
||||
key[6] ^= 0xFF;
|
||||
key[7] = (byte)~Binary.RotByteR (key[7], 3);
|
||||
key[8] = Binary.RotByteL (key[8], 3);
|
||||
key[9] ^= 0x7F;
|
||||
key[10] = (byte)(Binary.RotByteR (key[10], 4) ^ 0xD6);
|
||||
key[11] ^= 0xCC;
|
||||
return key;
|
||||
}
|
||||
|
||||
string RestoreKey (byte[] key)
|
||||
{
|
||||
var bin = key.Clone() as byte[];
|
||||
bin[0] ^= 0xFF;
|
||||
bin[1] = Binary.RotByteL (bin[1], 4);
|
||||
bin[2] ^= 0x8A;
|
||||
bin[3] = Binary.RotByteL ((byte)~bin[3], 4);
|
||||
bin[4] ^= 0xFF;
|
||||
bin[5] ^= 0xAC;
|
||||
bin[6] ^= 0xFF;
|
||||
bin[7] = Binary.RotByteL ((byte)~bin[7], 3);
|
||||
bin[8] = Binary.RotByteR (bin[8], 3);
|
||||
bin[9] ^= 0x7F;
|
||||
bin[10] = Binary.RotByteL ((byte)(bin[10] ^ 0xD6), 4);
|
||||
bin[11] ^= 0xCC;
|
||||
return Encodings.cp932.GetString (bin);
|
||||
}
|
||||
|
||||
public override ResourceScheme Scheme
|
||||
{
|
||||
get { return DefaultScheme; }
|
||||
@@ -393,6 +347,8 @@ namespace GameRes.Formats.DxLib
|
||||
protected Encoding m_encoding;
|
||||
protected List<Entry> m_dir = new List<Entry>();
|
||||
|
||||
internal int Version { get { return m_version; } }
|
||||
|
||||
protected IndexReader (DxHeader header, int version, Stream input)
|
||||
{
|
||||
m_header = header;
|
||||
@@ -405,7 +361,7 @@ namespace GameRes.Formats.DxLib
|
||||
{
|
||||
if (version <= 4)
|
||||
return new IndexReaderV2 (header, version, input);
|
||||
else if (6 == version)
|
||||
else if (version >= 6)
|
||||
return new IndexReaderV6 (header, version, input);
|
||||
else
|
||||
throw new InvalidFormatException ("Not supported DX archive version.");
|
||||
@@ -446,7 +402,7 @@ namespace GameRes.Formats.DxLib
|
||||
|
||||
public IndexReaderV2 (DxHeader header, int version, Stream input) : base (header, version, input)
|
||||
{
|
||||
m_entry_size = m_version >= 2 ? 0x2C : 0x28;
|
||||
m_entry_size = Version >= 2 ? 0x2C : 0x28;
|
||||
}
|
||||
|
||||
private class DxDirectory
|
||||
@@ -494,7 +450,7 @@ namespace GameRes.Formats.DxLib
|
||||
{
|
||||
uint size = m_input.ReadUInt32();
|
||||
int packed_size = -1;
|
||||
if (m_version >= 2)
|
||||
if (Version >= 2)
|
||||
packed_size = m_input.ReadInt32();
|
||||
var entry = FormatCatalog.Instance.Create<PackedEntry> (Path.Combine (root, ExtractFileName (name_offset)));
|
||||
entry.Offset = m_header.BaseOffset + offset;
|
||||
|
||||
156
ArcFormats/DxLib/DxKey.cs
Normal file
156
ArcFormats/DxLib/DxKey.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
//! \file DxKey.cs
|
||||
//! \date 2019 Feb 01
|
||||
//! \brief DxLib archive encryption classes.
|
||||
//
|
||||
// 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.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.DxLib
|
||||
{
|
||||
public interface IDxKey
|
||||
{
|
||||
string Password { get; }
|
||||
byte[] Key { get; }
|
||||
|
||||
byte[] GetEntryKey (string name);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DxKey : IDxKey
|
||||
{
|
||||
string m_password;
|
||||
byte[] m_key;
|
||||
|
||||
public DxKey () : this (string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
public DxKey (string password)
|
||||
{
|
||||
Password = password;
|
||||
}
|
||||
|
||||
public DxKey (byte[] key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get { return m_password; }
|
||||
set { m_password = value; m_key = null; }
|
||||
}
|
||||
|
||||
public byte[] Key
|
||||
{
|
||||
get { return m_key ?? (m_key = CreateKey (m_password)); }
|
||||
set { m_key = value; m_password = RestoreKey (m_key); }
|
||||
}
|
||||
|
||||
public virtual byte[] GetEntryKey (string name)
|
||||
{
|
||||
return Key;
|
||||
}
|
||||
|
||||
protected virtual byte[] CreateKey (string keyword)
|
||||
{
|
||||
byte[] key;
|
||||
if (string.IsNullOrEmpty (keyword))
|
||||
{
|
||||
key = Enumerable.Repeat<byte> (0xAA, 12).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = new byte[12];
|
||||
int char_count = Math.Min (keyword.Length, 12);
|
||||
int length = Encodings.cp932.GetBytes (keyword, 0, char_count, key, 0);
|
||||
if (length < 12)
|
||||
Binary.CopyOverlapped (key, 0, length, 12-length);
|
||||
}
|
||||
key[0] ^= 0xFF;
|
||||
key[1] = Binary.RotByteR (key[1], 4);
|
||||
key[2] ^= 0x8A;
|
||||
key[3] = (byte)~Binary.RotByteR (key[3], 4);
|
||||
key[4] ^= 0xFF;
|
||||
key[5] ^= 0xAC;
|
||||
key[6] ^= 0xFF;
|
||||
key[7] = (byte)~Binary.RotByteR (key[7], 3);
|
||||
key[8] = Binary.RotByteL (key[8], 3);
|
||||
key[9] ^= 0x7F;
|
||||
key[10] = (byte)(Binary.RotByteR (key[10], 4) ^ 0xD6);
|
||||
key[11] ^= 0xCC;
|
||||
return key;
|
||||
}
|
||||
|
||||
protected virtual string RestoreKey (byte[] key)
|
||||
{
|
||||
var bin = key.Clone() as byte[];
|
||||
bin[0] ^= 0xFF;
|
||||
bin[1] = Binary.RotByteL (bin[1], 4);
|
||||
bin[2] ^= 0x8A;
|
||||
bin[3] = Binary.RotByteL ((byte)~bin[3], 4);
|
||||
bin[4] ^= 0xFF;
|
||||
bin[5] ^= 0xAC;
|
||||
bin[6] ^= 0xFF;
|
||||
bin[7] = Binary.RotByteL ((byte)~bin[7], 3);
|
||||
bin[8] = Binary.RotByteR (bin[8], 3);
|
||||
bin[9] ^= 0x7F;
|
||||
bin[10] = Binary.RotByteL ((byte)(bin[10] ^ 0xD6), 4);
|
||||
bin[11] ^= 0xCC;
|
||||
return Encodings.cp932.GetString (bin);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DxKey7 : DxKey
|
||||
{
|
||||
public DxKey7 (string password) : base (password ?? "DXARC")
|
||||
{
|
||||
}
|
||||
|
||||
public override byte[] GetEntryKey (string name)
|
||||
{
|
||||
var password = this.Password;
|
||||
var path = name.Split ('\\', '/');
|
||||
password += string.Join ("", path.Reverse().Select (n => n.ToUpperInvariant()));
|
||||
return CreateKey (password);
|
||||
}
|
||||
|
||||
protected override byte[] CreateKey (string keyword)
|
||||
{
|
||||
using (var sha = SHA256.Create())
|
||||
{
|
||||
var bytes = Encodings.cp932.GetBytes (keyword);
|
||||
return sha.ComputeHash (bytes);
|
||||
}
|
||||
}
|
||||
|
||||
protected override string RestoreKey (byte[] key)
|
||||
{
|
||||
throw new NotSupportedException ("SHA-256 key cannot be restored.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,14 +49,14 @@ namespace GameRes.Formats.Macromedia
|
||||
public class SwfOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "SWF"; } }
|
||||
public override string Description { get { return "Shockeave Flash presentation"; } }
|
||||
public override string Description { get { return "Shockwave Flash presentation"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public SwfOpener ()
|
||||
{
|
||||
Signatures = new uint[] { 0x08535743, 0 };
|
||||
Signatures = new uint[] { 0x08535743, 0x08535746, 0 };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
@@ -173,14 +173,35 @@ namespace GameRes.Formats.Macromedia
|
||||
case Types.DefineBitsLossless2:
|
||||
return new LosslessImageDecoder (swent.Chunk);
|
||||
|
||||
case Types.DefineBitsJpeg2:
|
||||
return new SwfJpeg2Decoder (swent.Chunk);
|
||||
|
||||
case Types.DefineBitsJpeg3:
|
||||
return new SwfJpeg3Decoder (swent.Chunk);
|
||||
|
||||
case Types.DefineBitsJpeg:
|
||||
return OpenBitsJpeg (swent.Chunk);
|
||||
|
||||
default:
|
||||
return base.OpenImage (arc, entry);
|
||||
}
|
||||
}
|
||||
|
||||
IImageDecoder OpenBitsJpeg (SwfChunk chunk)
|
||||
{
|
||||
int jpeg_pos = 0;
|
||||
for (int i = 0; i < chunk.Data.Length - 2; ++i)
|
||||
{
|
||||
if (chunk.Data[i] == 0xFF && chunk.Data[i+1] == 0xD8)
|
||||
{
|
||||
jpeg_pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var input = new BinMemoryStream (chunk.Data, jpeg_pos, chunk.Data.Length - jpeg_pos);
|
||||
return ImageFormatDecoder.Create (input);
|
||||
}
|
||||
|
||||
delegate Stream Extractor (SwfEntry entry);
|
||||
|
||||
static Dictionary<Types, Extractor> ExtractMap = new Dictionary<Types, Extractor> {
|
||||
@@ -195,12 +216,20 @@ namespace GameRes.Formats.Macromedia
|
||||
|
||||
static Dictionary<Types, string> TypeMap = new Dictionary<Types, string> {
|
||||
{ Types.DefineBitsJpeg, "image" },
|
||||
{ Types.DefineBitsJpeg2, "DefineBitsJpeg2" },
|
||||
{ Types.DefineBitsJpeg2, "image" },
|
||||
{ Types.DefineBitsJpeg3, "image" },
|
||||
{ Types.DefineBitsLossless, "image" },
|
||||
{ Types.DefineBitsLossless2, "image" },
|
||||
{ Types.DefineSound, "audio" },
|
||||
{ Types.DoAction, "" },
|
||||
|
||||
{ Types.JpegTables, "JpegTables" },
|
||||
/*
|
||||
{ Types.DefineText, "Text" },
|
||||
{ Types.DefineText2, "Text2" },
|
||||
{ Types.DefineVideoStream, "VideoStream" },
|
||||
{ Types.VideoFrame, "VideoFrame" },
|
||||
*/
|
||||
};
|
||||
|
||||
internal static bool IsSoundStream (SwfChunk chunk)
|
||||
@@ -217,17 +246,23 @@ namespace GameRes.Formats.Macromedia
|
||||
ShowFrame = 1,
|
||||
DefineShape = 2,
|
||||
DefineBitsJpeg = 6,
|
||||
JpegTables = 8,
|
||||
DefineText = 11,
|
||||
DoAction = 12,
|
||||
DefineSound = 14,
|
||||
SoundStreamHead = 18,
|
||||
SoundStreamBlock = 19,
|
||||
DefineBitsLossless = 20,
|
||||
DefineBitsJpeg2 = 21,
|
||||
DefineShape2 = 22,
|
||||
DefineShape3 = 32,
|
||||
DefineText2 = 33,
|
||||
DefineBitsJpeg3 = 35,
|
||||
DefineBitsLossless2 = 36,
|
||||
DefineSprite = 39,
|
||||
SoundStreamHead2 = 45,
|
||||
ExportAssets = 56,
|
||||
DefineVideoStream = 60,
|
||||
VideoFrame = 61,
|
||||
FileAttributes = 69,
|
||||
Font3 = 75,
|
||||
@@ -401,9 +436,12 @@ namespace GameRes.Formats.Macromedia
|
||||
for (int i = 0; i < pixels.Length; i += 4)
|
||||
{
|
||||
byte a = pixels[i];
|
||||
pixels[i] = pixels[i+1];
|
||||
pixels[i+1] = pixels[i+2];
|
||||
pixels[i+2] = pixels[i+3];
|
||||
byte r = pixels[i+1];
|
||||
byte g = pixels[i+2];
|
||||
byte b = pixels[i+3];
|
||||
pixels[i] = b;
|
||||
pixels[i+1] = g;
|
||||
pixels[i+2] = r;
|
||||
pixels[i+3] = a;
|
||||
}
|
||||
}
|
||||
@@ -412,6 +450,65 @@ namespace GameRes.Formats.Macromedia
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SwfJpeg2Decoder : IImageDecoder
|
||||
{
|
||||
byte[] m_input;
|
||||
ImageData m_image;
|
||||
|
||||
public Stream Source { get { return Stream.Null; } }
|
||||
public ImageFormat SourceFormat { get { return null; } }
|
||||
public ImageMetaData Info { get; private set; }
|
||||
public ImageData Image { get { return m_image ?? (m_image = Unpack()); } }
|
||||
|
||||
public SwfJpeg2Decoder (SwfChunk chunk)
|
||||
{
|
||||
m_input = chunk.Data;
|
||||
}
|
||||
|
||||
ImageData Unpack ()
|
||||
{
|
||||
int jpeg_pos = FindJpegSignature();
|
||||
if (jpeg_pos < 0)
|
||||
throw new InvalidFormatException();
|
||||
using (var jpeg = new BinMemoryStream (m_input, jpeg_pos, m_input.Length-jpeg_pos))
|
||||
{
|
||||
var decoder = new JpegBitmapDecoder (jpeg, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||
var frame = decoder.Frames[0];
|
||||
Info = new ImageMetaData {
|
||||
Width = (uint)frame.PixelWidth,
|
||||
Height = (uint)frame.PixelHeight,
|
||||
BPP = frame.Format.BitsPerPixel,
|
||||
};
|
||||
return new ImageData (frame, Info);
|
||||
}
|
||||
}
|
||||
|
||||
int FindJpegSignature ()
|
||||
{
|
||||
int jpeg_pos = 2;
|
||||
while (jpeg_pos < m_input.Length-4)
|
||||
{
|
||||
if (m_input[jpeg_pos] != 0xFF)
|
||||
jpeg_pos++;
|
||||
else if (m_input[jpeg_pos+1] == 0xD8)
|
||||
return jpeg_pos;
|
||||
else if (m_input[jpeg_pos+1] != 0xD9)
|
||||
jpeg_pos++;
|
||||
else if (m_input[jpeg_pos+2] != 0xFF)
|
||||
jpeg_pos += 3;
|
||||
else if (m_input[jpeg_pos+3] != 0xD8)
|
||||
jpeg_pos += 2;
|
||||
else
|
||||
return jpeg_pos+4;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SwfJpeg3Decoder : IImageDecoder
|
||||
{
|
||||
byte[] m_input;
|
||||
|
||||
137
ArcFormats/Nonono/ArcNPF.cs
Normal file
137
ArcFormats/Nonono/ArcNPF.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
//! \file ArcNPF.cs
|
||||
//! \date 2019 Feb 02
|
||||
//! \brief NGS engine 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.Nonono
|
||||
{
|
||||
internal class NpfEntry : Entry
|
||||
{
|
||||
public int Seed;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class NpfOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "NPF"; } }
|
||||
public override string Description { get { return "NGS engine resource archive"; } }
|
||||
public override uint Signature { get { return 0x4B434150; } } // 'PACK'
|
||||
public override bool IsHierarchic { get { return true; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
const int DefaultSeed = 0x46415420; // 'FAT '
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (file.View.ReadInt32 (4) != 4 || file.View.ReadInt32 (8) != 1)
|
||||
return null;
|
||||
var header = file.View.ReadBytes (12, 20);
|
||||
var rnd = new RandomGenerator (DefaultSeed);
|
||||
Decrypt (header, 0, header.Length, rnd);
|
||||
if (!header.AsciiEqual ("FAT "))
|
||||
return null;
|
||||
int count = header.ToInt32 (8);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
rnd.SRand (count);
|
||||
var index = file.View.ReadBytes (0x20, 20 * (uint)count);
|
||||
Decrypt (index, 0, index.Length, rnd);
|
||||
int pos = 0;
|
||||
int name_pos = 0x20 + 20 * count;
|
||||
var dir = new List<Entry> (count);
|
||||
var name_buffer = new byte[0x100];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
int name_length = index.ToInt32 (pos+12);
|
||||
if (name_length <= 0 || name_length > name_buffer.Length)
|
||||
return null;
|
||||
file.View.Read (name_pos, name_buffer, 0, (uint)name_length);
|
||||
int seed = index.ToInt32 (pos+8);
|
||||
rnd.SRand (seed);
|
||||
Decrypt (name_buffer, 0, name_length, rnd);
|
||||
var name = Encodings.cp932.GetString (name_buffer, 0, name_length);
|
||||
var entry = Create<NpfEntry> (name);
|
||||
entry.Offset = index.ToUInt32 (pos+4);
|
||||
entry.Size = index.ToUInt32 (pos+16);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
entry.Seed = seed;
|
||||
dir.Add (entry);
|
||||
pos += 20;
|
||||
name_pos += name_length;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var nent = entry as NpfEntry;
|
||||
if (null == nent)
|
||||
return base.OpenEntry (arc, entry);
|
||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
var rnd = new RandomGenerator (nent.Seed);
|
||||
Decrypt (data, 0, data.Length, rnd);
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
|
||||
internal void Decrypt (byte[] data, int pos, int count, RandomGenerator rnd)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
data[pos + i] ^= (byte)rnd.Rand();
|
||||
}
|
||||
}
|
||||
|
||||
internal class RandomGenerator
|
||||
{
|
||||
int m_seed;
|
||||
|
||||
const int DefaultSeed = 0x67895;
|
||||
|
||||
public RandomGenerator (int seed = DefaultSeed)
|
||||
{
|
||||
SRand (seed);
|
||||
}
|
||||
|
||||
public void SRand (int seed)
|
||||
{
|
||||
m_seed = seed;
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
Rand();
|
||||
}
|
||||
}
|
||||
|
||||
public int Rand ()
|
||||
{
|
||||
m_seed ^= 0x65AC9365;
|
||||
m_seed ^= (((m_seed >> 1) ^ m_seed) >> 3)
|
||||
^ (((m_seed << 1) ^ m_seed) << 3);
|
||||
return m_seed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,20 +58,22 @@ namespace GameRes.Formats.Pajamas
|
||||
|
||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||
{
|
||||
var info = new EpaMetaData();
|
||||
info.Mode = file.ReadInt32() >> 24;
|
||||
info.ColorType = file.ReadInt32() & 0xff;
|
||||
var header = file.ReadHeader (16);
|
||||
var info = new EpaMetaData {
|
||||
Width = header.ToUInt32 (8),
|
||||
Height = header.ToUInt32 (12),
|
||||
Mode = header[3],
|
||||
ColorType = header[4],
|
||||
};
|
||||
switch (info.ColorType)
|
||||
{
|
||||
case 0: info.BPP = 8; break;
|
||||
case 1: info.BPP = 24; break;
|
||||
case 2: info.BPP = 32; break;
|
||||
case 3: info.BPP = 15; break;
|
||||
case 3: info.BPP = 16; break;
|
||||
case 4: info.BPP = 8; break;
|
||||
default: return null;
|
||||
}
|
||||
info.Width = file.ReadUInt32();
|
||||
info.Height = file.ReadUInt32();
|
||||
if (2 == info.Mode)
|
||||
{
|
||||
info.OffsetX = file.ReadInt32();
|
||||
@@ -109,7 +111,7 @@ namespace GameRes.Formats.Pajamas
|
||||
case 0: m_pixel_size = 1; Format = PixelFormats.Indexed8; break;
|
||||
case 1: m_pixel_size = 3; Format = PixelFormats.Bgr24; break;
|
||||
case 2: m_pixel_size = 4; Format = PixelFormats.Bgra32; break;
|
||||
case 3: m_pixel_size = 2; Format = PixelFormats.Bgr555; break;
|
||||
case 3: m_pixel_size = 2; Format = PixelFormats.Bgr565; break;
|
||||
case 4: m_pixel_size = 1; Format = PixelFormats.Bgra32; m_has_alpha = true; break;
|
||||
default: throw new NotSupportedException ("Not supported EPA color depth");
|
||||
}
|
||||
@@ -163,18 +165,37 @@ namespace GameRes.Formats.Pajamas
|
||||
if (m_pixel_size > 1)
|
||||
{
|
||||
var bitmap = new byte[m_output.Length];
|
||||
int stride = m_width * m_pixel_size;
|
||||
int i = 0;
|
||||
for (int p = 0; p < m_pixel_size; ++p)
|
||||
int src = 0;
|
||||
if (m_pixel_size > 2)
|
||||
{
|
||||
int stride = m_width * m_pixel_size;
|
||||
for (int p = 0; p < m_pixel_size; ++p)
|
||||
{
|
||||
for (int y = 0; y < m_height; ++y)
|
||||
{
|
||||
int dst = y * stride + p;
|
||||
for (int x = 0; x < m_width; ++x)
|
||||
{
|
||||
bitmap[dst] = m_output[src++];
|
||||
dst += m_pixel_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int dst = 0;
|
||||
int channel_size = m_width * m_height;
|
||||
for (int y = 0; y < m_height; ++y)
|
||||
{
|
||||
int pixel = y * stride + p;
|
||||
for (int x = 0; x < m_width; ++x)
|
||||
{
|
||||
bitmap[pixel] = m_output[i++];
|
||||
pixel += m_pixel_size;
|
||||
byte c1 = m_output[src + x];
|
||||
byte c2 = m_output[src + x + channel_size];
|
||||
bitmap[dst++] = (byte)(c2 & 3 | (c1 & 7 | (c2 & 0xFC) << 1) << 2);
|
||||
bitmap[dst++] = (byte)(c1 & 0xC0 | (c2 & 0xE3 | (c1 >> 1) & 0x1C) >> 2);
|
||||
}
|
||||
src += m_width;
|
||||
}
|
||||
}
|
||||
m_output = bitmap;
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.2.46.2082")]
|
||||
[assembly: AssemblyFileVersion ("1.2.46.2082")]
|
||||
[assembly: AssemblyVersion ("1.2.47.2120")]
|
||||
[assembly: AssemblyFileVersion ("1.2.47.2120")]
|
||||
|
||||
Binary file not shown.
@@ -41,7 +41,7 @@ namespace GameRes.Formats.Seraphim
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (file.View.ReadInt32 (0) != 0 || !file.View.AsciiEqual (4, "MCs"))
|
||||
if (file.View.ReadInt32 (0) != 0 || !file.View.AsciiEqual (4, "MC"))
|
||||
return null;
|
||||
int count = file.View.ReadInt32 (8);
|
||||
if (!IsSaneCount (count))
|
||||
|
||||
@@ -80,25 +80,35 @@ namespace GameRes.Formats.Seraphim
|
||||
if (0 == entry.Size)
|
||||
return Stream.Null;
|
||||
uint signature = arc.File.View.ReadUInt32 (entry.Offset);
|
||||
ArcViewStream input;
|
||||
IBinaryStream input;
|
||||
if (1 == signature && 0x78 == arc.File.View.ReadByte (entry.Offset+4))
|
||||
{
|
||||
input = arc.File.CreateStream (entry.Offset+4, entry.Size-4);
|
||||
return new ZLibStream (input, CompressionMode.Decompress);
|
||||
return new ZLibStream (input.AsStream, CompressionMode.Decompress);
|
||||
}
|
||||
input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
if (signature < 4 || 0 != (signature & 0xFF000000))
|
||||
return input;
|
||||
{
|
||||
if (0x78 == (signature & 0xFF))
|
||||
{
|
||||
var compr = new ZLibStream (input.AsStream, CompressionMode.Decompress);
|
||||
input = new BinaryStream (compr, entry.Name);
|
||||
}
|
||||
else
|
||||
return input.AsStream;
|
||||
}
|
||||
try
|
||||
{
|
||||
var data = LzDecompress (input);
|
||||
input.Dispose();
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
catch
|
||||
{
|
||||
input.Position = 0;
|
||||
return input;
|
||||
return arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
}
|
||||
finally
|
||||
{
|
||||
input.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace GameRes.Formats.StudioSakura
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var name = file.View.ReadString (index_offset, 0x100);
|
||||
if (string.IsNullOrWhiteSpace (name))
|
||||
return null;
|
||||
var entry = new PackedEntry();
|
||||
entry.IsPacked = name.HasExtension (".pr3");
|
||||
if (entry.IsPacked)
|
||||
|
||||
@@ -165,8 +165,9 @@ namespace GameRes.Formats.Tamamo
|
||||
return decoder;
|
||||
using (decoder)
|
||||
{
|
||||
var ev_bitmap = CreateCanvas (1280, 720, source, new Int32Rect (0, 0, 1024, 720));
|
||||
CopyRegion (source, new Int32Rect (0, 720, 720, 256), ev_bitmap, 1024, 0);
|
||||
var ev_bitmap = CreateCanvas (1280, 720, source, new Int32Rect (0, 0, 1024, 719));
|
||||
// XXX Senkou no Kishi texture
|
||||
CopyRegion (source, new Int32Rect (0, 719, 720, 256), ev_bitmap, 1024, 0);
|
||||
return new BitmapSourceDecoder (ev_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
247
ArcFormats/Unity/ArcBIN.cs
Normal file
247
ArcFormats/Unity/ArcBIN.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
//! \file ArcBIN.cs
|
||||
//! \date 2019 Feb 23
|
||||
//! \brief Unity binary data asset.
|
||||
//
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Unity
|
||||
{
|
||||
internal class BinArchive : ArcFile
|
||||
{
|
||||
public readonly Aes Encryption;
|
||||
|
||||
public BinArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, Aes enc)
|
||||
: base (arc, impl, dir)
|
||||
{
|
||||
Encryption = enc;
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
bool _bin_disposed = false;
|
||||
protected override void Dispose (bool disposing)
|
||||
{
|
||||
if (_bin_disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
Encryption.Dispose();
|
||||
_bin_disposed = true;
|
||||
base.Dispose (disposing);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BinPackKey
|
||||
{
|
||||
public byte[] Key;
|
||||
public byte[] IV;
|
||||
|
||||
public BinPackKey (string key, string iv)
|
||||
{
|
||||
Key = Encoding.UTF8.GetBytes (key);
|
||||
IV = Encoding.UTF8.GetBytes (iv);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BinPackScheme : ResourceScheme
|
||||
{
|
||||
public Dictionary<string, BinPackKey> KnownKeys;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class BinOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "BIN/IDX"; } }
|
||||
public override string Description { get { return "Unity engine resource asset"; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
public override bool IsHierarchic { get { return true; } }
|
||||
public override bool CanWrite { get { return false; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
if (!file.Name.HasExtension (".bin"))
|
||||
return null;
|
||||
var idx_name = Path.ChangeExtension (file.Name, "idx");
|
||||
if (!VFS.FileExists (idx_name))
|
||||
return null;
|
||||
var scheme = QueryScheme (file.Name);
|
||||
if (null == scheme)
|
||||
return null;
|
||||
var dir = new List<Entry>();
|
||||
using (var idx = VFS.OpenBinaryStream (idx_name))
|
||||
using (var aes = Aes.Create())
|
||||
{
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.KeySize = 128;
|
||||
aes.Key = scheme.Key;
|
||||
aes.IV = scheme.IV;
|
||||
var input_buffer = new byte[0x100];
|
||||
var unpacker = new BinDeserializer();
|
||||
while (idx.PeekByte() != -1)
|
||||
{
|
||||
int length = idx.ReadInt32();
|
||||
if (length <= 0)
|
||||
return null;
|
||||
if (length > input_buffer.Length)
|
||||
input_buffer = new byte[length];
|
||||
if (idx.Read (input_buffer, 0, length) < length)
|
||||
return null;
|
||||
using (var decryptor = aes.CreateDecryptor())
|
||||
using (var encrypted = new MemoryStream (input_buffer, 0, length))
|
||||
using (var input = new InputCryptoStream (encrypted, decryptor))
|
||||
{
|
||||
var info = unpacker.DeserializeEntry (input);
|
||||
var filename = info["fileName"] as string;
|
||||
if (string.IsNullOrEmpty (filename))
|
||||
return null;
|
||||
filename = filename.TrimStart ('/', '\\');
|
||||
var entry = Create<Entry> (filename);
|
||||
entry.Offset = Convert.ToInt64 (info["index"]);
|
||||
entry.Size = Convert.ToUInt32 (info["size"]);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (0 == dir.Count)
|
||||
return null;
|
||||
var arc_aes = Aes.Create();
|
||||
arc_aes.Padding = PaddingMode.PKCS7;
|
||||
arc_aes.Mode = CipherMode.CBC;
|
||||
arc_aes.KeySize = 256;
|
||||
arc_aes.Key = scheme.Key;
|
||||
arc_aes.IV = scheme.IV;
|
||||
return new BinArchive (file, this, dir, arc_aes);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var bin_arc = (BinArchive)arc;
|
||||
var decryptor = bin_arc.Encryption.CreateDecryptor();
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
return new InputCryptoStream (input, decryptor);
|
||||
}
|
||||
|
||||
BinPackKey QueryScheme (string arc_name)
|
||||
{
|
||||
return DefaultScheme.KnownKeys.Values.FirstOrDefault();
|
||||
}
|
||||
|
||||
static BinPackScheme DefaultScheme = new BinPackScheme { KnownKeys = new Dictionary<string, BinPackKey>() };
|
||||
|
||||
public override ResourceScheme Scheme
|
||||
{
|
||||
get { return DefaultScheme; }
|
||||
set { DefaultScheme = (BinPackScheme)value; }
|
||||
}
|
||||
}
|
||||
|
||||
internal class BinDeserializer
|
||||
{
|
||||
byte[] m_buffer = new byte[0x20];
|
||||
|
||||
public IDictionary DeserializeEntry (Stream input)
|
||||
{
|
||||
int id = input.ReadByte();
|
||||
if (id < 0x80 || id > 0x8F)
|
||||
throw new FormatException();
|
||||
int field_count = id & 0xF;
|
||||
var map = new Hashtable (field_count);
|
||||
for (int i = 0; i < field_count; ++i)
|
||||
{
|
||||
id = input.ReadByte();
|
||||
if (id < 0xA0 || id > 0xBF)
|
||||
throw new FormatException();
|
||||
int length = id & 0x1F;
|
||||
if (input.Read (m_buffer, 0, length) < length)
|
||||
throw new FormatException();
|
||||
var key = Encoding.UTF8.GetString (m_buffer, 0, length);
|
||||
var value = ReadField (input);
|
||||
map[key] = value;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
object ReadField (Stream input)
|
||||
{
|
||||
int id = input.ReadByte();
|
||||
if (id >= 0 && id < 0x80)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
else if (id >= 0xA0 && id < 0xC0)
|
||||
{
|
||||
int length = id & 0x1F;
|
||||
return ReadString (input, length);
|
||||
}
|
||||
switch (id)
|
||||
{
|
||||
case 0xD0: // Int8
|
||||
int value = input.ReadByte();
|
||||
if (-1 == value)
|
||||
throw new FormatException();
|
||||
return (sbyte)value;
|
||||
|
||||
case 0xD1: // Int16
|
||||
if (input.Read (m_buffer, 0, 2) < 2)
|
||||
throw new FormatException();
|
||||
return BigEndian.ToInt16 (m_buffer, 0);
|
||||
|
||||
case 0xD2: // Int32
|
||||
if (input.Read (m_buffer, 0, 4) < 4)
|
||||
throw new FormatException();
|
||||
return BigEndian.ToInt32 (m_buffer, 0);
|
||||
|
||||
case 0xDA: // Raw16
|
||||
if (input.Read (m_buffer, 0, 2) < 2)
|
||||
throw new FormatException();
|
||||
int length = BigEndian.ToUInt16 (m_buffer, 0);
|
||||
return ReadString (input, length);
|
||||
|
||||
default:
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
string ReadString (Stream input, int length)
|
||||
{
|
||||
if (length > m_buffer.Length)
|
||||
m_buffer = new byte[(length + 0xF) & ~0xF];
|
||||
input.Read (m_buffer, 0, length);
|
||||
return Encoding.UTF8.GetString (m_buffer, 0, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using GameRes.Formats.Strings;
|
||||
using GameRes.Compression;
|
||||
|
||||
namespace GameRes.Formats.Will
|
||||
{
|
||||
@@ -46,6 +47,7 @@ namespace GameRes.Formats.Will
|
||||
public Arc2Opener ()
|
||||
{
|
||||
Extensions = new string[] { "arc", "ar2" };
|
||||
ContainedFormats = new[] { "PNG", "PNA", "PSB", "OGG", "SCR" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
@@ -83,7 +85,7 @@ namespace GameRes.Formats.Will
|
||||
if (0 == name_buffer.Length)
|
||||
return null;
|
||||
var name = name_buffer.ToString();
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||
var entry = Create<Entry> (name);
|
||||
entry.Offset = offset;
|
||||
entry.Size = size;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
@@ -97,8 +99,12 @@ namespace GameRes.Formats.Will
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
if (!IsScriptFile (entry.Name))
|
||||
if (!IsScriptFile (entry.Name) || Path.GetFileName (arc.File.Name).Contains ("Model"))
|
||||
{
|
||||
if (entry.Name.HasExtension (".PSP"))
|
||||
return OpenPsp (arc, entry);
|
||||
return base.OpenEntry (arc, entry);
|
||||
}
|
||||
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
|
||||
for (int i = 0; i < data.Length; ++i)
|
||||
{
|
||||
@@ -107,6 +113,42 @@ namespace GameRes.Formats.Will
|
||||
return new BinMemoryStream (data, entry.Name);
|
||||
}
|
||||
|
||||
Stream OpenPsp (ArcFile arc, Entry entry)
|
||||
{
|
||||
using (var input = arc.File.CreateStream (entry.Offset, entry.Size))
|
||||
{
|
||||
int unpacked_size = input.ReadInt32();
|
||||
var output = new byte[unpacked_size];
|
||||
int dst = 0;
|
||||
var frame = new byte[0x1000];
|
||||
int frame_pos = 1;
|
||||
while (dst < unpacked_size)
|
||||
{
|
||||
int ctl = input.ReadByte();
|
||||
for (int bit = 1; dst < unpacked_size && bit != 0x100; bit <<= 1)
|
||||
{
|
||||
if (0 != (ctl & bit))
|
||||
{
|
||||
byte b = input.ReadUInt8();
|
||||
output[dst++] = frame[frame_pos++ & 0xFFF] = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
int hi = input.ReadByte();
|
||||
int lo = input.ReadByte();
|
||||
int offset = hi << 4 | lo >> 4;
|
||||
for (int count = 2 + (lo & 0xF); count != 0; --count)
|
||||
{
|
||||
byte v = frame[offset++ & 0xFFF];
|
||||
output[dst++] = frame[frame_pos++ & 0xFFF] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new BinMemoryStream (output, entry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsScriptFile (string name)
|
||||
{
|
||||
return name.HasAnyOfExtensions ("ws2", "json");
|
||||
@@ -179,4 +221,9 @@ namespace GameRes.Formats.Will
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ResourceAlias))]
|
||||
[ExportMetadata("Extension", "PSP")]
|
||||
[ExportMetadata("Target", "PSB")]
|
||||
public class PspFormat : ResourceAlias { }
|
||||
}
|
||||
|
||||
@@ -93,10 +93,15 @@ namespace GameRes.Formats.Artemis
|
||||
public override ImageData Read (IBinaryStream file, ImageMetaData info)
|
||||
{
|
||||
var meta = (IptMetaData)info;
|
||||
if (meta.Mode != "diff" && meta.Mode != "cut")
|
||||
PixelFormat format;
|
||||
if ("cut" == meta.Mode)
|
||||
format = PixelFormats.Bgra32;
|
||||
else if ("diff" == meta.Mode)
|
||||
format = PixelFormats.Bgr32;
|
||||
else
|
||||
throw new InvalidFormatException (string.Format ("Not supported IPT tile mode '{0}'.", meta.Mode));
|
||||
var canvas = new WriteableBitmap (meta.iWidth, meta.iHeight, ImageData.DefaultDpiX,
|
||||
ImageData.DefaultDpiY, PixelFormats.Bgr32, null);
|
||||
ImageData.DefaultDpiY, format, null);
|
||||
var base_dir = VFS.GetDirectoryName (file.Name);
|
||||
try
|
||||
{
|
||||
@@ -167,7 +172,7 @@ namespace GameRes.Formats.Artemis
|
||||
byte src_alpha = pixels[src+3];
|
||||
if (src_alpha > 0)
|
||||
{
|
||||
if (0xFF == src_alpha)
|
||||
if (0xFF == src_alpha || 0 == buffer[dst+3])
|
||||
{
|
||||
buffer[dst ] = pixels[src];
|
||||
buffer[dst+1] = pixels[src+1];
|
||||
@@ -179,6 +184,7 @@ namespace GameRes.Formats.Artemis
|
||||
buffer[dst+1] = (byte)((pixels[src+1] * src_alpha + buffer[dst+1] * (0xFF - src_alpha)) / 0xFF);
|
||||
buffer[dst+2] = (byte)((pixels[src+2] * src_alpha + buffer[dst+2] * (0xFF - src_alpha)) / 0xFF);
|
||||
}
|
||||
buffer[dst+3] = src_alpha;
|
||||
}
|
||||
dst += 4;
|
||||
src += 4;
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.14.35")]
|
||||
[assembly: AssemblyFileVersion ("1.0.14.35")]
|
||||
[assembly: AssemblyVersion ("1.0.15.38")]
|
||||
[assembly: AssemblyFileVersion ("1.0.15.38")]
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Windows;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany ("mørkt")]
|
||||
[assembly: AssemblyProduct("GARbro.GUI")]
|
||||
[assembly: AssemblyCopyright ("Copyright © 2014-2018 mørkt")]
|
||||
[assembly: AssemblyCopyright ("Copyright © 2014-2019 mørkt")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -51,5 +51,5 @@ using System.Windows;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.5.42.2807")]
|
||||
[assembly: AssemblyFileVersion ("1.5.42.2807")]
|
||||
[assembly: AssemblyVersion ("1.5.43.2857")]
|
||||
[assembly: AssemblyFileVersion ("1.5.43.2857")]
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.5.42.315")]
|
||||
[assembly: AssemblyFileVersion ("1.5.42.315")]
|
||||
[assembly: AssemblyVersion ("1.5.43.316")]
|
||||
[assembly: AssemblyFileVersion ("1.5.43.316")]
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Text.RegularExpressions;
|
||||
using GameRes.Utility;
|
||||
|
||||
// [031024][Lazycrew] Sister Mermaid
|
||||
// [020927][Ga-Bang] Sorairo Memories
|
||||
|
||||
namespace GameRes.Formats.Lazycrew
|
||||
{
|
||||
@@ -52,10 +53,11 @@ namespace GameRes.Formats.Lazycrew
|
||||
|
||||
public DatOpener ()
|
||||
{
|
||||
Extensions = new string[] { "dat", "" };
|
||||
Signatures = new uint[] { 2, 0 };
|
||||
}
|
||||
|
||||
static readonly Regex NamePattern = new Regex (@"^(0\d\d\d)\.dat$", RegexOptions.IgnoreCase);
|
||||
static readonly Regex NamePattern = new Regex (@"^(?:(?<num>0\d\d\d)\.dat|data(?<num>\d+)?)$", RegexOptions.IgnoreCase);
|
||||
|
||||
const uint DefaultPcmKey = 0x4B5AB4A5;
|
||||
|
||||
@@ -65,7 +67,10 @@ namespace GameRes.Formats.Lazycrew
|
||||
if (!NamePattern.IsMatch (name))
|
||||
return null;
|
||||
var match = NamePattern.Match (name);
|
||||
int name_id = Int32.Parse (match.Groups[1].Value);
|
||||
int name_id = 1;
|
||||
var num_str = match.Groups["num"].Value;
|
||||
if (!string.IsNullOrEmpty (num_str))
|
||||
name_id = Int32.Parse (num_str);
|
||||
if (name_id < 1)
|
||||
return null;
|
||||
ArcView index = file;
|
||||
@@ -73,7 +78,11 @@ namespace GameRes.Formats.Lazycrew
|
||||
{
|
||||
if (name_id != 1)
|
||||
{
|
||||
var index_name = VFS.ChangeFileName (file.Name, "0001.dat");
|
||||
string index_name;
|
||||
if (file.Name.HasExtension (".dat"))
|
||||
index_name = VFS.ChangeFileName (file.Name, "0001.dat");
|
||||
else
|
||||
index_name = VFS.ChangeFileName (file.Name, "data");
|
||||
if (!VFS.FileExists (index_name))
|
||||
return null;
|
||||
index = VFS.OpenView (index_name);
|
||||
@@ -98,7 +107,6 @@ namespace GameRes.Formats.Lazycrew
|
||||
var dir_list = new List<DirEntry> (dir_count);
|
||||
int dir_offset = 4;
|
||||
int first_offset = dir_count * 0x10 + 4;
|
||||
int file_count = 0;
|
||||
for (int i = 0; i < dir_count; ++i)
|
||||
{
|
||||
var dir_entry = new DirEntry {
|
||||
@@ -109,11 +117,10 @@ namespace GameRes.Formats.Lazycrew
|
||||
if (dir_entry.Offset < first_offset || dir_entry.Offset >= index.MaxOffset
|
||||
|| !IsSaneCount (dir_entry.Count))
|
||||
return null;
|
||||
file_count += dir_entry.Count;
|
||||
dir_list.Add (dir_entry);
|
||||
dir_offset += 16;
|
||||
}
|
||||
var file_list = new List<Entry> (file_count);
|
||||
var file_list = new List<Entry>();
|
||||
foreach (var dir in dir_list)
|
||||
{
|
||||
dir_offset = dir.Offset;
|
||||
@@ -150,6 +157,8 @@ namespace GameRes.Formats.Lazycrew
|
||||
uint signature = arc.File.View.ReadUInt32 (entry.Offset);
|
||||
if (signature == 0x10000 || signature == 0)
|
||||
return OpenAudio (arc, entry);
|
||||
else if (signature == 1 || signature == 0x10001)
|
||||
return arc.File.CreateStream (entry.Offset+4, entry.Size-4);
|
||||
}
|
||||
return base.OpenEntry (arc, entry);
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.0.8.174")]
|
||||
[assembly: AssemblyFileVersion ("1.0.8.174")]
|
||||
[assembly: AssemblyVersion ("1.0.9.183")]
|
||||
[assembly: AssemblyFileVersion ("1.0.9.183")]
|
||||
|
||||
@@ -646,6 +646,7 @@ Signalist Stars!!<span class="footnote">ShiinaRio v2.50</span><br/>
|
||||
Son of a ☆ Bitch <span class="footnote">ShiinaRio v2.49</span><br/>
|
||||
Sorcery Jokers<span class="footnote">ShiinaRio v2.50</span><br/>
|
||||
Stage <span class="footnote">ShiinaRio v2.20</span><br/>
|
||||
Stellula Eques Codex ~Tasogare no Himekishi~ <span class="footnote">ShiinaRio v2.46</span><br/>
|
||||
Tanetsuke Mura <span class="footnote">ShiinaRio v2.48</span><br/>
|
||||
Tantei Shounen A<span class="footnote">some old version, like 2.twenty-something</span><br/>
|
||||
Tekoire Princess!<span class="footnote">ShiinaRio v2.37</span><br/>
|
||||
@@ -1519,6 +1520,7 @@ Kowaku no Toki<br/>
|
||||
Kuraibito<br/>
|
||||
Mahou Shoujo Nayuta<br/>
|
||||
Mouryou no Nie<br/>
|
||||
Mugen no Sakura ~Hitsuya-hime Injoku Youshokutan~<br/>
|
||||
Natsu Doki! Harem<br/>
|
||||
Natsu Koi!<br/>
|
||||
Naze ka Kanojo ga Boku ni Ecchi o Sematte Kuru Ken<br/>
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<GARbro>
|
||||
<Release>
|
||||
<Version>1.5.42</Version>
|
||||
<Version>1.5.43</Version>
|
||||
<Url>https://github.com/morkt/GARbro/releases/latest</Url>
|
||||
<Notes>New formats:
|
||||
- LNK archives, PRT images and WAF audio
|
||||
- MCG images and KOE audio
|
||||
- 'AsuraPak' archives and MTG images
|
||||
- GHP2 images
|
||||
- NPP archives
|
||||
- SWF containers
|
||||
- FL2 archives and WV1 audio
|
||||
- TIC and TIM images
|
||||
- SCP images
|
||||
- updated KiriKiri and ShiinaRio encryption schemes
|
||||
- CSAF archives
|
||||
- CPC archives, ERP images and EZS audio
|
||||
- GP1 images and PWV audio
|
||||
- CGD images and ASD archives
|
||||
- ANI animation frames
|
||||
- IPT composite images
|
||||
- ZLK archives
|
||||
- LPG images
|
||||
- RAD images
|
||||
- NPF archives
|
||||
- BIN+IDX archives
|
||||
|
||||
Updated KiriKiri and ShiinaRio encryption schemes.
|
||||
</Notes>
|
||||
</Release>
|
||||
<FormatsData>
|
||||
<FileVersion>141</FileVersion>
|
||||
<FileVersion>142</FileVersion>
|
||||
<Url>https://github.com/morkt/GARbro/raw/master/ArcFormats/Resources/Formats.dat</Url>
|
||||
<Requires>
|
||||
<Assembly Name="ArcFormats" Version="1.2.46.2120"/>
|
||||
<Assembly Name="GameRes" Version="1.4.26.238"/>
|
||||
</Requires>
|
||||
</FormatsData>
|
||||
<FormatsData>
|
||||
<FileVersion>141</FileVersion>
|
||||
<Url>https://github.com/morkt/GARbro/raw/bc315942658151c3c8d28d7976734422f87631da/ArcFormats/Resources/Formats.dat</Url>
|
||||
<Requires>
|
||||
<Assembly Name="ArcFormats" Version="1.2.44.2064"/>
|
||||
<Assembly Name="GameRes" Version="1.4.26.238"/>
|
||||
|
||||
Reference in New Issue
Block a user