Compare commits

...

12 Commits

Author SHA1 Message Date
morkt
118504e620 released v1.5.35 2018-02-16 20:09:58 +04:00
morkt
a3f4d7bcc8 (TextureFormat): added BC7. 2018-02-16 20:07:03 +04:00
morkt
41a81c63f2 (Legacy): implemented CPN archives. 2018-02-16 19:47:52 +04:00
morkt
a249a664d3 (CFP): implemented REB2 images. 2018-02-16 19:44:20 +04:00
morkt
c68a04586b (DatOpener): fixed entry flags setting, tweaked logging. 2018-02-16 19:41:15 +04:00
morkt
0661f12b6b (ACV): rely on base class. 2018-02-16 19:34:56 +04:00
morkt
34fce4538a (XP3): lookup game files in parent directory. 2018-02-16 19:33:33 +04:00
morkt
e09d5ae5df (Ail): detect audio and video files. 2018-02-16 19:32:41 +04:00
morkt
787cc68192 (Legacy): implemented BIZ images. 2018-02-12 10:42:38 +04:00
morkt
431d6c937f (CRXD): return base image when diff is empty. 2018-02-12 10:38:26 +04:00
morkt
653c26b2ce (CRX): unnecessary dithering (#156) 2018-02-12 10:33:40 +04:00
morkt
43fc625d81 (YPF): detect archives embedded into EXE files. 2018-02-11 10:50:09 +04:00
25 changed files with 368 additions and 153 deletions

View File

@@ -116,7 +116,7 @@ namespace GameRes.Formats.Ail
entry.IsPacked = true;
entry.UnpackedSize = file.View.ReadUInt32 (entry.Offset+2);
}
else if (0 == signature)
else if (0 == signature || file.View.AsciiEqual (entry.Offset+4, "OggS"))
{
extra = 4;
}
@@ -142,9 +142,17 @@ namespace GameRes.Formats.Ail
static void SetEntryType (Entry entry, uint signature)
{
var res = AutoEntry.DetectFileType (signature);
if (null != res)
entry.ChangeType (res);
if (0xBA010000 == signature)
{
entry.Type = "video";
entry.Name = Path.ChangeExtension (entry.Name, "mpg");
}
else
{
var res = AutoEntry.DetectFileType (signature);
if (null != res)
entry.ChangeType (res);
}
}
/// <summary>

View File

@@ -172,88 +172,21 @@ namespace GameRes.Formats.Circus
int line = 0;
for (int h = 0; h < m_height; h++)
{
int shift = (h & 1) * 3;
for (int w = 0; w < m_width; w++)
{
int pixel = line + w * 4;
int alpha = m_output[pixel];
int b = m_output[pixel+1];
int g = m_output[pixel+2];
int r = m_output[pixel+3];
if (!is_diff && alpha != alpha_flip)
{
b += (w & 1) + shift;
if (b < 0)
b = 0;
else if (b > 0xff)
b = 0xff;
g += (w & 1) + shift;
if (g < 0)
g = 0;
else if (g > 0xff)
g = 0xff;
r += (w & 1) + shift;
if (r < 0)
r = 0;
else if (r > 0xff)
r = 0xff;
}
m_output[pixel] = (byte)b;
m_output[pixel+1] = (byte)g;
m_output[pixel+2] = (byte)r;
var alpha = m_output[pixel];
var b = m_output[pixel+1];
var g = m_output[pixel+2];
var r = m_output[pixel+3];
m_output[pixel] = b;
m_output[pixel+1] = g;
m_output[pixel+2] = r;
m_output[pixel+3] = (byte)(alpha ^ alpha_flip);
shift = -shift;
}
line += m_stride;
}
}
else if (24 == m_bpp)
{
int pixel = 0;
for (int h = 0; h < m_height; h++)
{
int shift = (h & 1) * 3;
for (int w = 0; w < m_width; w++)
{
int b = m_output[pixel];
int g = m_output[pixel+1];
int r = m_output[pixel+2];
if (b != 0xff || 0 != g || r != b)
{
b += (w & 1) + shift;
if (b < 0)
b = 0;
else if (b > 0xff)
b = 0xff;
g += (w & 1) + shift;
if (g < 0)
g = 0;
else if (g > 0xff)
g = 0xff;
r += (w & 1) + shift;
if (r < 0)
r = 0;
else if (r > 0xff)
r = 0xff;
m_output[pixel] = (byte)b;
m_output[pixel+1] = (byte)g;
m_output[pixel+2] = (byte)r;
}
shift = -shift;
pixel += 3;
}
}
}
}
private void UnpackV1 ()

