mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 05:35:34 +08:00
reorganized project directory structure.
This commit is contained in:
parent
dd2c19c8c1
commit
b05c253e8b
@ -1,515 +1,436 @@
|
||||
//! \file ArcAMI.cs
|
||||
//! \date Thu Jul 03 09:40:40 2014
|
||||
//! \brief Muv-Luv Amaterasu Translation archive.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Formats.Strings;
|
||||
using GameRes.Formats.Properties;
|
||||
|
||||
namespace GameRes.Formats
|
||||
{
|
||||
internal class AmiEntry : PackedEntry
|
||||
{
|
||||
public uint Id;
|
||||
|
||||
private Lazy<string> m_ext;
|
||||
private Lazy<string> m_name;
|
||||
private Lazy<string> m_type;
|
||||
public override string Name
|
||||
{
|
||||
get { return m_name.Value; }
|
||||
set { m_name = new Lazy<string> (() => value); }
|
||||
}
|
||||
public override string Type
|
||||
{
|
||||
get { return m_type.Value; }
|
||||
set { m_type = new Lazy<string> (() => value); }
|
||||
}
|
||||
|
||||
public AmiEntry (uint id, Func<string> ext_factory)
|
||||
{
|
||||
Id = id;
|
||||
m_ext = new Lazy<string> (ext_factory);
|
||||
m_name = new Lazy<string> (GetName);
|
||||
m_type = new Lazy<string> (GetEntryType);
|
||||
}
|
||||
|
||||
private string GetName ()
|
||||
{
|
||||
return string.Format ("{0:x8}.{1}", Id, m_ext.Value);
|
||||
}
|
||||
|
||||
private string GetEntryType ()
|
||||
{
|
||||
var ext = m_ext.Value;
|
||||
if ("grp" == ext)
|
||||
return "image";
|
||||
if ("scr" == ext)
|
||||
return "script";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
internal class AmiOptions : ResourceOptions
|
||||
{
|
||||
public bool UseBaseArchive;
|
||||
public string BaseArchive;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class AmiOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "AMI"; } }
|
||||
public override string Description { get { return Strings.arcStrings.AMIDescription; } }
|
||||
public override uint Signature { get { return 0x00494d41; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return true; } }
|
||||
|
||||
public AmiOpener ()
|
||||
{
|
||||
Extensions = new string[] { "ami", "amr" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (4);
|
||||
if (count <= 0)
|
||||
return null;
|
||||
uint base_offset = file.View.ReadUInt32 (8);
|
||||
long max_offset = file.MaxOffset;
|
||||
if (base_offset >= max_offset)
|
||||
return null;
|
||||
|
||||
uint cur_offset = 16;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (cur_offset+16 > base_offset)
|
||||
return null;
|
||||
uint id = file.View.ReadUInt32 (cur_offset);
|
||||
uint offset = file.View.ReadUInt32 (cur_offset+4);
|
||||
uint size = file.View.ReadUInt32 (cur_offset+8);
|
||||
uint packed_size = file.View.ReadUInt32 (cur_offset+12);
|
||||
|
||||
var entry = new AmiEntry (id, () => {
|
||||
uint signature = file.View.ReadUInt32 (offset);
|
||||
if (0x00524353 == signature)
|
||||
return "scr";
|
||||
else if (0 != packed_size || 0x00505247 == signature)
|
||||
return "grp";
|
||||
else
|
||||
return "dat";
|
||||
});
|
||||
|
||||
entry.Offset = offset;
|
||||
entry.UnpackedSize = size;
|
||||
entry.IsPacked = 0 != packed_size;
|
||||
entry.Size = entry.IsPacked ? packed_size : size;
|
||||
if (!entry.CheckPlacement (max_offset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
cur_offset += 16;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
var packed_entry = entry as AmiEntry;
|
||||
if (null == packed_entry || !packed_entry.IsPacked)
|
||||
return input;
|
||||
else
|
||||
return new ZLibStream (input, CompressionMode.Decompress);
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
EntryCallback callback)
|
||||
{
|
||||
ArcFile base_archive = null;
|
||||
var ami_options = GetOptions<AmiOptions> (options);
|
||||
if (null != ami_options && ami_options.UseBaseArchive && !string.IsNullOrEmpty (ami_options.BaseArchive))
|
||||
{
|
||||
var base_file = new ArcView (ami_options.BaseArchive);
|
||||
try
|
||||
{
|
||||
if (base_file.View.ReadUInt32(0) == Signature)
|
||||
base_archive = TryOpen (base_file);
|
||||
if (null == base_archive)
|
||||
throw new InvalidFormatException (string.Format ("{0}: base archive could not be read",
|
||||
Path.GetFileName (ami_options.BaseArchive)));
|
||||
base_file = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != base_file)
|
||||
base_file.Dispose();
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
var file_table = new SortedDictionary<uint, PackedEntry>();
|
||||
if (null != base_archive)
|
||||
{
|
||||
foreach (var entry in base_archive.Dir.Cast<AmiEntry>())
|
||||
file_table[entry.Id] = entry;
|
||||
}
|
||||
int update_count = UpdateFileTable (file_table, list);
|
||||
if (0 == update_count)
|
||||
throw new InvalidFormatException (arcStrings.AMINoFiles);
|
||||
|
||||
uint file_count = (uint)file_table.Count;
|
||||
if (null != callback)
|
||||
callback ((int)file_count+1, null, null);
|
||||
|
||||
int callback_count = 0;
|
||||
long start_offset = output.Position;
|
||||
uint data_offset = file_count * 16 + 16;
|
||||
output.Seek (data_offset, SeekOrigin.Current);
|
||||
foreach (var entry in file_table)
|
||||
{
|
||||
if (null != callback)
|
||||
callback (callback_count++, entry.Value, arcStrings.MsgAddingFile);
|
||||
long current_offset = output.Position;
|
||||
if (current_offset > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
if (entry.Value is AmiEntry)
|
||||
CopyAmiEntry (base_archive, entry.Value, output);
|
||||
else
|
||||
entry.Value.Size = WriteAmiEntry (entry.Value, output);
|
||||
entry.Value.Offset = (uint)current_offset;
|
||||
}
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||
output.Position = start_offset;
|
||||
using (var header = new BinaryWriter (output, Encoding.ASCII, true))
|
||||
{
|
||||
header.Write (Signature);
|
||||
header.Write (file_count);
|
||||
header.Write (data_offset);
|
||||
header.Write ((uint)0);
|
||||
foreach (var entry in file_table)
|
||||
{
|
||||
header.Write (entry.Key);
|
||||
header.Write ((uint)entry.Value.Offset);
|
||||
header.Write ((uint)entry.Value.UnpackedSize);
|
||||
header.Write ((uint)entry.Value.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != base_archive)
|
||||
base_archive.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
int UpdateFileTable (IDictionary<uint, PackedEntry> table, IEnumerable<Entry> list)
|
||||
{
|
||||
int update_count = 0;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
if (entry.Type != "image" && !entry.Name.EndsWith (".scr", StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
uint id;
|
||||
if (!uint.TryParse (Path.GetFileNameWithoutExtension (entry.Name), NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture, out id))
|
||||
continue;
|
||||
PackedEntry existing;
|
||||
if (table.TryGetValue (id, out existing) && !(existing is AmiEntry))
|
||||
{
|
||||
var file_new = new FileInfo (entry.Name);
|
||||
if (!file_new.Exists)
|
||||
continue;
|
||||
var file_old = new FileInfo (existing.Name);
|
||||
if (file_new.LastWriteTime <= file_old.LastWriteTime)
|
||||
continue;
|
||||
}
|
||||
table[id] = new PackedEntry
|
||||
{
|
||||
Name = entry.Name,
|
||||
Type = entry.Type
|
||||
};
|
||||
++update_count;
|
||||
}
|
||||
return update_count;
|
||||
}
|
||||
|
||||
void CopyAmiEntry (ArcFile base_archive, Entry entry, Stream output)
|
||||
{
|
||||
using (var input = base_archive.File.CreateStream (entry.Offset, entry.Size))
|
||||
input.CopyTo (output);
|
||||
}
|
||||
|
||||
uint WriteAmiEntry (PackedEntry entry, Stream output)
|
||||
{
|
||||
uint packed_size = 0;
|
||||
using (var input = File.OpenRead (entry.Name))
|
||||
{
|
||||
long file_size = input.Length;
|
||||
if (file_size > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
entry.UnpackedSize = (uint)file_size;
|
||||
if ("image" == entry.Type)
|
||||
{
|
||||
packed_size = WriteImageEntry (entry, input, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.CopyTo (output);
|
||||
}
|
||||
}
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
static Lazy<GrpFormat> s_grp_format = new Lazy<GrpFormat> (() =>
|
||||
FormatCatalog.Instance.ImageFormats.OfType<GrpFormat>().FirstOrDefault());
|
||||
|
||||
uint WriteImageEntry (PackedEntry entry, Stream input, Stream output)
|
||||
{
|
||||
var grp = s_grp_format.Value;
|
||||
if (null == grp) // probably never happens
|
||||
throw new FileFormatException ("GRP image encoder not available");
|
||||
bool is_grp = grp.Signature == FormatCatalog.ReadSignature (input);
|
||||
input.Position = 0;
|
||||
var start = output.Position;
|
||||
using (var zstream = new ZLibStream (output, CompressionMode.Compress, CompressionLevel.Level9, true))
|
||||
{
|
||||
if (is_grp)
|
||||
{
|
||||
input.CopyTo (zstream);
|
||||
}
|
||||
else
|
||||
{
|
||||
var image = ImageFormat.Read (input);
|
||||
if (null == image)
|
||||
throw new InvalidFormatException (string.Format (arcStrings.MsgInvalidImageFormat, entry.Name));
|
||||
grp.Write (zstream, image);
|
||||
entry.UnpackedSize = (uint)zstream.TotalIn;
|
||||
}
|
||||
}
|
||||
return (uint)(output.Position - start);
|
||||
}
|
||||
|
||||
public override ResourceOptions GetDefaultOptions ()
|
||||
{
|
||||
return new AmiOptions {
|
||||
UseBaseArchive = Settings.Default.AMIUseBaseArchive,
|
||||
BaseArchive = Settings.Default.AMIBaseArchive,
|
||||
};
|
||||
}
|
||||
|
||||
public override object GetCreationWidget ()
|
||||
{
|
||||
return new GUI.CreateAMIWidget();
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class GrpFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "GRP"; } }
|
||||
public override string Description { get { return Strings.arcStrings.GRPDescription; } }
|
||||
public override uint Signature { get { return 0x00505247; } }
|
||||
|
||||
public override ImageMetaData ReadMetaData (Stream stream)
|
||||
{
|
||||
using (var file = new BinaryReader (stream, Encoding.ASCII, true))
|
||||
{
|
||||
if (file.ReadUInt32() != Signature)
|
||||
return null;
|
||||
var meta = new ImageMetaData();
|
||||
meta.OffsetX = file.ReadInt16();
|
||||
meta.OffsetY = file.ReadInt16();
|
||||
meta.Width = file.ReadUInt16();
|
||||
meta.Height = file.ReadUInt16();
|
||||
meta.BPP = 32;
|
||||
stream.Position = 0;
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
|
||||
public override ImageData Read (Stream file, ImageMetaData info)
|
||||
{
|
||||
int width = (int)info.Width;
|
||||
int height = (int)info.Height;
|
||||
int stride = width*4;
|
||||
byte[] pixels = new byte[stride*height];
|
||||
file.Position = 12;
|
||||
for (int row = height-1; row >= 0; --row)
|
||||
{
|
||||
if (stride != file.Read (pixels, row*stride, stride))
|
||||
throw new InvalidFormatException();
|
||||
}
|
||||
var bitmap = BitmapSource.Create (width, height, 96, 96,
|
||||
PixelFormats.Bgra32, null, pixels, stride);
|
||||
bitmap.Freeze();
|
||||
|
||||
return new ImageData (bitmap, info);
|
||||
}
|
||||
|
||||
public override void Write (Stream stream, ImageData image)
|
||||
{
|
||||
using (var file = new BinaryWriter (stream, Encoding.ASCII, true))
|
||||
{
|
||||
file.Write (Signature);
|
||||
file.Write ((short)image.OffsetX);
|
||||
file.Write ((short)image.OffsetY);
|
||||
file.Write ((ushort)image.Width);
|
||||
file.Write ((ushort)image.Height);
|
||||
|
||||
var bitmap = image.Bitmap;
|
||||
if (bitmap.Format != PixelFormats.Bgra32)
|
||||
{
|
||||
var converted_bitmap = new FormatConvertedBitmap();
|
||||
converted_bitmap.BeginInit();
|
||||
converted_bitmap.Source = image.Bitmap;
|
||||
converted_bitmap.DestinationFormat = PixelFormats.Bgra32;
|
||||
converted_bitmap.EndInit();
|
||||
bitmap = converted_bitmap;
|
||||
}
|
||||
int stride = (int)image.Width * 4;
|
||||
byte[] row_data = new byte[stride];
|
||||
Int32Rect rect = new Int32Rect (0, (int)image.Height, (int)image.Width, 1);
|
||||
for (uint row = 0; row < image.Height; ++row)
|
||||
{
|
||||
--rect.Y;
|
||||
bitmap.CopyPixels (rect, row_data, stride, 0);
|
||||
file.Write (row_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AmiScriptData : ScriptData
|
||||
{
|
||||
public uint Id;
|
||||
public uint Type;
|
||||
}
|
||||
|
||||
[Export(typeof(ScriptFormat))]
|
||||
public class ScrFormat : ScriptFormat
|
||||
{
|
||||
public override string Tag { get { return "SCR"; } }
|
||||
public override string Description { get { return Strings.arcStrings.SCRDescription; } }
|
||||
public override uint Signature { get { return 0x00524353; } }
|
||||
|
||||
public override ScriptData Read (string name, Stream stream)
|
||||
{
|
||||
if (Signature != FormatCatalog.ReadSignature (stream))
|
||||
return null;
|
||||
uint script_id = Convert.ToUInt32 (name, 16);
|
||||
uint max_offset = (uint)Math.Min (stream.Length, 0xffffffff);
|
||||
|
||||
using (var file = new BinaryReader (stream, Encodings.cp932, true))
|
||||
{
|
||||
uint script_type = file.ReadUInt32();
|
||||
var script = new AmiScriptData {
|
||||
Id = script_id,
|
||||
Type = script_type
|
||||
};
|
||||
uint count = file.ReadUInt32();
|
||||
for (uint i = 0; i < count; ++i)
|
||||
{
|
||||
uint offset = file.ReadUInt32();
|
||||
if (offset >= max_offset)
|
||||
throw new InvalidFormatException ("Invalid offset in script data file");
|
||||
int size = file.ReadInt32();
|
||||
uint id = file.ReadUInt32();
|
||||
var header_pos = file.BaseStream.Position;
|
||||
file.BaseStream.Position = offset;
|
||||
byte[] line = file.ReadBytes (size);
|
||||
if (line.Length != size)
|
||||
throw new InvalidFormatException ("Premature end of file");
|
||||
string text = Encodings.cp932.GetString (line);
|
||||
|
||||
script.TextLines.Add (new ScriptLine { Id = id, Text = text });
|
||||
file.BaseStream.Position = header_pos;
|
||||
}
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetName (ScriptData script_data)
|
||||
{
|
||||
var script = script_data as AmiScriptData;
|
||||
if (null != script)
|
||||
return script.Id.ToString ("x8");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
struct IndexEntry
|
||||
{
|
||||
public uint offset, size, id;
|
||||
}
|
||||
|
||||
public override void Write (Stream stream, ScriptData script_data)
|
||||
{
|
||||
var script = script_data as AmiScriptData;
|
||||
if (null == script)
|
||||
throw new ArgumentException ("Illegal ScriptData", "script_data");
|
||||
using (var file = new BinaryWriter (stream, Encodings.cp932, true))
|
||||
{
|
||||
file.Write (Signature);
|
||||
file.Write (script.Type);
|
||||
uint count = (uint)script.TextLines.Count;
|
||||
file.Write (count);
|
||||
var index_pos = file.BaseStream.Position;
|
||||
file.Seek ((int)count*12, SeekOrigin.Current);
|
||||
var index = new IndexEntry[count];
|
||||
int i = 0;
|
||||
foreach (var line in script.TextLines)
|
||||
{
|
||||
var text = Encodings.cp932.GetBytes (line.Text);
|
||||
index[i].offset = (uint)file.BaseStream.Position;
|
||||
index[i].size = (uint)text.Length;
|
||||
index[i].id = line.Id;
|
||||
file.Write (text);
|
||||
file.Write ((byte)0);
|
||||
++i;
|
||||
}
|
||||
var end_pos = file.BaseStream.Position;
|
||||
file.BaseStream.Position = index_pos;
|
||||
foreach (var entry in index)
|
||||
{
|
||||
file.Write (entry.offset);
|
||||
file.Write (entry.size);
|
||||
file.Write (entry.id);
|
||||
}
|
||||
file.BaseStream.Position = end_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//! \file ArcAMI.cs
|
||||
//! \date Thu Jul 03 09:40:40 2014
|
||||
//! \brief Muv-Luv Amaterasu Translation archive.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Globalization;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Formats.Strings;
|
||||
using GameRes.Formats.Properties;
|
||||
|
||||
namespace GameRes.Formats.Amaterasu
|
||||
{
|
||||
internal class AmiEntry : PackedEntry
|
||||
{
|
||||
public uint Id;
|
||||
|
||||
private Lazy<string> m_ext;
|
||||
private Lazy<string> m_name;
|
||||
private Lazy<string> m_type;
|
||||
public override string Name
|
||||
{
|
||||
get { return m_name.Value; }
|
||||
set { m_name = new Lazy<string> (() => value); }
|
||||
}
|
||||
public override string Type
|
||||
{
|
||||
get { return m_type.Value; }
|
||||
set { m_type = new Lazy<string> (() => value); }
|
||||
}
|
||||
|
||||
public AmiEntry (uint id, Func<string> ext_factory)
|
||||
{
|
||||
Id = id;
|
||||
m_ext = new Lazy<string> (ext_factory);
|
||||
m_name = new Lazy<string> (GetName);
|
||||
m_type = new Lazy<string> (GetEntryType);
|
||||
}
|
||||
|
||||
private string GetName ()
|
||||
{
|
||||
return string.Format ("{0:x8}.{1}", Id, m_ext.Value);
|
||||
}
|
||||
|
||||
private string GetEntryType ()
|
||||
{
|
||||
var ext = m_ext.Value;
|
||||
if ("grp" == ext)
|
||||
return "image";
|
||||
if ("scr" == ext)
|
||||
return "script";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
internal class AmiOptions : ResourceOptions
|
||||
{
|
||||
public bool UseBaseArchive;
|
||||
public string BaseArchive;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class AmiOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "AMI"; } }
|
||||
public override string Description { get { return Strings.arcStrings.AMIDescription; } }
|
||||
public override uint Signature { get { return 0x00494d41; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return true; } }
|
||||
|
||||
public AmiOpener ()
|
||||
{
|
||||
Extensions = new string[] { "ami", "amr" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (4);
|
||||
if (count <= 0)
|
||||
return null;
|
||||
uint base_offset = file.View.ReadUInt32 (8);
|
||||
long max_offset = file.MaxOffset;
|
||||
if (base_offset >= max_offset)
|
||||
return null;
|
||||
|
||||
uint cur_offset = 16;
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (cur_offset+16 > base_offset)
|
||||
return null;
|
||||
uint id = file.View.ReadUInt32 (cur_offset);
|
||||
uint offset = file.View.ReadUInt32 (cur_offset+4);
|
||||
uint size = file.View.ReadUInt32 (cur_offset+8);
|
||||
uint packed_size = file.View.ReadUInt32 (cur_offset+12);
|
||||
|
||||
var entry = new AmiEntry (id, () => {
|
||||
uint signature = file.View.ReadUInt32 (offset);
|
||||
if (0x00524353 == signature)
|
||||
return "scr";
|
||||
else if (0 != packed_size || 0x00505247 == signature)
|
||||
return "grp";
|
||||
else
|
||||
return "dat";
|
||||
});
|
||||
|
||||
entry.Offset = offset;
|
||||
entry.UnpackedSize = size;
|
||||
entry.IsPacked = 0 != packed_size;
|
||||
entry.Size = entry.IsPacked ? packed_size : size;
|
||||
if (!entry.CheckPlacement (max_offset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
cur_offset += 16;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
var packed_entry = entry as AmiEntry;
|
||||
if (null == packed_entry || !packed_entry.IsPacked)
|
||||
return input;
|
||||
else
|
||||
return new ZLibStream (input, CompressionMode.Decompress);
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
EntryCallback callback)
|
||||
{
|
||||
ArcFile base_archive = null;
|
||||
var ami_options = GetOptions<AmiOptions> (options);
|
||||
if (null != ami_options && ami_options.UseBaseArchive && !string.IsNullOrEmpty (ami_options.BaseArchive))
|
||||
{
|
||||
var base_file = new ArcView (ami_options.BaseArchive);
|
||||
try
|
||||
{
|
||||
if (base_file.View.ReadUInt32(0) == Signature)
|
||||
base_archive = TryOpen (base_file);
|
||||
if (null == base_archive)
|
||||
throw new InvalidFormatException (string.Format ("{0}: base archive could not be read",
|
||||
Path.GetFileName (ami_options.BaseArchive)));
|
||||
base_file = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != base_file)
|
||||
base_file.Dispose();
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
var file_table = new SortedDictionary<uint, PackedEntry>();
|
||||
if (null != base_archive)
|
||||
{
|
||||
foreach (var entry in base_archive.Dir.Cast<AmiEntry>())
|
||||
file_table[entry.Id] = entry;
|
||||
}
|
||||
int update_count = UpdateFileTable (file_table, list);
|
||||
if (0 == update_count)
|
||||
throw new InvalidFormatException (arcStrings.AMINoFiles);
|
||||
|
||||
uint file_count = (uint)file_table.Count;
|
||||
if (null != callback)
|
||||
callback ((int)file_count+1, null, null);
|
||||
|
||||
int callback_count = 0;
|
||||
long start_offset = output.Position;
|
||||
uint data_offset = file_count * 16 + 16;
|
||||
output.Seek (data_offset, SeekOrigin.Current);
|
||||
foreach (var entry in file_table)
|
||||
{
|
||||
if (null != callback)
|
||||
callback (callback_count++, entry.Value, arcStrings.MsgAddingFile);
|
||||
long current_offset = output.Position;
|
||||
if (current_offset > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
if (entry.Value is AmiEntry)
|
||||
CopyAmiEntry (base_archive, entry.Value, output);
|
||||
else
|
||||
entry.Value.Size = WriteAmiEntry (entry.Value, output);
|
||||
entry.Value.Offset = (uint)current_offset;
|
||||
}
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||
output.Position = start_offset;
|
||||
using (var header = new BinaryWriter (output, Encoding.ASCII, true))
|
||||
{
|
||||
header.Write (Signature);
|
||||
header.Write (file_count);
|
||||
header.Write (data_offset);
|
||||
header.Write ((uint)0);
|
||||
foreach (var entry in file_table)
|
||||
{
|
||||
header.Write (entry.Key);
|
||||
header.Write ((uint)entry.Value.Offset);
|
||||
header.Write ((uint)entry.Value.UnpackedSize);
|
||||
header.Write ((uint)entry.Value.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != base_archive)
|
||||
base_archive.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
int UpdateFileTable (IDictionary<uint, PackedEntry> table, IEnumerable<Entry> list)
|
||||
{
|
||||
int update_count = 0;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
if (entry.Type != "image" && !entry.Name.EndsWith (".scr", StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
uint id;
|
||||
if (!uint.TryParse (Path.GetFileNameWithoutExtension (entry.Name), NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture, out id))
|
||||
continue;
|
||||
PackedEntry existing;
|
||||
if (table.TryGetValue (id, out existing) && !(existing is AmiEntry))
|
||||
{
|
||||
var file_new = new FileInfo (entry.Name);
|
||||
if (!file_new.Exists)
|
||||
continue;
|
||||
var file_old = new FileInfo (existing.Name);
|
||||
if (file_new.LastWriteTime <= file_old.LastWriteTime)
|
||||
continue;
|
||||
}
|
||||
table[id] = new PackedEntry
|
||||
{
|
||||
Name = entry.Name,
|
||||
Type = entry.Type
|
||||
};
|
||||
++update_count;
|
||||
}
|
||||
return update_count;
|
||||
}
|
||||
|
||||
void CopyAmiEntry (ArcFile base_archive, Entry entry, Stream output)
|
||||
{
|
||||
using (var input = base_archive.File.CreateStream (entry.Offset, entry.Size))
|
||||
input.CopyTo (output);
|
||||
}
|
||||
|
||||
uint WriteAmiEntry (PackedEntry entry, Stream output)
|
||||
{
|
||||
uint packed_size = 0;
|
||||
using (var input = File.OpenRead (entry.Name))
|
||||
{
|
||||
long file_size = input.Length;
|
||||
if (file_size > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
entry.UnpackedSize = (uint)file_size;
|
||||
if ("image" == entry.Type)
|
||||
{
|
||||
packed_size = WriteImageEntry (entry, input, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
input.CopyTo (output);
|
||||
}
|
||||
}
|
||||
return packed_size;
|
||||
}
|
||||
|
||||
static Lazy<GrpFormat> s_grp_format = new Lazy<GrpFormat> (() =>
|
||||
FormatCatalog.Instance.ImageFormats.OfType<GrpFormat>().FirstOrDefault());
|
||||
|
||||
uint WriteImageEntry (PackedEntry entry, Stream input, Stream output)
|
||||
{
|
||||
var grp = s_grp_format.Value;
|
||||
if (null == grp) // probably never happens
|
||||
throw new FileFormatException ("GRP image encoder not available");
|
||||
bool is_grp = grp.Signature == FormatCatalog.ReadSignature (input);
|
||||
input.Position = 0;
|
||||
var start = output.Position;
|
||||
using (var zstream = new ZLibStream (output, CompressionMode.Compress, CompressionLevel.Level9, true))
|
||||
{
|
||||
if (is_grp)
|
||||
{
|
||||
input.CopyTo (zstream);
|
||||
}
|
||||
else
|
||||
{
|
||||
var image = ImageFormat.Read (input);
|
||||
if (null == image)
|
||||
throw new InvalidFormatException (string.Format (arcStrings.MsgInvalidImageFormat, entry.Name));
|
||||
grp.Write (zstream, image);
|
||||
entry.UnpackedSize = (uint)zstream.TotalIn;
|
||||
}
|
||||
}
|
||||
return (uint)(output.Position - start);
|
||||
}
|
||||
|
||||
public override ResourceOptions GetDefaultOptions ()
|
||||
{
|
||||
return new AmiOptions {
|
||||
UseBaseArchive = Settings.Default.AMIUseBaseArchive,
|
||||
BaseArchive = Settings.Default.AMIBaseArchive,
|
||||
};
|
||||
}
|
||||
|
||||
public override object GetCreationWidget ()
|
||||
{
|
||||
return new GUI.CreateAMIWidget();
|
||||
}
|
||||
}
|
||||
|
||||
public class AmiScriptData : ScriptData
|
||||
{
|
||||
public uint Id;
|
||||
public uint Type;
|
||||
}
|
||||
|
||||
[Export(typeof(ScriptFormat))]
|
||||
public class ScrFormat : ScriptFormat
|
||||
{
|
||||
public override string Tag { get { return "SCR"; } }
|
||||
public override string Description { get { return Strings.arcStrings.SCRDescription; } }
|
||||
public override uint Signature { get { return 0x00524353; } }
|
||||
|
||||
public override ScriptData Read (string name, Stream stream)
|
||||
{
|
||||
if (Signature != FormatCatalog.ReadSignature (stream))
|
||||
return null;
|
||||
uint script_id = Convert.ToUInt32 (name, 16);
|
||||
uint max_offset = (uint)Math.Min (stream.Length, 0xffffffff);
|
||||
|
||||
using (var file = new BinaryReader (stream, Encodings.cp932, true))
|
||||
{
|
||||
uint script_type = file.ReadUInt32();
|
||||
var script = new AmiScriptData {
|
||||
Id = script_id,
|
||||
Type = script_type
|
||||
};
|
||||
uint count = file.ReadUInt32();
|
||||
for (uint i = 0; i < count; ++i)
|
||||
{
|
||||
uint offset = file.ReadUInt32();
|
||||
if (offset >= max_offset)
|
||||
throw new InvalidFormatException ("Invalid offset in script data file");
|
||||
int size = file.ReadInt32();
|
||||
uint id = file.ReadUInt32();
|
||||
var header_pos = file.BaseStream.Position;
|
||||
file.BaseStream.Position = offset;
|
||||
byte[] line = file.ReadBytes (size);
|
||||
if (line.Length != size)
|
||||
throw new InvalidFormatException ("Premature end of file");
|
||||
string text = Encodings.cp932.GetString (line);
|
||||
|
||||
script.TextLines.Add (new ScriptLine { Id = id, Text = text });
|
||||
file.BaseStream.Position = header_pos;
|
||||
}
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetName (ScriptData script_data)
|
||||
{
|
||||
var script = script_data as AmiScriptData;
|
||||
if (null != script)
|
||||
return script.Id.ToString ("x8");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
struct IndexEntry
|
||||
{
|
||||
public uint offset, size, id;
|
||||
}
|
||||
|
||||
public override void Write (Stream stream, ScriptData script_data)
|
||||
{
|
||||
var script = script_data as AmiScriptData;
|
||||
if (null == script)
|
||||
throw new ArgumentException ("Illegal ScriptData", "script_data");
|
||||
using (var file = new BinaryWriter (stream, Encodings.cp932, true))
|
||||
{
|
||||
file.Write (Signature);
|
||||
file.Write (script.Type);
|
||||
uint count = (uint)script.TextLines.Count;
|
||||
file.Write (count);
|
||||
var index_pos = file.BaseStream.Position;
|
||||
file.Seek ((int)count*12, SeekOrigin.Current);
|
||||
var index = new IndexEntry[count];
|
||||
int i = 0;
|
||||
foreach (var line in script.TextLines)
|
||||
{
|
||||
var text = Encodings.cp932.GetBytes (line.Text);
|
||||
index[i].offset = (uint)file.BaseStream.Position;
|
||||
index[i].size = (uint)text.Length;
|
||||
index[i].id = line.Id;
|
||||
file.Write (text);
|
||||
file.Write ((byte)0);
|
||||
++i;
|
||||
}
|
||||
var end_pos = file.BaseStream.Position;
|
||||
file.BaseStream.Position = index_pos;
|
||||
foreach (var entry in index)
|
||||
{
|
||||
file.Write (entry.offset);
|
||||
file.Write (entry.size);
|
||||
file.Write (entry.id);
|
||||
}
|
||||
file.BaseStream.Position = end_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
100
ArcFormats/Amaterasu/ImageGRP.cs
Normal file
100
ArcFormats/Amaterasu/ImageGRP.cs
Normal file
@ -0,0 +1,100 @@
|
||||
//! \file ImageGRP.cs
|
||||
//! \date Wed Aug 19 20:58:51 2015
|
||||
//! \brief Muv-Luv Amaterasu Translation RGB bitmap.
|
||||
//
|
||||
// Copyright (C) 2014-2015 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.IO;
|
||||
using System.Text;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace GameRes.Formats.Amaterasu
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class GrpFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "GRP"; } }
|
||||
public override string Description { get { return Strings.arcStrings.GRPDescription; } }
|
||||
public override uint Signature { get { return 0x00505247; } }
|
||||
|
||||
public override ImageMetaData ReadMetaData (Stream stream)
|
||||
{
|
||||
using (var file = new BinaryReader (stream, Encoding.ASCII, true))
|
||||
{
|
||||
if (file.ReadUInt32() != Signature)
|
||||
return null;
|
||||
var meta = new ImageMetaData();
|
||||
meta.OffsetX = file.ReadInt16();
|
||||
meta.OffsetY = file.ReadInt16();
|
||||
meta.Width = file.ReadUInt16();
|
||||
meta.Height = file.ReadUInt16();
|
||||
meta.BPP = 32;
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
|
||||
public override ImageData Read (Stream file, ImageMetaData info)
|
||||
{
|
||||
int width = (int)info.Width;
|
||||
int height = (int)info.Height;
|
||||
int stride = width*4;
|
||||
byte[] pixels = new byte[stride*height];
|
||||
file.Position = 12;
|
||||
for (int row = height-1; row >= 0; --row)
|
||||
{
|
||||
if (stride != file.Read (pixels, row*stride, stride))
|
||||
throw new InvalidFormatException();
|
||||
}
|
||||
return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
|
||||
}
|
||||
|
||||
public override void Write (Stream stream, ImageData image)
|
||||
{
|
||||
using (var file = new BinaryWriter (stream, Encoding.ASCII, true))
|
||||
{
|
||||
file.Write (Signature);
|
||||
file.Write ((short)image.OffsetX);
|
||||
file.Write ((short)image.OffsetY);
|
||||
file.Write ((ushort)image.Width);
|
||||
file.Write ((ushort)image.Height);
|
||||
|
||||
var bitmap = image.Bitmap;
|
||||
if (bitmap.Format != PixelFormats.Bgra32)
|
||||
{
|
||||
bitmap = new FormatConvertedBitmap (image.Bitmap, PixelFormats.Bgra32, null, 0);
|
||||
}
|
||||
int stride = (int)image.Width * 4;
|
||||
byte[] row_data = new byte[stride];
|
||||
Int32Rect rect = new Int32Rect (0, (int)image.Height, (int)image.Width, 1);
|
||||
for (uint row = 0; row < image.Height; ++row)
|
||||
{
|
||||
--rect.Y;
|
||||
bitmap.CopyPixels (rect, row_data, stride, 0);
|
||||
file.Write (row_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -61,199 +61,200 @@
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ArcABM.cs" />
|
||||
<Compile Include="ArcADPACK.cs" />
|
||||
<Compile Include="Amaterasu\ImageGRP.cs" />
|
||||
<Compile Include="Lilim\ArcABM.cs" />
|
||||
<Compile Include="ActiveSoft\ArcADPACK.cs" />
|
||||
<Compile Include="ArcAdvCls.cs" />
|
||||
<Compile Include="ArcAdvSysT.cs" />
|
||||
<Compile Include="AdvSys\ArcAdvSysT.cs" />
|
||||
<Compile Include="ArcAFS.cs" />
|
||||
<Compile Include="ArcAi5Win.cs" />
|
||||
<Compile Include="elf\ArcAi5Win.cs" />
|
||||
<Compile Include="ArcAil.cs" />
|
||||
<Compile Include="ArcALD.cs" />
|
||||
<Compile Include="ArcAMI.cs" />
|
||||
<Compile Include="ArcAOS.cs" />
|
||||
<Compile Include="AliceSoft\ArcALD.cs" />
|
||||
<Compile Include="Amaterasu\ArcAMI.cs" />
|
||||
<Compile Include="Lilim\ArcAOS.cs" />
|
||||
<Compile Include="ArcAST.cs" />
|
||||
<Compile Include="ArcAVC.cs" />
|
||||
<Compile Include="ArcAZSys.cs" />
|
||||
<Compile Include="ArcBGI.cs" />
|
||||
<Compile Include="ArcBlackPackage.cs" />
|
||||
<Compile Include="ArcCCT.cs" />
|
||||
<Compile Include="ArcCherry.cs" />
|
||||
<Compile Include="ArcCircus.cs" />
|
||||
<Compile Include="AZSys\ArcAZSys.cs" />
|
||||
<Compile Include="Ethornell\ArcBGI.cs" />
|
||||
<Compile Include="Ffa\ArcBlackPackage.cs" />
|
||||
<Compile Include="Macromedia\ArcCCT.cs" />
|
||||
<Compile Include="Cherry\ArcCherry.cs" />
|
||||
<Compile Include="Circus\ArcCircus.cs" />
|
||||
<Compile Include="ArcCommon.cs" />
|
||||
<Compile Include="ArcDPK.cs" />
|
||||
<Compile Include="ArcDRS.cs" />
|
||||
<Compile Include="ArcEAGLS.cs" />
|
||||
<Compile Include="Dac\ArcDPK.cs" />
|
||||
<Compile Include="Ikura\ArcDRS.cs" />
|
||||
<Compile Include="Eagls\ArcEAGLS.cs" />
|
||||
<Compile Include="ArcEGO.cs" />
|
||||
<Compile Include="ArcFFA.cs" />
|
||||
<Compile Include="ArcFPK.cs" />
|
||||
<Compile Include="Ffa\ArcFFA.cs" />
|
||||
<Compile Include="Interheart\ArcFPK.cs" />
|
||||
<Compile Include="ArcFVP.cs" />
|
||||
<Compile Include="ArcGameDat.cs" />
|
||||
<Compile Include="ArcGCEX.cs" />
|
||||
<Compile Include="ArcGPK.cs" />
|
||||
<Compile Include="ArcGSP.cs" />
|
||||
<Compile Include="ArcGsPack.cs" />
|
||||
<Compile Include="ArcHED.cs" />
|
||||
<Compile Include="ArcIFL.cs" />
|
||||
<Compile Include="Pajamas\ArcGameDat.cs" />
|
||||
<Compile Include="G2\ArcGCEX.cs" />
|
||||
<Compile Include="BlackCyc\ArcGPK.cs" />
|
||||
<Compile Include="BlackRainbow\ArcGSP.cs" />
|
||||
<Compile Include="GsPack\ArcGsPack.cs" />
|
||||
<Compile Include="elf\ArcHED.cs" />
|
||||
<Compile Include="Silky\ArcIFL.cs" />
|
||||
<Compile Include="ArcIKS.cs" />
|
||||
<Compile Include="ArcInnGrey.cs" />
|
||||
<Compile Include="ArcINT.cs" />
|
||||
<Compile Include="CatSystem\ArcINT.cs" />
|
||||
<Compile Include="ArcISA.cs" />
|
||||
<Compile Include="ArcKAAS.cs" />
|
||||
<Compile Include="ArcKaguya.cs" />
|
||||
<Compile Include="ArcKCAP.cs" />
|
||||
<Compile Include="Kaas\ArcKAAS.cs" />
|
||||
<Compile Include="Kaguya\ArcKaguya.cs" />
|
||||
<Compile Include="Selene\ArcKCAP.cs" />
|
||||
<Compile Include="ArcKogado.cs" />
|
||||
<Compile Include="ArcLIB.cs" />
|
||||
<Compile Include="ArcLPK.cs" />
|
||||
<Compile Include="Malie\ArcLIB.cs" />
|
||||
<Compile Include="Lucifen\ArcLPK.cs" />
|
||||
<Compile Include="ArcLST.cs" />
|
||||
<Compile Include="ArcMAI.cs" />
|
||||
<Compile Include="ArcMajiro.cs" />
|
||||
<Compile Include="ArcMBL.cs" />
|
||||
<Compile Include="ArcMFG.cs" />
|
||||
<Compile Include="ArcMGD.cs" />
|
||||
<Compile Include="Majiro\ArcMajiro.cs" />
|
||||
<Compile Include="Marble\ArcMBL.cs" />
|
||||
<Compile Include="Silky\ArcMFG.cs" />
|
||||
<Compile Include="Masys\ArcMGD.cs" />
|
||||
<Compile Include="ArcMGPK.cs" />
|
||||
<Compile Include="ArcMnoViolet.cs" />
|
||||
<Compile Include="ArcMRG.cs" />
|
||||
<Compile Include="MnoViolet\ArcMnoViolet.cs" />
|
||||
<Compile Include="FC01\ArcMRG.cs" />
|
||||
<Compile Include="ArcNEKO.cs" />
|
||||
<Compile Include="ArcNexas.cs" />
|
||||
<Compile Include="ArcNitro.cs" />
|
||||
<Compile Include="ArcNOA.cs" />
|
||||
<Compile Include="ArcNPA.cs" />
|
||||
<Compile Include="ArcNSA.cs" />
|
||||
<Compile Include="ArcPAC.cs" />
|
||||
<Compile Include="ArcPCK.cs" />
|
||||
<Compile Include="ArcPD.cs" />
|
||||
<Compile Include="ArcPK.cs" />
|
||||
<Compile Include="NitroPlus\ArcNitro.cs" />
|
||||
<Compile Include="Entis\ArcNOA.cs" />
|
||||
<Compile Include="NitroPlus\ArcNPA.cs" />
|
||||
<Compile Include="NScripter\ArcNSA.cs" />
|
||||
<Compile Include="RiddleSoft\ArcPAC.cs" />
|
||||
<Compile Include="Crowd\ArcPCK.cs" />
|
||||
<Compile Include="FlyingShine\ArcPD.cs" />
|
||||
<Compile Include="UMeSoft\ArcPK.cs" />
|
||||
<Compile Include="ArcQLIE.cs" />
|
||||
<Compile Include="ArcRPA.cs" />
|
||||
<Compile Include="ArcS25.cs" />
|
||||
<Compile Include="RenPy\ArcRPA.cs" />
|
||||
<Compile Include="ShiinaRio\ArcS25.cs" />
|
||||
<Compile Include="ArcSAF.cs" />
|
||||
<Compile Include="ArcVPK.cs" />
|
||||
<Compile Include="ArcWAG.cs" />
|
||||
<Compile Include="ArcXuse.cs" />
|
||||
<Compile Include="ArcYKC.cs" />
|
||||
<Compile Include="AudioVAW.cs" />
|
||||
<Compile Include="AudioWPN.cs" />
|
||||
<Compile Include="AudioWWA.cs" />
|
||||
<Compile Include="EriReader.cs" />
|
||||
<Compile Include="ImageABM.cs" />
|
||||
<Compile Include="ImageBGRA.cs" />
|
||||
<Compile Include="ImageDWQ.cs" />
|
||||
<Compile Include="ImageHIZ.cs" />
|
||||
<Compile Include="ImageKG.cs" />
|
||||
<Compile Include="ImageYKG.cs" />
|
||||
<Compile Include="MioDecoder.cs" />
|
||||
<Compile Include="WidgetRCT.xaml.cs">
|
||||
<Compile Include="BlackCyc\ArcVPK.cs" />
|
||||
<Compile Include="Xuse\ArcWAG.cs" />
|
||||
<Compile Include="Xuse\ArcXuse.cs" />
|
||||
<Compile Include="Yuka\ArcYKC.cs" />
|
||||
<Compile Include="BlackCyc\AudioVAW.cs" />
|
||||
<Compile Include="WildBug\AudioWPN.cs" />
|
||||
<Compile Include="WildBug\AudioWWA.cs" />
|
||||
<Compile Include="Entis\EriReader.cs" />
|
||||
<Compile Include="Lilim\ImageABM.cs" />
|
||||
<Compile Include="G2\ImageBGRA.cs" />
|
||||
<Compile Include="BlackCyc\ImageDWQ.cs" />
|
||||
<Compile Include="elf\ImageHIZ.cs" />
|
||||
<Compile Include="Interheart\ImageKG.cs" />
|
||||
<Compile Include="Yuka\ImageYKG.cs" />
|
||||
<Compile Include="Entis\MioDecoder.cs" />
|
||||
<Compile Include="Majiro\WidgetRCT.xaml.cs">
|
||||
<DependentUpon>WidgetRCT.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ZLibStream.cs" />
|
||||
<None Include="ArcSeraph.cs" />
|
||||
<Compile Include="ArcSPack.cs" />
|
||||
<Compile Include="ArcSteinsGate.cs" />
|
||||
<Compile Include="ArcSUD.cs" />
|
||||
<Compile Include="ArcTactics.cs" />
|
||||
<Compile Include="ArcWARC.cs" />
|
||||
<Compile Include="ArcWBP.cs" />
|
||||
<Compile Include="ArcWILL.cs" />
|
||||
<Compile Include="ArcXFL.cs" />
|
||||
<Compile Include="ArcXP3.cs" />
|
||||
<Compile Include="ArcYPF.cs" />
|
||||
<Compile Include="AudioEDIM.cs" />
|
||||
<Compile Include="AudioEOG.cs" />
|
||||
<Compile Include="AudioMIO.cs" />
|
||||
<Compile Include="NitroPlus\ArcSteinsGate.cs" />
|
||||
<Compile Include="Triangle\ArcSUD.cs" />
|
||||
<Compile Include="Tactics\ArcTactics.cs" />
|
||||
<Compile Include="ShiinaRio\ArcWARC.cs" />
|
||||
<Compile Include="WildBug\ArcWBP.cs" />
|
||||
<Compile Include="Will\ArcWILL.cs" />
|
||||
<Compile Include="Liar\ArcXFL.cs" />
|
||||
<Compile Include="KiriKiri\ArcXP3.cs" />
|
||||
<Compile Include="YuRis\ArcYPF.cs" />
|
||||
<Compile Include="Macromedia\AudioEDIM.cs" />
|
||||
<Compile Include="Crowd\AudioEOG.cs" />
|
||||
<Compile Include="Entis\AudioMIO.cs" />
|
||||
<Compile Include="AudioMP3.cs" />
|
||||
<Compile Include="AudioOGV.cs" />
|
||||
<Compile Include="AudioPAD.cs" />
|
||||
<Compile Include="AudioPCM.cs" />
|
||||
<Compile Include="AudioPMW.cs" />
|
||||
<Compile Include="AudioWA1.cs" />
|
||||
<Compile Include="AudioWADY.cs" />
|
||||
<Compile Include="ShiinaRio\AudioOGV.cs" />
|
||||
<Compile Include="ShiinaRio\AudioPAD.cs" />
|
||||
<Compile Include="Circus\AudioPCM.cs" />
|
||||
<Compile Include="ScenePlayer\AudioPMW.cs" />
|
||||
<Compile Include="Ffa\AudioWA1.cs" />
|
||||
<Compile Include="Marble\AudioWADY.cs" />
|
||||
<Compile Include="Blowfish.cs" />
|
||||
<Compile Include="Camellia.cs" />
|
||||
<Compile Include="CreateAMIWidget.xaml.cs">
|
||||
<Compile Include="Amaterasu\CreateAMIWidget.xaml.cs">
|
||||
<DependentUpon>CreateAMIWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateINTWidget.xaml.cs">
|
||||
<Compile Include="CatSystem\CreateINTWidget.xaml.cs">
|
||||
<DependentUpon>CreateINTWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateNPAWidget.xaml.cs">
|
||||
<Compile Include="NitroPlus\CreateNPAWidget.xaml.cs">
|
||||
<DependentUpon>CreateNPAWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateONSWidget.xaml.cs">
|
||||
<Compile Include="NScripter\CreateONSWidget.xaml.cs">
|
||||
<DependentUpon>CreateONSWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreatePDWidget.xaml.cs">
|
||||
<Compile Include="FlyingShine\CreatePDWidget.xaml.cs">
|
||||
<DependentUpon>CreatePDWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateRPAWidget.xaml.cs">
|
||||
<Compile Include="RenPy\CreateRPAWidget.xaml.cs">
|
||||
<DependentUpon>CreateRPAWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateSGWidget.xaml.cs">
|
||||
<Compile Include="NitroPlus\CreateSGWidget.xaml.cs">
|
||||
<DependentUpon>CreateSGWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateARCWidget.xaml.cs">
|
||||
<Compile Include="Will\CreateARCWidget.xaml.cs">
|
||||
<DependentUpon>CreateARCWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateXP3Widget.xaml.cs">
|
||||
<Compile Include="KiriKiri\CreateXP3Widget.xaml.cs">
|
||||
<DependentUpon>CreateXP3Widget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="CreateYPFWidget.xaml.cs">
|
||||
<Compile Include="YuRis\CreateYPFWidget.xaml.cs">
|
||||
<DependentUpon>CreateYPFWidget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ImageACD.cs" />
|
||||
<Compile Include="ImageAG.cs" />
|
||||
<Compile Include="FC01\ImageACD.cs" />
|
||||
<Compile Include="Masys\ImageAG.cs" />
|
||||
<Compile Include="ImageAinos.cs" />
|
||||
<Compile Include="ImageAP.cs" />
|
||||
<Compile Include="ImageBGI.cs" />
|
||||
<Compile Include="Kaguya\ImageAP.cs" />
|
||||
<Compile Include="Ethornell\ImageBGI.cs" />
|
||||
<Compile Include="ImageBIP.cs" />
|
||||
<Compile Include="ImageBITD.cs" />
|
||||
<Compile Include="ImageBMD.cs" />
|
||||
<Compile Include="ImageBMZ.cs" />
|
||||
<Compile Include="ImageCPB.cs" />
|
||||
<Compile Include="ImageCRX.cs" />
|
||||
<Compile Include="ImageCWL.cs" />
|
||||
<Compile Include="ImageCWP.cs" />
|
||||
<Compile Include="Macromedia\ImageBITD.cs" />
|
||||
<Compile Include="BlackRainbow\ImageBMD.cs" />
|
||||
<Compile Include="BlackRainbow\ImageBMZ.cs" />
|
||||
<Compile Include="AZSys\ImageCPB.cs" />
|
||||
<Compile Include="Circus\ImageCRX.cs" />
|
||||
<Compile Include="Crowd\ImageCWL.cs" />
|
||||
<Compile Include="Crowd\ImageCWP.cs" />
|
||||
<Compile Include="ImageDDS.cs" />
|
||||
<Compile Include="ImageDGC.cs" />
|
||||
<Compile Include="ImageDRG.cs" />
|
||||
<Compile Include="ImageDZI.cs" />
|
||||
<Compile Include="ImageEDT.cs" />
|
||||
<Compile Include="Dac\ImageDGC.cs" />
|
||||
<Compile Include="Ikura\ImageDRG.cs" />
|
||||
<Compile Include="Malie\ImageDZI.cs" />
|
||||
<Compile Include="ActiveSoft\ImageEDT.cs" />
|
||||
<Compile Include="ImageEGN.cs" />
|
||||
<Compile Include="ImageELG.cs" />
|
||||
<Compile Include="ImageEPA.cs" />
|
||||
<Compile Include="ImageERI.cs" />
|
||||
<Compile Include="ImageGCC.cs" />
|
||||
<Compile Include="ImageGCP.cs" />
|
||||
<Compile Include="ImageGGP.cs" />
|
||||
<Compile Include="ImageGR.cs" />
|
||||
<Compile Include="ImageGR2.cs" />
|
||||
<Compile Include="ImageGRP.cs" />
|
||||
<Compile Include="ImageGRX.cs" />
|
||||
<Compile Include="ImageGS.cs" />
|
||||
<Compile Include="ImageHG3.cs" />
|
||||
<Compile Include="ImageIAF.cs" />
|
||||
<Compile Include="ImageIGF.cs" />
|
||||
<Compile Include="Lucifen\ImageELG.cs" />
|
||||
<Compile Include="Pajamas\ImageEPA.cs" />
|
||||
<Compile Include="Entis\ImageERI.cs" />
|
||||
<Compile Include="elf\ImageGCC.cs" />
|
||||
<Compile Include="RiddleSoft\ImageGCP.cs" />
|
||||
<Compile Include="Ikura\ImageGGP.cs" />
|
||||
<Compile Include="Eagls\ImageGR.cs" />
|
||||
<Compile Include="AdvSys\ImageGR2.cs" />
|
||||
<Compile Include="Cherry\ImageGRP.cs" />
|
||||
<Compile Include="UMeSoft\ImageGRX.cs" />
|
||||
<Compile Include="GsPack\ImageGS.cs" />
|
||||
<Compile Include="CatSystem\ImageHG3.cs" />
|
||||
<Compile Include="Triangle\ImageIAF.cs" />
|
||||
<Compile Include="Silky\ImageIGF.cs" />
|
||||
<Compile Include="ImageISG.cs" />
|
||||
<Compile Include="ImageKAAS.cs" />
|
||||
<Compile Include="Kaas\ImageKAAS.cs" />
|
||||
<Compile Include="ImageMAI.cs" />
|
||||
<Compile Include="ImageMCG.cs" />
|
||||
<Compile Include="ImageMFG.cs" />
|
||||
<Compile Include="ImageMGF.cs" />
|
||||
<Compile Include="ImageMI4.cs" />
|
||||
<Compile Include="ImageMNV.cs" />
|
||||
<Compile Include="ImagePMP.cs" />
|
||||
<Compile Include="ImagePRS.cs" />
|
||||
<Compile Include="ImagePT1.cs" />
|
||||
<Compile Include="ImageQNT.cs" />
|
||||
<Compile Include="ImageRCT.cs" />
|
||||
<Compile Include="ImageS25.cs" />
|
||||
<Compile Include="FC01\ImageMCG.cs" />
|
||||
<Compile Include="Silky\ImageMFG.cs" />
|
||||
<Compile Include="Malie\ImageMGF.cs" />
|
||||
<Compile Include="ShiinaRio\ImageMI4.cs" />
|
||||
<Compile Include="MnoViolet\ImageGRA.cs" />
|
||||
<Compile Include="ScenePlayer\ImagePMP.cs" />
|
||||
<Compile Include="Marble\ImagePRS.cs" />
|
||||
<Compile Include="Ffa\ImagePT1.cs" />
|
||||
<Compile Include="AliceSoft\ImageQNT.cs" />
|
||||
<Compile Include="Majiro\ImageRCT.cs" />
|
||||
<Compile Include="ShiinaRio\ImageS25.cs" />
|
||||
<Compile Include="ImageSeraph.cs" />
|
||||
<Compile Include="ImageTGF.cs" />
|
||||
<Compile Include="ImageTLG.cs" />
|
||||
<Compile Include="ImageWBM.cs" />
|
||||
<Compile Include="ImageWCG.cs" />
|
||||
<Compile Include="ImageWIP.cs" />
|
||||
<Compile Include="ImageZBM.cs" />
|
||||
<Compile Include="KiriKiriCx.cs" />
|
||||
<Compile Include="Tactics\ImageTGF.cs" />
|
||||
<Compile Include="KiriKiri\ImageTLG.cs" />
|
||||
<Compile Include="WildBug\ImageWBM.cs" />
|
||||
<Compile Include="Liar\ImageWCG.cs" />
|
||||
<Compile Include="Will\ImageWIP.cs" />
|
||||
<Compile Include="Crowd\ImageZBM.cs" />
|
||||
<Compile Include="KiriKiri\KiriKiriCx.cs" />
|
||||
<Compile Include="KogadoCocotte.cs" />
|
||||
<Compile Include="AudioOGG.cs" />
|
||||
<Compile Include="LzssStream.cs" />
|
||||
@ -269,38 +270,38 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>arcStrings.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetDPK.xaml.cs">
|
||||
<Compile Include="Dac\WidgetDPK.xaml.cs">
|
||||
<DependentUpon>WidgetDPK.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetINT.xaml.cs">
|
||||
<Compile Include="CatSystem\WidgetINT.xaml.cs">
|
||||
<DependentUpon>WidgetINT.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetISF.xaml.cs">
|
||||
<Compile Include="Ikura\WidgetISF.xaml.cs">
|
||||
<DependentUpon>WidgetISF.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetKCAP.xaml.cs">
|
||||
<Compile Include="Selene\WidgetKCAP.xaml.cs">
|
||||
<DependentUpon>WidgetKCAP.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetLPK.xaml.cs">
|
||||
<Compile Include="Lucifen\WidgetLPK.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
<DependentUpon>WidgetLPK.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetMBL.xaml.cs">
|
||||
<Compile Include="Marble\WidgetMBL.xaml.cs">
|
||||
<DependentUpon>WidgetMBL.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetNOA.xaml.cs">
|
||||
<Compile Include="Entis\WidgetNOA.xaml.cs">
|
||||
<DependentUpon>WidgetNOA.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetNPA.xaml.cs">
|
||||
<Compile Include="NitroPlus\WidgetNPA.xaml.cs">
|
||||
<DependentUpon>WidgetNPA.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetWARC.xaml.cs">
|
||||
<Compile Include="ShiinaRio\WidgetWARC.xaml.cs">
|
||||
<DependentUpon>WidgetWARC.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetXP3.xaml.cs">
|
||||
<Compile Include="KiriKiri\WidgetXP3.xaml.cs">
|
||||
<DependentUpon>WidgetXP3.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WidgetYPF.xaml.cs">
|
||||
<Compile Include="YuRis\WidgetYPF.xaml.cs">
|
||||
<DependentUpon>WidgetYPF.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
@ -328,91 +329,91 @@
|
||||
<EmbeddedResource Include="Resources\DecodeV249.bin" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="CreateAMIWidget.xaml">
|
||||
<Page Include="Amaterasu\CreateAMIWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateINTWidget.xaml">
|
||||
<Page Include="CatSystem\CreateINTWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateNPAWidget.xaml">
|
||||
<Page Include="NitroPlus\CreateNPAWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateONSWidget.xaml">
|
||||
<Page Include="NScripter\CreateONSWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreatePDWidget.xaml">
|
||||
<Page Include="FlyingShine\CreatePDWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateRPAWidget.xaml">
|
||||
<Page Include="RenPy\CreateRPAWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateSGWidget.xaml">
|
||||
<Page Include="NitroPlus\CreateSGWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateARCWidget.xaml">
|
||||
<Page Include="Will\CreateARCWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateXP3Widget.xaml">
|
||||
<Page Include="KiriKiri\CreateXP3Widget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="CreateYPFWidget.xaml">
|
||||
<Page Include="YuRis\CreateYPFWidget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetDPK.xaml">
|
||||
<Page Include="Dac\WidgetDPK.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetINT.xaml">
|
||||
<Page Include="CatSystem\WidgetINT.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="WidgetISF.xaml">
|
||||
<Page Include="Ikura\WidgetISF.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetKCAP.xaml">
|
||||
<Page Include="Selene\WidgetKCAP.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetLPK.xaml">
|
||||
<Page Include="Lucifen\WidgetLPK.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="WidgetMBL.xaml">
|
||||
<Page Include="Marble\WidgetMBL.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetNOA.xaml">
|
||||
<Page Include="Entis\WidgetNOA.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetNPA.xaml">
|
||||
<Page Include="NitroPlus\WidgetNPA.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetRCT.xaml">
|
||||
<Page Include="Majiro\WidgetRCT.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetWARC.xaml">
|
||||
<Page Include="ShiinaRio\WidgetWARC.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="WidgetXP3.xaml">
|
||||
<Page Include="KiriKiri\WidgetXP3.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WidgetYPF.xaml">
|
||||
<Page Include="YuRis\WidgetYPF.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@ -424,6 +425,7 @@
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Strings\arcStrings.ru-RU.resx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName)</PreBuildEvent>
|
||||
|
@ -1,425 +1,425 @@
|
||||
//! \file ArcINT.cs
|
||||
//! \date Fri Jul 11 09:32:36 2014
|
||||
//! \brief Frontwing games archive.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Simias.Encryption;
|
||||
using System.Runtime.InteropServices;
|
||||
using GameRes.Formats.Strings;
|
||||
using GameRes.Formats.Properties;
|
||||
|
||||
namespace GameRes.Formats
|
||||
{
|
||||
public class FrontwingArchive : ArcFile
|
||||
{
|
||||
public readonly Blowfish Encryption;
|
||||
|
||||
public FrontwingArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, Blowfish cipher)
|
||||
: base (arc, impl, dir)
|
||||
{
|
||||
Encryption = cipher;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable()]
|
||||
public class IntEncryptionInfo
|
||||
{
|
||||
public uint? Key { get; set; }
|
||||
public string Scheme { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public uint? GetKey ()
|
||||
{
|
||||
if (null != Key && Key.HasValue)
|
||||
return Key;
|
||||
|
||||
if (!string.IsNullOrEmpty (Scheme))
|
||||
{
|
||||
IntOpener.KeyData keydata;
|
||||
if (IntOpener.KnownSchemes.TryGetValue (Scheme, out keydata))
|
||||
return keydata.Key;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty (Password))
|
||||
return IntOpener.EncodePassPhrase (Password);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class IntOptions : ResourceOptions
|
||||
{
|
||||
public IntEncryptionInfo EncryptionInfo { get; set; }
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class IntOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "INT"; } }
|
||||
public override string Description { get { return arcStrings.INTDescription; } }
|
||||
public override uint Signature { get { return 0x0046494b; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return true; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint entry_count = file.View.ReadUInt32 (4);
|
||||
if (0 == entry_count || 0 != ((entry_count - 1) >> 0x14))
|
||||
{
|
||||
Trace.WriteLine (string.Format ("Invalid entry count ({0})", entry_count));
|
||||
return null;
|
||||
}
|
||||
if (file.View.AsciiEqual (8, "__key__.dat\x00"))
|
||||
{
|
||||
uint? key = QueryEncryptionInfo();
|
||||
if (null == key)
|
||||
throw new UnknownEncryptionScheme();
|
||||
return OpenEncrypted (file, entry_count, key.Value);
|
||||
}
|
||||
|
||||
long current_offset = 8;
|
||||
var dir = new List<Entry> ((int)entry_count);
|
||||
for (uint i = 0; i < entry_count; ++i)
|
||||
{
|
||||
string name = file.View.ReadString (current_offset, 0x40);
|
||||
var entry = FormatCatalog.Instance.CreateEntry (name);
|
||||
entry.Offset = file.View.ReadUInt32 (current_offset+0x40);
|
||||
entry.Size = file.View.ReadUInt32 (current_offset+0x44);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
current_offset += 0x48;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
private ArcFile OpenEncrypted (ArcView file, uint entry_count, uint main_key)
|
||||
{
|
||||
if (1 == entry_count)
|
||||
return null; // empty archive
|
||||
long current_offset = 8;
|
||||
var twister = new Twister();
|
||||
|
||||
// [@@L1] = 32-bit key
|
||||
// [@@L1+4] = 0 if key is available, -1 otherwise
|
||||
uint key_data = file.View.ReadUInt32 (current_offset+0x44);
|
||||
uint twist_key = twister.Twist (key_data);
|
||||
// [@@L0] = 32-bit twist key
|
||||
byte[] blowfish_key = BitConverter.GetBytes (twist_key);
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Array.Reverse (blowfish_key);
|
||||
|
||||
var blowfish = new Blowfish (blowfish_key);
|
||||
var dir = new List<Entry> ((int)entry_count-1);
|
||||
byte[] name_info = new byte[0x40];
|
||||
for (uint i = 1; i < entry_count; ++i)
|
||||
{
|
||||
current_offset += 0x48;
|
||||
file.View.Read (current_offset, name_info, 0, 0x40);
|
||||
uint eax = file.View.ReadUInt32 (current_offset+0x40);
|
||||
uint edx = file.View.ReadUInt32 (current_offset+0x44);
|
||||
eax += i;
|
||||
blowfish.Decipher (ref eax, ref edx);
|
||||
uint key = twister.Twist (main_key + i);
|
||||
string name = DecipherName (name_info, key);
|
||||
|
||||
var entry = FormatCatalog.Instance.CreateEntry (name);
|
||||
entry.Offset = eax;
|
||||
entry.Size = edx;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
}
|
||||
return new FrontwingArchive (file, this, dir, blowfish);
|
||||
}
|
||||
|
||||
private Stream OpenEncryptedEntry (FrontwingArchive arc, Entry entry)
|
||||
{
|
||||
using (var view = arc.File.CreateViewAccessor (entry.Offset, entry.Size))
|
||||
{
|
||||
byte[] data = new byte[entry.Size];
|
||||
// below is supposedly faster version of
|
||||
//arc.File.View.Read (entry.Offset, data, 0, entry.Size);
|
||||
unsafe
|
||||
{
|
||||
byte* ptr = view.GetPointer (entry.Offset);
|
||||
try {
|
||||
Marshal.Copy (new IntPtr(ptr), data, 0, data.Length);
|
||||
} finally {
|
||||
view.SafeMemoryMappedViewHandle.ReleasePointer();
|
||||
}
|
||||
}
|
||||
arc.Encryption.Decipher (data, data.Length/8*8);
|
||||
return new MemoryStream (data, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
if (arc is FrontwingArchive)
|
||||
return OpenEncryptedEntry (arc as FrontwingArchive, entry);
|
||||
else
|
||||
return base.OpenEntry (arc, entry);
|
||||
}
|
||||
|
||||
public string DecipherName (byte[] name, uint key)
|
||||
{
|
||||
key += (key >> 8) + (key >> 16) + (key >> 24);
|
||||
key &= 0xff;
|
||||
key %= 0x34;
|
||||
int count = 0;
|
||||
for (int i = 0; i < name.Length; ++i)
|
||||
{
|
||||
byte al = name[i];
|
||||
if (0 == al)
|
||||
break;
|
||||
byte bl = (byte)key;
|
||||
++count;
|
||||
uint edx = al;
|
||||
al |= 0x20;
|
||||
al -= 0x61;
|
||||
if (al < 0x1a)
|
||||
{
|
||||
if (0 != (edx & 0x20))
|
||||
al += 0x1a;
|
||||
al = (byte)~al;
|
||||
al += 0x34;
|
||||
if (al >= bl)
|
||||
al -= bl;
|
||||
else
|
||||
al = (byte)(al - bl + 0x34);
|
||||
if (al >= 0x1a)
|
||||
al += 6;
|
||||
al += 0x41;
|
||||
name[i] = al;
|
||||
}
|
||||
++key;
|
||||
if (0x34 == key)
|
||||
key = 0;
|
||||
}
|
||||
return Encodings.cp932.GetString (name, 0, count);
|
||||
}
|
||||
|
||||
class Twister
|
||||
{
|
||||
const uint TwisterLength = 0x270;
|
||||
uint[] m_twister = new uint[TwisterLength];
|
||||
uint m_twister_pos = 0;
|
||||
|
||||
public uint Twist (uint key)
|
||||
{
|
||||
Init (key);
|
||||
return Next();
|
||||
}
|
||||
|
||||
public void Init (uint key)
|
||||
{
|
||||
uint edx = key;
|
||||
for (int i = 0; i < TwisterLength; ++i)
|
||||
{
|
||||
uint ecx = edx * 0x10dcd + 1;
|
||||
m_twister[i] = (edx & 0xffff0000) | (ecx >> 16);
|
||||
edx *= 0x1C587629;
|
||||
edx += 0x10dce;
|
||||
}
|
||||
m_twister_pos = 0;
|
||||
}
|
||||
|
||||
public uint Next ()
|
||||
{
|
||||
uint ecx = m_twister[m_twister_pos];
|
||||
uint edx = m_twister_pos + 1;
|
||||
if (TwisterLength == edx)
|
||||
edx = 0;
|
||||
uint edi = m_twister[edx];
|
||||
edi = ((edi ^ ecx) & 0x7FFFFFFF) ^ ecx;
|
||||
bool carry = 0 != (edi & 1);
|
||||
edi >>= 1;
|
||||
if (carry)
|
||||
edi ^= 0x9908B0DF;
|
||||
ecx = m_twister_pos + 0x18d;
|
||||
if (ecx >= TwisterLength)
|
||||
ecx -= TwisterLength;
|
||||
edi ^= m_twister[ecx];
|
||||
m_twister[m_twister_pos] = edi;
|
||||
m_twister_pos = edx;
|
||||
uint eax = edi ^ (edi >> 11);
|
||||
eax = ((eax & 0xFF3A58AD) << 7) ^ eax;
|
||||
eax = ((eax & 0xFFFFDF8C) << 15) ^ eax;
|
||||
eax = (eax >> 18) ^ eax;
|
||||
return eax;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint EncodePassPhrase (string password)
|
||||
{
|
||||
byte[] pass_bytes = Encodings.cp932.GetBytes (password);
|
||||
uint key = 0xffffffff;
|
||||
foreach (var c in pass_bytes)
|
||||
{
|
||||
uint val = (uint)c << 24;
|
||||
key ^= val;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
bool carry = 0 != (key & 0x80000000);
|
||||
key <<= 1;
|
||||
if (carry)
|
||||
key ^= 0x4C11DB7;
|
||||
}
|
||||
key = ~key;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public struct KeyData
|
||||
{
|
||||
public uint Key;
|
||||
public string Passphrase;
|
||||
}
|
||||
|
||||
public static readonly Dictionary<string, KeyData> KnownSchemes = new Dictionary<string, KeyData> {
|
||||
{ "Grisaia no Kajitsu", new KeyData { Key=0x1DAD9120, Passphrase="FW-6JD55162" }},
|
||||
{ "Shukufuku no Campanella", new KeyData { Key=0x4260E643, Passphrase="CAMPANELLA" }},
|
||||
{ "Makai Tenshi Djibril -Episode 4-", new KeyData { Key=0xA5A166AA, Passphrase="FW_MAKAI-TENSHI_DJIBRIL4" }},
|
||||
{ "Sengoku Tenshi Djibril (trial)", new KeyData { Key=0xef870610, Passphrase="FW-8O9B6WDS" }},
|
||||
};
|
||||
|
||||
public override ResourceOptions GetDefaultOptions ()
|
||||
{
|
||||
return new IntOptions {
|
||||
EncryptionInfo = Settings.Default.INTEncryption ?? new IntEncryptionInfo(),
|
||||
};
|
||||
}
|
||||
|
||||
public override ResourceOptions GetOptions (object w)
|
||||
{
|
||||
var widget = w as GUI.WidgetINT;
|
||||
if (null != widget)
|
||||
{
|
||||
Settings.Default.INTEncryption = widget.Info;
|
||||
return new IntOptions { EncryptionInfo = widget.Info };
|
||||
}
|
||||
return this.GetDefaultOptions();
|
||||
}
|
||||
|
||||
public override object GetAccessWidget ()
|
||||
{
|
||||
return new GUI.WidgetINT ();
|
||||
}
|
||||
|
||||
public override object GetCreationWidget ()
|
||||
{
|
||||
return new GUI.CreateINTWidget();
|
||||
}
|
||||
|
||||
uint? QueryEncryptionInfo ()
|
||||
{
|
||||
var options = Query<IntOptions> (arcStrings.INTNotice);
|
||||
return options.EncryptionInfo.GetKey();
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
EntryCallback callback)
|
||||
{
|
||||
int file_count = list.Count();
|
||||
if (null != callback)
|
||||
callback (file_count+2, null, null);
|
||||
int callback_count = 0;
|
||||
using (var writer = new BinaryWriter (output, Encoding.ASCII, true))
|
||||
{
|
||||
writer.Write (Signature);
|
||||
writer.Write (file_count);
|
||||
long dir_offset = output.Position;
|
||||
|
||||
var encoding = Encodings.cp932.WithFatalFallback();
|
||||
byte[] name_buf = new byte[0x40];
|
||||
int previous_size = 0;
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||
|
||||
// first, write names only
|
||||
foreach (var entry in list)
|
||||
{
|
||||
string name = Path.GetFileName (entry.Name);
|
||||
try
|
||||
{
|
||||
int size = encoding.GetBytes (name, 0, name.Length, name_buf, 0);
|
||||
for (int i = size; i < previous_size; ++i)
|
||||
name_buf[i] = 0;
|
||||
previous_size = size;
|
||||
}
|
||||
catch (EncoderFallbackException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
|
||||
}
|
||||
catch (ArgumentException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong, X);
|
||||
}
|
||||
writer.Write (name_buf);
|
||||
writer.BaseStream.Seek (8, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// now, write files and remember offset/sizes
|
||||
long current_offset = output.Position;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
if (null != callback)
|
||||
callback (callback_count++, entry, arcStrings.MsgAddingFile);
|
||||
|
||||
entry.Offset = current_offset;
|
||||
using (var input = File.OpenRead (entry.Name))
|
||||
{
|
||||
var size = input.Length;
|
||||
if (size > uint.MaxValue || current_offset + size > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
current_offset += (uint)size;
|
||||
entry.Size = (uint)size;
|
||||
input.CopyTo (output);
|
||||
}
|
||||
}
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgUpdatingIndex);
|
||||
|
||||
// at last, go back to directory and write offset/sizes
|
||||
dir_offset += 0x40;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
writer.BaseStream.Position = dir_offset;
|
||||
writer.Write ((uint)entry.Offset);
|
||||
writer.Write (entry.Size);
|
||||
dir_offset += 0x48;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//! \file ArcINT.cs
|
||||
//! \date Fri Jul 11 09:32:36 2014
|
||||
//! \brief Frontwing games archive.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Simias.Encryption;
|
||||
using System.Runtime.InteropServices;
|
||||
using GameRes.Formats.Strings;
|
||||
using GameRes.Formats.Properties;
|
||||
|
||||
namespace GameRes.Formats.CatSystem
|
||||
{
|
||||
public class FrontwingArchive : ArcFile
|
||||
{
|
||||
public readonly Blowfish Encryption;
|
||||
|
||||
public FrontwingArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, Blowfish cipher)
|
||||
: base (arc, impl, dir)
|
||||
{
|
||||
Encryption = cipher;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable()]
|
||||
public class IntEncryptionInfo
|
||||
{
|
||||
public uint? Key { get; set; }
|
||||
public string Scheme { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public uint? GetKey ()
|
||||
{
|
||||
if (null != Key && Key.HasValue)
|
||||
return Key;
|
||||
|
||||
if (!string.IsNullOrEmpty (Scheme))
|
||||
{
|
||||
IntOpener.KeyData keydata;
|
||||
if (IntOpener.KnownSchemes.TryGetValue (Scheme, out keydata))
|
||||
return keydata.Key;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty (Password))
|
||||
return IntOpener.EncodePassPhrase (Password);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class IntOptions : ResourceOptions
|
||||
{
|
||||
public IntEncryptionInfo EncryptionInfo { get; set; }
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class IntOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "INT"; } }
|
||||
public override string Description { get { return arcStrings.INTDescription; } }
|
||||
public override uint Signature { get { return 0x0046494b; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return true; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint entry_count = file.View.ReadUInt32 (4);
|
||||
if (0 == entry_count || 0 != ((entry_count - 1) >> 0x14))
|
||||
{
|
||||
Trace.WriteLine (string.Format ("Invalid entry count ({0})", entry_count));
|
||||
return null;
|
||||
}
|
||||
if (file.View.AsciiEqual (8, "__key__.dat\x00"))
|
||||
{
|
||||
uint? key = QueryEncryptionInfo();
|
||||
if (null == key)
|
||||
throw new UnknownEncryptionScheme();
|
||||
return OpenEncrypted (file, entry_count, key.Value);
|
||||
}
|
||||
|
||||
long current_offset = 8;
|
||||
var dir = new List<Entry> ((int)entry_count);
|
||||
for (uint i = 0; i < entry_count; ++i)
|
||||
{
|
||||
string name = file.View.ReadString (current_offset, 0x40);
|
||||
var entry = FormatCatalog.Instance.CreateEntry (name);
|
||||
entry.Offset = file.View.ReadUInt32 (current_offset+0x40);
|
||||
entry.Size = file.View.ReadUInt32 (current_offset+0x44);
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
current_offset += 0x48;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
private ArcFile OpenEncrypted (ArcView file, uint entry_count, uint main_key)
|
||||
{
|
||||
if (1 == entry_count)
|
||||
return null; // empty archive
|
||||
long current_offset = 8;
|
||||
var twister = new Twister();
|
||||
|
||||
// [@@L1] = 32-bit key
|
||||
// [@@L1+4] = 0 if key is available, -1 otherwise
|
||||
uint key_data = file.View.ReadUInt32 (current_offset+0x44);
|
||||
uint twist_key = twister.Twist (key_data);
|
||||
// [@@L0] = 32-bit twist key
|
||||
byte[] blowfish_key = BitConverter.GetBytes (twist_key);
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
Array.Reverse (blowfish_key);
|
||||
|
||||
var blowfish = new Blowfish (blowfish_key);
|
||||
var dir = new List<Entry> ((int)entry_count-1);
|
||||
byte[] name_info = new byte[0x40];
|
||||
for (uint i = 1; i < entry_count; ++i)
|
||||
{
|
||||
current_offset += 0x48;
|
||||
file.View.Read (current_offset, name_info, 0, 0x40);
|
||||
uint eax = file.View.ReadUInt32 (current_offset+0x40);
|
||||
uint edx = file.View.ReadUInt32 (current_offset+0x44);
|
||||
eax += i;
|
||||
blowfish.Decipher (ref eax, ref edx);
|
||||
uint key = twister.Twist (main_key + i);
|
||||
string name = DecipherName (name_info, key);
|
||||
|
||||
var entry = FormatCatalog.Instance.CreateEntry (name);
|
||||
entry.Offset = eax;
|
||||
entry.Size = edx;
|
||||
if (!entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
}
|
||||
return new FrontwingArchive (file, this, dir, blowfish);
|
||||
}
|
||||
|
||||
private Stream OpenEncryptedEntry (FrontwingArchive arc, Entry entry)
|
||||
{
|
||||
using (var view = arc.File.CreateViewAccessor (entry.Offset, entry.Size))
|
||||
{
|
||||
byte[] data = new byte[entry.Size];
|
||||
// below is supposedly faster version of
|
||||
//arc.File.View.Read (entry.Offset, data, 0, entry.Size);
|
||||
unsafe
|
||||
{
|
||||
byte* ptr = view.GetPointer (entry.Offset);
|
||||
try {
|
||||
Marshal.Copy (new IntPtr(ptr), data, 0, data.Length);
|
||||
} finally {
|
||||
view.SafeMemoryMappedViewHandle.ReleasePointer();
|
||||
}
|
||||
}
|
||||
arc.Encryption.Decipher (data, data.Length/8*8);
|
||||
return new MemoryStream (data, false);
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
if (arc is FrontwingArchive)
|
||||
return OpenEncryptedEntry (arc as FrontwingArchive, entry);
|
||||
else
|
||||
return base.OpenEntry (arc, entry);
|
||||
}
|
||||
|
||||
public string DecipherName (byte[] name, uint key)
|
||||
{
|
||||
key += (key >> 8) + (key >> 16) + (key >> 24);
|
||||
key &= 0xff;
|
||||
key %= 0x34;
|
||||
int count = 0;
|
||||
for (int i = 0; i < name.Length; ++i)
|
||||
{
|
||||
byte al = name[i];
|
||||
if (0 == al)
|
||||
break;
|
||||
byte bl = (byte)key;
|
||||
++count;
|
||||
uint edx = al;
|
||||
al |= 0x20;
|
||||
al -= 0x61;
|
||||
if (al < 0x1a)
|
||||
{
|
||||
if (0 != (edx & 0x20))
|
||||
al += 0x1a;
|
||||
al = (byte)~al;
|
||||
al += 0x34;
|
||||
if (al >= bl)
|
||||
al -= bl;
|
||||
else
|
||||
al = (byte)(al - bl + 0x34);
|
||||
if (al >= 0x1a)
|
||||
al += 6;
|
||||
al += 0x41;
|
||||
name[i] = al;
|
||||
}
|
||||
++key;
|
||||
if (0x34 == key)
|
||||
key = 0;
|
||||
}
|
||||
return Encodings.cp932.GetString (name, 0, count);
|
||||
}
|
||||
|
||||
class Twister
|
||||
{
|
||||
const uint TwisterLength = 0x270;
|
||||
uint[] m_twister = new uint[TwisterLength];
|
||||
uint m_twister_pos = 0;
|
||||
|
||||
public uint Twist (uint key)
|
||||
{
|
||||
Init (key);
|
||||
return Next();
|
||||
}
|
||||
|
||||
public void Init (uint key)
|
||||
{
|
||||
uint edx = key;
|
||||
for (int i = 0; i < TwisterLength; ++i)
|
||||
{
|
||||
uint ecx = edx * 0x10dcd + 1;
|
||||
m_twister[i] = (edx & 0xffff0000) | (ecx >> 16);
|
||||
edx *= 0x1C587629;
|
||||
edx += 0x10dce;
|
||||
}
|
||||
m_twister_pos = 0;
|
||||
}
|
||||
|
||||
public uint Next ()
|
||||
{
|
||||
uint ecx = m_twister[m_twister_pos];
|
||||
uint edx = m_twister_pos + 1;
|
||||
if (TwisterLength == edx)
|
||||
edx = 0;
|
||||
uint edi = m_twister[edx];
|
||||
edi = ((edi ^ ecx) & 0x7FFFFFFF) ^ ecx;
|
||||
bool carry = 0 != (edi & 1);
|
||||
edi >>= 1;
|
||||
if (carry)
|
||||
edi ^= 0x9908B0DF;
|
||||
ecx = m_twister_pos + 0x18d;
|
||||
if (ecx >= TwisterLength)
|
||||
ecx -= TwisterLength;
|
||||
edi ^= m_twister[ecx];
|
||||
m_twister[m_twister_pos] = edi;
|
||||
m_twister_pos = edx;
|
||||
uint eax = edi ^ (edi >> 11);
|
||||
eax = ((eax & 0xFF3A58AD) << 7) ^ eax;
|
||||
eax = ((eax & 0xFFFFDF8C) << 15) ^ eax;
|
||||
eax = (eax >> 18) ^ eax;
|
||||
return eax;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint EncodePassPhrase (string password)
|
||||
{
|
||||
byte[] pass_bytes = Encodings.cp932.GetBytes (password);
|
||||
uint key = 0xffffffff;
|
||||
foreach (var c in pass_bytes)
|
||||
{
|
||||
uint val = (uint)c << 24;
|
||||
key ^= val;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
bool carry = 0 != (key & 0x80000000);
|
||||
key <<= 1;
|
||||
if (carry)
|
||||
key ^= 0x4C11DB7;
|
||||
}
|
||||
key = ~key;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public struct KeyData
|
||||
{
|
||||
public uint Key;
|
||||
public string Passphrase;
|
||||
}
|
||||
|
||||
public static readonly Dictionary<string, KeyData> KnownSchemes = new Dictionary<string, KeyData> {
|
||||
{ "Grisaia no Kajitsu", new KeyData { Key=0x1DAD9120, Passphrase="FW-6JD55162" }},
|
||||
{ "Shukufuku no Campanella", new KeyData { Key=0x4260E643, Passphrase="CAMPANELLA" }},
|
||||
{ "Makai Tenshi Djibril -Episode 4-", new KeyData { Key=0xA5A166AA, Passphrase="FW_MAKAI-TENSHI_DJIBRIL4" }},
|
||||
{ "Sengoku Tenshi Djibril (trial)", new KeyData { Key=0xef870610, Passphrase="FW-8O9B6WDS" }},
|
||||
};
|
||||
|
||||
public override ResourceOptions GetDefaultOptions ()
|
||||
{
|
||||
return new IntOptions {
|
||||
EncryptionInfo = Settings.Default.INTEncryption ?? new IntEncryptionInfo(),
|
||||
};
|
||||
}
|
||||
|
||||
public override ResourceOptions GetOptions (object w)
|
||||
{
|
||||
var widget = w as GUI.WidgetINT;
|
||||
if (null != widget)
|
||||
{
|
||||
Settings.Default.INTEncryption = widget.Info;
|
||||
return new IntOptions { EncryptionInfo = widget.Info };
|
||||
}
|
||||
return this.GetDefaultOptions();
|
||||
}
|
||||
|
||||
public override object GetAccessWidget ()
|
||||
{
|
||||
return new GUI.WidgetINT ();
|
||||
}
|
||||
|
||||
public override object GetCreationWidget ()
|
||||
{
|
||||
return new GUI.CreateINTWidget();
|
||||
}
|
||||
|
||||
uint? QueryEncryptionInfo ()
|
||||
{
|
||||
var options = Query<IntOptions> (arcStrings.INTNotice);
|
||||
return options.EncryptionInfo.GetKey();
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
EntryCallback callback)
|
||||
{
|
||||
int file_count = list.Count();
|
||||
if (null != callback)
|
||||
callback (file_count+2, null, null);
|
||||
int callback_count = 0;
|
||||
using (var writer = new BinaryWriter (output, Encoding.ASCII, true))
|
||||
{
|
||||
writer.Write (Signature);
|
||||
writer.Write (file_count);
|
||||
long dir_offset = output.Position;
|
||||
|
||||
var encoding = Encodings.cp932.WithFatalFallback();
|
||||
byte[] name_buf = new byte[0x40];
|
||||
int previous_size = 0;
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||
|
||||
// first, write names only
|
||||
foreach (var entry in list)
|
||||
{
|
||||
string name = Path.GetFileName (entry.Name);
|
||||
try
|
||||
{
|
||||
int size = encoding.GetBytes (name, 0, name.Length, name_buf, 0);
|
||||
for (int i = size; i < previous_size; ++i)
|
||||
name_buf[i] = 0;
|
||||
previous_size = size;
|
||||
}
|
||||
catch (EncoderFallbackException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
|
||||
}
|
||||
catch (ArgumentException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong, X);
|
||||
}
|
||||
writer.Write (name_buf);
|
||||
writer.BaseStream.Seek (8, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// now, write files and remember offset/sizes
|
||||
long current_offset = output.Position;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
if (null != callback)
|
||||
callback (callback_count++, entry, arcStrings.MsgAddingFile);
|
||||
|
||||
entry.Offset = current_offset;
|
||||
using (var input = File.OpenRead (entry.Name))
|
||||
{
|
||||
var size = input.Length;
|
||||
if (size > uint.MaxValue || current_offset + size > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
current_offset += (uint)size;
|
||||
entry.Size = (uint)size;
|
||||
input.CopyTo (output);
|
||||
}
|
||||
}
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgUpdatingIndex);
|
||||
|
||||
// at last, go back to directory and write offset/sizes
|
||||
dir_offset += 0x40;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
writer.BaseStream.Position = dir_offset;
|
||||
writer.Write ((uint)entry.Offset);
|
||||
writer.Write (entry.Size);
|
||||
dir_offset += 0x48;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,362 +1,362 @@
|
||||
//! \file ImageHG3.cs
|
||||
//! \date Sat Jul 19 17:31:09 2014
|
||||
//! \brief Frontwing HG3 image format implementation.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class Hg3Format : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "HG3"; } }
|
||||
public override string Description { get { return "Frontwing proprietary image format"; } }
|
||||
public override uint Signature { get { return 0x332d4748; } }
|
||||
|
||||
public override ImageMetaData ReadMetaData (Stream stream)
|
||||
{
|
||||
var header = new byte[0x4c];
|
||||
if (0x4c != stream.Read (header, 0, header.Length))
|
||||
return null;
|
||||
if (LittleEndian.ToUInt32 (header, 0) != Signature)
|
||||
return null;
|
||||
if (LittleEndian.ToUInt32 (header, 4) != 0x0c)
|
||||
return null;
|
||||
if (!Binary.AsciiEqual (header, 0x14, "stdinfo\0"))
|
||||
return null;
|
||||
if (0x38 != LittleEndian.ToUInt32 (header, 0x1c))
|
||||
return null;
|
||||
if (0x20 != LittleEndian.ToUInt32 (header, 0x2c))
|
||||
return null;
|
||||
uint width = LittleEndian.ToUInt32 (header, 0x24); // @@L0
|
||||
uint height = LittleEndian.ToUInt32 (header, 0x28);
|
||||
int pos_x = LittleEndian.ToInt32 (header, 0x30);
|
||||
int pos_y = LittleEndian.ToInt32 (header, 0x34);
|
||||
pos_x -= LittleEndian.ToInt32 (header, 0x44);
|
||||
pos_y -= LittleEndian.ToInt32 (header, 0x48);
|
||||
|
||||
return new ImageMetaData
|
||||
{
|
||||
Width = width,
|
||||
Height = height,
|
||||
OffsetX = pos_x,
|
||||
OffsetY = pos_y,
|
||||
BPP = 32,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||
{
|
||||
stream.Position = 0x40;
|
||||
bool flipped = 0 == (stream.ReadByte() & 1) || info.OffsetY < 0;
|
||||
stream.Position = 0x4c;
|
||||
var header = new byte[0x28];
|
||||
if (0x28 != stream.Read (header, 0, header.Length))
|
||||
return null;
|
||||
if (!Binary.AsciiEqual (header, "img0000\0"))
|
||||
return null;
|
||||
uint data_size = LittleEndian.ToUInt32 (header, 0x0c);
|
||||
if (data_size < 0x18)
|
||||
return null;
|
||||
if (info.Height != LittleEndian.ToUInt32 (header, 0x14))
|
||||
return null;
|
||||
uint packed2_size = LittleEndian.ToUInt32 (header, 0x18);
|
||||
uint unpacked2_size = LittleEndian.ToUInt32 (header, 0x1c);
|
||||
uint packed1_size = LittleEndian.ToUInt32 (header, 0x20);
|
||||
uint unpacked1_size = LittleEndian.ToUInt32 (header, 0x24);
|
||||
if (packed2_size + packed1_size < packed2_size)
|
||||
return null;
|
||||
if (unpacked2_size + unpacked1_size < unpacked2_size)
|
||||
return null;
|
||||
|
||||
long data_pos = stream.Position;
|
||||
using (var unpacked2 = ZLibCompressor.DeCompress (stream))
|
||||
{
|
||||
stream.Position = data_pos + packed2_size;
|
||||
using (var unpacked1 = ZLibCompressor.DeCompress (stream))
|
||||
{
|
||||
var decoder = new Decoder (unpacked1.GetBuffer(), unpacked1_size,
|
||||
unpacked2.GetBuffer(), unpacked2_size,
|
||||
info.Width, info.Height);
|
||||
decoder.Unpack();
|
||||
var pixels = decoder.Data;
|
||||
int stride = (int)info.Width * 4;
|
||||
var bitmap = BitmapSource.Create ((int)info.Width, (int)info.Height, 96, 96,
|
||||
PixelFormats.Bgra32, null, pixels, stride);
|
||||
if (flipped)
|
||||
{
|
||||
var flipped_bitmap = new TransformedBitmap();
|
||||
flipped_bitmap.BeginInit();
|
||||
flipped_bitmap.Source = bitmap;
|
||||
flipped_bitmap.Transform = new ScaleTransform { ScaleY = -1 };
|
||||
flipped_bitmap.EndInit();
|
||||
bitmap = flipped_bitmap;
|
||||
}
|
||||
bitmap.Freeze();
|
||||
return new ImageData (bitmap, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new NotImplementedException ("Hg3Format.Write not implemented");
|
||||
}
|
||||
|
||||
class Decoder
|
||||
{
|
||||
byte[] m_in1;
|
||||
byte[] m_in2;
|
||||
byte[] m_image;
|
||||
uint m_in1_size;
|
||||
uint m_in2_size;
|
||||
uint m_dst_size;
|
||||
uint m_width;
|
||||
uint m_height;
|
||||
|
||||
public byte[] Data { get { return m_image; } }
|
||||
|
||||
public Decoder (byte[] in1, uint in1_size, byte[] in2, uint in2_size,
|
||||
uint width, uint height)
|
||||
{
|
||||
m_in1 = in1;
|
||||
m_in1_size = in1_size;
|
||||
m_in2 = in2;
|
||||
m_in2_size = in2_size;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_dst_size = width*height*4;
|
||||
m_image = new byte[(int)m_dst_size];
|
||||
}
|
||||
|
||||
uint esi;
|
||||
uint edi;
|
||||
uint eax;
|
||||
uint ebx;
|
||||
uint ecx;
|
||||
uint edx;
|
||||
|
||||
uint L0, L1, L2, L3, L4;
|
||||
uint m_plane;
|
||||
|
||||
public void Unpack ()
|
||||
{
|
||||
m_plane = 0;
|
||||
edi = 0;
|
||||
esi = 0;
|
||||
ebx = 0;
|
||||
eax = m_in1_size;
|
||||
L0 = m_in2_size;
|
||||
L1 = 0;
|
||||
bool skip_first = GetNextBit();
|
||||
Proc4();
|
||||
ecx = m_dst_size;
|
||||
if (eax > m_dst_size)
|
||||
throw new InvalidFormatException ("Underflow at Hg3Format.Decoder.Unpack()");
|
||||
m_dst_size -= eax;
|
||||
ecx >>= 2;
|
||||
L2 = eax;
|
||||
L3 = ecx;
|
||||
L4 = ecx;
|
||||
for (;;)
|
||||
{
|
||||
if (!skip_first)
|
||||
{
|
||||
// @@1:
|
||||
if (0 == L2)
|
||||
break;
|
||||
Proc4();
|
||||
ecx = eax;
|
||||
if (ecx > L2)
|
||||
throw new InvalidFormatException ("Overflow at Hg3Format.Decoder.Unpack()");
|
||||
L2 -= ecx;
|
||||
eax = 0;
|
||||
do
|
||||
Proc2();
|
||||
while (0 != --ecx);
|
||||
}
|
||||
// @@1a:
|
||||
if (0 == L2)
|
||||
break;
|
||||
Proc4();
|
||||
ecx = eax;
|
||||
if (ecx > L2 || ecx > L0)
|
||||
throw new InvalidFormatException ("Overflow (2) at Hg3Format.Decoder.Unpack()");
|
||||
L2 -= ecx;
|
||||
L0 -= ecx;
|
||||
do
|
||||
{
|
||||
eax = m_in2[L1++];
|
||||
Proc2();
|
||||
}
|
||||
while (0 != --ecx);
|
||||
skip_first = false;
|
||||
}
|
||||
// @@7:
|
||||
ecx = m_dst_size;
|
||||
esi = 0;
|
||||
if (0 != ecx)
|
||||
{
|
||||
eax = 0;
|
||||
do
|
||||
Proc2();
|
||||
while (0 != --ecx);
|
||||
}
|
||||
Proc6 (m_width, m_height);
|
||||
// @@9:
|
||||
eax = 0;
|
||||
edx = m_in1_size;
|
||||
}
|
||||
|
||||
void Proc2 () // @@2
|
||||
{
|
||||
m_image[edi] = (byte)eax;
|
||||
edi += 4;
|
||||
if (0 == --L3)
|
||||
{
|
||||
edi = ++m_plane;
|
||||
L3 = L4;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetNextBit () // @@3
|
||||
{
|
||||
bool carry = 0 != (ebx & 1);
|
||||
ebx >>= 1;
|
||||
if (0 == ebx)
|
||||
{
|
||||
if (0 == m_in1_size--)
|
||||
throw new InvalidFormatException ("Hg3Format.Decoder.Underflow at GetNextBit()");
|
||||
ebx = (uint)(m_in1[esi++] | 0x100);
|
||||
carry = 0 != (ebx & 1);
|
||||
ebx >>= 1;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
void Proc4 () // @@4
|
||||
{
|
||||
ecx = 0;
|
||||
eax = 0;
|
||||
do
|
||||
{
|
||||
if (ecx >= 0x20)
|
||||
throw new InvalidFormatException ("Hg3Format.Decoder.Overflow at Proc4");
|
||||
++ecx;
|
||||
}
|
||||
while (!GetNextBit());
|
||||
++eax;
|
||||
while (0 != --ecx)
|
||||
{
|
||||
eax += eax + (uint)(GetNextBit() ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Proc6 (uint width, uint height)
|
||||
{
|
||||
uint[] table = new uint[0x100];
|
||||
ecx = 0;
|
||||
for (uint i = 0; i < 0x100; ++i)
|
||||
{
|
||||
eax = 0xffffffff;
|
||||
edx = i;
|
||||
do
|
||||
{
|
||||
eax >>= 2;
|
||||
eax |= (edx & 3) << 30;
|
||||
eax >>= 6;
|
||||
edx >>= 2;
|
||||
}
|
||||
while (0 != (0x80 & eax));
|
||||
table[i] = eax;
|
||||
}
|
||||
ecx = width * height * 4;
|
||||
for (uint i = 0; i < ecx; i += 4)
|
||||
{
|
||||
eax = m_image[i];
|
||||
edx = table[eax];
|
||||
edx <<= 2;
|
||||
eax = m_image[i+1];
|
||||
edx += table[eax];
|
||||
edx <<= 2;
|
||||
eax = m_image[i+2];
|
||||
edx += table[eax];
|
||||
edx <<= 2;
|
||||
eax = m_image[i+3];
|
||||
edx += table[eax];
|
||||
m_image[i] = (byte)(edx);
|
||||
m_image[i+1] = (byte)(edx >> 8);
|
||||
m_image[i+2] = (byte)(edx >> 16);
|
||||
m_image[i+3] = (byte)(edx >> 24);
|
||||
}
|
||||
edi = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
eax = m_image[edi];
|
||||
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
|
||||
eax >>= 1;
|
||||
eax ^= edx;
|
||||
m_image[edi++] = (byte)eax;
|
||||
}
|
||||
ecx = width;
|
||||
if (0 != --ecx)
|
||||
{
|
||||
ecx <<= 2;
|
||||
do
|
||||
{
|
||||
eax = m_image[edi];
|
||||
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
|
||||
eax >>= 1;
|
||||
eax ^= edx;
|
||||
eax += m_image[edi-4];
|
||||
m_image[edi++] = (byte)eax;
|
||||
}
|
||||
while (0 != --ecx);
|
||||
}
|
||||
ecx = height;
|
||||
if (0 != --ecx)
|
||||
{
|
||||
uint stride = width*4;
|
||||
ecx *= stride;
|
||||
do
|
||||
{
|
||||
eax = m_image[edi];
|
||||
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
|
||||
eax >>= 1;
|
||||
eax ^= edx;
|
||||
eax += m_image[edi-stride];
|
||||
m_image[edi++] = (byte)eax;
|
||||
}
|
||||
while (0 != --ecx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//! \file ImageHG3.cs
|
||||
//! \date Sat Jul 19 17:31:09 2014
|
||||
//! \brief Frontwing HG3 image format implementation.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.CatSystem
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class Hg3Format : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "HG3"; } }
|
||||
public override string Description { get { return "Frontwing proprietary image format"; } }
|
||||
public override uint Signature { get { return 0x332d4748; } }
|
||||
|
||||
public override ImageMetaData ReadMetaData (Stream stream)
|
||||
{
|
||||
var header = new byte[0x4c];
|
||||
if (0x4c != stream.Read (header, 0, header.Length))
|
||||
return null;
|
||||
if (LittleEndian.ToUInt32 (header, 0) != Signature)
|
||||
return null;
|
||||
if (LittleEndian.ToUInt32 (header, 4) != 0x0c)
|
||||
return null;
|
||||
if (!Binary.AsciiEqual (header, 0x14, "stdinfo\0"))
|
||||
return null;
|
||||
if (0x38 != LittleEndian.ToUInt32 (header, 0x1c))
|
||||
return null;
|
||||
if (0x20 != LittleEndian.ToUInt32 (header, 0x2c))
|
||||
return null;
|
||||
uint width = LittleEndian.ToUInt32 (header, 0x24); // @@L0
|
||||
uint height = LittleEndian.ToUInt32 (header, 0x28);
|
||||
int pos_x = LittleEndian.ToInt32 (header, 0x30);
|
||||
int pos_y = LittleEndian.ToInt32 (header, 0x34);
|
||||
pos_x -= LittleEndian.ToInt32 (header, 0x44);
|
||||
pos_y -= LittleEndian.ToInt32 (header, 0x48);
|
||||
|
||||
return new ImageMetaData
|
||||
{
|
||||
Width = width,
|
||||
Height = height,
|
||||
OffsetX = pos_x,
|
||||
OffsetY = pos_y,
|
||||
BPP = 32,
|
||||
};
|
||||
}
|
||||
|
||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||
{
|
||||
stream.Position = 0x40;
|
||||
bool flipped = 0 == (stream.ReadByte() & 1) || info.OffsetY < 0;
|
||||
stream.Position = 0x4c;
|
||||
var header = new byte[0x28];
|
||||
if (0x28 != stream.Read (header, 0, header.Length))
|
||||
return null;
|
||||
if (!Binary.AsciiEqual (header, "img0000\0"))
|
||||
return null;
|
||||
uint data_size = LittleEndian.ToUInt32 (header, 0x0c);
|
||||
if (data_size < 0x18)
|
||||
return null;
|
||||
if (info.Height != LittleEndian.ToUInt32 (header, 0x14))
|
||||
return null;
|
||||
uint packed2_size = LittleEndian.ToUInt32 (header, 0x18);
|
||||
uint unpacked2_size = LittleEndian.ToUInt32 (header, 0x1c);
|
||||
uint packed1_size = LittleEndian.ToUInt32 (header, 0x20);
|
||||
uint unpacked1_size = LittleEndian.ToUInt32 (header, 0x24);
|
||||
if (packed2_size + packed1_size < packed2_size)
|
||||
return null;
|
||||
if (unpacked2_size + unpacked1_size < unpacked2_size)
|
||||
return null;
|
||||
|
||||
long data_pos = stream.Position;
|
||||
using (var unpacked2 = ZLibCompressor.DeCompress (stream))
|
||||
{
|
||||
stream.Position = data_pos + packed2_size;
|
||||
using (var unpacked1 = ZLibCompressor.DeCompress (stream))
|
||||
{
|
||||
var decoder = new Decoder (unpacked1.GetBuffer(), unpacked1_size,
|
||||
unpacked2.GetBuffer(), unpacked2_size,
|
||||
info.Width, info.Height);
|
||||
decoder.Unpack();
|
||||
var pixels = decoder.Data;
|
||||
int stride = (int)info.Width * 4;
|
||||
var bitmap = BitmapSource.Create ((int)info.Width, (int)info.Height, 96, 96,
|
||||
PixelFormats.Bgra32, null, pixels, stride);
|
||||
if (flipped)
|
||||
{
|
||||
var flipped_bitmap = new TransformedBitmap();
|
||||
flipped_bitmap.BeginInit();
|
||||
flipped_bitmap.Source = bitmap;
|
||||
flipped_bitmap.Transform = new ScaleTransform { ScaleY = -1 };
|
||||
flipped_bitmap.EndInit();
|
||||
bitmap = flipped_bitmap;
|
||||
}
|
||||
bitmap.Freeze();
|
||||
return new ImageData (bitmap, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new NotImplementedException ("Hg3Format.Write not implemented");
|
||||
}
|
||||
|
||||
class Decoder
|
||||
{
|
||||
byte[] m_in1;
|
||||
byte[] m_in2;
|
||||
byte[] m_image;
|
||||
uint m_in1_size;
|
||||
uint m_in2_size;
|
||||
uint m_dst_size;
|
||||
uint m_width;
|
||||
uint m_height;
|
||||
|
||||
public byte[] Data { get { return m_image; } }
|
||||
|
||||
public Decoder (byte[] in1, uint in1_size, byte[] in2, uint in2_size,
|
||||
uint width, uint height)
|
||||
{
|
||||
m_in1 = in1;
|
||||
m_in1_size = in1_size;
|
||||
m_in2 = in2;
|
||||
m_in2_size = in2_size;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_dst_size = width*height*4;
|
||||
m_image = new byte[(int)m_dst_size];
|
||||
}
|
||||
|
||||
uint esi;
|
||||
uint edi;
|
||||
uint eax;
|
||||
uint ebx;
|
||||
uint ecx;
|
||||
uint edx;
|
||||
|
||||
uint L0, L1, L2, L3, L4;
|
||||
uint m_plane;
|
||||
|
||||
public void Unpack ()
|
||||
{
|
||||
m_plane = 0;
|
||||
edi = 0;
|
||||
esi = 0;
|
||||
ebx = 0;
|
||||
eax = m_in1_size;
|
||||
L0 = m_in2_size;
|
||||
L1 = 0;
|
||||
bool skip_first = GetNextBit();
|
||||
Proc4();
|
||||
ecx = m_dst_size;
|
||||
if (eax > m_dst_size)
|
||||
throw new InvalidFormatException ("Underflow at Hg3Format.Decoder.Unpack()");
|
||||
m_dst_size -= eax;
|
||||
ecx >>= 2;
|
||||
L2 = eax;
|
||||
L3 = ecx;
|
||||
L4 = ecx;
|
||||
for (;;)
|
||||
{
|
||||
if (!skip_first)
|
||||
{
|
||||
// @@1:
|
||||
if (0 == L2)
|
||||
break;
|
||||
Proc4();
|
||||
ecx = eax;
|
||||
if (ecx > L2)
|
||||
throw new InvalidFormatException ("Overflow at Hg3Format.Decoder.Unpack()");
|
||||
L2 -= ecx;
|
||||
eax = 0;
|
||||
do
|
||||
Proc2();
|
||||
while (0 != --ecx);
|
||||
}
|
||||
// @@1a:
|
||||
if (0 == L2)
|
||||
break;
|
||||
Proc4();
|
||||
ecx = eax;
|
||||
if (ecx > L2 || ecx > L0)
|
||||
throw new InvalidFormatException ("Overflow (2) at Hg3Format.Decoder.Unpack()");
|
||||
L2 -= ecx;
|
||||
L0 -= ecx;
|
||||
do
|
||||
{
|
||||
eax = m_in2[L1++];
|
||||
Proc2();
|
||||
}
|
||||
while (0 != --ecx);
|
||||
skip_first = false;
|
||||
}
|
||||
// @@7:
|
||||
ecx = m_dst_size;
|
||||
esi = 0;
|
||||
if (0 != ecx)
|
||||
{
|
||||
eax = 0;
|
||||
do
|
||||
Proc2();
|
||||
while (0 != --ecx);
|
||||
}
|
||||
Proc6 (m_width, m_height);
|
||||
// @@9:
|
||||
eax = 0;
|
||||
edx = m_in1_size;
|
||||
}
|
||||
|
||||
void Proc2 () // @@2
|
||||
{
|
||||
m_image[edi] = (byte)eax;
|
||||
edi += 4;
|
||||
if (0 == --L3)
|
||||
{
|
||||
edi = ++m_plane;
|
||||
L3 = L4;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetNextBit () // @@3
|
||||
{
|
||||
bool carry = 0 != (ebx & 1);
|
||||
ebx >>= 1;
|
||||
if (0 == ebx)
|
||||
{
|
||||
if (0 == m_in1_size--)
|
||||
throw new InvalidFormatException ("Hg3Format.Decoder.Underflow at GetNextBit()");
|
||||
ebx = (uint)(m_in1[esi++] | 0x100);
|
||||
carry = 0 != (ebx & 1);
|
||||
ebx >>= 1;
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
void Proc4 () // @@4
|
||||
{
|
||||
ecx = 0;
|
||||
eax = 0;
|
||||
do
|
||||
{
|
||||
if (ecx >= 0x20)
|
||||
throw new InvalidFormatException ("Hg3Format.Decoder.Overflow at Proc4");
|
||||
++ecx;
|
||||
}
|
||||
while (!GetNextBit());
|
||||
++eax;
|
||||
while (0 != --ecx)
|
||||
{
|
||||
eax += eax + (uint)(GetNextBit() ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Proc6 (uint width, uint height)
|
||||
{
|
||||
uint[] table = new uint[0x100];
|
||||
ecx = 0;
|
||||
for (uint i = 0; i < 0x100; ++i)
|
||||
{
|
||||
eax = 0xffffffff;
|
||||
edx = i;
|
||||
do
|
||||
{
|
||||
eax >>= 2;
|
||||
eax |= (edx & 3) << 30;
|
||||
eax >>= 6;
|
||||
edx >>= 2;
|
||||
}
|
||||
while (0 != (0x80 & eax));
|
||||
table[i] = eax;
|
||||
}
|
||||
ecx = width * height * 4;
|
||||
for (uint i = 0; i < ecx; i += 4)
|
||||
{
|
||||
eax = m_image[i];
|
||||
edx = table[eax];
|
||||
edx <<= 2;
|
||||
eax = m_image[i+1];
|
||||
edx += table[eax];
|
||||
edx <<= 2;
|
||||
eax = m_image[i+2];
|
||||
edx += table[eax];
|
||||
edx <<= 2;
|
||||
eax = m_image[i+3];
|
||||
edx += table[eax];
|
||||
m_image[i] = (byte)(edx);
|
||||
m_image[i+1] = (byte)(edx >> 8);
|
||||
m_image[i+2] = (byte)(edx >> 16);
|
||||
m_image[i+3] = (byte)(edx >> 24);
|
||||
}
|
||||
edi = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
eax = m_image[edi];
|
||||
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
|
||||
eax >>= 1;
|
||||
eax ^= edx;
|
||||
m_image[edi++] = (byte)eax;
|
||||
}
|
||||
ecx = width;
|
||||
if (0 != --ecx)
|
||||
{
|
||||
ecx <<= 2;
|
||||
do
|
||||
{
|
||||
eax = m_image[edi];
|
||||
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
|
||||
eax >>= 1;
|
||||
eax ^= edx;
|
||||
eax += m_image[edi-4];
|
||||
m_image[edi++] = (byte)eax;
|
||||
}
|
||||
while (0 != --ecx);
|
||||
}
|
||||
ecx = height;
|
||||
if (0 != --ecx)
|
||||
{
|
||||
uint stride = width*4;
|
||||
ecx *= stride;
|
||||
do
|
||||
{
|
||||
eax = m_image[edi];
|
||||
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
|
||||
eax >>= 1;
|
||||
eax ^= edx;
|
||||
eax += m_image[edi-stride];
|
||||
m_image[edi++] = (byte)eax;
|
||||
}
|
||||
while (0 != --ecx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +1,59 @@
|
||||
<Grid x:Class="GameRes.Formats.GUI.WidgetINT"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:GameRes.Formats.Strings"
|
||||
xmlns:fmt="clr-namespace:GameRes.Formats"
|
||||
xmlns:local="clr-namespace:GameRes.Formats.GUI"
|
||||
MaxWidth="260">
|
||||
<Grid.Resources>
|
||||
<local:KeyConverter x:Key="keyConverter"/>
|
||||
<Style TargetType="{x:Type TextBox}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Validation.HasError" Value="true">
|
||||
<Setter Property="ToolTip"
|
||||
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition MinWidth="130" Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="{x:Static s:arcStrings.INTLabelNumericKey}" Target="{Binding ElementName=Passkey}"
|
||||
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
|
||||
<TextBox Name="Passkey" Grid.Column="1" Grid.Row="0" Margin="0,3,0,3">
|
||||
<TextBox.Text>
|
||||
<Binding Path="Key" Converter="{StaticResource keyConverter}" UpdateSourceTrigger="PropertyChanged">
|
||||
<Binding.ValidationRules>
|
||||
<local:PasskeyRule/>
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox.Text>
|
||||
<Validation.ErrorTemplate>
|
||||
<ControlTemplate>
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Right" Foreground="Red" FontWeight="Bold" Text="!" VerticalAlignment="Center"/>
|
||||
<Border BorderBrush="Red" BorderThickness="1">
|
||||
<AdornedElementPlaceholder Name="ValidationAdorner" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</ControlTemplate>
|
||||
</Validation.ErrorTemplate>
|
||||
</TextBox>
|
||||
<Label Content="{x:Static s:arcStrings.LabelPassphrase}" Target="{Binding ElementName=Passphrase}"
|
||||
Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right"/>
|
||||
<TextBox Name="Passphrase" Grid.Column="1" Grid.Row="1" Margin="0,3,0,3"
|
||||
Text="{Binding Path=Password}"/>
|
||||
<Label Content="{x:Static s:arcStrings.LabelScheme}" Target="{Binding ElementName=EncScheme}"
|
||||
Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right"/>
|
||||
<ComboBox Name="EncScheme" Grid.Column="1" Grid.Row="2" Margin="0,3,0,0"
|
||||
ItemsSource="{Binding Source={x:Static fmt:IntOpener.KnownSchemes}, Path=Keys, Mode=OneWay}"
|
||||
Width="{Binding ElementName=Passkey, Path=ActualWidth}"
|
||||
SelectedValue="{Binding Path=Scheme}"/>
|
||||
</Grid>
|
||||
<Grid x:Class="GameRes.Formats.GUI.WidgetINT"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:GameRes.Formats.Strings"
|
||||
xmlns:fmt="clr-namespace:GameRes.Formats.CatSystem"
|
||||
xmlns:local="clr-namespace:GameRes.Formats.GUI"
|
||||
MaxWidth="260">
|
||||
<Grid.Resources>
|
||||
<local:KeyConverter x:Key="keyConverter"/>
|
||||
<Style TargetType="{x:Type TextBox}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Validation.HasError" Value="true">
|
||||
<Setter Property="ToolTip"
|
||||
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition MinWidth="130" Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="{x:Static s:arcStrings.INTLabelNumericKey}" Target="{Binding ElementName=Passkey}"
|
||||
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
|
||||
<TextBox Name="Passkey" Grid.Column="1" Grid.Row="0" Margin="0,3,0,3">
|
||||
<TextBox.Text>
|
||||
<Binding Path="Key" Converter="{StaticResource keyConverter}" UpdateSourceTrigger="PropertyChanged">
|
||||
<Binding.ValidationRules>
|
||||
<local:PasskeyRule/>
|
||||
</Binding.ValidationRules>
|
||||
</Binding>
|
||||
</TextBox.Text>
|
||||
<Validation.ErrorTemplate>
|
||||
<ControlTemplate>
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Right" Foreground="Red" FontWeight="Bold" Text="!" VerticalAlignment="Center"/>
|
||||
<Border BorderBrush="Red" BorderThickness="1">
|
||||
<AdornedElementPlaceholder Name="ValidationAdorner" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</ControlTemplate>
|
||||
</Validation.ErrorTemplate>
|
||||
</TextBox>
|
||||
<Label Content="{x:Static s:arcStrings.LabelPassphrase}" Target="{Binding ElementName=Passphrase}"
|
||||
Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right"/>
|
||||
<TextBox Name="Passphrase" Grid.Column="1" Grid.Row="1" Margin="0,3,0,3"
|
||||
Text="{Binding Path=Password}"/>
|
||||
<Label Content="{x:Static s:arcStrings.LabelScheme}" Target="{Binding ElementName=EncScheme}"
|
||||
Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right"/>
|
||||
<ComboBox Name="EncScheme" Grid.Column="1" Grid.Row="2" Margin="0,3,0,0"
|
||||
ItemsSource="{Binding Source={x:Static fmt:IntOpener.KnownSchemes}, Path=Keys, Mode=OneWay}"
|
||||
Width="{Binding ElementName=Passkey, Path=ActualWidth}"
|
||||
SelectedValue="{Binding Path=Scheme}"/>
|
||||
</Grid>
|
@ -1,107 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GameRes.Formats.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WidgetINT.xaml
|
||||
/// </summary>
|
||||
public partial class WidgetINT : Grid
|
||||
{
|
||||
public WidgetINT ()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.DataContext = GameRes.Formats.Properties.Settings.Default.INTEncryption ?? new IntEncryptionInfo();
|
||||
|
||||
Passphrase.TextChanged += OnPassphraseChanged;
|
||||
EncScheme.SelectionChanged += OnSchemeChanged;
|
||||
}
|
||||
|
||||
public IntEncryptionInfo Info { get { return this.DataContext as IntEncryptionInfo; } }
|
||||
|
||||
void OnPasskeyChanged (object sender, TextChangedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
void OnPassphraseChanged (object sender, TextChangedEventArgs e)
|
||||
{
|
||||
var widget = sender as TextBox;
|
||||
uint key = IntOpener.EncodePassPhrase (widget.Text);
|
||||
Passkey.Text = key.ToString ("X8");
|
||||
}
|
||||
|
||||
void OnSchemeChanged (object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var widget = sender as ComboBox;
|
||||
IntOpener.KeyData keydata;
|
||||
if (IntOpener.KnownSchemes.TryGetValue (widget.SelectedItem as string, out keydata))
|
||||
{
|
||||
Passphrase.TextChanged -= OnPassphraseChanged;
|
||||
try
|
||||
{
|
||||
Passphrase.Text = keydata.Passphrase;
|
||||
Passkey.Text = keydata.Key.ToString ("X8");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Passphrase.TextChanged += OnPassphraseChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(uint?), typeof(string))]
|
||||
public class KeyConverter : IValueConverter
|
||||
{
|
||||
public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
uint? key = (uint?)value;
|
||||
return null != key ? key.Value.ToString ("X") : "";
|
||||
}
|
||||
|
||||
public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
string strValue = value as string;
|
||||
uint result_key;
|
||||
if (uint.TryParse(strValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result_key))
|
||||
return new uint? (result_key);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class PasskeyRule : ValidationRule
|
||||
{
|
||||
public PasskeyRule()
|
||||
{
|
||||
}
|
||||
|
||||
public override ValidationResult Validate (object value, CultureInfo cultureInfo)
|
||||
{
|
||||
uint key = 0;
|
||||
try
|
||||
{
|
||||
if (((string)value).Length > 0)
|
||||
key = UInt32.Parse ((string)value, NumberStyles.HexNumber);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ValidationResult (false, Strings.arcStrings.INTKeyRequirement);
|
||||
}
|
||||
return new ValidationResult (true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using GameRes.Formats.CatSystem;
|
||||
|
||||
namespace GameRes.Formats.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WidgetINT.xaml
|
||||
/// </summary>
|
||||
public partial class WidgetINT : Grid
|
||||
{
|
||||
public WidgetINT ()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.DataContext = GameRes.Formats.Properties.Settings.Default.INTEncryption ?? new IntEncryptionInfo();
|
||||
|
||||
Passphrase.TextChanged += OnPassphraseChanged;
|
||||
EncScheme.SelectionChanged += OnSchemeChanged;
|
||||
}
|
||||
|
||||
public IntEncryptionInfo Info { get { return this.DataContext as IntEncryptionInfo; } }
|
||||
|
||||
void OnPasskeyChanged (object sender, TextChangedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
void OnPassphraseChanged (object sender, TextChangedEventArgs e)
|
||||
{
|
||||
var widget = sender as TextBox;
|
||||
uint key = IntOpener.EncodePassPhrase (widget.Text);
|
||||
Passkey.Text = key.ToString ("X8");
|
||||
}
|
||||
|
||||
void OnSchemeChanged (object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var widget = sender as ComboBox;
|
||||
IntOpener.KeyData keydata;
|
||||
if (IntOpener.KnownSchemes.TryGetValue (widget.SelectedItem as string, out keydata))
|
||||
{
|
||||
Passphrase.TextChanged -= OnPassphraseChanged;
|
||||
try
|
||||
{
|
||||
Passphrase.Text = keydata.Passphrase;
|
||||
Passkey.Text = keydata.Key.ToString ("X8");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Passphrase.TextChanged += OnPassphraseChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ValueConversion(typeof(uint?), typeof(string))]
|
||||
public class KeyConverter : IValueConverter
|
||||
{
|
||||
public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
uint? key = (uint?)value;
|
||||
return null != key ? key.Value.ToString ("X") : "";
|
||||
}
|
||||
|
||||
public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
string strValue = value as string;
|
||||
uint result_key;
|
||||
if (uint.TryParse(strValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result_key))
|
||||
return new uint? (result_key);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class PasskeyRule : ValidationRule
|
||||
{
|
||||
public PasskeyRule()
|
||||
{
|
||||
}
|
||||
|
||||
public override ValidationResult Validate (object value, CultureInfo cultureInfo)
|
||||
{
|
||||
uint key = 0;
|
||||
try
|
||||
{
|
||||
if (((string)value).Length > 0)
|
||||
key = UInt32.Parse ((string)value, NumberStyles.HexNumber);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new ValidationResult (false, Strings.arcStrings.INTKeyRequirement);
|
||||
}
|
||||
return new ValidationResult (true, null);
|
||||
}
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ using GameRes.Utility;
|
||||
using GameRes.Formats.Strings;
|
||||
using GameRes.Formats.Properties;
|
||||
|
||||
namespace GameRes.Formats.DRS
|
||||
namespace GameRes.Formats.Ikura
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class DrsOpener : ArchiveFormat
|
@ -34,7 +34,7 @@ using System.Windows.Media.Imaging;
|
||||
using GameRes.Compression;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.DRS
|
||||
namespace GameRes.Formats.Ikura
|
||||
{
|
||||
[Export(typeof(ImageFormat))]
|
||||
public class DrgFormat : ImageFormat
|
@ -28,7 +28,7 @@ using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.DRS
|
||||
namespace GameRes.Formats.Ikura
|
||||
{
|
||||
internal class GgpMetaData : ImageMetaData
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
<StackPanel x:Class="GameRes.Formats.GUI.WidgetISF"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:fmt="clr-namespace:GameRes.Formats.DRS"
|
||||
xmlns:fmt="clr-namespace:GameRes.Formats.Ikura"
|
||||
xmlns:p="clr-namespace:GameRes.Formats.Properties"
|
||||
Orientation="Vertical" MaxWidth="250">
|
||||
<ComboBox Name="Scheme" ItemsSource="{Binding Source={x:Static fmt:MpxOpener.KnownSecrets}, Path=Keys, Mode=OneWay}"
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
||||
<Grid x:Class="GameRes.Formats.GUI.WidgetXP3"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:fmt="clr-namespace:GameRes.Formats.KiriKiri"
|
||||
xmlns:p="clr-namespace:GameRes.Formats.Properties"
|
||||
MaxWidth="250">
|
||||
<ComboBox Name="Scheme" ItemsSource="{Binding Source={x:Static fmt:Xp3Opener.KnownSchemes}, Path=Keys, Mode=OneWay}"
|
||||
SelectedValue="{Binding Source={x:Static p:Settings.Default}, Path=XP3Scheme, Mode=TwoWay}" Width="180"/>
|
||||
</Grid>
|
||||
<Grid x:Class="GameRes.Formats.GUI.WidgetXP3"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:fmt="clr-namespace:GameRes.Formats.KiriKiri"
|
||||
xmlns:p="clr-namespace:GameRes.Formats.Properties"
|
||||
MaxWidth="250">
|
||||
<ComboBox Name="Scheme" ItemsSource="{Binding Source={x:Static fmt:Xp3Opener.KnownSchemes}, Path=Keys, Mode=OneWay}"
|
||||
SelectedValue="{Binding Source={x:Static p:Settings.Default}, Path=XP3Scheme, Mode=TwoWay}" Width="180"/>
|
||||
</Grid>
|
@ -1,27 +1,27 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using GameRes.Formats.KiriKiri;
|
||||
using GameRes.Formats.Properties;
|
||||
using GameRes.Formats.Strings;
|
||||
|
||||
|
||||
namespace GameRes.Formats.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WidgetXP3.xaml
|
||||
/// </summary>
|
||||
public partial class WidgetXP3 : Grid
|
||||
{
|
||||
public WidgetXP3 ()
|
||||
{
|
||||
InitializeComponent();
|
||||
if (null == Scheme.SelectedItem)
|
||||
Scheme.SelectedItem = arcStrings.ArcNoEncryption;
|
||||
}
|
||||
|
||||
public ICrypt GetScheme ()
|
||||
{
|
||||
return Xp3Opener.GetScheme (Scheme.SelectedItem as string);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using GameRes.Formats.KiriKiri;
|
||||
using GameRes.Formats.Properties;
|
||||
using GameRes.Formats.Strings;
|
||||
|
||||
|
||||
namespace GameRes.Formats.GUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WidgetXP3.xaml
|
||||
/// </summary>
|
||||
public partial class WidgetXP3 : Grid
|
||||
{
|
||||
public WidgetXP3 ()
|
||||
{
|
||||
InitializeComponent();
|
||||
if (null == Scheme.SelectedItem)
|
||||
Scheme.SelectedItem = arcStrings.ArcNoEncryption;
|
||||
}
|
||||
|
||||
public ICrypt GetScheme ()
|
||||
{
|
||||
return Xp3Opener.GetScheme (Scheme.SelectedItem as string);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,312 +1,312 @@
|
||||
//! \file ArcXFL.cs
|
||||
//! \date Mon Jun 30 21:18:29 2014
|
||||
//! \brief XFL resource format implementation.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using GameRes.Formats.Strings;
|
||||
|
||||
namespace GameRes.Formats.Liar
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class XflOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "XFL"; } }
|
||||
public override string Description { get { return Strings.arcStrings.XFLDescription; } }
|
||||
public override uint Signature { get { return 0x0001424c; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return true; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint dir_size = file.View.ReadUInt32 (4);
|
||||
int count = file.View.ReadInt32 (8);
|
||||
if (count <= 0)
|
||||
return null;
|
||||
long max_offset = file.MaxOffset;
|
||||
uint base_offset = dir_size + 12;
|
||||
if (dir_size >= max_offset || base_offset >= max_offset)
|
||||
return null;
|
||||
|
||||
file.View.Reserve (0, base_offset);
|
||||
long cur_offset = 12;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (cur_offset+40 > base_offset)
|
||||
return null;
|
||||
string name = file.View.ReadString (cur_offset, 32);
|
||||
var entry = FormatCatalog.Instance.CreateEntry (name);
|
||||
entry.Offset = base_offset + file.View.ReadUInt32 (cur_offset+32);
|
||||
entry.Size = file.View.ReadUInt32 (cur_offset+36);
|
||||
if (!entry.CheckPlacement (max_offset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
cur_offset += 40;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
EntryCallback callback)
|
||||
{
|
||||
using (var writer = new BinaryWriter (output, Encoding.ASCII, true))
|
||||
{
|
||||
writer.Write (Signature);
|
||||
int list_size = list.Count();
|
||||
uint dir_size = (uint)(list_size * 40);
|
||||
writer.Write (dir_size);
|
||||
writer.Write (list_size);
|
||||
|
||||
var encoding = Encodings.cp932.WithFatalFallback();
|
||||
|
||||
byte[] name_buf = new byte[32];
|
||||
int callback_count = 0;
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||
|
||||
// first, write names only
|
||||
foreach (var entry in list)
|
||||
{
|
||||
string name = Path.GetFileName (entry.Name);
|
||||
try
|
||||
{
|
||||
int size = encoding.GetBytes (name, 0, name.Length, name_buf, 0);
|
||||
if (size < name_buf.Length)
|
||||
name_buf[size] = 0;
|
||||
}
|
||||
catch (EncoderFallbackException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
|
||||
}
|
||||
catch (ArgumentException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong, X);
|
||||
}
|
||||
writer.Write (name_buf);
|
||||
writer.BaseStream.Seek (8, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// now, write files and remember offset/sizes
|
||||
uint current_offset = 0;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
if (null != callback)
|
||||
callback (callback_count++, entry, arcStrings.MsgAddingFile);
|
||||
|
||||
entry.Offset = current_offset;
|
||||
using (var input = File.Open (entry.Name, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
var size = input.Length;
|
||||
if (size > uint.MaxValue || current_offset + size > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
current_offset += (uint)size;
|
||||
entry.Size = (uint)size;
|
||||
input.CopyTo (output);
|
||||
}
|
||||
}
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgUpdatingIndex);
|
||||
|
||||
// at last, go back to directory and write offset/sizes
|
||||
long dir_offset = 12+32;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
writer.BaseStream.Position = dir_offset;
|
||||
writer.Write ((uint)entry.Offset);
|
||||
writer.Write (entry.Size);
|
||||
dir_offset += 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LwgImageEntry : ImageEntry
|
||||
{
|
||||
public int PosX;
|
||||
public int PosY;
|
||||
public int BPP;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class LwgOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "LWG"; } }
|
||||
public override string Description { get { return Strings.arcStrings.LWGDescription; } }
|
||||
public override uint Signature { get { return 0x0001474c; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint height = file.View.ReadUInt32 (4);
|
||||
uint width = file.View.ReadUInt32 (8);
|
||||
int count = file.View.ReadInt32 (12);
|
||||
if (count <= 0)
|
||||
return null;
|
||||
uint dir_size = file.View.ReadUInt32 (20);
|
||||
uint cur_offset = 24;
|
||||
uint data_offset = cur_offset + dir_size;
|
||||
uint data_size = file.View.ReadUInt32 (data_offset);
|
||||
data_offset += 4;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry = new LwgImageEntry();
|
||||
entry.PosX = file.View.ReadInt32 (cur_offset);
|
||||
entry.PosY = file.View.ReadInt32 (cur_offset+4);
|
||||
entry.BPP = file.View.ReadByte (cur_offset+8);
|
||||
entry.Offset = data_offset + file.View.ReadUInt32 (cur_offset+9);
|
||||
entry.Size = file.View.ReadUInt32 (cur_offset+13);
|
||||
|
||||
uint name_length = file.View.ReadByte (cur_offset+17);
|
||||
string name = file.View.ReadString (cur_offset+18, name_length, Encoding.ASCII);
|
||||
entry.Name = name + ".wcg";
|
||||
cur_offset += 18+name_length;
|
||||
if (cur_offset > dir_size+24)
|
||||
return null;
|
||||
if (entry.CheckPlacement (data_offset + data_size))
|
||||
dir.Add (entry);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
public class GscScriptData : ScriptData
|
||||
{
|
||||
public byte[] Header;
|
||||
public byte[] Code;
|
||||
public byte[] Footer;
|
||||
}
|
||||
|
||||
//[Export(typeof(ScriptFormat))]
|
||||
public class GscFormat : ScriptFormat
|
||||
{
|
||||
public override string Tag { get { return "GSC"; } }
|
||||
public override string Description { get { return Strings.arcStrings.GSCDescription; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
|
||||
public override ScriptData Read (string name, Stream stream)
|
||||
{
|
||||
using (var file = new BinaryReader (stream, Encodings.cp932, true))
|
||||
{
|
||||
uint signature = file.ReadUInt32();
|
||||
if (signature != file.BaseStream.Length)
|
||||
return null;
|
||||
uint header_size = file.ReadUInt32();
|
||||
if (header_size > 0x24 || header_size < 0x14)
|
||||
return null;
|
||||
uint code_size = file.ReadUInt32();
|
||||
uint text_index_size = file.ReadUInt32();
|
||||
uint text_size = file.ReadUInt32();
|
||||
byte[] header_data = file.ReadBytes ((int)header_size-0x14);
|
||||
byte[] code = file.ReadBytes ((int)code_size);
|
||||
uint[] index = new uint[text_index_size/4];
|
||||
for (int i = 0; i < index.Length; ++i)
|
||||
{
|
||||
index[i] = file.ReadUInt32();
|
||||
if (index[i] >= text_size)
|
||||
return null;
|
||||
}
|
||||
long text_offset = header_size + code_size + text_index_size;
|
||||
|
||||
var script = new GscScriptData();
|
||||
script.Header = header_data;
|
||||
script.Code = code;
|
||||
for (int i = 0; i < index.Length; ++i)
|
||||
{
|
||||
file.BaseStream.Position = text_offset + index[i];
|
||||
string text = StreamExtension.ReadCString (file.BaseStream);
|
||||
script.TextLines.Add (new ScriptLine { Id = (uint)i, Text = text });
|
||||
}
|
||||
long footer_pos = text_offset + text_size;
|
||||
file.BaseStream.Position = footer_pos;
|
||||
script.Footer = new byte[file.BaseStream.Length - footer_pos];
|
||||
file.BaseStream.Read (script.Footer, 0, script.Footer.Length);
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream stream, ScriptData script_data)
|
||||
{
|
||||
var script = script_data as GscScriptData;
|
||||
if (null == script)
|
||||
throw new InvalidFormatException();
|
||||
using (var file = new BinaryWriter (stream, Encodings.cp932, true))
|
||||
{
|
||||
long file_size_pos = file.BaseStream.Position;
|
||||
file.Write ((int)0);
|
||||
|
||||
file.Write ((int)(script.Header.Length + 0x14));
|
||||
file.Write ((int)script.Code.Length);
|
||||
int line_count = script.TextLines.Count;
|
||||
int text_index_size = line_count * 4;
|
||||
file.Write (text_index_size);
|
||||
|
||||
long text_size_pos = file.BaseStream.Position;
|
||||
file.Write ((int)0);
|
||||
if (0 < script.Header.Length)
|
||||
file.Write (script.Header);
|
||||
if (0 < script.Code.Length)
|
||||
file.Write (script.Code);
|
||||
|
||||
long text_index_pos = file.BaseStream.Position;
|
||||
var index = new uint[line_count];
|
||||
file.BaseStream.Seek (text_index_size, SeekOrigin.Current);
|
||||
int i = 0;
|
||||
long text_pos = file.BaseStream.Position;
|
||||
uint current_pos = 0;
|
||||
foreach (var line in script.TextLines)
|
||||
{
|
||||
index[i] = current_pos;
|
||||
var text = Encodings.cp932.GetBytes (line.Text);
|
||||
file.Write (text);
|
||||
file.Write ((byte)0);
|
||||
++i;
|
||||
current_pos += (uint)text.Length + 1;
|
||||
}
|
||||
uint text_size = (uint)(file.BaseStream.Position - text_pos);
|
||||
if (0 < script.Footer.Length)
|
||||
file.Write (script.Footer);
|
||||
uint file_size = (uint)(file.BaseStream.Position - file_size_pos);
|
||||
file.BaseStream.Position = file_size_pos;
|
||||
file.Write (file_size);
|
||||
file.BaseStream.Position = text_size_pos;
|
||||
file.Write (text_size);
|
||||
file.BaseStream.Position = text_index_pos;
|
||||
foreach (var offset in index)
|
||||
file.Write (offset);
|
||||
file.BaseStream.Position = file_size_pos + file_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//! \file ArcXFL.cs
|
||||
//! \date Mon Jun 30 21:18:29 2014
|
||||
//! \brief XFL resource format implementation.
|
||||
//
|
||||
// Copyright (C) 2014 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.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using GameRes.Formats.Strings;
|
||||
|
||||
namespace GameRes.Formats.Liar
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class XflOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "XFL"; } }
|
||||
public override string Description { get { return Strings.arcStrings.XFLDescription; } }
|
||||
public override uint Signature { get { return 0x0001424c; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return true; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint dir_size = file.View.ReadUInt32 (4);
|
||||
int count = file.View.ReadInt32 (8);
|
||||
if (count <= 0)
|
||||
return null;
|
||||
long max_offset = file.MaxOffset;
|
||||
uint base_offset = dir_size + 12;
|
||||
if (dir_size >= max_offset || base_offset >= max_offset)
|
||||
return null;
|
||||
|
||||
file.View.Reserve (0, base_offset);
|
||||
long cur_offset = 12;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (cur_offset+40 > base_offset)
|
||||
return null;
|
||||
string name = file.View.ReadString (cur_offset, 32);
|
||||
var entry = FormatCatalog.Instance.CreateEntry (name);
|
||||
entry.Offset = base_offset + file.View.ReadUInt32 (cur_offset+32);
|
||||
entry.Size = file.View.ReadUInt32 (cur_offset+36);
|
||||
if (!entry.CheckPlacement (max_offset))
|
||||
return null;
|
||||
dir.Add (entry);
|
||||
cur_offset += 40;
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||
EntryCallback callback)
|
||||
{
|
||||
using (var writer = new BinaryWriter (output, Encoding.ASCII, true))
|
||||
{
|
||||
writer.Write (Signature);
|
||||
int list_size = list.Count();
|
||||
uint dir_size = (uint)(list_size * 40);
|
||||
writer.Write (dir_size);
|
||||
writer.Write (list_size);
|
||||
|
||||
var encoding = Encodings.cp932.WithFatalFallback();
|
||||
|
||||
byte[] name_buf = new byte[32];
|
||||
int callback_count = 0;
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||
|
||||
// first, write names only
|
||||
foreach (var entry in list)
|
||||
{
|
||||
string name = Path.GetFileName (entry.Name);
|
||||
try
|
||||
{
|
||||
int size = encoding.GetBytes (name, 0, name.Length, name_buf, 0);
|
||||
if (size < name_buf.Length)
|
||||
name_buf[size] = 0;
|
||||
}
|
||||
catch (EncoderFallbackException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
|
||||
}
|
||||
catch (ArgumentException X)
|
||||
{
|
||||
throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong, X);
|
||||
}
|
||||
writer.Write (name_buf);
|
||||
writer.BaseStream.Seek (8, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// now, write files and remember offset/sizes
|
||||
uint current_offset = 0;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
if (null != callback)
|
||||
callback (callback_count++, entry, arcStrings.MsgAddingFile);
|
||||
|
||||
entry.Offset = current_offset;
|
||||
using (var input = File.Open (entry.Name, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
var size = input.Length;
|
||||
if (size > uint.MaxValue || current_offset + size > uint.MaxValue)
|
||||
throw new FileSizeException();
|
||||
current_offset += (uint)size;
|
||||
entry.Size = (uint)size;
|
||||
input.CopyTo (output);
|
||||
}
|
||||
}
|
||||
|
||||
if (null != callback)
|
||||
callback (callback_count++, null, arcStrings.MsgUpdatingIndex);
|
||||
|
||||
// at last, go back to directory and write offset/sizes
|
||||
long dir_offset = 12+32;
|
||||
foreach (var entry in list)
|
||||
{
|
||||
writer.BaseStream.Position = dir_offset;
|
||||
writer.Write ((uint)entry.Offset);
|
||||
writer.Write (entry.Size);
|
||||
dir_offset += 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LwgImageEntry : ImageEntry
|
||||
{
|
||||
public int PosX;
|
||||
public int PosY;
|
||||
public int BPP;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class LwgOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "LWG"; } }
|
||||
public override string Description { get { return Strings.arcStrings.LWGDescription; } }
|
||||
public override uint Signature { get { return 0x0001474c; } }
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
uint height = file.View.ReadUInt32 (4);
|
||||
uint width = file.View.ReadUInt32 (8);
|
||||
int count = file.View.ReadInt32 (12);
|
||||
if (count <= 0)
|
||||
return null;
|
||||
uint dir_size = file.View.ReadUInt32 (20);
|
||||
uint cur_offset = 24;
|
||||
uint data_offset = cur_offset + dir_size;
|
||||
uint data_size = file.View.ReadUInt32 (data_offset);
|
||||
data_offset += 4;
|
||||
|
||||
var dir = new List<Entry> (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
var entry = new LwgImageEntry();
|
||||
entry.PosX = file.View.ReadInt32 (cur_offset);
|
||||
entry.PosY = file.View.ReadInt32 (cur_offset+4);
|
||||
entry.BPP = file.View.ReadByte (cur_offset+8);
|
||||
entry.Offset = data_offset + file.View.ReadUInt32 (cur_offset+9);
|
||||
entry.Size = file.View.ReadUInt32 (cur_offset+13);
|
||||
|
||||
uint name_length = file.View.ReadByte (cur_offset+17);
|
||||
string name = file.View.ReadString (cur_offset+18, name_length, Encoding.ASCII);
|
||||
entry.Name = name + ".wcg";
|
||||
cur_offset += 18+name_length;
|
||||
if (cur_offset > dir_size+24)
|
||||
return null;
|
||||
if (entry.CheckPlacement (data_offset + data_size))
|
||||
dir.Add (entry);
|
||||
}
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
}
|
||||
|
||||
public class GscScriptData : ScriptData
|
||||
{
|
||||
public byte[] Header;
|
||||
public byte[] Code;
|
||||
public byte[] Footer;
|
||||
}
|
||||
|
||||
//[Export(typeof(ScriptFormat))]
|
||||
public class GscFormat : ScriptFormat
|
||||
{
|
||||
public override string Tag { get { return "GSC"; } }
|
||||
public override string Description { get { return Strings.arcStrings.GSCDescription; } }
|
||||
public override uint Signature { get { return 0; } }
|
||||
|
||||
public override ScriptData Read (string name, Stream stream)
|
||||
{
|
||||
using (var file = new BinaryReader (stream, Encodings.cp932, true))
|
||||
{
|
||||
uint signature = file.ReadUInt32();
|
||||
if (signature != file.BaseStream.Length)
|
||||
return null;
|
||||
uint header_size = file.ReadUInt32();
|
||||
if (header_size > 0x24 || header_size < 0x14)
|
||||
return null;
|
||||
uint code_size = file.ReadUInt32();
|
||||
uint text_index_size = file.ReadUInt32();
|
||||
uint text_size = file.ReadUInt32();
|
||||
byte[] header_data = file.ReadBytes ((int)header_size-0x14);
|
||||
byte[] code = file.ReadBytes ((int)code_size);
|
||||
uint[] index = new uint[text_index_size/4];
|
||||
for (int i = 0; i < index.Length; ++i)
|
||||
{
|
||||
index[i] = file.ReadUInt32();
|
||||
if (index[i] >= text_size)
|
||||
return null;
|
||||
}
|
||||
long text_offset = header_size + code_size + text_index_size;
|
||||
|
||||
var script = new GscScriptData();
|
||||
script.Header = header_data;
|
||||
script.Code = code;
|
||||
for (int i = 0; i < index.Length; ++i)
|
||||
{
|
||||
file.BaseStream.Position = text_offset + index[i];
|
||||
string text = StreamExtension.ReadCString (file.BaseStream);
|
||||
script.TextLines.Add (new ScriptLine { Id = (uint)i, Text = text });
|
||||
}
|
||||
long footer_pos = text_offset + text_size;
|
||||
file.BaseStream.Position = footer_pos;
|
||||
script.Footer = new byte[file.BaseStream.Length - footer_pos];
|
||||
file.BaseStream.Read (script.Footer, 0, script.Footer.Length);
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream stream, ScriptData script_data)
|
||||
{
|
||||
var script = script_data as GscScriptData;
|
||||
if (null == script)
|
||||
throw new InvalidFormatException();
|
||||
using (var file = new BinaryWriter (stream, Encodings.cp932, true))
|
||||
{
|
||||
long file_size_pos = file.BaseStream.Position;
|
||||
file.Write ((int)0);
|
||||
|
||||
file.Write ((int)(script.Header.Length + 0x14));
|
||||
file.Write ((int)script.Code.Length);
|
||||
int line_count = script.TextLines.Count;
|
||||
int text_index_size = line_count * 4;
|
||||
file.Write (text_index_size);
|
||||
|
||||
long text_size_pos = file.BaseStream.Position;
|
||||
file.Write ((int)0);
|
||||
if (0 < script.Header.Length)
|
||||
file.Write (script.Header);
|
||||
if (0 < script.Code.Length)
|
||||
file.Write (script.Code);
|
||||
|
||||
long text_index_pos = file.BaseStream.Position;
|
||||
var index = new uint[line_count];
|
||||
file.BaseStream.Seek (text_index_size, SeekOrigin.Current);
|
||||
int i = 0;
|
||||
long text_pos = file.BaseStream.Position;
|
||||
uint current_pos = 0;
|
||||
foreach (var line in script.TextLines)
|
||||
{
|
||||
index[i] = current_pos;
|
||||
var text = Encodings.cp932.GetBytes (line.Text);
|
||||
file.Write (text);
|
||||
file.Write ((byte)0);
|
||||
++i;
|
||||
current_pos += (uint)text.Length + 1;
|
||||
}
|
||||
uint text_size = (uint)(file.BaseStream.Position - text_pos);
|
||||
if (0 < script.Footer.Length)
|
||||
file.Write (script.Footer);
|
||||
uint file_size = (uint)(file.BaseStream.Position - file_size_pos);
|
||||
file.BaseStream.Position = file_size_pos;
|
||||
file.Write (file_size);
|
||||
file.BaseStream.Position = text_size_pos;
|
||||
file.Write (text_size);
|
||||
file.BaseStream.Position = text_index_pos;
|
||||
foreach (var offset in index)
|
||||
file.Write (offset);
|
||||
file.BaseStream.Position = file_size_pos + file_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user