using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using Robust.Shared.ContentPack;
using Robust.Shared.Utility;
namespace Robust.Client.Replays.Loading;
///
/// Simple interface that the replay system loads files from.
///
[NotContentImplementable]
public interface IReplayFileReader : IDisposable
{
///
/// Check whether a file exists in the replay data.
///
/// The path to check. Doesn't need to be rooted.
/// True if the file exists.
bool Exists(ResPath path);
///
/// Open a file in the replay data.
///
/// The path to the file. Doesn't need to be rooted.
/// A stream containing the file contents.
/// Thrown if the file does not exist.
Stream Open(ResPath path);
///
/// Returns all files in the replay data.
///
///
/// File paths are rooted.
///
IEnumerable AllFiles { get; }
}
///
/// Replay file reader that loads files from the VFS ().
///
public sealed class ReplayFileReaderResources : IReplayFileReader
{
private readonly IResourceManager _resourceManager;
private readonly ResPath _prefix;
/// The resource manager.
/// The directory in the VFS that contains the replay files. Must be rooted.
public ReplayFileReaderResources(IResourceManager resourceManager, ResPath prefix)
{
_resourceManager = resourceManager;
_prefix = prefix;
}
public bool Exists(ResPath path)
{
return _resourceManager.ContentFileExists(GetPath(path));
}
public Stream Open(ResPath path)
{
return _resourceManager.ContentFileRead(GetPath(path));
}
public IEnumerable AllFiles
{
get
{
foreach (var path in _resourceManager.ContentFindRelativeFiles(_prefix))
{
yield return path.ToRelativePath();
}
}
}
private ResPath GetPath(ResPath path) => _prefix / path.ToRelativePath();
public void Dispose()
{
// Don't need to do anything.
}
}
///
/// Replay file reader that loads files from a zip file.
///
///
/// The zip archive is disposed when this instance is disposed.
///
public sealed class ReplayFileReaderZip : IReplayFileReader
{
private readonly ZipArchive _archive;
private readonly ResPath _prefix;
/// The archive to read files from.
/// The directory in the zip that contains the replay files. Must NOT be rooted.
public ReplayFileReaderZip(ZipArchive archive, ResPath prefix)
{
_archive = archive;
_prefix = prefix;
}
public bool Exists(ResPath path)
{
return GetEntry(path) != null;
}
public Stream Open(ResPath path)
{
var entry = GetEntry(path);
if (entry == null)
throw new FileNotFoundException();
return entry.Open();
}
public IEnumerable AllFiles
{
get
{
foreach (var entry in _archive.Entries)
{
// Ignore directories.
if (entry.FullName.EndsWith("/"))
continue;
var entryPath = new ResPath(entry.FullName);
if (entryPath.TryRelativeTo(_prefix, out var path))
yield return path.Value.ToRootedPath();
}
}
}
private ZipArchiveEntry? GetEntry(ResPath path) => _archive.GetEntry((_prefix / path.ToRelativePath()).ToString());
public void Dispose()
{
_archive.Dispose();
}
}