mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 03:44:13 +08:00
added creation options for AMI archives.
This commit is contained in:
parent
b1015ff785
commit
eefa7d2fc2
@ -35,27 +35,56 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using ZLibNet;
|
using ZLibNet;
|
||||||
using GameRes.Formats.Strings;
|
using GameRes.Formats.Strings;
|
||||||
|
using GameRes.Formats.Properties;
|
||||||
|
|
||||||
namespace GameRes.Formats
|
namespace GameRes.Formats
|
||||||
{
|
{
|
||||||
public class AmiEntry : PackedEntry
|
internal class AmiEntry : PackedEntry
|
||||||
{
|
{
|
||||||
private Lazy<Tuple<string,string>> m_item;
|
public uint Id;
|
||||||
|
|
||||||
|
private Lazy<string> m_ext;
|
||||||
|
private Lazy<string> m_name;
|
||||||
|
private Lazy<string> m_type;
|
||||||
public override string Name
|
public override string Name
|
||||||
{
|
{
|
||||||
get { return m_item.Value.Item1; }
|
get { return m_name.Value; }
|
||||||
set { m_item = new Lazy<Tuple<string, string>>(() => new Tuple<string, string>(value, Type)); }
|
set { m_name = new Lazy<string> (() => value); }
|
||||||
}
|
}
|
||||||
public override string Type
|
public override string Type
|
||||||
{
|
{
|
||||||
get { return m_item.Value.Item2; }
|
get { return m_type.Value; }
|
||||||
set { m_item = new Lazy<Tuple<string, string>>(() => new Tuple<string, string>(Name, value)); }
|
set { m_type = new Lazy<string> (() => value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public AmiEntry (Func<Tuple<string, string>> factory)
|
public AmiEntry (uint id, Func<string> ext_factory)
|
||||||
{
|
{
|
||||||
m_item = new Lazy<Tuple<string, string>> (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))]
|
[Export(typeof(ArchiveFormat))]
|
||||||
@ -93,18 +122,14 @@ namespace GameRes.Formats
|
|||||||
uint size = file.View.ReadUInt32 (cur_offset+8);
|
uint size = file.View.ReadUInt32 (cur_offset+8);
|
||||||
uint packed_size = file.View.ReadUInt32 (cur_offset+12);
|
uint packed_size = file.View.ReadUInt32 (cur_offset+12);
|
||||||
|
|
||||||
var entry = new AmiEntry (() => {
|
var entry = new AmiEntry (id, () => {
|
||||||
uint signature = file.View.ReadUInt32 (offset);
|
uint signature = file.View.ReadUInt32 (offset);
|
||||||
string ext, type;
|
if (0x00524353 == signature)
|
||||||
if (0x00524353 == signature) {
|
return "scr";
|
||||||
ext = "scr"; type = "script";
|
else if (0 != packed_size || 0x00505247 == signature)
|
||||||
} else if (0 != packed_size) {
|
return "grp";
|
||||||
ext = "grp"; type = "image";
|
else
|
||||||
} else {
|
return "dat";
|
||||||
ext = "dat"; type = "";
|
|
||||||
}
|
|
||||||
string name = string.Format ("{0:x8}.{1}", id, ext);
|
|
||||||
return new Tuple<string,string> (name, type);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
entry.Offset = offset;
|
entry.Offset = offset;
|
||||||
@ -132,10 +157,39 @@ namespace GameRes.Formats
|
|||||||
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||||
EntryCallback callback)
|
EntryCallback callback)
|
||||||
{
|
{
|
||||||
IDictionary<uint, PackedEntry> file_table = BuildFileTable (list);
|
ArcFile base_archive = null;
|
||||||
uint file_count = (uint)file_table.Count;
|
var ami_options = GetOptions<AmiOptions> (options);
|
||||||
if (0 == file_count)
|
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);
|
throw new InvalidFormatException (arcStrings.AMINoFiles);
|
||||||
|
|
||||||
|
uint file_count = (uint)file_table.Count;
|
||||||
if (null != callback)
|
if (null != callback)
|
||||||
callback ((int)file_count+1, null, null);
|
callback ((int)file_count+1, null, null);
|
||||||
|
|
||||||
@ -150,8 +204,11 @@ namespace GameRes.Formats
|
|||||||
long current_offset = output.Position;
|
long current_offset = output.Position;
|
||||||
if (current_offset > uint.MaxValue)
|
if (current_offset > uint.MaxValue)
|
||||||
throw new FileSizeException();
|
throw new FileSizeException();
|
||||||
entry.Value.Offset = (uint)current_offset;
|
if (entry.Value is AmiEntry)
|
||||||
|
CopyAmiEntry (base_archive, entry.Value, output);
|
||||||
|
else
|
||||||
entry.Value.Size = WriteAmiEntry (entry.Value, output);
|
entry.Value.Size = WriteAmiEntry (entry.Value, output);
|
||||||
|
entry.Value.Offset = (uint)current_offset;
|
||||||
}
|
}
|
||||||
if (null != callback)
|
if (null != callback)
|
||||||
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
callback (callback_count++, null, arcStrings.MsgWritingIndex);
|
||||||
@ -171,10 +228,16 @@ namespace GameRes.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
IDictionary<uint, PackedEntry> BuildFileTable (IEnumerable<Entry> list)
|
|
||||||
{
|
{
|
||||||
var table = new SortedDictionary<uint, PackedEntry>();
|
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)
|
foreach (var entry in list)
|
||||||
{
|
{
|
||||||
string ext = Path.GetExtension (entry.Name).ToLower();
|
string ext = Path.GetExtension (entry.Name).ToLower();
|
||||||
@ -185,7 +248,7 @@ namespace GameRes.Formats
|
|||||||
CultureInfo.InvariantCulture, out id))
|
CultureInfo.InvariantCulture, out id))
|
||||||
continue;
|
continue;
|
||||||
PackedEntry existing;
|
PackedEntry existing;
|
||||||
if (table.TryGetValue (id, out existing))
|
if (table.TryGetValue (id, out existing) && !(existing is AmiEntry))
|
||||||
{
|
{
|
||||||
var file_new = new FileInfo (entry.Name);
|
var file_new = new FileInfo (entry.Name);
|
||||||
var file_old = new FileInfo (existing.Name);
|
var file_old = new FileInfo (existing.Name);
|
||||||
@ -197,8 +260,15 @@ namespace GameRes.Formats
|
|||||||
Name = entry.Name,
|
Name = entry.Name,
|
||||||
Type = entry.Type
|
Type = entry.Type
|
||||||
};
|
};
|
||||||
|
++update_count;
|
||||||
}
|
}
|
||||||
return table;
|
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 WriteAmiEntry (PackedEntry entry, Stream output)
|
||||||
@ -247,6 +317,19 @@ namespace GameRes.Formats
|
|||||||
return (uint)zstream.TotalOut;
|
return (uint)zstream.TotalOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))]
|
[Export(typeof(ImageFormat))]
|
||||||
|
18
ArcFormats/CreateAMIWidget.xaml
Normal file
18
ArcFormats/CreateAMIWidget.xaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<Grid x:Class="GameRes.Formats.GUI.CreateAMIWidget"
|
||||||
|
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:p="clr-namespace:GameRes.Formats.Properties"
|
||||||
|
xmlns:local="clr-namespace:GameRes.Formats.GUI">
|
||||||
|
<StackPanel Orientation="Vertical" Margin="0">
|
||||||
|
<Label Target="{Binding ElementName=BaseArchive}" ToolTip="{x:Static s:arcStrings.AMIBaseTooltip}" Padding="1,0,0,5">
|
||||||
|
<CheckBox Name="UseBaseArchive" Content="{x:Static s:arcStrings.AMIBaseArchive}"
|
||||||
|
IsChecked="{Binding Source={x:Static p:Settings.Default}, Path=AMIUseBaseArchive, Mode=TwoWay}"/>
|
||||||
|
</Label>
|
||||||
|
<StackPanel Orientation="Horizontal" IsEnabled="{Binding ElementName=UseBaseArchive, Path=IsChecked}">
|
||||||
|
<TextBox Name="BaseArchive" Width="200" Text="{Binding Source={x:Static p:Settings.Default}, Path=AMIBaseArchive, Mode=TwoWay}" ToolTip="{x:Static s:arcStrings.AMIBaseTooltip}" HorizontalAlignment="Left"/>
|
||||||
|
<Button Content="..." Height="{Binding ElementName=BaseArchive, Path=ActualHeight}" Width="{Binding Path=Height, RelativeSource={RelativeSource Self}, Mode=OneWay}"
|
||||||
|
Margin="7,0,0,0" Click="Browse_Click"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
59
ArcFormats/CreateAMIWidget.xaml.cs
Normal file
59
ArcFormats/CreateAMIWidget.xaml.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using GameRes.Formats.Strings;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
namespace GameRes.Formats.GUI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for CreateAMIWidget.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class CreateAMIWidget : Grid
|
||||||
|
{
|
||||||
|
public CreateAMIWidget ()
|
||||||
|
{
|
||||||
|
InitializeComponent ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Browse_Click (object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
string initial = BaseArchive.Text;
|
||||||
|
string dir = ".";
|
||||||
|
if (!string.IsNullOrEmpty (initial))
|
||||||
|
{
|
||||||
|
var parent = Directory.GetParent (initial);
|
||||||
|
if (null != parent)
|
||||||
|
{
|
||||||
|
dir = parent.FullName;
|
||||||
|
initial = Path.GetFileName (initial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir = Path.GetFullPath (dir);
|
||||||
|
var dlg = new OpenFileDialog {
|
||||||
|
CheckFileExists = true,
|
||||||
|
CheckPathExists = true,
|
||||||
|
FileName = initial,
|
||||||
|
InitialDirectory = dir,
|
||||||
|
Multiselect = false,
|
||||||
|
Title = arcStrings.AMIChooseBase,
|
||||||
|
};
|
||||||
|
var owner = FindVisualParent<Window> (this);
|
||||||
|
if (dlg.ShowDialog (owner).Value && !string.IsNullOrEmpty (dlg.FileName))
|
||||||
|
BaseArchive.Text = dlg.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static parentItem FindVisualParent<parentItem> (DependencyObject obj) where parentItem : DependencyObject
|
||||||
|
{
|
||||||
|
if (null == obj)
|
||||||
|
return null;
|
||||||
|
DependencyObject parent = VisualTreeHelper.GetParent (obj);
|
||||||
|
while (parent != null && !(parent is parentItem))
|
||||||
|
{
|
||||||
|
parent = VisualTreeHelper.GetParent (parent);
|
||||||
|
}
|
||||||
|
return parent as parentItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ArcFormats/Properties/Settings.Designer.cs
generated
24
ArcFormats/Properties/Settings.Designer.cs
generated
@ -141,5 +141,29 @@ namespace GameRes.Formats.Properties {
|
|||||||
this["ONSCompression"] = value;
|
this["ONSCompression"] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||||
|
public string AMIBaseArchive {
|
||||||
|
get {
|
||||||
|
return ((string)(this["AMIBaseArchive"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["AMIBaseArchive"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||||
|
public bool AMIUseBaseArchive {
|
||||||
|
get {
|
||||||
|
return ((bool)(this["AMIUseBaseArchive"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["AMIUseBaseArchive"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,11 @@
|
|||||||
<Setting Name="ONSCompression" Type="GameRes.Formats.ONScripter.Compression" Scope="User">
|
<Setting Name="ONSCompression" Type="GameRes.Formats.ONScripter.Compression" Scope="User">
|
||||||
<Value Profile="(Default)">None</Value>
|
<Value Profile="(Default)">None</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="AMIBaseArchive" Type="System.String" Scope="User">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="AMIUseBaseArchive" Type="System.Boolean" Scope="User">
|
||||||
|
<Value Profile="(Default)">False</Value>
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
27
ArcFormats/Strings/arcStrings.Designer.cs
generated
27
ArcFormats/Strings/arcStrings.Designer.cs
generated
@ -60,6 +60,33 @@ namespace GameRes.Formats.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Base archive.
|
||||||
|
/// </summary>
|
||||||
|
public static string AMIBaseArchive {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AMIBaseArchive", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to New archive will also contain entries from the base archive..
|
||||||
|
/// </summary>
|
||||||
|
public static string AMIBaseTooltip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AMIBaseTooltip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select base archive.
|
||||||
|
/// </summary>
|
||||||
|
public static string AMIChooseBase {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AMIChooseBase", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Amaterasu Translations Muv-Luv archive.
|
/// Looks up a localized string similar to Amaterasu Translations Muv-Luv archive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -117,6 +117,15 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="AMIBaseArchive" xml:space="preserve">
|
||||||
|
<value>Base archive</value>
|
||||||
|
</data>
|
||||||
|
<data name="AMIBaseTooltip" xml:space="preserve">
|
||||||
|
<value>New archive will also contain entries from the base archive.</value>
|
||||||
|
</data>
|
||||||
|
<data name="AMIChooseBase" xml:space="preserve">
|
||||||
|
<value>Select base archive</value>
|
||||||
|
</data>
|
||||||
<data name="AMIDescription" xml:space="preserve">
|
<data name="AMIDescription" xml:space="preserve">
|
||||||
<value>Amaterasu Translations Muv-Luv archive</value>
|
<value>Amaterasu Translations Muv-Luv archive</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -117,6 +117,15 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="AMIBaseArchive" xml:space="preserve">
|
||||||
|
<value>Базовый архив</value>
|
||||||
|
</data>
|
||||||
|
<data name="AMIBaseTooltip" xml:space="preserve">
|
||||||
|
<value>В новый архив будут также включены файлы из базового архива.</value>
|
||||||
|
</data>
|
||||||
|
<data name="AMIChooseBase" xml:space="preserve">
|
||||||
|
<value>Укажите базовый архив</value>
|
||||||
|
</data>
|
||||||
<data name="AMINoFiles" xml:space="preserve">
|
<data name="AMINoFiles" xml:space="preserve">
|
||||||
<value>Не найдено файлов, подходящих для архива AMI.</value>
|
<value>Не найдено файлов, подходящих для архива AMI.</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -34,6 +34,12 @@
|
|||||||
<setting name="ONSCompression" serializeAs="String">
|
<setting name="ONSCompression" serializeAs="String">
|
||||||
<value>None</value>
|
<value>None</value>
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting name="AMIBaseArchive" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
|
<setting name="AMIUseBaseArchive" serializeAs="String">
|
||||||
|
<value>False</value>
|
||||||
|
</setting>
|
||||||
</GameRes.Formats.Properties.Settings>
|
</GameRes.Formats.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
</configuration>
|
</configuration>
|
Loading…
x
Reference in New Issue
Block a user