Compare commits

...

13 Commits

Author SHA1 Message Date
Matt Nadareski
f83dbee1b1 Fix version for getopts 2026-09-21 09:23:13 -04:00
Matt Nadareski
d44873b37b Enable versions in publish script 2026-09-21 09:21:54 -04:00
Matt Nadareski
bbe12c5358 Handle edge case of scanning temp directory (fixes #423) 2026-09-20 08:24:29 -04:00
Matt Nadareski
9f49f910ea Use correct README path for the future 2026-09-04 08:56:49 -04:00
Matt Nadareski
9403a338bb Bump version 2026-09-04 08:51:10 -04:00
Matt Nadareski
6b19685108 Update packages 2026-08-31 19:50:24 -04:00
Matt Nadareski
9d03ea57aa Bump version 2026-07-10 18:13:59 -04:00
Matt Nadareski
0672f0c6e1 Update copyright dates 2026-07-10 13:49:26 -04:00
Matt Nadareski
080f4327bf Update packages, relax requirements 2026-07-10 13:49:09 -04:00
Matt Nadareski
521797b7b1 Add readme to package finally 2026-07-09 09:37:59 -04:00
Matt Nadareski
f4987e1862 Bump version 2026-07-06 10:32:00 -04:00
Matt Nadareski
34a0fb1f87 Update Serialization to 3.0.1 2026-07-06 10:19:49 -04:00
HeroponRikiBestest
8ca25c6370 Update GCF output string for encrypted GCFs (#417)
* Update GCF output string for encrypted GCFs

* Use Array.Exists since some early GCFs have only some files encrypted
2026-06-26 20:45:18 -04:00
8 changed files with 122 additions and 49 deletions

View File

@@ -16,10 +16,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="SabreTools.Serialization" Version="[3.0.0]" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
<PackageReference Include="SabreTools.Serialization" Version="3.2.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PackageReference Include="xunit.runner.visualstudio" Version="4.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@@ -13,13 +13,13 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.7.0</Version>
<Version>3.9.0</Version>
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Protection scanning library</Description>
<Copyright>Copyright (c)2018-2025 Matt Nadareski</Copyright>
<Copyright>Copyright (c)2018-2026 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/SabreTools/BinaryObjectScanner</RepositoryUrl>
<RepositoryType>git</RepositoryType>
@@ -46,12 +46,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="GrindCore.SharpCompress" Version="0.48.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GrindCore.SharpCompress" Version="0.50.5" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="MinThreadingBridge" Version="0.11.4" Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))" />
<PackageReference Include="SabreTools.Hashing" Version="[2.0.0]" />
<PackageReference Include="SabreTools.IO" Version="[2.1.0]" />
<PackageReference Include="SabreTools.Serialization" Version="[3.0.0]" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.9" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
<PackageReference Include="SabreTools.Hashing" Version="2.1.0" />
<PackageReference Include="SabreTools.IO" Version="2.3.0" />
<PackageReference Include="SabreTools.Serialization" Version="3.2.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.11" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
namespace BinaryObjectScanner.FileType
@@ -16,19 +17,19 @@ namespace BinaryObjectScanner.FileType
// Filename is worth reporting, since it's descriptive and has to match the Steam2 CDN in order to work.
string fileName = Path.GetFileName(file);
uint depotId = _wrapper.Model.Header.CacheID;
uint manifestVersion = _wrapper.Model.Header.LastVersionPlayed;
uint depotVersion = _wrapper.Model.Header.LastVersionPlayed;
// At the moment, all samples of GCF files on redump are unencrypted. Combined with being uncertain about
// whether this is the best way to check whether the GCF is encrypted, this block will be left commented
// out until further research is done.
// bool encrypted = false;
// if (_wrapper.Files != null && _wrapper.Files.Length > 0)
// encrypted = _wrapper.Files[0].Encrypted;
// While there is a depot-level encrypted flag on the GCF, it's unfortunately completely unreliable.
// Technically speaking, there are some known GCFs that only have some files encrypted. HL2 discs from
// 2004 have several GCFs like this, one being base_source_engine.gcf (depot 200). Thus, it's necessary
// to iterate all file info to check if any files are encrypted
bool encrypted = false;
if (_wrapper.Files != null && _wrapper.Files.Length > 0)
encrypted = Array.Exists(_wrapper.Files, fileInfo => fileInfo.Encrypted);
// string encryptedString = encrypted ? "encrypted" : "unencrypted";
// string returnString = $"{fileName} - {depotId} (v{manifestVersion}, {encryptedString})";
string returnString = $"{fileName} - {depotId} (v{manifestVersion})";
// Only note encryption status if the GCF is encrypted
string encryptedString = encrypted ? ", encrypted" : "";
string returnString = $"{fileName} - {depotId} (v{depotVersion}{encryptedString})";
return returnString;
}
}

