magellan/Lucidiot.Magellan/MapArchiveStorage.cs

55 lines
2.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using Lucidiot.Raima;
namespace Lucidiot.Magellan {
public class MapArchiveStorage : ReadOnlyDatabaseStorage, IDisposable {
private Dictionary<string, MapArchiveEntry> entriesCache;
private readonly Stream ArchiveStream;
public MapArchiveStorage(string path) {
if (!File.Exists(path))
throw new FileNotFoundException("Archive file not found.", path);
this.ArchiveStream = File.OpenRead(path);
}
public MapArchiveStorage(Stream stream) {
if (!stream.CanSeek)
throw new ArgumentException("Seeking capability is required on the stream in order to use it as database storage.", "br");
if (!stream.CanRead)
throw new ArgumentException("Reading capability is required on the stream in order to use it as database storage.", "br");
this.ArchiveStream = stream;
}
public MapArchiveEntry? TryFindEntry(string fileName) {
if (entriesCache == null) {
ArchiveStream.Seek(0, SeekOrigin.Begin);
entriesCache = new Dictionary<string, MapArchiveEntry>();
foreach (MapArchiveEntry entry in MapArchive.ReadHeader(new BinaryReader(ArchiveStream))) {
entriesCache[entry.FullName] = entry;
}
}
MapArchiveEntry result;
if (!entriesCache.TryGetValue(fileName, out result))
return null;
return result;
}
public override bool Exists(string fileName) {
return TryFindEntry(fileName) != null;
}
public override BinaryReader GetReader(string fileName) {
MapArchiveEntry? entry = TryFindEntry(fileName);
if (entry == null)
throw new FileNotFoundException("File does not exist", fileName);
return new BinaryReader(new Substream(ArchiveStream, entry.Value.Offset, entry.Value.Length));
}
public void Dispose() {
ArchiveStream.Dispose();
}
}
}