using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Text; using GMWare.IO; namespace LibDgf.Aqualead.Archive { public class AlArchiveV2 : IDisposable { AlAarHeaderV2 header; List entries; Stream stream; private bool disposedValue; public AlArchiveV2(Stream stream) { this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); Load(); } public IList Entries { get { CheckDisposed(); return new ReadOnlyCollection(entries); } } void Load() { BinaryReader br = new BinaryReader(stream); if (new string(br.ReadChars(4)) != "ALAR") throw new InvalidDataException("Not an AquaLead archive."); if (br.ReadByte() != 2) throw new NotSupportedException("Not version 2 archive."); header = new AlAarHeaderV2(); header.Read(br); entries = new List(); for (int i = 0; i < header.Count; ++i) { var entry = new AlAarEntryV2(); entry.Read(br); entries.Add(entry); } foreach (var entry in entries) { if ((entry.Flags & AlAarEntryFlags.IsUseName) != 0) { stream.Seek(entry.Offset - 0x22, SeekOrigin.Begin); entry.Name = StringReadingHelper.ReadNullTerminatedStringFromFixedSizeBlock(br, 0x20, Encoding.UTF8); } if ((entry.Flags & ~AlAarEntryFlags.IsUseName) != 0) { Console.WriteLine($"Entry {entry.Name} has other flags set: {entry.Flags}"); //Debugger.Break(); } } } public Stream GetFile(AlAarEntryV2 entry) { if (!entries.Contains(entry)) throw new ArgumentException("Entry not from this archive.", nameof(entry)); if (stream == null) throw new InvalidOperationException("Archive is not opened from existing."); CheckDisposed(); stream.Seek(entry.Offset, SeekOrigin.Begin); MemoryStream ms = new MemoryStream(); StreamUtils.StreamCopy(stream, ms, entry.Length); ms.Seek(0, SeekOrigin.Begin); return Utils.CheckDecompress(ms); } void CheckDisposed() { if (disposedValue) throw new ObjectDisposedException(GetType().FullName); } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { stream.Close(); } entries = null; disposedValue = true; } } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } } }