using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace TinfoilVibeServer.Utilities;
///
/// Streams a multipart RAR as a single, seekable stream.
/// Supports:
/// • myGame.rar (single volume)
/// • myGame.r00 / r01 … (RAR 4.x style)
/// • myGame.part01.rar … (WinRAR “part” style)
///
public static class MultiPartRarHelper
{
public static string GetBaseNameForRarVolume(string fileName)
{
string baseName = string.Empty;
// Multipart – remove the ".rNN" or ".partNN" suffix
var m = Regex.Match(fileName,
@"^(?.+?)(\.r\d\d|\.part\d\d)\.rar$",
RegexOptions.IgnoreCase);
if (!m.Success)
{
if (fileName.EndsWith(".rar", StringComparison.OrdinalIgnoreCase))
{
// Single‑volume archive – just drop the suffix
baseName = fileName.Substring(0, fileName.Length - 4);
}
}
else
{
baseName = m.Groups["base"].Value;
}
return baseName;
}
///
/// Returns the list of files that belong to the same multipart set.
///
public static List DiscoverVolumes(string dir, string baseName)
{
// Pattern: .(rar | rNN | partNN.rar)
string pattern =
$@"^{Regex.Escape(baseName)}(\.rar|\.r\d\d|\.part\d\d\.rar)$";
return Directory.GetFiles(dir)
.Where(f => Regex.IsMatch(Path.GetFileName(f), pattern, RegexOptions.IgnoreCase))
.OrderBy(f => GetPartNumber(Path.GetFileName(f), baseName))
.ToList();
}
///
/// Gives each file a numeric key that guarantees the correct order.
/// 0 → .rar (first volume)
/// 1 → .r00 or .part01
/// 2 → .r01 or .part02
/// … and so on.
///
private static int GetPartNumber(string fileName, string baseName)
{
// 1️⃣ ".rar" → 0
if (fileName.Equals($"{baseName}.rar", StringComparison.OrdinalIgnoreCase))
return 0;
// 2️⃣ ".rNN" or ".partNN.rar"
var m = Regex.Match(fileName,
$@"\.r(?\d\d)$|\.part(?\d\d)\.rar$",
RegexOptions.IgnoreCase);
if (m.Success)
{
int partNum = int.Parse(m.Groups["num"].Value);
return partNum + 1; // so r00 → 1, r01 → 2; part01 → 1, part02 → 2
}
// 3️⃣ unknown pattern – treat as first part
return 0;
}
}