Initial commit

This commit is contained in:
Yukai Li 2021-02-16 01:04:29 -07:00
commit 0f86b0434b
38 changed files with 2370 additions and 0 deletions

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace LibDgf.Aqualead.Archive
{
[Flags]
public enum AlAarArchiveFlags : byte
{
IsValid = 1 << 0,
IsSorted = 1 << 5,
IsUseNameHash = 1 << 6
}
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace LibDgf.Aqualead.Archive
{
[Flags]
public enum AlAarEntryFlags : byte
{
IsResident = 1 << 0,
IsPrepare = 1 << 1,
Unknown2 = 1 << 6,
IsUseName = 1 << 7
}
}

View file

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LibDgf.Aqualead.Archive
{
public class AlAarEntryV2
{
uint rest;
public uint Id { get; set; }
public uint Offset { get; set; }
public uint Length { get; set; }
public uint Range
{
get
{
return rest & 0xffffff;
}
set
{
if (value > 0xffffff) throw new ArgumentOutOfRangeException(nameof(value));
rest = value | (rest & 0xff000000);
}
}
public AlAarEntryFlags Flags
{
get
{
return (AlAarEntryFlags)((rest >> 24) & 0xff);
}
set
{
if ((uint)value > 0xff) throw new ArgumentOutOfRangeException(nameof(value));
rest = ((uint)value << 24) | (rest & 0xffffff);
}
}
public string Name { get; set; }
public void Read(BinaryReader br)
{
Id = br.ReadUInt32();
Offset = br.ReadUInt32();
Length = br.ReadUInt32();
rest = br.ReadUInt32();
}
}
}

View file

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LibDgf.Aqualead.Archive
{
public class AlAarHeaderV2
{
// Magic and version omitted, handled in archive class
public AlAarArchiveFlags Flags { get; set; }
public ushort Count { get; set; }
public uint LowId { get; set; }
public uint HighId { get; set; }
public void Read(BinaryReader br)
{
Flags = (AlAarArchiveFlags)br.ReadByte();
Count = br.ReadUInt16();
LowId = br.ReadUInt32();
HighId = br.ReadUInt32();
}
}
}

View file

@ -0,0 +1,108 @@
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<AlAarEntryV2> entries;
Stream stream;
private bool disposedValue;
public AlArchiveV2(Stream stream)
{
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
Load();
}
public IList<AlAarEntryV2> Entries
{
get
{
CheckDisposed();
return new ReadOnlyCollection<AlAarEntryV2>(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<AlAarEntryV2>();
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);
}
}
}