mirror of
https://github.com/crskycode/GARbro.git
synced 2026-06-06 21:58:53 +08:00
Compare commits
8 Commits
runtime-co
...
v1.2.15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6548dcf5b | ||
|
|
16d433a29e | ||
|
|
eb1a913f1b | ||
|
|
3dc35d77e9 | ||
|
|
477d94552a | ||
|
|
65d04bc1c2 | ||
|
|
0a8454d95d | ||
|
|
c92fde67a5 |
@@ -179,7 +179,7 @@ namespace GameRes.Formats.Amaterasu
|
||||
var file_table = new SortedDictionary<uint, PackedEntry>();
|
||||
if (null != base_archive)
|
||||
{
|
||||
foreach (var entry in base_archive.Dir.Cast<AmiEntry>())
|
||||
foreach (AmiEntry entry in base_archive.Dir)
|
||||
file_table[entry.Id] = entry;
|
||||
}
|
||||
int update_count = UpdateFileTable (file_table, list);
|
||||
|
||||
@@ -27,7 +27,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Ankh
|
||||
@@ -78,7 +77,7 @@ namespace GameRes.Formats.Ankh
|
||||
}
|
||||
if (0 == dir.Count)
|
||||
return null;
|
||||
foreach (var entry in dir.Cast<PackedEntry>())
|
||||
foreach (PackedEntry entry in dir)
|
||||
{
|
||||
if (entry.Size < 4)
|
||||
continue;
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace GameRes.Formats.Ail
|
||||
return null;
|
||||
byte[] preview = new byte[16];
|
||||
byte[] sign_buf = new byte[4];
|
||||
foreach (var entry in dir.Cast<PackedEntry>())
|
||||
foreach (PackedEntry entry in dir)
|
||||
{
|
||||
uint extra = 6;
|
||||
if (extra > entry.Size)
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<Compile Include="Entis\ErisaMatrix.cs" />
|
||||
<Compile Include="Hexenhaus\ArcARCC.cs" />
|
||||
<Compile Include="Hexenhaus\ArcODIO.cs" />
|
||||
<Compile Include="Emote\ArcPSB.cs" />
|
||||
<Compile Include="Hexenhaus\ArcWAG.cs" />
|
||||
<Compile Include="Ikura\ImageYGP.cs" />
|
||||
<Compile Include="ImageLZ.cs" />
|
||||
@@ -150,6 +151,7 @@
|
||||
<Compile Include="Softpal\ImagePIC.cs" />
|
||||
<Compile Include="StudioEgo\ArcPAK0.cs" />
|
||||
<Compile Include="StudioEgo\ImageANT.cs" />
|
||||
<Compile Include="SuperNekoX\ArcGPC.cs" />
|
||||
<Compile Include="TechnoBrain\ImageIPH.cs" />
|
||||
<Compile Include="DxLib\ArcDX.cs" />
|
||||
<Compile Include="ArcMiris.cs" />
|
||||
|
||||
658
ArcFormats/Emote/ArcPSB.cs
Normal file
658
ArcFormats/Emote/ArcPSB.cs
Normal file
@@ -0,0 +1,658 @@
|
||||
//! \file ArcPSB.cs
|
||||
//! \date Thu Mar 24 01:40:57 2016
|
||||
//! \brief E-mote engine image container.
|
||||
//
|
||||
// Copyright (C) 2016 by morkt
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Emote
|
||||
{
|
||||
internal class TexEntry : Entry
|
||||
{
|
||||
public string TexType;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int TruncatedWidth;
|
||||
public int TruncatedHeight;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PsbScheme : ResourceScheme
|
||||
{
|
||||
public uint[] KnownKeys;
|
||||
}
|
||||
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class PsbOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "PSB/EMOTE"; } }
|
||||
public override string Description { get { return "E-mote engine texture container"; } }
|
||||
public override uint Signature { get { return 0x425350; } } // 'PSB'
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return false; } }
|
||||
|
||||
static uint[] KnownKeys = new uint[] { 970396437u };
|
||||
|
||||
public PsbOpener ()
|
||||
{
|
||||
Extensions = new string[] { "psb" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
using (var input = file.CreateStream())
|
||||
using (var reader = new PsbReader (input))
|
||||
{
|
||||
foreach (var key in KnownKeys)
|
||||
{
|
||||
if (reader.Parse (key))
|
||||
{
|
||||
var dir = reader.GetTextures();
|
||||
if (null == dir || 0 == dir.Count)
|
||||
return null;
|
||||
else
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
if (!reader.IsEncrypted)
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var tex = entry as TexEntry;
|
||||
if (null == tex)
|
||||
return base.OpenEntry (arc, entry);
|
||||
|
||||
byte[] header;
|
||||
using (var mem = new MemoryStream())
|
||||
using (var writer = new BinaryWriter (mem))
|
||||
{
|
||||
writer.Write ((uint)0x81C3D2D1); // 'PSB' ^ 0x81818181
|
||||
writer.Write ((int)0);
|
||||
writer.Write (tex.Width);
|
||||
writer.Write (tex.Height);
|
||||
writer.Write (tex.TruncatedWidth);
|
||||
writer.Write (tex.TruncatedHeight);
|
||||
writer.Write (tex.TexType);
|
||||
writer.BaseStream.Position = 4;
|
||||
writer.Write ((int)writer.BaseStream.Length);
|
||||
header = mem.ToArray();
|
||||
}
|
||||
var input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
return new PrefixStream (header, input);
|
||||
}
|
||||
|
||||
public override ResourceScheme Scheme
|
||||
{
|
||||
get { return new PsbScheme { KnownKeys = KnownKeys }; }
|
||||
set { KnownKeys = ((PsbScheme)value).KnownKeys; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PSB container deserialization.
|
||||
/// </summary>
|
||||
internal sealed class PsbReader : IDisposable
|
||||
{
|
||||
BinaryReader m_input;
|
||||
|
||||
public PsbReader (Stream input)
|
||||
{
|
||||
m_input = new ArcView.Reader (input);
|
||||
}
|
||||
|
||||
public int Version { get { return m_version; } }
|
||||
public bool IsEncrypted { get { return 0 != (m_flags & 3); } }
|
||||
public int DataOffset { get { return m_chunk_data; } }
|
||||
|
||||
public T GetRootKey<T> (string key)
|
||||
{
|
||||
int obj_offset;
|
||||
if (!GetKey (key, m_root, out obj_offset))
|
||||
return default(T);
|
||||
return (T)GetObject (obj_offset);
|
||||
}
|
||||
|
||||
int m_version;
|
||||
int m_flags;
|
||||
|
||||
uint[] m_key = new uint[6];
|
||||
Dictionary<int, string> m_name_map;
|
||||
|
||||
public bool Parse (uint key)
|
||||
{
|
||||
m_key[0] = 0x075BCD15;
|
||||
m_key[1] = 0x159A55E5;
|
||||
m_key[2] = 0x1F123BB5;
|
||||
m_key[3] = key;
|
||||
m_key[4] = 0;
|
||||
m_key[5] = 0;
|
||||
|
||||
if (!ReadHeader())
|
||||
return false;
|
||||
if (Version < 2)
|
||||
throw new NotSupportedException ("Not supported PSB version");
|
||||
m_name_map = ReadNames();
|
||||
#if DEBUG
|
||||
var dict = GetDict (m_root); // returns all metadata in a single dictionary
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Entry> GetTextures ()
|
||||
{
|
||||
var source = GetRootKey<IDictionary> ("source");
|
||||
if (null == source || 0 == source.Count)
|
||||
return null;
|
||||
var dir = new List<Entry> (source.Count);
|
||||
foreach (DictionaryEntry item in source)
|
||||
{
|
||||
var item_value = item.Value as IDictionary;
|
||||
if (null == item_value)
|
||||
continue;
|
||||
var texture = item_value["texture"] as IDictionary;
|
||||
if (null == texture)
|
||||
continue;
|
||||
var pixel = texture["pixel"] as EmChunk;
|
||||
if (null == pixel)
|
||||
continue;
|
||||
var entry = new TexEntry {
|
||||
Name = item.Key.ToString(),
|
||||
Type = "image",
|
||||
Offset = DataOffset + pixel.Offset,
|
||||
Size = (uint)pixel.Length,
|
||||
TexType = texture["type"].ToString(),
|
||||
Width = Convert.ToInt32 (texture["width"]),
|
||||
Height = Convert.ToInt32 (texture["height"]),
|
||||
TruncatedWidth = Convert.ToInt32 (texture["truncated_width"]),
|
||||
TruncatedHeight = Convert.ToInt32 (texture["truncated_height"]),
|
||||
};
|
||||
dir.Add (entry);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
int m_names;
|
||||
int m_strings;
|
||||
int m_strings_data;
|
||||
int m_chunk_offsets;
|
||||
int m_chunk_lengths;
|
||||
int m_chunk_data;
|
||||
int m_root;
|
||||
byte[] m_data;
|
||||
|
||||
bool ReadHeader ()
|
||||
{
|
||||
m_input.BaseStream.Position = 4;
|
||||
m_version = m_input.ReadUInt16();
|
||||
m_flags = m_input.ReadUInt16();
|
||||
if (m_version < 3)
|
||||
m_flags = 2;
|
||||
|
||||
var header = new byte[0x20];
|
||||
m_input.Read (header, 0, header.Length);
|
||||
if (0 != (m_flags & 1))
|
||||
Decrypt (header, 0, 0x20);
|
||||
|
||||
m_names = LittleEndian.ToInt32 (header, 0x04);
|
||||
m_strings = LittleEndian.ToInt32 (header, 0x08);
|
||||
m_strings_data = LittleEndian.ToInt32 (header, 0x0C);
|
||||
m_chunk_offsets = LittleEndian.ToInt32 (header, 0x10);
|
||||
m_chunk_lengths = LittleEndian.ToInt32 (header, 0x14);
|
||||
m_chunk_data = LittleEndian.ToInt32 (header, 0x18);
|
||||
m_root = LittleEndian.ToInt32 (header, 0x1C);
|
||||
|
||||
int buffer_length = (int)m_input.BaseStream.Length;
|
||||
if (!(m_names >= 0x28 && m_names < m_chunk_data
|
||||
&& m_strings >= 0x28 && m_strings < m_chunk_data
|
||||
&& m_strings_data >= 0x28 && m_strings_data < m_chunk_data
|
||||
&& m_chunk_offsets >= 0x28 && m_chunk_offsets < m_chunk_data
|
||||
&& m_chunk_lengths >= 0x28 && m_chunk_lengths < m_chunk_data
|
||||
&& m_chunk_data >= 0x28 && m_chunk_data < buffer_length
|
||||
&& m_root >= 0x28 && m_root < m_chunk_data))
|
||||
return false;
|
||||
|
||||
if (null == m_data || m_data.Length < m_chunk_data)
|
||||
m_data = new byte[m_chunk_data];
|
||||
int data_pos = (int)m_input.BaseStream.Position;
|
||||
m_input.Read (m_data, data_pos, m_chunk_data-data_pos);
|
||||
if (0 != (m_flags & 2))
|
||||
Decrypt (m_data, m_names, m_chunk_offsets-m_names);
|
||||
// root object is a dictionary
|
||||
return 0x21 == m_data[m_root];
|
||||
}
|
||||
|
||||
bool GetKey (string name, int dict_offset, out int value_offset)
|
||||
{
|
||||
value_offset = 0;
|
||||
int offset;
|
||||
if (!GetOffset (name, out offset))
|
||||
return false;
|
||||
var keys = GetArray (++dict_offset);
|
||||
if (0 == keys.Count)
|
||||
return false;
|
||||
|
||||
int upper_bound = keys.Count;
|
||||
int lower_bound = 0;
|
||||
int key_index = 0;
|
||||
while (lower_bound < upper_bound)
|
||||
{
|
||||
key_index = (upper_bound + lower_bound) >> 1;
|
||||
int key = GetArrayElem (keys, key_index);
|
||||
if (key == offset)
|
||||
break;
|
||||
if (key >= offset)
|
||||
upper_bound = (upper_bound + lower_bound) >> 1;
|
||||
else
|
||||
lower_bound = key_index + 1;
|
||||
}
|
||||
if (lower_bound >= upper_bound)
|
||||
return false;
|
||||
|
||||
var values = GetArray (dict_offset + keys.ArraySize);
|
||||
int data_offset = GetArrayElem (values, key_index);
|
||||
value_offset = dict_offset + keys.ArraySize + values.ArraySize + data_offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetOffset (string name, out int offset)
|
||||
{
|
||||
// FIXME works for ASCII names only.
|
||||
var nm1 = GetArray (m_names);
|
||||
var nm2 = GetArray (m_names + nm1.ArraySize);
|
||||
int i = 0;
|
||||
for (int name_idx = 0; ; ++name_idx)
|
||||
{
|
||||
char symbol = name_idx < name.Length ? name[name_idx] : '\0';
|
||||
int prev_i = i;
|
||||
i = symbol + GetArrayElem (nm1, i);
|
||||
if (i >= nm1.Count || GetArrayElem (nm2, i) != prev_i)
|
||||
break;
|
||||
|
||||
if (name_idx >= name.Length)
|
||||
{
|
||||
offset = GetArrayElem (nm1, i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
offset = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
Dictionary<int, string> ReadNames ()
|
||||
{
|
||||
// this implementation is utterly inefficient. FIXME
|
||||
var lookup = new Dictionary<int, byte[]>();
|
||||
var next_lookup = new Dictionary<int, byte[]>();
|
||||
var dict = new Dictionary<int, string>();
|
||||
var nm1 = GetArray (m_names);
|
||||
var nm2 = GetArray (m_names + nm1.ArraySize);
|
||||
lookup[0] = new byte[0];
|
||||
while (lookup.Count > 0)
|
||||
{
|
||||
foreach (var item in lookup)
|
||||
{
|
||||
int first = GetArrayElem (nm1, item.Key);
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
if (GetArrayElem (nm2, i + first) == item.Key)
|
||||
{
|
||||
if (0 == i)
|
||||
dict[GetArrayElem (nm1, i + first)] = Encoding.UTF8.GetString (item.Value);
|
||||
else
|
||||
next_lookup[i+first] = ArrayAppend (item.Value, (byte)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
var tmp = lookup;
|
||||
lookup = next_lookup;
|
||||
next_lookup = tmp;
|
||||
next_lookup.Clear();
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
static byte[] ArrayAppend (byte[] array, byte n)
|
||||
{
|
||||
var new_array = new byte[array.Length+1];
|
||||
Buffer.BlockCopy (array, 0, new_array, 0, array.Length);
|
||||
new_array[array.Length] = n;
|
||||
return new_array;
|
||||
}
|
||||
|
||||
EmArray GetArray (int offset)
|
||||
{
|
||||
int data_offset = m_data[offset] - 10;
|
||||
var array = new EmArray {
|
||||
Count = GetInteger (offset, 0xC),
|
||||
ElemSize = m_data[offset + data_offset - 1] - 12,
|
||||
DataOffset = offset + data_offset,
|
||||
};
|
||||
array.ArraySize = array.Count * array.ElemSize + data_offset;
|
||||
return array;
|
||||
}
|
||||
|
||||
int GetArrayElem (EmArray a1, int index)
|
||||
{
|
||||
int offset = index * a1.ElemSize;
|
||||
switch (a1.ElemSize)
|
||||
{
|
||||
case 1:
|
||||
return m_data[a1.DataOffset + offset];
|
||||
case 2:
|
||||
return LittleEndian.ToUInt16 (m_data, a1.DataOffset + offset);
|
||||
case 3:
|
||||
return LittleEndian.ToUInt16 (m_data, a1.DataOffset + offset) | m_data[a1.DataOffset + offset + 2] << 16;
|
||||
case 4:
|
||||
return LittleEndian.ToInt32 (m_data, a1.DataOffset + offset);
|
||||
default:
|
||||
throw new InvalidFormatException ("Invalid PSB array structure");
|
||||
}
|
||||
}
|
||||
|
||||
object GetObject (int offset)
|
||||
{
|
||||
switch (m_data[offset])
|
||||
{
|
||||
case 1: return null;
|
||||
case 2: return true;
|
||||
case 3: return false;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8: return GetInteger (offset, 4);
|
||||
|
||||
case 9:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C: return GetLong (offset);
|
||||
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
case 0x18: return GetString (offset);
|
||||
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C: return GetChunk (offset);
|
||||
|
||||
case 0x1D:
|
||||
case 0x1E: return GetFloat (offset);
|
||||
case 0x1F: return GetDouble (offset);
|
||||
case 0x20: return GetList (offset);
|
||||
case 0x21: return GetDict (offset);
|
||||
default:
|
||||
throw new InvalidFormatException (string.Format ("Unknown serialized object type 0x{0:X2}", m_data[offset]));
|
||||
}
|
||||
}
|
||||
|
||||
int GetInteger (int offset, int base_type)
|
||||
{
|
||||
switch (m_data[offset] - base_type)
|
||||
{
|
||||
case 1: return m_data[offset+1];
|
||||
case 2: return LittleEndian.ToUInt16 (m_data, offset+1);
|
||||
case 3: return LittleEndian.ToUInt16 (m_data, offset+1) | m_data[offset+3] << 16;
|
||||
case 4: return LittleEndian.ToInt32 (m_data, offset+1);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float GetFloat (int offset)
|
||||
{
|
||||
if (0x1E == m_data[offset])
|
||||
return BitConverter.ToSingle (m_data, offset+1); // FIXME endianness
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
double GetDouble (int offset)
|
||||
{
|
||||
if (0x1F == m_data[offset])
|
||||
return BitConverter.ToDouble (m_data, offset+1); // FIXME endianness
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
long GetLong (int offset)
|
||||
{
|
||||
switch (m_data[offset])
|
||||
{
|
||||
case 0x09: return LittleEndian.ToUInt32 (m_data, offset+1) | (long)(sbyte)m_data[offset+5] << 32;
|
||||
case 0x0A: return LittleEndian.ToUInt32 (m_data, offset+1)
|
||||
| (long)LittleEndian.ToInt16 (m_data, offset+5) << 32;
|
||||
case 0x0B: return LittleEndian.ToUInt32 (m_data, offset+1)
|
||||
| (long)LittleEndian.ToUInt16 (m_data, offset+5) << 32
|
||||
| (long)(sbyte)m_data[offset+6] << 48;
|
||||
case 0x0C: return LittleEndian.ToInt64 (m_data, offset+1);
|
||||
default: return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
string GetString (int obj_offset)
|
||||
{
|
||||
int index = GetInteger (obj_offset, 0x14);
|
||||
var array = GetArray (m_strings);
|
||||
int data_offset = m_strings_data + GetArrayElem (array, index);
|
||||
return Binary.GetCString (m_data, data_offset, m_data.Length-data_offset, Encoding.UTF8);
|
||||
}
|
||||
|
||||
IList GetList (int offset)
|
||||
{
|
||||
var array = GetArray (++offset);
|
||||
var list = new ArrayList (array.Count);
|
||||
for (int i = 0; i < array.Count; ++i)
|
||||
{
|
||||
int item_offset = offset + array.ArraySize + GetArrayElem (array, i);
|
||||
var item = GetObject (item_offset);
|
||||
list.Add (item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
IDictionary GetDict (int offset)
|
||||
{
|
||||
var keys = GetArray (++offset);
|
||||
if (0 == keys.Count)
|
||||
return new Dictionary<string, object>();
|
||||
var values = GetArray (offset + keys.ArraySize);
|
||||
var dict = new Dictionary<string, object> (keys.Count);
|
||||
for (int i = 0; i < keys.Count; ++i)
|
||||
{
|
||||
int key = GetArrayElem (keys, i);
|
||||
var value_offset = GetArrayElem (values, i);
|
||||
string key_name = m_name_map[key];
|
||||
dict[key_name] = GetObject (offset + value_offset + keys.ArraySize + values.ArraySize);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
EmChunk GetChunk (int offset)
|
||||
{
|
||||
var chunk_index = GetInteger (offset, 0x18);
|
||||
var chunks = GetArray (m_chunk_offsets);
|
||||
if (chunk_index >= chunks.Count)
|
||||
throw new InvalidFormatException ("Invalid chunk index");
|
||||
var lengths = GetArray (m_chunk_lengths);
|
||||
return new EmChunk {
|
||||
Offset = GetArrayElem (chunks, chunk_index),
|
||||
Length = GetArrayElem (lengths, chunk_index),
|
||||
};
|
||||
}
|
||||
|
||||
void Decrypt (byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
if (0 == m_key[4])
|
||||
{
|
||||
var v5 = m_key[3];
|
||||
var v6 = m_key[0] ^ (m_key[0] << 11);
|
||||
m_key[0] = m_key[1];
|
||||
m_key[1] = m_key[2];
|
||||
var eax = v6 ^ v5 ^ ((v6 ^ (v5 >> 11)) >> 8);
|
||||
m_key[2] = v5;
|
||||
m_key[3] = eax;
|
||||
m_key[4] = eax;
|
||||
}
|
||||
data[offset+i] ^= (byte)m_key[4];
|
||||
m_key[4] >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
internal class EmArray
|
||||
{
|
||||
public int ArraySize;
|
||||
public int Count;
|
||||
public int ElemSize;
|
||||
public int DataOffset;
|
||||
}
|
||||
|
||||
internal class EmChunk
|
||||
{
|
||||
public int Offset;
|
||||
public int Length;
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
bool _disposed = false;
|
||||
public void Dispose ()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
m_input.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class PsbTexMetaData : ImageMetaData
|
||||
{
|
||||
public string TexType;
|
||||
public int FullWidth;
|
||||
public int FullHeight;
|
||||
public int DataOffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Artificial format representing PSB texture.
|
||||
/// </summary>
|
||||
[Export(typeof(ImageFormat))]
|
||||
internal class PsbTextureFormat : ImageFormat
|
||||
{
|
||||
public override string Tag { get { return "PSB/TEXTURE"; } }
|
||||
public override string Description { get { return "PSB texture format"; } }
|
||||
public override uint Signature { get { return 0x81C3D2D1; } } // 'PSB' ^ 0x81818181
|
||||
|
||||
public PsbTextureFormat ()
|
||||
{
|
||||
Extensions = new string[0];
|
||||
}
|
||||
|
||||
public override ImageMetaData ReadMetaData (Stream stream)
|
||||
{
|
||||
stream.Position = 4;
|
||||
using (var reader = new BinaryReader (stream, Encoding.UTF8, true))
|
||||
{
|
||||
var info = new PsbTexMetaData { BPP = 32 };
|
||||
info.DataOffset = reader.ReadInt32();
|
||||
info.FullWidth = reader.ReadInt32();
|
||||
info.FullHeight = reader.ReadInt32();
|
||||
info.Width = reader.ReadUInt32();
|
||||
info.Height = reader.ReadUInt32();
|
||||
info.TexType = reader.ReadString();
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
public override ImageData Read (Stream stream, ImageMetaData info)
|
||||
{
|
||||
var meta = (PsbTexMetaData)info;
|
||||
var pixels = new byte[meta.Width * meta.Height * 4];
|
||||
if ("RGBA8" == meta.TexType)
|
||||
ReadRgba8 (stream, meta, pixels);
|
||||
else if ("RGBA4444" == meta.TexType)
|
||||
ReadRgba4444 (stream, meta, pixels);
|
||||
else
|
||||
throw new NotImplementedException (string.Format ("PSB texture format '{0}' not implemented", meta.TexType));
|
||||
return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
|
||||
}
|
||||
|
||||
void ReadRgba8 (Stream input, PsbTexMetaData meta, byte[] output)
|
||||
{
|
||||
int dst_stride = (int)meta.Width * 4;
|
||||
long next_row = meta.DataOffset;
|
||||
int src_stride = meta.FullWidth * 4;
|
||||
int dst = 0;
|
||||
for (uint i = 0; i < meta.Height; ++i)
|
||||
{
|
||||
input.Position = next_row;
|
||||
input.Read (output, dst, dst_stride);
|
||||
dst += dst_stride;
|
||||
next_row += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadRgba4444 (Stream input, PsbTexMetaData meta, byte[] output)
|
||||
{
|
||||
int dst_stride = (int)meta.Width * 4;
|
||||
int src_stride = meta.FullWidth * 2;
|
||||
int dst = 0;
|
||||
var row = new byte[src_stride];
|
||||
input.Position = meta.DataOffset;
|
||||
for (uint i = 0; i < meta.Height; ++i)
|
||||
{
|
||||
input.Read (row, 0, src_stride);
|
||||
int src = 0;
|
||||
for (int x = 0; x < dst_stride; x += 4)
|
||||
{
|
||||
uint p = LittleEndian.ToUInt16 (row, src);
|
||||
src += 2;
|
||||
output[dst++] = (byte)((p & 0x000Fu) * 0xFFu / 0x000Fu);
|
||||
output[dst++] = (byte)((p & 0x00F0u) * 0xFFu / 0x00F0u);
|
||||
output[dst++] = (byte)((p & 0x0F00u) * 0xFFu / 0x0F00u);
|
||||
output[dst++] = (byte)((p & 0xF000u) * 0xFFu / 0xF000u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write (Stream file, ImageData image)
|
||||
{
|
||||
throw new NotSupportedException ("PsbTextureFormat.Write not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.Propeller
|
||||
@@ -79,7 +78,7 @@ namespace GameRes.Formats.Propeller
|
||||
{
|
||||
dir.Add (new PackedEntry { Name = base_name+".bmp", Type = "image", Offset = current });
|
||||
}
|
||||
foreach (var entry in dir.Cast<PackedEntry>())
|
||||
foreach (PackedEntry entry in dir)
|
||||
{
|
||||
entry.UnpackedSize = file.View.ReadUInt32 (entry.Offset);
|
||||
entry.Size = file.View.ReadUInt32 (entry.Offset+4);
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.2.18.766")]
|
||||
[assembly: AssemblyFileVersion ("1.2.18.766")]
|
||||
[assembly: AssemblyVersion ("1.2.19.818")]
|
||||
[assembly: AssemblyFileVersion ("1.2.19.818")]
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace GameRes.Formats.SHSystem
|
||||
static protected void DetectFileTypes (ArcView file, List<Entry> dir)
|
||||
{
|
||||
byte[] signature_buffer = new byte[4];
|
||||
foreach (var entry in dir.Cast<PackedEntry>())
|
||||
foreach (PackedEntry entry in dir)
|
||||
{
|
||||
uint packed_size = file.View.ReadUInt32 (entry.Offset);
|
||||
uint unpacked_size = file.View.ReadUInt32 (entry.Offset+4);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
SelectedValue="{Binding Source={x:Static p:Settings.Default}, Path=WARCScheme, Mode=TwoWay}"
|
||||
SelectedValuePath="Name"
|
||||
DisplayMemberPath="Name"
|
||||
Width="200" Grid.Row="0"/>
|
||||
Width="200" Grid.Row="0" HorizontalAlignment="Left"/>
|
||||
<TextBox Name="Original" Background="Transparent" BorderThickness="0" Text="{Binding Path=OriginalTitle}"
|
||||
IsReadOnly="True" TextWrapping="NoWrap" Grid.Row="1" Margin="0,3,0,3"
|
||||
IsReadOnly="True" TextWrapping="NoWrap" Grid.Row="1" Margin="0,3,0,3" HorizontalAlignment="Left"
|
||||
DataContext="{Binding ElementName=Scheme, Path=SelectedItem}"/>
|
||||
</Grid>
|
||||
|
||||
257
ArcFormats/SuperNekoX/ArcGPC.cs
Normal file
257
ArcFormats/SuperNekoX/ArcGPC.cs
Normal file
@@ -0,0 +1,257 @@
|
||||
//! \file ArcGPC.cs
|
||||
//! \date Tue Mar 22 01:38:13 2016
|
||||
//! \brief Super Neko X engine resource archive.
|
||||
//
|
||||
// Copyright (C) 2016 by morkt
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GameRes.Utility;
|
||||
|
||||
namespace GameRes.Formats.SuperNekoX
|
||||
{
|
||||
[Export(typeof(ArchiveFormat))]
|
||||
public class GpcOpener : ArchiveFormat
|
||||
{
|
||||
public override string Tag { get { return "GPC7"; } }
|
||||
public override string Description { get { return "Super NekoX engine resource archive"; } }
|
||||
public override uint Signature { get { return 0x37637047; } } // 'Gpc7'
|
||||
public override bool IsHierarchic { get { return false; } }
|
||||
public override bool CanCreate { get { return false; } }
|
||||
|
||||
public GpcOpener ()
|
||||
{
|
||||
Extensions = new string[] { "gpc" };
|
||||
}
|
||||
|
||||
public override ArcFile TryOpen (ArcView file)
|
||||
{
|
||||
int count = file.View.ReadInt32 (4);
|
||||
if (!IsSaneCount (count))
|
||||
return null;
|
||||
|
||||
var base_name = Path.GetFileNameWithoutExtension (file.Name);
|
||||
var dir = new List<Entry> (count);
|
||||
int index_offset = 8;
|
||||
long data_offset = count * 4 + 8;
|
||||
uint next_offset = file.View.ReadUInt32 (index_offset);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
index_offset += 4;
|
||||
var entry = new PackedEntry { Offset = next_offset };
|
||||
next_offset = i + 1 < count ? file.View.ReadUInt32 (index_offset) : (uint)file.MaxOffset;
|
||||
entry.Size = next_offset - (uint)entry.Offset;
|
||||
if (entry.Offset < data_offset || !entry.CheckPlacement (file.MaxOffset))
|
||||
return null;
|
||||
entry.Name = string.Format ("{0}#{1:D4}", base_name, i);
|
||||
dir.Add (entry);
|
||||
}
|
||||
DetectFileTypes (file, dir);
|
||||
return new ArcFile (file, this, dir);
|
||||
}
|
||||
|
||||
public override Stream OpenEntry (ArcFile arc, Entry entry)
|
||||
{
|
||||
var pent = entry as PackedEntry;
|
||||
Stream input = arc.File.CreateStream (entry.Offset, entry.Size);
|
||||
if (null != pent && pent.IsPacked)
|
||||
{
|
||||
Stream unpacked;
|
||||
using (input)
|
||||
{
|
||||
var data = new byte[pent.UnpackedSize];
|
||||
UnpackEntry (input, data);
|
||||
unpacked = new MemoryStream (data);
|
||||
}
|
||||
input = unpacked;
|
||||
}
|
||||
if (input.Length > 4 && input.Length < 0x10000)
|
||||
{
|
||||
using (var reader = new ArcView.Reader (input))
|
||||
{
|
||||
int unpacked_size = reader.ReadUInt16();
|
||||
int packed_size = reader.ReadUInt16();
|
||||
if (packed_size == input.Length-4)
|
||||
{
|
||||
using (input)
|
||||
{
|
||||
var data = new byte[unpacked_size];
|
||||
UnpackLz77 (input, data);
|
||||
return new MemoryStream (data);
|
||||
}
|
||||
}
|
||||
input.Position = 0;
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
void DetectFileTypes (ArcView file, List<Entry> dir)
|
||||
{
|
||||
using (var input = file.CreateStream())
|
||||
using (var reader = new ArcView.Reader (input))
|
||||
{
|
||||
var buffer = new byte[0x10];
|
||||
foreach (PackedEntry entry in dir)
|
||||
{
|
||||
input.Position = entry.Offset;
|
||||
uint packed_size = reader.ReadUInt32();
|
||||
entry.UnpackedSize = reader.ReadUInt32();
|
||||
entry.Offset += 8;
|
||||
if (0 == packed_size)
|
||||
{
|
||||
entry.Size = entry.UnpackedSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.IsPacked = true;
|
||||
entry.Size = packed_size;
|
||||
}
|
||||
if (entry.Size < 0x10)
|
||||
continue;
|
||||
uint signature;
|
||||
if (entry.IsPacked)
|
||||
{
|
||||
UnpackEntry (input, buffer);
|
||||
signature = LittleEndian.ToUInt32 (buffer, 0);
|
||||
}
|
||||
else
|
||||
signature = reader.ReadUInt32();
|
||||
IResource res;
|
||||
if (0x020000 == signature || 0x0A0000 == signature)
|
||||
res = ImageFormat.Tga;
|
||||
else
|
||||
res = AutoEntry.DetectFileType (signature);
|
||||
if (null != res)
|
||||
{
|
||||
entry.Type = res.Type;
|
||||
var ext = res.Extensions.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty (ext))
|
||||
entry.Name = Path.ChangeExtension (entry.Name, ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackEntry (Stream input, byte[] output)
|
||||
{
|
||||
int dst = 0;
|
||||
while (dst < output.Length)
|
||||
{
|
||||
int ctl = input.ReadByte();
|
||||
if (-1 == ctl)
|
||||
break;
|
||||
int count, offset;
|
||||
if (ctl >= 0x20)
|
||||
{
|
||||
if (ctl >= 0x80)
|
||||
{
|
||||
count = (ctl >> 5) & 3;
|
||||
offset = (ctl & 0x1F) << 8;
|
||||
offset |= input.ReadByte();
|
||||
}
|
||||
else if ((ctl & 0x60) == 0x20)
|
||||
{
|
||||
offset = (ctl >> 2) & 7;
|
||||
count = ctl & 3;
|
||||
}
|
||||
else if ((ctl & 0x60) == 0x40)
|
||||
{
|
||||
offset = (ctl & 0x1F) << 8;
|
||||
offset |= input.ReadByte();
|
||||
count = input.ReadByte() + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = (ctl & 0x1F) << 8 | input.ReadByte();
|
||||
count = input.ReadByte() << 24;
|
||||
count |= input.ReadByte() << 16;
|
||||
count |= input.ReadByte() << 8;
|
||||
count |= input.ReadByte();
|
||||
}
|
||||
count = Math.Min (count + 3, output.Length-dst);
|
||||
Binary.CopyOverlapped (output, dst-offset-1, dst, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctl < 0x1D)
|
||||
{
|
||||
count = ctl + 1;
|
||||
}
|
||||
else if (0x1D == ctl)
|
||||
{
|
||||
count = input.ReadByte() + 0x1E;
|
||||
}
|
||||
else if (0x1E == ctl)
|
||||
{
|
||||
count = input.ReadByte() << 8;
|
||||
count |= input.ReadByte();
|
||||
count += 286;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = input.ReadByte() << 24;
|
||||
count |= input.ReadByte() << 16;
|
||||
count |= input.ReadByte() << 8;
|
||||
count |= input.ReadByte();
|
||||
}
|
||||
count = Math.Min (count, output.Length-dst);
|
||||
input.Read (output, dst, count);
|
||||
}
|
||||
dst += count;
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackLz77 (Stream input, byte[] output)
|
||||
{
|
||||
int dst = 0;
|
||||
int mask = 0;
|
||||
int bits = 0;
|
||||
while (dst < output.Length)
|
||||
{
|
||||
mask >>= 1;
|
||||
if (0 == mask)
|
||||
{
|
||||
bits = input.ReadByte();
|
||||
if (-1 == bits)
|
||||
break;
|
||||
mask = 0x80;
|
||||
}
|
||||
if (0 != (bits & mask))
|
||||
{
|
||||
int count = input.ReadByte();
|
||||
int offset = input.ReadByte() << 4 | count >> 4;
|
||||
count = Math.Min ((count & 0xf) + 3, output.Length - dst);
|
||||
Binary.CopyOverlapped (output, dst-offset-1, dst, count);
|
||||
dst += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
output[dst++] = (byte)input.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace GameRes.Formats.Yuka
|
||||
index_offset += 0x14;
|
||||
}
|
||||
// read in two cycles to avoid memory mapped file page switching when accessing names
|
||||
foreach (var entry in dir.Cast<YukaEntry>())
|
||||
foreach (YukaEntry entry in dir)
|
||||
{
|
||||
entry.Name = file.View.ReadString (entry.NameOffset, entry.NameLength);
|
||||
entry.Type = FormatCatalog.Instance.GetTypeFromName (entry.Name);
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace GameRes.Formats.Zyx
|
||||
}
|
||||
pixels = FirstFrame.Clone() as byte[];
|
||||
int i = 1;
|
||||
foreach (var entry in Dir.Skip(1).Cast<BdfFrame>())
|
||||
foreach (BdfFrame entry in Dir.Skip(1))
|
||||
{
|
||||
if (i++ > frame.Number)
|
||||
break;
|
||||
|
||||
@@ -256,10 +256,6 @@
|
||||
<Resource Include="Images\search4files.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ArcFormats\ArcFormats.csproj">
|
||||
<Project>{a8865685-27cc-427b-ac38-e48d2ad05df4}</Project>
|
||||
<Name>ArcFormats</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GameRes\GameRes.csproj">
|
||||
<Project>{453c087f-e416-4ae9-8c03-d8760da0574b}</Project>
|
||||
<Name>GameRes</Name>
|
||||
|
||||
@@ -90,7 +90,6 @@ namespace GARbro.GUI
|
||||
|
||||
void WindowRendered ()
|
||||
{
|
||||
var compilation_error = FormatCatalog.Instance.LastError;
|
||||
DirectoryViewModel vm = null;
|
||||
try
|
||||
{
|
||||
@@ -106,10 +105,6 @@ namespace GARbro.GUI
|
||||
}
|
||||
ViewModel = vm;
|
||||
lv_SelectItem (0);
|
||||
if (compilation_error != null)
|
||||
{
|
||||
PopupError (compilation_error.Message, "GameRes library initialization error");
|
||||
}
|
||||
if (!vm.IsArchive)
|
||||
SetStatusText (guiStrings.MsgReady);
|
||||
}
|
||||
|
||||
@@ -51,5 +51,5 @@ using System.Windows;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.2.14.1086")]
|
||||
[assembly: AssemblyFileVersion ("1.2.14.1086")]
|
||||
[assembly: AssemblyVersion ("1.2.15.1142")]
|
||||
[assembly: AssemblyFileVersion ("1.2.15.1142")]
|
||||
|
||||
Binary file not shown.
@@ -29,11 +29,8 @@ using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using Microsoft.CSharp;
|
||||
using GameRes.Collections;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace GameRes
|
||||
{
|
||||
@@ -80,16 +77,12 @@ namespace GameRes
|
||||
|
||||
private FormatCatalog ()
|
||||
{
|
||||
var assembly_location = Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
var plugins_dll = Path.Combine (assembly_location, "ArcPlugins.dll");
|
||||
CompilePlugins (Path.Combine (assembly_location, "Plugins"), plugins_dll);
|
||||
|
||||
//An aggregate catalog that combines multiple catalogs
|
||||
var catalog = new AggregateCatalog();
|
||||
//Adds all the parts found in the same assembly as the Program class
|
||||
catalog.Catalogs.Add (new AssemblyCatalog (typeof(FormatCatalog).Assembly));
|
||||
//Adds parts matching pattern found in the directory of the assembly
|
||||
catalog.Catalogs.Add (new DirectoryCatalog (assembly_location, "Arc*.dll"));
|
||||
catalog.Catalogs.Add (new DirectoryCatalog (Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly().Location), "Arc*.dll"));
|
||||
|
||||
//Create the CompositionContainer with the parts in the catalog
|
||||
var container = new CompositionContainer (catalog);
|
||||
@@ -225,50 +218,6 @@ namespace GameRes
|
||||
var bin = new BinaryFormatter();
|
||||
bin.Serialize (output, db);
|
||||
}
|
||||
|
||||
private void CompilePlugins (string source_dir, string target)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists (source_dir))
|
||||
return;
|
||||
var dir = new DirectoryInfo (source_dir);
|
||||
var files = dir.EnumerateFiles ("*.cs");
|
||||
if (!files.Any())
|
||||
return;
|
||||
if (File.Exists (target))
|
||||
{
|
||||
var target_info = new FileInfo (target);
|
||||
var recent_plugin = files.OrderByDescending (f => f.LastWriteTime).First();
|
||||
if (recent_plugin.LastWriteTime < target_info.LastWriteTime)
|
||||
return;
|
||||
}
|
||||
var provider = new CSharpCodeProvider();
|
||||
var parameters = new CompilerParameters { OutputAssembly = target };
|
||||
#if DEBUG
|
||||
parameters.IncludeDebugInformation = true;
|
||||
#endif
|
||||
parameters.ReferencedAssemblies.Add ("System.dll");
|
||||
parameters.ReferencedAssemblies.Add ("System.ComponentModel.Composition.dll");
|
||||
parameters.ReferencedAssemblies.Add (System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
var source = files.Select (f => f.FullName).ToArray();
|
||||
var results = provider.CompileAssemblyFromFile (parameters, source);
|
||||
if (results.Errors.HasErrors)
|
||||
{
|
||||
var error_text = new StringBuilder ("Plugins compilation failed due to errors.\r\n");
|
||||
foreach (CompilerError error in results.Errors)
|
||||
{
|
||||
var filename = Path.GetFileName (error.FileName);
|
||||
error_text.AppendFormat ("{0}:{1}: [{2}] {3}\r\n", filename, error.Line, error.ErrorNumber, error.ErrorText);
|
||||
}
|
||||
throw new ApplicationException (error_text.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception X)
|
||||
{
|
||||
LastError = X;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion ("1.2.15.142")]
|
||||
[assembly: AssemblyFileVersion ("1.2.15.142")]
|
||||
[assembly: AssemblyVersion ("1.2.16.144")]
|
||||
[assembly: AssemblyFileVersion ("1.2.16.144")]
|
||||
|
||||
@@ -298,10 +298,11 @@ Touka Gettan<br/>
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*</td><td><tt>\x00\x00\x04\x00</tt></td><td>No</td></tr>
|
||||
<tr><td>*.war</td><td><tt>WARC 1.7</tt><br/><tt>WARC 1.5</tt><br/><tt>WARC 1.3</tt></td><td>No</td><td rowspan="5">Shiina Rio</td><td rowspan="5">
|
||||
Classmate no Okaa-san <span class="footnote">ShiinaRio v2.37</span><br/>
|
||||
Can Fes! ~Itazura Majo to Naisho no Gakuensai~ <span class="footnote">ShiinaRio v2.47</span><br/>
|
||||
Chikan Circle <span class="footnote">ShiinaRio v2.46</span><br/>
|
||||
Chikan Circle 2 <span class="footnote">ShiinaRio v2.47</span><br/>
|
||||
Chuuchuu Nurse <span class="footnote">ShiinaRio v2.45</span><br/>
|
||||
Classmate no Okaa-san <span class="footnote">ShiinaRio v2.37</span><br/>
|
||||
Enkaku Sousa <span class="footnote">2.36 or 2.37</span><br/>
|
||||
Helter Skelter <span class="footnote">ShiinaRio v2.40</span><br/>
|
||||
Hitozuma Onna Kyoushi Reika <span class="footnote">ShiinaRio v2.39</span><br/>
|
||||
@@ -425,8 +426,9 @@ X Change R<br/>
|
||||
X Change<br/>
|
||||
X Change 2<br/>
|
||||
X Change 2R<br/>
|
||||
Ryoujoku Gojuusou<br/>
|
||||
Eve to Iu Na no Omocha<br/>
|
||||
Hissatsu Chikannin II<br/>
|
||||
Ryoujoku Gojuusou<br/>
|
||||
Tokumei Sentai Sirenger<br/>
|
||||
Tokumei Sentai Yuzu Ranger<br/>
|
||||
</td></tr>
|
||||
@@ -514,6 +516,7 @@ Shinsetsu Ryouki no Ori<br/>
|
||||
Gokudou no Hanayome<br/>
|
||||
Knight Carnival!<br/>
|
||||
Seal Princess<br/>
|
||||
Zettai★Maou ~Boku no Mune-kyun Gakuen Saga~<br/>
|
||||
</td></tr>
|
||||
<tr><td>*.sud</td><td>-</td><td>No</td><td rowspan="3">Triangle</td><td rowspan="3">
|
||||
Kourin Tenshi En Ciel Rena<br/>
|
||||
@@ -758,6 +761,12 @@ Ase Nure Shoujo Misaki "Anata no Nioi de Icchau!"<br/>
|
||||
<tr class="odd"><td>*.grp</td><td>-</td><td>No</td><td>Ankh</td><td>
|
||||
Mozu<br/>
|
||||
</td></tr>
|
||||
<tr><td>*.gpc</td><td><tt>Gpc7</tt></td><td>No</td><td>Super NekoX</td><td>
|
||||
Sister Contrast!
|
||||
</td></tr>
|
||||
<tr class="odd"><td>*.psb</td><td><tt>PSB</tt></td><td>No</td><td>E-mote</td><td>
|
||||
Angenehm Platz -Kleiner Garten Sie Erstellen-<br/>
|
||||
</td></tr>
|
||||
</table>
|
||||
<p><a name="note-1" class="footnote">1</a> Non-encrypted only</p>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user