diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 07455422..1920ebc3 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -70,6 +70,9 @@ CreateAMIWidget.xaml + + CreateINTWidget.xaml + CreateONSWidget.xaml @@ -139,6 +142,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/ArcFormats/ArcINT.cs b/ArcFormats/ArcINT.cs index 0ac68e89..dbdf83c4 100644 --- a/ArcFormats/ArcINT.cs +++ b/ArcFormats/ArcINT.cs @@ -48,6 +48,7 @@ namespace GameRes.Formats } } + [Serializable()] public class IntEncryptionInfo { public uint? Key { get; set; } @@ -85,6 +86,7 @@ namespace GameRes.Formats public override string Description { get { return arcStrings.INTDescription; } } public override uint Signature { get { return 0x0046494b; } } public override bool IsHierarchic { get { return false; } } + public override bool CanCreate { get { return true; } } public override ArcFile TryOpen (ArcView file) { @@ -103,7 +105,7 @@ namespace GameRes.Formats } long current_offset = 8; - var dir = new List(); + var dir = new List ((int)entry_count); for (uint i = 0; i < entry_count; ++i) { string name = file.View.ReadString (current_offset, 0x40); @@ -135,7 +137,7 @@ namespace GameRes.Formats Array.Reverse (blowfish_key); var blowfish = new Blowfish (blowfish_key); - var dir = new List(); + var dir = new List ((int)entry_count-1); byte[] name_info = new byte[0x40]; for (uint i = 1; i < entry_count; ++i) { @@ -332,10 +334,92 @@ namespace GameRes.Formats return new GUI.WidgetINT (); } + public override object GetCreationWidget () + { + return new GUI.CreateINTWidget(); + } + uint? QueryEncryptionInfo () { var options = Query (arcStrings.INTNotice); return options.EncryptionInfo.GetKey(); } + + public override void Create (Stream output, IEnumerable list, ResourceOptions options, + EntryCallback callback) + { + int file_count = list.Count(); + if (null != callback) + callback (file_count+2, null, null); + int callback_count = 0; + using (var writer = new BinaryWriter (output, Encoding.ASCII, true)) + { + writer.Write (Signature); + writer.Write (file_count); + long dir_offset = output.Position; + + var encoding = Encodings.cp932.WithFatalFallback(); + byte[] name_buf = new byte[0x40]; + int previous_size = 0; + + if (null != callback) + callback (callback_count++, null, arcStrings.MsgWritingIndex); + + // first, write names only + foreach (var entry in list) + { + string name = Path.GetFileName (entry.Name); + try + { + int size = encoding.GetBytes (name, 0, name.Length, name_buf, 0); + for (int i = size; i < previous_size; ++i) + name_buf[i] = 0; + previous_size = size; + } + 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 + long current_offset = output.Position; + foreach (var entry in list) + { + if (null != callback) + callback (callback_count++, entry, arcStrings.MsgAddingFile); + + entry.Offset = current_offset; + using (var input = File.OpenRead (entry.Name)) + { + 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); + } + } + + if (null != callback) + callback (callback_count++, null, arcStrings.MsgUpdatingIndex); + + // at last, go back to directory and write offset/sizes + dir_offset += 0x40; + foreach (var entry in list) + { + writer.BaseStream.Position = dir_offset; + writer.Write ((uint)entry.Offset); + writer.Write (entry.Size); + dir_offset += 0x48; + } + } + } } } diff --git a/ArcFormats/CreateINTWidget.xaml b/ArcFormats/CreateINTWidget.xaml new file mode 100644 index 00000000..17295086 --- /dev/null +++ b/ArcFormats/CreateINTWidget.xaml @@ -0,0 +1,6 @@ + + + diff --git a/ArcFormats/CreateINTWidget.xaml.cs b/ArcFormats/CreateINTWidget.xaml.cs new file mode 100644 index 00000000..8fe74e57 --- /dev/null +++ b/ArcFormats/CreateINTWidget.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows.Controls; + +namespace GameRes.Formats.GUI +{ + /// + /// Interaction logic for CreateINTWidget.xaml + /// + public partial class CreateINTWidget : Grid + { + public CreateINTWidget () + { + InitializeComponent (); + } + } +} diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs index d1e0d0db..f4e68dca 100644 --- a/ArcFormats/Strings/arcStrings.Designer.cs +++ b/ArcFormats/Strings/arcStrings.Designer.cs @@ -142,6 +142,15 @@ namespace GameRes.Formats.Strings { } } + /// + /// Looks up a localized string similar to Encrypted archives creation is not implemented.. + /// + public static string INTCreationNotice { + get { + return ResourceManager.GetString("INTCreationNotice", resourceCulture); + } + } + /// /// Looks up a localized string similar to FrontWing game resource archive. /// diff --git a/ArcFormats/Strings/arcStrings.resx b/ArcFormats/Strings/arcStrings.resx index f186a541..5e1be3c9 100644 --- a/ArcFormats/Strings/arcStrings.resx +++ b/ArcFormats/Strings/arcStrings.resx @@ -145,6 +145,9 @@ Choose appropriate encryption scheme. Liar-soft proprietary script format + + Encrypted archives creation is not implemented. + FrontWing game resource archive diff --git a/ArcFormats/Strings/arcStrings.ru-RU.resx b/ArcFormats/Strings/arcStrings.ru-RU.resx index b8dfe3cd..60868c06 100644 --- a/ArcFormats/Strings/arcStrings.ru-RU.resx +++ b/ArcFormats/Strings/arcStrings.ru-RU.resx @@ -136,6 +136,9 @@ без шифрования + + Создание зашифрованных архивов не реализовано. + Цифровой ключ должен быть 32-битным шестнадцатиричным числом