View File

@@ -46,6 +46,22 @@ namespace BinaryObjectScanner
#endregion
#region Static Variables
/// <summary>
/// Path to the temporary directory
/// </summary>
/// <remarks>Value has trailing directory separators trimmed</remarks>
private static readonly string TempFilePath = Path.GetTempPath().TrimEnd('\\', '/');
/// <summary>
/// Template for determining if a file is a temporary extracted path
/// </summary>
/// <remarks>Value has trailing directory separators trimmed and the GUID value itself does not matter</remarks>
private static readonly string TempFilePathWithGuid = Path.Combine(TempFilePath, Guid.NewGuid().ToString()).TrimEnd('\\', '/');
#endregion
/// <summary>
/// Constructor
/// </summary>
@@ -123,10 +139,6 @@ namespace BinaryObjectScanner
// Checkpoint
_fileProgress?.Report(new ProtectionProgress(null, depth, 0, null));
// Temp variables for reporting
string tempFilePath = Path.GetTempPath();
string tempFilePathWithGuid = Path.Combine(tempFilePath, Guid.NewGuid().ToString());
// Loop through each path and get the returned values
var protections = new ProtectionDictionary();
foreach (string path in paths)
@@ -152,13 +164,7 @@ namespace BinaryObjectScanner
string file = files[i];
// Get the reportable file name
string reportableFileName = file;
if (reportableFileName.StartsWith(tempFilePath))
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
reportableFileName = reportableFileName[tempFilePathWithGuid.Length..];
#else
reportableFileName = reportableFileName.Substring(tempFilePathWithGuid.Length);
#endif
string reportableFileName = GetReportableFileName(file);
// Checkpoint
_fileProgress?.Report(new ProtectionProgress(reportableFileName, depth, i / (float)files.Count, "Checking file" + (file != reportableFileName ? " from archive" : string.Empty)));
@@ -193,13 +199,7 @@ namespace BinaryObjectScanner
else if (File.Exists(path))
{
// Get the reportable file name
string reportableFileName = path;
if (reportableFileName.StartsWith(tempFilePath))
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
reportableFileName = reportableFileName[tempFilePathWithGuid.Length..];
#else
reportableFileName = reportableFileName.Substring(tempFilePathWithGuid.Length);
#endif
string reportableFileName = GetReportableFileName(path);
// Checkpoint
_fileProgress?.Report(new ProtectionProgress(reportableFileName, depth, 0, "Checking file" + (path != reportableFileName ? " from archive" : string.Empty)));
@@ -517,6 +517,44 @@ namespace BinaryObjectScanner
};
}
/// <summary>
/// Get the reportable file name by determining if the file was
/// likely extracted as a part of the scanning run.
/// </summary>
/// <param name="path">File path to check</param>
/// <returns>Trimmed file path if it should be an extracted file, the full path as passed in otherwise</returns>
/// <remarks>
/// This will be a false positive if intentionally scanning a path that
/// fits the pattern of '%TEMP%/{GUID}/{file}'.
private static string GetReportableFileName(string path)
{
// If the file is not in the temp directory
if (!path.StartsWith(TempFilePath))
return path;
// If the filename isn't longer than the template path
if (path.Length < TempFilePathWithGuid.Length)
return path;
// Check if we're in a GUID subdirectory
string possibleGuid = path.Substring(TempFilePath.Length + 1, 36);
#if NET20 || NET35
if (System.Text.RegularExpressions.Regex.IsMatch(possibleGuid, @"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"))
#else
if (Guid.TryParse(possibleGuid, out _))
#endif
{
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
return path[TempFilePathWithGuid.Length..];
#else
return path.Substring(TempFilePathWithGuid.Length);
#endif
}
// Otherwise, return the path as given
return path;
}
#endregion
}
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018-2025 Matt Nadareski
Copyright (c) 2018-2026 Matt Nadareski
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@@ -10,7 +10,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.7.0</Version>
<Version>3.9.0</Version>
</PropertyGroup>
<!-- Support All Frameworks -->
@@ -32,8 +32,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
<PackageReference Include="SabreTools.Serialization" Version="[3.0.0]" />
<PackageReference Include="SabreTools.CommandLine" Version="1.5.0" />
<PackageReference Include="SabreTools.Serialization" Version="3.2.0" />
</ItemGroup>
</Project>

