mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-13 05:35:24 +00:00
392 lines
18 KiB
C#
392 lines
18 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using BurnOutSharp.Matching;
|
||
using SharpCompress.Archives;
|
||
using SharpCompress.Archives.Zip;
|
||
|
||
namespace BurnOutSharp.PackerType
|
||
{
|
||
public class WinZipSFX : IContentCheck, IScannable
|
||
{
|
||
/// <inheritdoc/>
|
||
public bool ShouldScan(byte[] magic) => true;
|
||
|
||
/// <inheritdoc/>
|
||
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
|
||
{
|
||
var matchers = new List<ContentMatchSet>
|
||
{
|
||
// WinZip Self-Extractor
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53,
|
||
0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72,
|
||
0x61, 0x63, 0x74, 0x6F, 0x72
|
||
}, GetVersion, "WinZip SFX"),
|
||
|
||
// _winzip_
|
||
new ContentMatchSet(new byte?[] { 0x5F, 0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5F }, GetVersion, "WinZip SFX"),
|
||
};
|
||
|
||
return MatchUtil.GetFirstMatch(file, fileContent, matchers, includePosition);
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public Dictionary<string, List<string>> Scan(Scanner scanner, string file)
|
||
{
|
||
if (!File.Exists(file))
|
||
return null;
|
||
|
||
using (var fs = File.OpenRead(file))
|
||
{
|
||
return Scan(scanner, fs, file);
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public Dictionary<string, List<string>> Scan(Scanner scanner, Stream stream, string file)
|
||
{
|
||
// If the zip file itself fails
|
||
try
|
||
{
|
||
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||
Directory.CreateDirectory(tempPath);
|
||
|
||
// Should be using stream instead of file, but stream fails to extract anything. My guess is that the executable portion of the archive is causing stream to fail, but not file.
|
||
using (ZipArchive zipFile = ZipArchive.Open(file))
|
||
{
|
||
foreach (var entry in zipFile.Entries)
|
||
{
|
||
// If an individual entry fails
|
||
try
|
||
{
|
||
// If we have a directory, skip it
|
||
if (entry.IsDirectory)
|
||
continue;
|
||
|
||
string tempFile = Path.Combine(tempPath, entry.Key);
|
||
entry.WriteToFile(tempFile);
|
||
}
|
||
catch { }
|
||
}
|
||
}
|
||
|
||
// Collect and format all found protections
|
||
var protections = scanner.GetProtections(tempPath);
|
||
|
||
// If temp directory cleanup fails
|
||
try
|
||
{
|
||
Directory.Delete(tempPath, true);
|
||
}
|
||
catch { }
|
||
|
||
// Remove temporary path references
|
||
Utilities.StripFromKeys(protections, tempPath);
|
||
|
||
return protections;
|
||
}
|
||
catch { }
|
||
|
||
return null;
|
||
}
|
||
|
||
public static string GetVersion(string file, byte[] fileContent, List<int> positions)
|
||
{
|
||
// Check the manifest version first
|
||
string version = Utilities.GetManifestVersion(fileContent);
|
||
if (!string.IsNullOrEmpty(version))
|
||
return GetV3PlusVersion(version);
|
||
|
||
// Assume an earlier version
|
||
return GetV2Version(file, fileContent);
|
||
}
|
||
|
||
private static string GetV2Version(string file, byte[] fileContent)
|
||
{
|
||
var matchers = new List<ContentMatchSet>
|
||
{
|
||
#region 16-bit NE Header Checks
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0xE6, 0x2B, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6C, 0x00, 0xB8, 0x44, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "2.0 (MS-DOS/16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0x74, 0x31, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6C, 0x00, 0x98, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "2.0 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x80, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0xA0, 0x24, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6A, 0x00, 0x92, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "Compact 2.0 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0xCD, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0xFA, 0x36, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x97, 0x00,
|
||
0xA3, 0x00, 0xAD, 0x00, 0xDF, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "Software Installation 2.0 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0x86, 0x33, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6C, 0x00, 0xC8, 0x43, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "2.1 RC2 (MS-DOS/16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0x56, 0x3E, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
|
||
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "2.1 RC2 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x80, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0x84, 0x2B, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6A, 0x00, 0x92, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "Compact 2.1 RC2 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x40, 0xAC, 0x43, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
|
||
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "Software Installation 2.1 RC2 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x86, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x3A, 0x96, 0x33, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6C, 0x00, 0xC8, 0x43, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "2.1 (MS-DOS/16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x3A, 0x7E, 0x3E, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
|
||
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "2.1 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0x80, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x3A, 0x90, 0x2B, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x58, 0x00,
|
||
0x64, 0x00, 0x6A, 0x00, 0x92, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "Compact 2.1 (16-bit)"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x4E, 0x45, 0x11, 0x20, 0xBE, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x00,
|
||
0x00, 0x20, 0x00, 0x3A, 0x08, 0x44, 0x01, 0x00,
|
||
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00,
|
||
0x4B, 0x00, 0x40, 0x00, 0x58, 0x00, 0x90, 0x00,
|
||
0x9C, 0x00, 0xA4, 0x00, 0xD0, 0x01, 0x00, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||
}, "Software Installation 2.1 (16-bit)"),
|
||
|
||
#endregion
|
||
|
||
#region 32-bit SFX Header Checks
|
||
|
||
// .............8<EFBFBD>92....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SE.SFX
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9C, 0x39,
|
||
0x32, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E,
|
||
0x53, 0x46, 0x58,
|
||
}, "2.0 (32-bit)"),
|
||
|
||
// .............]<5D>92....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x9C, 0x39,
|
||
0x32, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45,
|
||
0x2E, 0x53, 0x46, 0x58,
|
||
}, "Software Installation 2.0 (32-bit)"),
|
||
|
||
// .............<2E><><EFBFBD>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SE.SFX
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x82, 0x94,
|
||
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E,
|
||
0x53, 0x46, 0x58,
|
||
}, "2.1 RC2 (32-bit)"),
|
||
|
||
// .............<2E><><EFBFBD>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x82, 0x94,
|
||
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45,
|
||
0x2E, 0x53, 0x46, 0x58,
|
||
}, "Software Installation 2.1 RC2 (32-bit)"),
|
||
|
||
// .............U<><55>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SE.SFX
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xCD, 0xCC,
|
||
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x45, 0x2E,
|
||
0x53, 0x46, 0x58,
|
||
}, "2.1 (32-bit)"),
|
||
|
||
// .............{<7B><>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xCD, 0xCC,
|
||
0x33, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x88, 0x50, 0x00, 0x00, 0x88, 0x50, 0x00,
|
||
0x00, 0x56, 0x57, 0x39, 0x35, 0x53, 0x52, 0x45,
|
||
0x2E, 0x53, 0x46, 0x58,
|
||
}, "Software Installation 2.1 (32-bit)"),
|
||
|
||
#endregion
|
||
|
||
#region 32-bit PE Header Checks
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
|
||
0x69, 0x1B, 0x5B, 0x3A, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
|
||
0x0B, 0x01, 0x05, 0x0A, 0x00, 0x4A, 0x00, 0x00,
|
||
0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0xD8, 0x39, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
|
||
}, "2.2.4003"),
|
||
|
||
new ContentMatchSet(new byte?[]
|
||
{
|
||
0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x05, 0x00,
|
||
0x81, 0x1B, 0x5B, 0x3A, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x01,
|
||
0x0B, 0x01, 0x05, 0x0A, 0x00, 0x56, 0x00, 0x00,
|
||
0x00, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x8F, 0x3F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
|
||
}, "Software Installation 2.2.4003"),
|
||
|
||
#endregion
|
||
};
|
||
|
||
string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, false);
|
||
return match ?? "Unknown 2.x";
|
||
}
|
||
|
||
private static string GetV3PlusVersion(string version)
|
||
{
|
||
// Some version strings don't exactly match the public version number
|
||
switch (version)
|
||
{
|
||
case "3.0.7158.0":
|
||
return "3.0.7158";
|
||
case "3.1.7556.0":
|
||
return "3.1.7556";
|
||
case "3.1.8421.0":
|
||
return "4.0.8421";
|
||
case "3.1.8672.0":
|
||
return "4.0.8672";
|
||
case "4.0.1221.0":
|
||
return "4.0.12218";
|
||
default:
|
||
return $"(Unknown - {version})";
|
||
}
|
||
}
|
||
}
|
||
}
|