From eefa7d2fc2c3cb986ce4941f96651a5a0c572024 Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 1 Aug 2014 16:44:53 +0400 Subject: [PATCH] added creation options for AMI archives. --- ArcFormats/ArcAMI.cs | 191 +++++++++++++++------ ArcFormats/CreateAMIWidget.xaml | 18 ++ ArcFormats/CreateAMIWidget.xaml.cs | 59 +++++++ ArcFormats/Properties/Settings.Designer.cs | 24 +++ ArcFormats/Properties/Settings.settings | 6 + ArcFormats/Strings/arcStrings.Designer.cs | 27 +++ ArcFormats/Strings/arcStrings.resx | 9 + ArcFormats/Strings/arcStrings.ru-RU.resx | 9 + ArcFormats/app.config | 6 + 9 files changed, 295 insertions(+), 54 deletions(-) create mode 100644 ArcFormats/CreateAMIWidget.xaml create mode 100644 ArcFormats/CreateAMIWidget.xaml.cs diff --git a/ArcFormats/ArcAMI.cs b/ArcFormats/ArcAMI.cs index 0fe695f6..e6837226 100644 --- a/ArcFormats/ArcAMI.cs +++ b/ArcFormats/ArcAMI.cs @@ -35,27 +35,56 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using ZLibNet; using GameRes.Formats.Strings; +using GameRes.Formats.Properties; namespace GameRes.Formats { - public class AmiEntry : PackedEntry + internal class AmiEntry : PackedEntry { - private Lazy> m_item; + public uint Id; + + private Lazy m_ext; + private Lazy m_name; + private Lazy m_type; public override string Name { - get { return m_item.Value.Item1; } - set { m_item = new Lazy>(() => new Tuple(value, Type)); } + get { return m_name.Value; } + set { m_name = new Lazy (() => value); } } public override string Type { - get { return m_item.Value.Item2; } - set { m_item = new Lazy>(() => new Tuple(Name, value)); } + get { return m_type.Value; } + set { m_type = new Lazy (() => value); } } - public AmiEntry (Func> factory) + public AmiEntry (uint id, Func ext_factory) { - m_item = new Lazy> (factory); + Id = id; + m_ext = new Lazy (ext_factory); + m_name = new Lazy (GetName); + m_type = new Lazy (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))] @@ -93,18 +122,14 @@ namespace GameRes.Formats uint size = file.View.ReadUInt32 (cur_offset+8); uint packed_size = file.View.ReadUInt32 (cur_offset+12); - var entry = new AmiEntry (() => { + var entry = new AmiEntry (id, () => { uint signature = file.View.ReadUInt32 (offset); - string ext, type; - if (0x00524353 == signature) { - ext = "scr"; type = "script"; - } else if (0 != packed_size) { - ext = "grp"; type = "image"; - } else { - ext = "dat"; type = ""; - } - string name = string.Format ("{0:x8}.{1}", id, ext); - return new Tuple (name, type); + if (0x00524353 == signature) + return "scr"; + else if (0 != packed_size || 0x00505247 == signature) + return "grp"; + else + return "dat"; }); entry.Offset = offset; @@ -132,49 +157,87 @@ namespace GameRes.Formats public override void Create (Stream output, IEnumerable list, ResourceOptions options, EntryCallback callback) { - IDictionary file_table = BuildFileTable (list); - uint file_count = (uint)file_table.Count; - if (0 == file_count) - throw new InvalidFormatException (arcStrings.AMINoFiles); - 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) + ArcFile base_archive = null; + var ami_options = GetOptions (options); + if (null != ami_options && ami_options.UseBaseArchive && !string.IsNullOrEmpty (ami_options.BaseArchive)) { - if (null != callback) - callback (callback_count++, entry.Value, arcStrings.MsgAddingFile); - long current_offset = output.Position; - if (current_offset > uint.MaxValue) - throw new FileSizeException(); - entry.Value.Offset = (uint)current_offset; - entry.Value.Size = WriteAmiEntry (entry.Value, output); + 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(); + } } - if (null != callback) - callback (callback_count++, null, arcStrings.MsgWritingIndex); - output.Position = start_offset; - using (var header = new BinaryWriter (output, Encoding.ASCII, true)) + try { - header.Write (Signature); - header.Write (file_count); - header.Write (data_offset); - header.Write ((uint)0); + var file_table = new SortedDictionary(); + if (null != base_archive) + { + foreach (var entry in base_archive.Dir.Cast()) + 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) { - header.Write (entry.Key); - header.Write ((uint)entry.Value.Offset); - header.Write ((uint)entry.Value.UnpackedSize); - header.Write ((uint)entry.Value.Size); + 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(); } } - IDictionary BuildFileTable (IEnumerable list) + int UpdateFileTable (IDictionary table, IEnumerable list) { - var table = new SortedDictionary(); + int update_count = 0; foreach (var entry in list) { string ext = Path.GetExtension (entry.Name).ToLower(); @@ -185,7 +248,7 @@ namespace GameRes.Formats CultureInfo.InvariantCulture, out id)) continue; 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_old = new FileInfo (existing.Name); @@ -197,8 +260,15 @@ namespace GameRes.Formats Name = entry.Name, 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) @@ -247,6 +317,19 @@ namespace GameRes.Formats 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))] diff --git a/ArcFormats/CreateAMIWidget.xaml b/ArcFormats/CreateAMIWidget.xaml new file mode 100644 index 00000000..6dee4128 --- /dev/null +++ b/ArcFormats/CreateAMIWidget.xaml @@ -0,0 +1,18 @@ + + + + + +