diff --git a/ArcFormats/ArcXFL.cs b/ArcFormats/ArcXFL.cs index 988d7dfe..8a6b3031 100644 --- a/ArcFormats/ArcXFL.cs +++ b/ArcFormats/ArcXFL.cs @@ -7,8 +7,10 @@ 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 { @@ -50,6 +52,71 @@ namespace GameRes.Formats } return new ArcFile (file, this, dir); } + + public override void Create (Stream output, IEnumerable list, ResourceOptions options) + { + 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.Clone() as Encoding; + encoding.EncoderFallback = EncoderFallback.ExceptionFallback; + + byte[] name_buf = new byte[32]; + + // first, write names only + foreach (var entry in list) + { + try + { + string name = Path.GetFileName (entry.Name); + 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) + { + 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); + } + } + + // 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 diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs index e961c210..59a45052 100644 --- a/ArcFormats/Strings/arcStrings.Designer.cs +++ b/ArcFormats/Strings/arcStrings.Designer.cs @@ -171,6 +171,24 @@ namespace GameRes.Formats.Strings { } } + /// + /// Looks up a localized string similar to File name is too long. + /// + public static string MsgFileNameTooLong { + get { + return ResourceManager.GetString("MsgFileNameTooLong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File name contains illegal characters. + /// + public static string MsgIllegalCharacters { + get { + return ResourceManager.GetString("MsgIllegalCharacters", resourceCulture); + } + } + /// /// Looks up a localized string similar to Nitro+ resource archive. /// diff --git a/ArcFormats/Strings/arcStrings.resx b/ArcFormats/Strings/arcStrings.resx index b755f965..50079bc0 100644 --- a/ArcFormats/Strings/arcStrings.resx +++ b/ArcFormats/Strings/arcStrings.resx @@ -156,6 +156,12 @@ predefined encryption scheme. Liar-soft image archive + + File name is too long + + + File name contains illegal characters + Nitro+ resource archive diff --git a/ArcFormats/Strings/arcStrings.ru-RU.resx b/ArcFormats/Strings/arcStrings.ru-RU.resx index 6c8b7625..842928f5 100644 --- a/ArcFormats/Strings/arcStrings.ru-RU.resx +++ b/ArcFormats/Strings/arcStrings.ru-RU.resx @@ -141,6 +141,12 @@ Введите ключ шифрования или выберите один из предопределённых вариантов. + + Слишком длинное имя файла + + + Имя файла содержит недопустимые символы + 8-битный ключ шифрования