Compare commits

...

15 Commits

Author SHA1 Message Date
morkt
c609792416 released v1.5.43 2019-02-25 13:45:11 +04:00
morkt
e3ddab124a (Lazycrew): alt archive naming scheme. 2019-02-25 13:07:15 +04:00
morkt
1c26c0a856 (IPT): support transparent 'cut' images. 2019-02-25 13:06:27 +04:00
morkt
5fd5a9a44c (Pulltop): unpack PSP files. 2019-02-25 13:05:58 +04:00
morkt
87fa5a3024 implemented BIN+IDX archives. 2019-02-25 13:04:47 +04:00
morkt
26eb42ee1d (PCK): 1280x720 textures handling. 2019-02-25 13:04:02 +04:00
morkt
e70251d304 (DAT/SAKURA): additional sanity check. 2019-02-25 13:02:49 +04:00
morkt
72452d664a (SCN): recongize zlib compression. 2019-02-25 12:57:23 +04:00
morkt
aadb48a7dc (MC): header check. 2019-02-25 12:56:22 +04:00
morkt
f79be94cde (EPA): support 16bpp images. 2019-02-25 12:56:04 +04:00
morkt
006004f170 (SWF): support BitsJpeg2 chunks. 2019-02-25 12:55:46 +04:00
morkt
91390fb69c (InKyouParser): updated. 2019-02-25 12:55:00 +04:00
morkt
69c60b0202 (PFS): added contained formats. 2019-02-25 12:54:31 +04:00
morkt
f452605e54 implemented NPF archives. 2019-02-25 12:54:18 +04:00
morkt
96d113115b (DxLib): support version 7 encryption. 2019-02-02 04:56:00 +04:00
24 changed files with 842 additions and 136 deletions

View File

@@ -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" />

View File

@@ -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 };
}

View File

@@ -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";
}
}

View File

@@ -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
View 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.");
}
}
}

View File

@@ -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
View 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;
}
}
}

View File

@@ -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;

View File

@@ -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")]

View File

Binary file not shown.

View File

@@ -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))

View File

@@ -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();
}
}

View File

@@ -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)

View File

@@ -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
View 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);
}
}
}

View File

@@ -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 { }
}

View File

@@ -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;

View File

@@ -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")]

View File

@@ -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")]

View File

@@ -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")]

View File

@@ -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);
}

View File

@@ -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")]

View File

@@ -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/>

View File

@@ -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"/>