diff --git a/ArcFormats/ArcAMI.cs b/ArcFormats/ArcAMI.cs index d9a68323..0fe695f6 100644 --- a/ArcFormats/ArcAMI.cs +++ b/ArcFormats/ArcAMI.cs @@ -26,12 +26,15 @@ 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 ZLibNet; +using GameRes.Formats.Strings; namespace GameRes.Formats { @@ -62,6 +65,7 @@ namespace GameRes.Formats 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 () { @@ -124,6 +128,125 @@ namespace GameRes.Formats else return new ZLibStream (input, CompressionMode.Decompress); } + + 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) + { + 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); + } + 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); + } + } + } + + IDictionary BuildFileTable (IEnumerable list) + { + var table = new SortedDictionary(); + foreach (var entry in list) + { + string ext = Path.GetExtension (entry.Name).ToLower(); + if (entry.Type != "image" && ext != ".scr") + 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)) + { + var file_new = new FileInfo (entry.Name); + 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 + }; + } + return table; + } + + 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; + } + + uint WriteImageEntry (PackedEntry entry, Stream input, Stream output) + { + var grp = FormatCatalog.Instance.LookupTag ("GRP").FirstOrDefault(); + 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; + using (var zstream = new ZLibStream (output, CompressionMode.Compress, 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; + } + zstream.Flush(); + return (uint)zstream.TotalOut; + } + } } [Export(typeof(ImageFormat))] diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs index a0052e8c..467b86cb 100644 --- a/ArcFormats/Strings/arcStrings.Designer.cs +++ b/ArcFormats/Strings/arcStrings.Designer.cs @@ -69,6 +69,15 @@ namespace GameRes.Formats.Strings { } } + /// + /// Looks up a localized string similar to No files suitable for AMI archive found.. + /// + public static string AMINoFiles { + get { + return ResourceManager.GetString("AMINoFiles", resourceCulture); + } + } + /// /// Looks up a localized string similar to Archive content is encrypted. ///Choose appropriate encryption scheme.. @@ -216,6 +225,15 @@ namespace GameRes.Formats.Strings { } } + /// + /// Looks up a localized string similar to {0}: image format not recognized.. + /// + public static string MsgInvalidImageFormat { + get { + return ResourceManager.GetString("MsgInvalidImageFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to Updating index.... /// diff --git a/ArcFormats/Strings/arcStrings.resx b/ArcFormats/Strings/arcStrings.resx index e2109835..dc9ea69e 100644 --- a/ArcFormats/Strings/arcStrings.resx +++ b/ArcFormats/Strings/arcStrings.resx @@ -120,6 +120,9 @@ Amaterasu Translations Muv-Luv archive + + No files suitable for AMI archive found. + Archive content is encrypted. Choose appropriate encryption scheme. @@ -171,6 +174,9 @@ predefined encryption scheme. File name contains illegal characters + + {0}: image format not recognized. + Updating index... diff --git a/ArcFormats/Strings/arcStrings.ru-RU.resx b/ArcFormats/Strings/arcStrings.ru-RU.resx index 63e095a8..cf5892ef 100644 --- a/ArcFormats/Strings/arcStrings.ru-RU.resx +++ b/ArcFormats/Strings/arcStrings.ru-RU.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Не найдено файлов, подходящих для архива AMI. + Содержимое архива зашифровано. Выберите алгоритм шифрования. @@ -156,6 +159,9 @@ Имя файла содержит недопустимые символы + + {0}: не удалось распознать формат изображения. + Обновляется оглавление...