160 lines
No EOL
5.5 KiB
C#
160 lines
No EOL
5.5 KiB
C#
using System.IO.Compression;
|
|
using MetaforceInstaller.Core.Models;
|
|
|
|
namespace MetaforceInstaller.Core.Services;
|
|
|
|
public class ZipScrapper
|
|
{
|
|
public static InstallationParts PeekFiles(ZipArchive archive)
|
|
{
|
|
return new InstallationParts
|
|
{
|
|
AndroidContentPath = FindAndroidContent(archive),
|
|
OculusClientPath = FindOculusClient(archive),
|
|
PicoClientPath = FindPicoClient(archive),
|
|
AndroidAdminPath = FindAndroidAdmin(archive),
|
|
WindowsAdminPath = FindPcAdmin(archive),
|
|
WindowsContentPath = FindWindowsContent(archive),
|
|
WindowsServerPath = FindServer(archive),
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extracts ZIP archive to a unique folder based on installation GUID
|
|
/// </summary>
|
|
/// <param name="archive">ZIP archive to extract</param>
|
|
/// <param name="baseOutputPath">Base storage path</param>
|
|
/// <param name="installationGuid">Unique GUID for this installation</param>
|
|
/// <param name="progress">Progress reporter</param>
|
|
/// <returns>Full path to the extracted folder</returns>
|
|
public static string ExtractZip(
|
|
ZipArchive archive,
|
|
string baseOutputPath,
|
|
Guid installationGuid,
|
|
IProgress<double>? progress = null)
|
|
{
|
|
// Create unique folder for this installation
|
|
var installationFolder = Path.Combine(baseOutputPath, installationGuid.ToString());
|
|
Directory.CreateDirectory(installationFolder);
|
|
|
|
var entries = archive.Entries.Where(e => !string.IsNullOrEmpty(e.Name)).ToList();
|
|
var totalEntries = entries.Count;
|
|
var processedEntries = 0;
|
|
|
|
foreach (var entry in entries)
|
|
{
|
|
var destinationPath = Path.Combine(installationFolder, entry.FullName);
|
|
var destinationDir = Path.GetDirectoryName(destinationPath);
|
|
|
|
if (!string.IsNullOrEmpty(destinationDir))
|
|
{
|
|
Directory.CreateDirectory(destinationDir);
|
|
}
|
|
|
|
entry.ExtractToFile(destinationPath, overwrite: true);
|
|
|
|
processedEntries++;
|
|
progress?.Report((double)processedEntries / totalEntries * 100);
|
|
}
|
|
|
|
return installationFolder;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates InstallationParts paths to reflect the actual extracted location
|
|
/// </summary>
|
|
public static InstallationParts UpdatePathsAfterExtraction(
|
|
InstallationParts parts,
|
|
string extractedFolderPath)
|
|
{
|
|
return new InstallationParts
|
|
{
|
|
AndroidContentPath = UpdatePath(parts.AndroidContentPath, extractedFolderPath),
|
|
OculusClientPath = UpdatePath(parts.OculusClientPath, extractedFolderPath),
|
|
PicoClientPath = UpdatePath(parts.PicoClientPath, extractedFolderPath),
|
|
AndroidAdminPath = UpdatePath(parts.AndroidAdminPath, extractedFolderPath),
|
|
WindowsAdminPath = UpdatePath(parts.WindowsAdminPath, extractedFolderPath),
|
|
WindowsContentPath = UpdatePath(parts.WindowsContentPath, extractedFolderPath),
|
|
WindowsServerPath = UpdatePath(parts.WindowsServerPath, extractedFolderPath),
|
|
};
|
|
}
|
|
|
|
private static string? UpdatePath(string? relativePath, string basePath)
|
|
{
|
|
if (string.IsNullOrEmpty(relativePath))
|
|
return null;
|
|
|
|
return Path.Combine(basePath, relativePath);
|
|
}
|
|
|
|
private static string? FindPicoClient(ZipArchive archive)
|
|
{
|
|
return FindEntry(archive,
|
|
name: "MetaforcePico",
|
|
extension: ".apk");
|
|
}
|
|
|
|
private static string? FindOculusClient(ZipArchive archive)
|
|
{
|
|
return FindEntry(archive,
|
|
name: "MetaforceOculus",
|
|
extension: ".apk");
|
|
}
|
|
|
|
private static string? FindAndroidAdmin(ZipArchive archive)
|
|
{
|
|
return FindEntry(archive,
|
|
name: "MetaforceAdmin",
|
|
extension: ".apk");
|
|
}
|
|
|
|
private static string? FindAndroidContent(ZipArchive archive)
|
|
{
|
|
return FindEntry(archive,
|
|
name: "Content_Android",
|
|
extension: ".zip");
|
|
}
|
|
|
|
private static string? FindWindowsContent(ZipArchive archive)
|
|
{
|
|
return FindEntry(archive,
|
|
name: "Content_StandaloneWindows",
|
|
extension: ".zip");
|
|
}
|
|
|
|
private static string? FindPcAdmin(ZipArchive archive)
|
|
{
|
|
return FindExecutable(archive, "MetaforceAdminPC");
|
|
}
|
|
|
|
private static string? FindServer(ZipArchive archive)
|
|
{
|
|
return FindExecutable(archive, "MetaforceServer");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds an entry in archive by name and extension
|
|
/// </summary>
|
|
private static string? FindEntry(ZipArchive archive, string name, string extension)
|
|
{
|
|
var entry = archive.Entries.FirstOrDefault(e =>
|
|
e.Name.Contains(name, StringComparison.OrdinalIgnoreCase) &&
|
|
e.Name.EndsWith(extension, StringComparison.OrdinalIgnoreCase));
|
|
|
|
return entry?.FullName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds an executable in archive, excluding crash handlers
|
|
/// </summary>
|
|
private static string? FindExecutable(ZipArchive archive, string containsName)
|
|
{
|
|
var entry = archive.Entries.FirstOrDefault(e =>
|
|
e.FullName.Contains(containsName, StringComparison.OrdinalIgnoreCase) &&
|
|
e.Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) &&
|
|
!e.Name.Contains("UnityCrashHandler", StringComparison.OrdinalIgnoreCase) &&
|
|
!e.Name.Contains("crashpad_handler", StringComparison.OrdinalIgnoreCase));
|
|
|
|
return entry?.FullName;
|
|
}
|
|
} |