public override ArcFile TryOpen(ArcView file) { int index_size = file.View.ReadInt32(0); if (index_size < 0x14 || index_size >= file.MaxOffset || index_size > 0xffffff) { return(null); } var stream = new SteinsGateEncryptedStream(file, 4, (uint)index_size); using (var header = new BinaryReader(stream)) { int entry_count = header.ReadInt32(); if (!IsSaneCount(entry_count)) { return(null); } index_size -= 4; int average_entry_size = index_size / entry_count; if (average_entry_size < 0x11) { return(null); } var dir = new List <Entry> (entry_count); for (int i = 0; i < entry_count; ++i) { int name_length = header.ReadInt32(); if (name_length + 0x10 > index_size) { return(null); } byte[] name_raw = header.ReadBytes(name_length); Encoding enc = GuessEncoding(name_raw); string filename = enc.GetString(name_raw); var entry = FormatCatalog.Instance.Create <Entry> (filename); entry.Size = header.ReadUInt32(); entry.Offset = header.ReadInt64(); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); index_size -= name_length + 0x10; } return(new ArcFile(file, this, dir)); } }
public override void Create(Stream output, IEnumerable <Entry> list, ResourceOptions options, EntryCallback callback) { var sg_options = GetOptions <SteinsGateOptions> (options); Encoding encoding = sg_options.FileNameEncoding.WithFatalFallback(); long start_pos = output.Position; int callback_count = 0; uint index_size = 4; var real_entry_list = new List <RawEntry> (list.Count()); var used_names = new HashSet <string>(); foreach (var entry in list) { string name = entry.Name.Replace(@"\", "/"); if (!used_names.Add(name)) // duplicate name { continue; } var header_entry = new RawEntry { Name = entry.Name }; try { header_entry.IndexName = encoding.GetBytes(name); } catch (EncoderFallbackException X) { throw new InvalidFileName(entry.Name, arcStrings.MsgIllegalCharacters, X); } index_size += (uint)header_entry.IndexName.Length + 16; real_entry_list.Add(header_entry); } output.Seek(4 + index_size, SeekOrigin.Current); foreach (var entry in real_entry_list) { using (var input = File.Open(entry.Name, FileMode.Open, FileAccess.Read)) { var file_size = input.Length; if (file_size > uint.MaxValue) { throw new FileSizeException(); } entry.Offset = output.Position; entry.Size = (uint)file_size; if (null != callback) { callback(callback_count++, entry, arcStrings.MsgAddingFile); } using (var stream = new SteinsGateEncryptedStream(output)) input.CopyTo(stream); } } if (null != callback) { callback(callback_count++, null, arcStrings.MsgWritingIndex); } output.Position = start_pos; output.WriteByte((byte)(index_size & 0xff)); output.WriteByte((byte)((index_size >> 8) & 0xff)); output.WriteByte((byte)((index_size >> 16) & 0xff)); output.WriteByte((byte)((index_size >> 24) & 0xff)); var encrypted_stream = new SteinsGateEncryptedStream(output); using (var header = new BinaryWriter(encrypted_stream)) { header.Write(real_entry_list.Count); foreach (var entry in real_entry_list) { header.Write(entry.IndexName.Length); header.Write(entry.IndexName); header.Write((uint)entry.Size); header.Write((long)entry.Offset); } } }