View File

@@ -151,7 +151,7 @@ namespace GameRes.Formats.Circus
(int)base_info.Width, (int)base_info.Height);
diff_rect = Rectangle.Intersect (diff_rect, base_rect);
if (diff_rect.IsEmpty)
throw new InvalidFormatException ("Empty diff region");
return ImageData.Create (base_info, reader.Format, reader.Palette, reader.Data, reader.Stride);
int pixel_size = base_info.BPP / 8;
int x = diff_rect.X - base_rect.X;

View File

@@ -661,6 +661,8 @@ NextEntry:
ICrypt GuessCryptAlgorithm (ArcView file)
{
var title = FormatCatalog.Instance.LookupGame (file.Name);
if (string.IsNullOrEmpty (title))
title = FormatCatalog.Instance.LookupGame (file.Name, @"..\*.exe");
if (string.IsNullOrEmpty (title))
return null;
ICrypt algorithm;

View File

@@ -23,12 +23,7 @@
// IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using GameRes.Compression;
using GameRes.Utility;
namespace GameRes.Formats.NonColor
{
@@ -65,29 +60,8 @@ namespace GameRes.Formats.NonColor
var dir = index.Read (file_map);
if (null == dir)
return null;
if (is_script)
{
foreach (ArcDatEntry entry in dir)
entry.Hash ^= scheme.Hash;
}
return new ArcFile (file, this, dir);
return new ArcDatArchive (file, this, dir, scheme.Hash);
}
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
var dent = entry as ArcDatEntry;
if (null == dent || 0 == dent.Size)
return arc.File.CreateStream (entry.Offset, entry.Size);
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
if (dent.IsPacked)
{
DecryptData (data, (uint)dent.Hash);
return new ZLibStream (new MemoryStream (data), CompressionMode.Decompress);
}
if (dent.RawName != null && 0 != dent.Flags)
DecryptWithName (data, dent.RawName);
return new BinMemoryStream (data, entry.Name);
}
}
}

View File