View File

@@ -13,7 +13,9 @@ USE_ALL=false
INCLUDE_DEBUG=false
NO_BUILD=false
NO_ARCHIVE=false
while getopts "udba" OPTION; do
HAS_VERSION=false
VERSION="NONE"
while getopts "udbav:" OPTION; do
case $OPTION in
u)
USE_ALL=true
@@ -27,6 +29,10 @@ while getopts "udba" OPTION; do
a)
NO_ARCHIVE=true
;;
v)
HAS_VERSION=true
VERSION=${OPTARG}
;;
*)
echo "Invalid option provided"
exit 1
@@ -46,6 +52,7 @@ echo " Use all frameworks (-u) $USE_ALL"
echo " Include debug builds (-d) $INCLUDE_DEBUG"
echo " No build (-b) $NO_BUILD"
echo " No archive (-a) $NO_ARCHIVE"
echo " Version (-v) $HAS_VERSION ($VERSION)"
echo " "
# Create the build matrix arrays
@@ -139,10 +146,18 @@ if [ $NO_ARCHIVE = false ]; then
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
cd $BUILD_FOLDER/ProtectionScan/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
zip -r $BUILD_FOLDER/ProtectionScan_${FRAMEWORK}_${RUNTIME}_debug.zip .
if [ $HAS_VERSION = true ]; then
zip -r $BUILD_FOLDER/ProtectionScan_${VERSION}_${FRAMEWORK}_${RUNTIME}_debug.zip .
else
zip -r $BUILD_FOLDER/ProtectionScan_${FRAMEWORK}_${RUNTIME}_debug.zip .
fi
fi
cd $BUILD_FOLDER/ProtectionScan/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/
zip -r $BUILD_FOLDER/ProtectionScan_${FRAMEWORK}_${RUNTIME}_release.zip .
if [ $HAS_VERSION = true ]; then
zip -r $BUILD_FOLDER/ProtectionScan_${VERSION}_${FRAMEWORK}_${RUNTIME}_release.zip .
else
zip -r $BUILD_FOLDER/ProtectionScan_${FRAMEWORK}_${RUNTIME}_release.zip .
fi
done
done

View File

@@ -22,7 +22,11 @@ param(
[Parameter(Mandatory = $false)]
[Alias("NoArchive")]
[switch]$NO_ARCHIVE
[switch]$NO_ARCHIVE,
[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
[Alias("BuildVersion")]
[string]$BUILD_VERSION
)
# Set the current directory as a variable
@@ -37,6 +41,7 @@ Write-Host " Use all frameworks (-UseAll) $USE_ALL"
Write-Host " Include debug builds (-IncludeDebug) $INCLUDE_DEBUG"
Write-Host " No build (-NoBuild) $NO_BUILD"
Write-Host " No archive (-NoArchive) $NO_ARCHIVE"
Write-Host " Version (-BuildVersion) $BUILD_VERSION"
Write-Host " "
# Create the build matrix arrays
@@ -123,11 +128,21 @@ if (!$NO_ARCHIVE.IsPresent) {
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
Set-Location -Path $BUILD_FOLDER\ProtectionScan\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
7z a -tzip $BUILD_FOLDER\ProtectionScan_${FRAMEWORK}_${RUNTIME}_debug.zip *
if ($BUILD_VERSION -ne $null) {
7z a -tzip $BUILD_FOLDER\ProtectionScan_${BUILD_VERSION}_${FRAMEWORK}_${RUNTIME}_debug.zip *
}
else {
7z a -tzip $BUILD_FOLDER\ProtectionScan_${FRAMEWORK}_${RUNTIME}_debug.zip *
}
}
Set-Location -Path $BUILD_FOLDER\ProtectionScan\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
7z a -tzip $BUILD_FOLDER\ProtectionScan_${FRAMEWORK}_${RUNTIME}_release.zip *
if ($BUILD_VERSION -ne $null) {
7z a -tzip $BUILD_FOLDER\ProtectionScan_${BUILD_VERSION}_${FRAMEWORK}_${RUNTIME}_release.zip *
}
else {
7z a -tzip $BUILD_FOLDER\ProtectionScan_${FRAMEWORK}_${RUNTIME}_release.zip *
}
}
}