@@ -133,10 +133,10 @@ namespace GameRes.Formats.NonColor
{
var darc = arc as ArcDatArchive;
var dent = entry as ArcDatEntry;
if (null == darc || null == dent || 0 == dent.Flags || 0 == dent.Size)
if (null == darc || null == dent || 0 == dent.Size)
return base.OpenEntry (arc, entry);
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
if (2 == dent.Flags)
if (dent.IsPacked)
{
if (darc.MasterKey != 0)
DecryptData (data, (uint)(dent.Hash ^ darc.MasterKey));
@@ -235,12 +235,14 @@ namespace GameRes.Formats.NonColor
}
}
public static Dictionary<string, Scheme> KnownSchemes = new Dictionary<string, Scheme>();
static ArcDatScheme DefaultScheme = new ArcDatScheme { KnownSchemes = new Dictionary<string, Scheme>() };
public static Dictionary<string, Scheme> KnownSchemes { get { return DefaultScheme.KnownSchemes; } }
public override ResourceScheme Scheme
{
get { return new ArcDatScheme { KnownSchemes = KnownSchemes }; }
set { KnownSchemes = ((ArcDatScheme)value).KnownSchemes; }
get { return DefaultScheme; }
set { DefaultScheme = (ArcDatScheme)value; }
}
internal Scheme QueryScheme (string arc_name)
@@ -287,7 +289,7 @@ namespace GameRes.Formats.NonColor
public List<Entry> Read (IDictionary<ulong, NameRecord> file_map)
{
int skipped = 0;
int skipped = 0, last_reported = -1;
string last_name = null;
m_input.Position = IndexPosition;
for (int i = 0; i < m_count; ++i)
@@ -304,7 +306,7 @@ namespace GameRes.Formats.NonColor
{
if (null == known_rec.Name)
{
if (last_name != null)
if (last_name != null && last_reported != i-1)
Trace.WriteLine (string.Format ("[{0}] {1}", i-1, last_name), "[noncolor]");
Trace.WriteLine (string.Format ("[{0}] Unknown hash {1:X8}", i, entry.Hash), "[noncolor]");
last_name = null;
@@ -315,7 +317,10 @@ namespace GameRes.Formats.NonColor
{
var raw_name = known_rec.NameBytes;
if (null == last_name && i > 0)
{
Trace.WriteLine (string.Format ("[{0}] {1}", i, known_rec.Name), "[noncolor]");
last_reported = i;
}
entry.Offset ^= raw_name[raw_name.Length >> 1];
entry.Size ^= raw_name[raw_name.Length >> 2];
entry.UnpackedSize ^= raw_name[raw_name.Length >> 3];
@@ -369,6 +374,7 @@ namespace GameRes.Formats.NonColor
int flags = m_input.ReadByte() ^ (byte)hash;
return new ArcDatEntry {
Hash = hash,
Flags = flags,
Offset = m_input.ReadUInt32() ^ (uint)hash ^ m_master_key,
Size = m_input.ReadUInt32() ^ (uint)hash,
UnpackedSize = m_input.ReadUInt32() ^ (uint)hash,

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.38.1650")]
[assembly: AssemblyFileVersion ("1.2.38.1650")]
[assembly: AssemblyVersion ("1.2.39.1685")]
[assembly: AssemblyFileVersion ("1.2.39.1685")]

View File

Binary file not shown.

View File

@@ -48,12 +48,13 @@ namespace GameRes.Formats.Tail
public override ImageData Read (IBinaryStream file, ImageMetaData info)
{
file.Position = 0x1C;
int stride = ((int)info.Width * 3 + 3) & -4;
int width = ((int)info.Width + 1) & -2;
int height = (int)info.Height;
int total = width * height;
var input = file.ReadBytes (total * 3);
int packed_size = total * 3;
file.Position = file.Length - packed_size;
var input = file.ReadBytes (packed_size);
var pixels = new byte[stride*height];
int src1 = 0;
int src2 = total / 2;
@@ -83,4 +84,66 @@ namespace GameRes.Formats.Tail
throw new System.NotImplementedException ("CfpFormat.Write not implemented");
}
}
internal class CfpMetaData : ImageMetaData
{
public int DataOffset;
}
[Export(typeof(ImageFormat))]
public class Cfp2Format : ImageFormat
{
public override string Tag { get { return "CFP/REB2"; } }
public override string Description { get { return "Tail transparent bitmap"; } }
public override uint Signature { get { return 0x32424552; } } // 'REB2'
public override ImageMetaData ReadMetaData (IBinaryStream file)
{
var header = file.ReadHeader (0x20);
int start_pos = header.ToInt32 (0x10);
int extra_length = header.ToInt32 (0x1C);
if (start_pos < 0x36)
return null;
return new CfpMetaData {
Width = header.ToUInt32 (0x14),
Height = header.ToUInt32 (0x18),
BPP = 32,
DataOffset = 0x20 + extra_length,
};
}
public override ImageData Read (IBinaryStream file, ImageMetaData info)
{
var meta = (CfpMetaData)info;
int width = (int)meta.Width;
int height = (int)meta.Height;
int stride = width * 4;
int total = width * height;
int packed_size = total * 4;
file.Position = meta.DataOffset;
var pixels = new byte[stride*height];
var input = file.ReadBytes (packed_size);
int b = 0;
int g = total;
int r = total * 2;
int a = total * 3;
for (int dst_row = stride * (height - 1); dst_row >= 0; dst_row -= stride)
{
int dst = dst_row;
for (int x = 0; x < width; ++x)
{
pixels[dst++] = input[b++];
pixels[dst++] = input[g++];
pixels[dst++] = input[r++];
pixels[dst++] = input[a++];
}
}
return ImageData.Create (info, PixelFormats.Bgra32, null, pixels, stride);
}
public override void Write (Stream file, ImageData image)
{
throw new System.NotImplementedException ("Cfp2Format.Write not implemented");
}
}
}

View File

@@ -44,6 +44,7 @@ namespace GameRes.Formats.Unity
DXT5 = 12,
RGBA4444 = 13,
BGRA32 = 14,
BC7 = 25,
DXT1Crunched = 28,
DXT5Crunched = 29,
}

View File

@@ -2,7 +2,7 @@
//! \date Mon Jul 14 14:40:06 2014
//! \brief YPF resource format implementation.
//
// Copyright (C) 2014-2015 by morkt
// Copyright (C) 2014-2018 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
@@ -103,27 +103,42 @@ namespace GameRes.Formats.YuRis
public override bool IsHierarchic { get { return true; } }
public override bool CanWrite { get { return true; } }
static public Dictionary<string, YpfScheme> KnownSchemes = new Dictionary<string, YpfScheme>();
public YpfOpener ()
{
Signatures = new uint[] { 0x00465059, 0 };
}
static public Dictionary<string, YpfScheme> KnownSchemes { get { return DefaultScheme.KnownSchemes; } }
static YuRisScheme DefaultScheme = new YuRisScheme { KnownSchemes = new Dictionary<string, YpfScheme>() };
public override ResourceScheme Scheme
{
get { return new YuRisScheme { KnownSchemes = KnownSchemes }; }
set { KnownSchemes = ((YuRisScheme)value).KnownSchemes; }
get { return DefaultScheme; }
set { DefaultScheme = (YuRisScheme)value; }
}
public override ArcFile TryOpen (ArcView file)
{
uint version = file.View.ReadUInt32 (4);
uint count = file.View.ReadUInt32 (8);
uint dir_size = file.View.ReadUInt32 (12);
if (dir_size < count * 0x17 || count > 0xfffff)
long ypf_offset = 0;
if (file.View.AsciiEqual (0, "MZ"))
{
ypf_offset = FindYser (file);
}
if (!file.View.AsciiEqual (ypf_offset, "YPF\0"))
return null;
if (dir_size > file.View.Reserve (0x20, dir_size))
uint version = file.View.ReadUInt32 (ypf_offset+4);
int count = file.View.ReadInt32 (ypf_offset+8);
uint dir_size = file.View.ReadUInt32 (ypf_offset+12);
if (!IsSaneCount (count) || dir_size < count * 0x17)
return null;
if (dir_size > file.View.Reserve (ypf_offset+0x20, dir_size))
return null;
var parser = new Parser (file, version, count, dir_size);
var scheme = QueryEncryptionScheme (file.Name, version);
var dir = parser.ScanDir (scheme);
var dir = parser.ScanDir (scheme, ypf_offset);
if (null == dir || 0 == dir.Count)
return null;
@@ -192,6 +207,16 @@ namespace GameRes.Formats.YuRis
return scheme;
}
internal long FindYser (ArcView file)
{
var exe = new ExeFile (file);
var offset = exe.FindAsciiString (exe.Overlay, "YSER", 0x10);
if (-1 == offset)
return 0;
uint header_size = file.View.ReadUInt32 (offset+4);
return offset + header_size;
}
delegate uint ChecksumFunc (byte[] data);
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
@@ -358,7 +383,7 @@ namespace GameRes.Formats.YuRis
uint* header = (uint*)raw;
uint version = header[1];
int first_item, last_item;
if (version >= 0x1CE || 0x12C == version || 0x19A == version)
if (version >= 0x1CE || 0x12C == version || 0x19A == version || 0x1C3 == version)
{
first_item = 3;
last_item = 7;
@@ -404,10 +429,10 @@ namespace GameRes.Formats.YuRis
{
ArcView m_file;
uint m_version;
uint m_count;
int m_count;
uint m_dir_size;
public Parser (ArcView file, uint version, uint count, uint dir_size)
public Parser (ArcView file, uint version, int count, uint dir_size)
{
m_file = file;
m_count = count;
@@ -417,15 +442,15 @@ namespace GameRes.Formats.YuRis
// int32-name_checksum, byte-name_count, *-name, byte-file_type
// byte-pack_flag, int32-size, int32-packed_size, int32-offset, int32-file_checksum
public List<Entry> ScanDir (YpfScheme scheme)
public List<Entry> ScanDir (YpfScheme scheme, long base_offset = 0)
{
uint dir_offset = 0x20;
long dir_offset = base_offset + 0x20;
uint dir_remaining = m_dir_size;
var dir = new List<Entry> ((int)m_count);
var dir = new List<Entry> (m_count);
byte key = scheme.Key;
bool guess_key = scheme.GuessKey;
uint extra_size = 0x12 + scheme.ExtraHeaderSize;
for (uint num = 0; num < m_count; ++num)
for (int num = 0; num < m_count; ++num)
{
if (dir_remaining < 5+extra_size)
return null;
@@ -482,7 +507,7 @@ namespace GameRes.Formats.YuRis
entry.IsPacked = 0 != m_file.View.ReadByte (dir_offset+1);
entry.UnpackedSize = m_file.View.ReadUInt32 (dir_offset+2);
entry.Size = m_file.View.ReadUInt32 (dir_offset+6);
entry.Offset = m_file.View.ReadUInt32 (dir_offset+10);
entry.Offset = m_file.View.ReadUInt32 (dir_offset+10) + base_offset;
if (entry.CheckPlacement (m_file.MaxOffset))
dir.Add (entry);
dir_offset += extra_size;

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.9.29")]
[assembly: AssemblyFileVersion ("1.0.9.29")]
[assembly: AssemblyVersion ("1.0.10.30")]
[assembly: AssemblyFileVersion ("1.0.10.30")]

View File

@@ -67,6 +67,8 @@ Section "install"
File "${RELEASE_DIR}\NAudio.dll"
File "${RELEASE_DIR}\NVorbis.dll"
File "${RELEASE_DIR}\System.Data.SQLite.dll"
File "${RELEASE_DIR}\System.IO.FileSystem.dll"
File "${RELEASE_DIR}\System.Security.Cryptography.Primitives.dll"
File "${RELEASE_DIR}\System.Windows.Controls.Input.Toolkit.dll"
File "${RELEASE_DIR}\WPFToolkit.dll"
File "${RELEASE_DIR}\README.txt"
@@ -74,6 +76,7 @@ Section "install"
File "${RELEASE_DIR}\supported.html"
!insertmacro InstallSubDir GameData
!insertmacro InstallSubDir ja-JP
!insertmacro InstallSubDir ko-KR
!insertmacro InstallSubDir ru-RU
!insertmacro InstallSubDir zh-Hans
@@ -122,6 +125,8 @@ Section "uninstall"
Delete $INSTDIR\NAudio.dll
Delete $INSTDIR\NVorbis.dll
Delete $INSTDIR\System.Data.SQLite.dll
Delete $INSTDIR\System.IO.FileSystem.dll
Delete $INSTDIR\System.Security.Cryptography.Primitives.dll
Delete $INSTDIR\System.Windows.Controls.Input.Toolkit.dll
Delete $INSTDIR\WPFToolkit.dll
Delete $INSTDIR\README.txt
@@ -129,6 +134,7 @@ Section "uninstall"
Delete $INSTDIR\supported.html
Delete $INSTDIR\uninstall.exe
RMDir /r $INSTDIR\GameData
RMDir /r $INSTDIR\ja-JP
RMDir /r $INSTDIR\ko-KR
RMDir /r $INSTDIR\ru-RU
RMDir /r $INSTDIR\zh-Hans

View File

@@ -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.34.2195")]
[assembly: AssemblyFileVersion ("1.5.34.2195")]
[assembly: AssemblyVersion ("1.5.35.2260")]
[assembly: AssemblyFileVersion ("1.5.35.2260")]

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.35.281")]
[assembly: AssemblyFileVersion ("1.5.35.281")]
[assembly: AssemblyVersion ("1.5.36.286")]
[assembly: AssemblyFileVersion ("1.5.36.286")]

View File

@@ -27,6 +27,8 @@ using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
// [000623][Marimo] Setsunai
namespace GameRes.Formats.Dice
{
[Export(typeof(ArchiveFormat))]

View File

@@ -83,10 +83,12 @@
<Compile Include="Iris\ArcFPACK.cs" />
<Compile Include="Jupiter\ArcLB5.cs" />
<Compile Include="Lune\ArcPACK.cs" />
<Compile Include="Marron\ArcCPN.cs" />
<Compile Include="Mina\ArcML2.cs" />
<Compile Include="Mina\ImageMD.cs" />
<Compile Include="Mink\ArcMINK.cs" />
<Compile Include="Mutation\ArcDPF.cs" />
<Compile Include="Sorciere\ImageBIZ.cs" />
<Compile Include="Uncanny\AudioCWV.cs" />
<Compile Include="Uncanny\ImageCII.cs" />
<Compile Include="Kurumi\ArcMPK.cs" />

108
Legacy/Marron/ArcCPN.cs Normal file
View File

@@ -0,0 +1,108 @@
//! \file ArcCPN.cs
//! \date 2018 Feb 14
//! \brief Marron resource archive.
//
// Copyright (C) 2018 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Text.RegularExpressions;
// [010727][Marron] Cosmos no Sora ni
namespace GameRes.Formats.Marron
{
internal class CpnArchive : ArcFile
{
public readonly byte Key;
public CpnArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, byte key)
: base (arc, impl, dir)
{
Key = key;
}
}
[Export(typeof(ArchiveFormat))]
public class DatOpener : ArchiveFormat
{
public override string Tag { get { return "DAT/CPN"; } }
public override string Description { get { return "Marron resource archive"; } }
public override uint Signature { get { return 0; } }
public override bool IsHierarchic { get { return true; } }
public override bool CanWrite { get { return false; } }
static readonly Regex CpnEntryRe = new Regex (@"#(?:\./)?(?<name>[^$]+)\$(?<offset>\d+)\*(?<size>\d+)\+");
public override ArcFile TryOpen (ArcView file)
{
if (!file.Name.HasExtension (".dat"))
return null;
var cpn_name = Path.ChangeExtension (file.Name, ".cpn");
if (!VFS.FileExists (cpn_name))
return null;
byte key;
string cpn_index;
using (var cpn = VFS.OpenView (cpn_name))
{
key = cpn.View.ReadByte (0);
var cpn_data = cpn.View.ReadBytes (1, (uint)(cpn.MaxOffset - 1));
for (int i = 0; i < cpn_data.Length; ++i)
cpn_data[i] ^= key;
cpn_index = Encodings.cp932.GetString (cpn_data);
}
int idx = cpn_index.IndexOf ('#', 1);
if (idx <= 1)
return null;
var data_name = cpn_index.Substring (1, idx-1);
if (!VFS.IsPathEqualsToFileName (file.Name, data_name))
return null;
var dir = new List<Entry>();
var match = CpnEntryRe.Match (cpn_index, idx);
while (match.Success)
{
var name = match.Groups["name"].Value;
var entry = FormatCatalog.Instance.Create<Entry> (name);
entry.Offset = UInt32.Parse (match.Groups["offset"].Value);
entry.Size = UInt32.Parse (match.Groups["size"].Value);
if (!entry.CheckPlacement (file.MaxOffset))
return null;
dir.Add (entry);
match = match.NextMatch();
}
if (0 == dir.Count)
return null;
return new CpnArchive (file, this, dir, key);
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
var input = arc.File.CreateStream (entry.Offset, entry.Size);
var carc = arc as CpnArchive;
if (null == carc)
return input;
return new XoredStream (input, carc.Key);
}
}
}

View File

@@ -26,6 +26,8 @@
using System.ComponentModel.Composition;
using System.IO;
// [000225][Mink] Wonpara Wars
namespace GameRes.Formats.Mink
{
[Export(typeof(ImageFormat))]

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.1.41")]
[assembly: AssemblyFileVersion ("1.0.1.41")]
[assembly: AssemblyVersion ("1.0.2.49")]
[assembly: AssemblyFileVersion ("1.0.2.49")]

View File

@@ -0,0 +1,70 @@
//! \file ImageBIZ.cs
//! \date 2018 Feb 11
//! \brief Sorciere compressed image.
//
// Copyright (C) 2018 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System.ComponentModel.Composition;
using System.IO;
using System.Windows.Media;
using GameRes.Compression;
// [000225][Sorciere] Karei
namespace GameRes.Formats.Sorciere
{
[Export(typeof(ImageFormat))]
public class BizFormat : ImageFormat
{
public override string Tag { get { return "BIZ"; } }
public override string Description { get { return "Sorciere compressed image"; } }
public override uint Signature { get { return 0x325A4942; } } // 'BIZ2'
public override ImageMetaData ReadMetaData (IBinaryStream file)
{
var header = file.ReadHeader (8);
return new ImageMetaData {
Width = header.ToUInt16 (4),
Height = header.ToUInt16 (6),
BPP = 24,
};
}
public override ImageData Read (IBinaryStream file, ImageMetaData info)
{
file.Position = 8;
using (var input = new LzssStream (file.AsStream, LzssMode.Decompress, true))
{
int stride = (int)info.Width * 3;
var pixels = new byte[stride * (int)info.Height];
if (pixels.Length != input.Read (pixels, 0, pixels.Length))
throw new InvalidFormatException();
return ImageData.CreateFlipped (info, PixelFormats.Bgr24, null, pixels, stride);
}
}
public override void Write (Stream file, ImageData image)
{
throw new System.NotImplementedException ("BizFormat.Write not implemented");
}
}
}

View File

@@ -28,6 +28,8 @@ using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
// [000114][Excellents] Thanksgiving Special
namespace GameRes.Formats.System21
{
[Export(typeof(ArchiveFormat))]

View File

@@ -29,6 +29,8 @@ using System.ComponentModel.Composition;
using System.IO;
using GameRes.Compression;
// [000224][Uran] P.S. 3 ~Harem Night~
namespace GameRes.Formats.Uran
{
internal class NclEntry : PackedEntry

View File

@@ -368,6 +368,7 @@ Senren*Banka<br/>
Serifu de Kanjite! Seiyuu Doushi<br/>
Sharin no Kuni, Himawari no Shoujo<br/>
Shokusai no Miyako<br/>
Shoujo to Toshi no Sa, Futamawari.<br/>
Shugaten! -sugarfull tempering-<br/>
Sis Koi<br/>
Smile Cubic!<br/>
@@ -532,6 +533,7 @@ Bitch Shimai ga Seijun na Hazu ga Nai!! <span class="footnote">ShiinaRio v2.50</
Bitch Gakuen ga Seijun na Hazu ga Nai!!? <span class="footnote">ShiinaRio v2.50</span><br/>
Calendar Girl <span class="footnote">ShiinaRio v2.02</span><br/>
Can Fes! ~Itazura Majo to Naisho no Gakuensai~ <span class="footnote">ShiinaRio v2.47</span><br/>
CC Hospital <span class="footnote">ShiinaRio v2.36</span><br/>
Chiccha na Hanayome ~Mada Mada Tsubomi da mon~ <span class="footnote">ShiinaRio v2.50</span><br/>
Chikan Circle <span class="footnote">ShiinaRio v2.46</span><br/>
Chikan Circle 2 <span class="footnote">ShiinaRio v2.47</span><br/>
@@ -588,6 +590,7 @@ Saimin Seikatsu ~Kousoku Dakara Shikatanai!?~ <span class="footnote">ShiinaRio v
Shinigami no Testament <span class="footnote">ShiinaRio v2.49</span><br/>
Shinseki no Oba-san ~Hanare no Netsujo, Honke no Gosai~ <span class="footnote">ShiinaRio v2.36</span><br/>
Shojo Mama<span class="footnote">ShiinaRio v2.49</span><br/>
Shokuinshitsu <span class="footnote">ShiinaRio v2.46</span><br/>
Signalist Stars!!<span class="footnote">ShiinaRio v2.50</span><br/>
Sorcery Jokers<span class="footnote">ShiinaRio v2.50</span><br/>
Stage <span class="footnote">ShiinaRio v2.20</span><br/>
@@ -1661,6 +1664,7 @@ femme fatale<br/>
</td></tr>
<tr><td>*.cdt<br/>*.pdt<br/>*.vdt<br/>*.ovd</td><td><tt>RK1</tt></td><td></td><td rowspan="2">NEJII</td><td rowspan="2">
Kidou Houshinki<br/>
Soeur ~Shibarareru Ai, Chiriyuku Ai~<br/>
Sutadoru!<br/>
</td></tr>
<tr class="last"><td>*.pcd</td><td>-</td><td></td></tr>
@@ -1803,6 +1807,11 @@ Yumemishi<br/>
<tr class="odd"><td>*.pak</td><td><tt>MD002</tt></td><td></td><td>ADVScripter</td><td>
Pinku no Ayumi!<br/>
</td></tr>
<tr><td>*.caf</td><td><tt>CAF0</tt></td><td></td><td rowspan="2">Raccoon<br/>Tail</td><td rowspan="2">
Koijibashi<br/>
Rimlet<br/>
</td></tr>
<tr class="last"><td>*.cfp</td><td><tt>REP</tt><br/><tt>REP2</tt></td><td></td></tr>
</table>
<p><a name="note-1" class="footnote">1</a> Non-encrypted only</p>
</body>

View File

@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<GARbro>
<Release>
<Version>1.5.34</Version>
<Version>1.5.35</Version>
<Url>https://github.com/morkt/GARbro/releases/latest</Url>
<Notes>Lifted .Net framework requirement up to v4.6.
Added GUI preferences window.
<Notes>Added Japanese translation.
New formats:
- DAI_SYSTEM archives
- PCG archives
- LAX archives and 'CLS_TEXFILE' images
- TPF archives
- DREF images
- DDS DXT3 textures
- PACK archives and OPF images
- MD002 archives
- More KiriKiri and ShiinaRio encryption schemes
Additions:
- optionally fix checksums of OGG audio files
- query password for encrypted ZIP files
</Notes>
</Release>
<FormatsData>
@@ -40,7 +40,7 @@ New formats:
</Requires>
</FormatsData>
<FormatsData>
<FileVersion>104</FileVersion>
<FileVersion>105</FileVersion>
<Url>https://github.com/morkt/GARbro/raw/master/ArcFormats/Resources/Formats.dat</Url>
<Requires>
<Assembly Name="ArcFormats" Version="1.2.38.1669"/>