mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Remove some unused code and add sensible coverage exclusions
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Squirrel.Packaging.Windows
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
[ExcludeFromCodeCoverage]
|
||||
public static class AuthenticodeTools
|
||||
{
|
||||
[DllImport("Wintrust.dll", PreserveSig = true, SetLastError = false)]
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
namespace Squirrel.Packaging.Windows;
|
||||
|
||||
internal static class CopStache
|
||||
{
|
||||
public static string Render(string template, Dictionary<string, string> identifiers)
|
||||
{
|
||||
var buf = new StringBuilder();
|
||||
|
||||
foreach (var line in template.Split('\n')) {
|
||||
identifiers["RandomGuid"] = (Guid.NewGuid()).ToString();
|
||||
|
||||
foreach (var key in identifiers.Keys) {
|
||||
buf.Replace("{{" + key + "}}", SecurityElement.Escape(identifiers[key]));
|
||||
}
|
||||
|
||||
buf.AppendLine(line);
|
||||
}
|
||||
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
#if false
|
||||
|
||||
// Parts of this file have been used from
|
||||
// https://github.com/icsharpcode/ILSpy/blob/f7460a041ea8fb8b0abf8527b97a5b890eb94eea/ICSharpCode.Decompiler/SingleFileBundle.cs
|
||||
|
||||
using Microsoft.NET.HostModel.AppHost;
|
||||
using Microsoft.NET.HostModel.Bundle;
|
||||
using NuGet.Versioning;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Squirrel.CommandLine.Windows
|
||||
{
|
||||
internal class DotnetUtil
|
||||
{
|
||||
private static IFullLogger Log = SquirrelLocator.CurrentMutable.GetService<ILogManager>().GetLogger(typeof(DotnetUtil));
|
||||
|
||||
// public static void CheckDotnetReferences(string filePath, PeNet.PeFile pe, IEnumerable<Runtimes.RuntimeInfo> dependencies)
|
||||
// {
|
||||
// try {
|
||||
// var name = Path.GetFileName(filePath);
|
||||
// var baseDir = Path.GetDirectoryName(filePath);
|
||||
//
|
||||
// if (pe == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Log.Debug($"Verifying dependencies for {name}");
|
||||
//
|
||||
// var probablyBitness = pe.IsExe && pe.Is32Bit ? "-x86" : ""; // used to construct a suggested reference later
|
||||
//
|
||||
// // might be an app host or single file bundle, lets look for a dotnet "dll"
|
||||
// if (pe.IsExe && !pe.IsDotNet) {
|
||||
// if (IsSingleFileBundle(filePath)) {
|
||||
// // TODO
|
||||
// Log.Info("Checking dependencies in SingleFileBundle's is not supported.");
|
||||
// return;
|
||||
// } else {
|
||||
// var st = pe.Resources.VsVersionInfo.StringFileInfo.StringTable;
|
||||
// if (st.Length > 0) {
|
||||
// var original = st[0].OriginalFilename;
|
||||
// if (original != null && original.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) && File.Exists(Path.Combine(baseDir, original))) {
|
||||
// pe = new PeNet.PeFile(Path.Combine(baseDir, original));
|
||||
// Log.Debug($"Redirecting to {original}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// var refs = pe.MetaDataStreamTablesHeader?.Tables?.AssemblyRef ?? new();
|
||||
// if (!pe.IsDotNet || refs.Count == 0) {
|
||||
// Log.Info($"{name} is not a CLR assembly or no assembly references were found.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var lookup = refs.ToDictionary(x => pe.MetaDataStreamString.GetStringAtIndex(x.Name), x => x, StringComparer.InvariantCultureIgnoreCase);
|
||||
//
|
||||
// // base lib is "mscorlib" for full framework or "System.Runtime" for dotnet
|
||||
// if (lookup.ContainsKey("mscorlib")) {
|
||||
// Log.Debug($"{name} references the full framework, skipping....");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var foundcore = lookup.TryGetValue("System.Runtime", out var corelib);
|
||||
// if (!foundcore) {
|
||||
// Log.Debug($"{name} has no reference to a known core lib, skipping...");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // don't bother checking any assemblies (exe or dll) that are present in the package
|
||||
// foreach (var k in Directory.GetFiles(baseDir)) {
|
||||
// if (Utility.FileIsLikelyPEImage(k)) {
|
||||
// if (lookup.ContainsKey(Path.GetFileNameWithoutExtension(k))) {
|
||||
// Log.Debug($"Reference {Path.GetFileName(k)} found in local directory.");
|
||||
// lookup.Remove(Path.GetFileNameWithoutExtension(k));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!lookup.Any())
|
||||
// return;
|
||||
//
|
||||
// var runtime = dependencies.OfType<Runtimes.DotnetInfo>()
|
||||
// .FirstOrDefault(f => f.MinVersion.Major == corelib.MajorVersion && f.MinVersion.Minor == corelib.MinorVersion);
|
||||
//
|
||||
// if (runtime == null) {
|
||||
// var suggestedArg = $"--framework net{corelib.MajorVersion}.{corelib.MinorVersion}" + probablyBitness;
|
||||
// Log.Warn($"{name} has {lookup.Count} unresolved references, and no matching runtimes were found. (Are you missing the '{suggestedArg}' argument?)");
|
||||
// foreach (var f in lookup)
|
||||
// Log.Debug($"{name} has unresolved reference {f.Key}.");
|
||||
//
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// foreach (var f in lookup) {
|
||||
// var fver = new NuGetVersion(f.Value.MajorVersion, f.Value.MinorVersion, f.Value.BuildNumber, f.Value.RevisionNumber);
|
||||
// if (fver > runtime.MinVersion) {
|
||||
// Log.Warn($"{name} references {f.Key},Version={fver} - which is higher than the current runtime version ({runtime.MinVersion}).");
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception ex) {
|
||||
// Log.WarnException("Failed to verify dependencies.", ex);
|
||||
// }
|
||||
// }
|
||||
|
||||
public static bool IsSingleFileBundle(string peFile)
|
||||
{
|
||||
return HostWriter.IsBundle(peFile, out var offset) && offset > 0;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static void UpdateSingleFileBundleIcon(string sourceFile, string destinationFile, string iconPath)
|
||||
{
|
||||
using var _ = Utility.GetTempDirectory(out var tmpdir);
|
||||
var sourceName = Path.GetFileNameWithoutExtension(sourceFile);
|
||||
var newAppHost = Path.Combine(tmpdir, sourceName + ".exe");
|
||||
|
||||
// extract bundled Update.exe assets to tmp dir
|
||||
Log.Info("Extracting Update.exe resources");
|
||||
File.Copy(sourceFile, newAppHost);
|
||||
DumpPackageAssemblies(sourceFile, tmpdir);
|
||||
|
||||
// set new icon (which eradicates bundled assets)
|
||||
Log.Info("Patching Update.exe icon");
|
||||
HelperExe.SetExeIcon(newAppHost, iconPath);
|
||||
HostWriter.ResetBundle(newAppHost);
|
||||
|
||||
// re-append bundled assets to exe
|
||||
Log.Info("Re-packing Update.exe bundle");
|
||||
var bundlerOutput = Path.Combine(tmpdir, "output");
|
||||
Directory.CreateDirectory(bundlerOutput);
|
||||
var bundler = new Bundler(
|
||||
sourceName + ".exe",
|
||||
bundlerOutput,
|
||||
BundleOptions.EnableCompression,
|
||||
OSPlatform.Windows,
|
||||
Architecture.X86,
|
||||
new Version(6, 0),
|
||||
false,
|
||||
sourceName
|
||||
);
|
||||
var singleFile = GenerateBundle(bundler, tmpdir, bundlerOutput);
|
||||
|
||||
// copy to requested location
|
||||
File.Copy(singleFile, destinationFile);
|
||||
}
|
||||
|
||||
private static void DumpPackageAssemblies(string packageFileName, string outputDirectory)
|
||||
{
|
||||
if (!HostWriter.IsBundle(packageFileName, out long bundleHeaderOffset)) {
|
||||
throw new InvalidOperationException($"Cannot dump assembiles for {packageFileName}, because it is not a single file bundle.");
|
||||
}
|
||||
|
||||
using (var memoryMappedPackage = MemoryMappedFile.CreateFromFile(packageFileName, FileMode.Open, null, 0, MemoryMappedFileAccess.Read)) {
|
||||
using (var packageView = memoryMappedPackage.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read)) {
|
||||
var manifest = ReadManifest(packageView, bundleHeaderOffset);
|
||||
foreach (var entry in manifest.Entries) {
|
||||
Stream contents;
|
||||
|
||||
if (entry.CompressedSize == 0) {
|
||||
contents = new UnmanagedMemoryStream(packageView.SafeMemoryMappedViewHandle, entry.Offset, entry.Size);
|
||||
} else {
|
||||
Stream compressedStream = new UnmanagedMemoryStream(packageView.SafeMemoryMappedViewHandle, entry.Offset, entry.CompressedSize);
|
||||
Stream decompressedStream = new MemoryStream((int) entry.Size);
|
||||
using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) {
|
||||
deflateStream.CopyTo(decompressedStream);
|
||||
}
|
||||
|
||||
if (decompressedStream.Length != entry.Size) {
|
||||
throw new Exception($"Corrupted single-file entry '${entry.RelativePath}'. Declared decompressed size '${entry.Size}' is not the same as actual decompressed size '${decompressedStream.Length}'.");
|
||||
}
|
||||
|
||||
decompressedStream.Seek(0, SeekOrigin.Begin);
|
||||
contents = decompressedStream;
|
||||
}
|
||||
|
||||
using (var fileStream = File.Create(Path.Combine(outputDirectory, entry.RelativePath))) {
|
||||
contents.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GenerateBundle(Bundler bundler, string sourceDir, string outputDir)
|
||||
{
|
||||
// Convert sourceDir to absolute path
|
||||
sourceDir = Path.GetFullPath(sourceDir);
|
||||
|
||||
// Get all files in the source directory and all sub-directories.
|
||||
string[] sources = Directory.GetFiles(sourceDir, searchPattern: "*", searchOption: SearchOption.AllDirectories);
|
||||
|
||||
// Sort the file names to keep the bundle construction deterministic.
|
||||
Array.Sort(sources, StringComparer.Ordinal);
|
||||
|
||||
List<FileSpec> fileSpecs = new List<FileSpec>(sources.Length);
|
||||
foreach (var file in sources) {
|
||||
fileSpecs.Add(new FileSpec(file, Path.GetRelativePath(sourceDir, file)));
|
||||
}
|
||||
|
||||
return bundler.GenerateBundle(fileSpecs);
|
||||
}
|
||||
|
||||
public struct Header
|
||||
{
|
||||
public uint MajorVersion;
|
||||
public uint MinorVersion;
|
||||
public int FileCount;
|
||||
public string BundleID;
|
||||
|
||||
// Fields introduced with v2:
|
||||
public long DepsJsonOffset;
|
||||
public long DepsJsonSize;
|
||||
public long RuntimeConfigJsonOffset;
|
||||
public long RuntimeConfigJsonSize;
|
||||
public ulong Flags;
|
||||
|
||||
public ImmutableArray<Entry> Entries;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FileType: Identifies the type of file embedded into the bundle.
|
||||
///
|
||||
/// The bundler differentiates a few kinds of files via the manifest,
|
||||
/// with respect to the way in which they'll be used by the runtime.
|
||||
/// </summary>
|
||||
public enum FileType : byte
|
||||
{
|
||||
Unknown, // Type not determined.
|
||||
Assembly, // IL and R2R Assemblies
|
||||
NativeBinary, // NativeBinaries
|
||||
DepsJson, // .deps.json configuration file
|
||||
RuntimeConfigJson, // .runtimeconfig.json configuration file
|
||||
Symbols // PDB Files
|
||||
};
|
||||
|
||||
public struct Entry
|
||||
{
|
||||
public long Offset;
|
||||
public long Size;
|
||||
public long CompressedSize; // 0 if not compressed, otherwise the compressed size in the bundle
|
||||
public FileType Type;
|
||||
public string RelativePath; // Path of an embedded file, relative to the Bundle source-directory.
|
||||
}
|
||||
|
||||
static UnmanagedMemoryStream AsStream(MemoryMappedViewAccessor view)
|
||||
{
|
||||
long size = checked((long) view.SafeMemoryMappedViewHandle.ByteLength);
|
||||
return new UnmanagedMemoryStream(view.SafeMemoryMappedViewHandle, 0, size);
|
||||
}
|
||||
|
||||
public static Header ReadManifest(MemoryMappedViewAccessor view, long bundleHeaderOffset)
|
||||
{
|
||||
using var stream = AsStream(view);
|
||||
stream.Seek(bundleHeaderOffset, SeekOrigin.Begin);
|
||||
return ReadManifest(stream);
|
||||
}
|
||||
|
||||
public static Header ReadManifest(Stream stream)
|
||||
{
|
||||
var header = new Header();
|
||||
using var reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true);
|
||||
header.MajorVersion = reader.ReadUInt32();
|
||||
header.MinorVersion = reader.ReadUInt32();
|
||||
|
||||
// Major versions 3, 4 and 5 were skipped to align bundle versioning with .NET versioning scheme
|
||||
if (header.MajorVersion < 1 || header.MajorVersion > 6) {
|
||||
throw new InvalidDataException($"Unsupported manifest version: {header.MajorVersion}.{header.MinorVersion}");
|
||||
}
|
||||
header.FileCount = reader.ReadInt32();
|
||||
header.BundleID = reader.ReadString();
|
||||
if (header.MajorVersion >= 2) {
|
||||
header.DepsJsonOffset = reader.ReadInt64();
|
||||
header.DepsJsonSize = reader.ReadInt64();
|
||||
header.RuntimeConfigJsonOffset = reader.ReadInt64();
|
||||
header.RuntimeConfigJsonSize = reader.ReadInt64();
|
||||
header.Flags = reader.ReadUInt64();
|
||||
}
|
||||
var entries = ImmutableArray.CreateBuilder<Entry>(header.FileCount);
|
||||
for (int i = 0; i < header.FileCount; i++) {
|
||||
entries.Add(ReadEntry(reader, header.MajorVersion));
|
||||
}
|
||||
header.Entries = entries.MoveToImmutable();
|
||||
return header;
|
||||
}
|
||||
|
||||
private static Entry ReadEntry(BinaryReader reader, uint bundleMajorVersion)
|
||||
{
|
||||
Entry entry;
|
||||
entry.Offset = reader.ReadInt64();
|
||||
entry.Size = reader.ReadInt64();
|
||||
entry.CompressedSize = bundleMajorVersion >= 6 ? reader.ReadInt64() : 0;
|
||||
entry.Type = (FileType) reader.ReadByte();
|
||||
entry.RelativePath = reader.ReadString();
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -17,12 +17,9 @@ public class HelperExe : HelperFile
|
||||
|
||||
public static string StubExecutablePath => FindHelperFile("StubExecutable.exe");
|
||||
|
||||
// private so we don't expose paths to internal tools. these should be exposed as a helper function
|
||||
private static string SignToolPath => FindHelperFile("signtool.exe");
|
||||
private static string WixTemplatePath => FindHelperFile("template.wxs");
|
||||
|
||||
private static string RceditPath => FindHelperFile("rcedit.exe");
|
||||
private static string WixCandlePath => FindHelperFile("candle.exe");
|
||||
private static string WixLightPath => FindHelperFile("light.exe");
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
private bool CheckIsAlreadySigned(string filePath)
|
||||
@@ -116,35 +113,6 @@ public class HelperExe : HelperFile
|
||||
Log.Info("Sign successful: " + result.StdOutput);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public string CompileWixTemplateToMsi(Dictionary<string, string> templateData, string workingDir, string appId)
|
||||
{
|
||||
var wxsFile = Path.Combine(workingDir, appId + ".wxs");
|
||||
var objFile = Path.Combine(workingDir, appId + ".wixobj");
|
||||
var msiFile = Path.Combine(workingDir, appId + "_DeploymentTool.msi");
|
||||
|
||||
try {
|
||||
// apply dictionary to wsx template
|
||||
var templateText = File.ReadAllText(WixTemplatePath);
|
||||
var templateResult = CopStache.Render(templateText, templateData);
|
||||
File.WriteAllText(wxsFile, templateResult, Encoding.UTF8);
|
||||
|
||||
// Candle reprocesses and compiles WiX source files into object files (.wixobj).
|
||||
Log.Info("Compiling WiX Template (candle.exe)");
|
||||
var candleParams = new string[] { "-nologo", "-ext", "WixNetFxExtension", "-out", objFile, wxsFile };
|
||||
InvokeAndThrowIfNonZero(WixCandlePath, candleParams, workingDir);
|
||||
|
||||
// Light links and binds one or more .wixobj files and creates a Windows Installer database (.msi or .msm).
|
||||
Log.Info("Linking WiX Template (light.exe)");
|
||||
var lightParams = new string[] { "-ext", "WixNetFxExtension", "-spdb", "-sval", "-out", msiFile, objFile };
|
||||
InvokeAndThrowIfNonZero(WixLightPath, lightParams, workingDir);
|
||||
return msiFile;
|
||||
} finally {
|
||||
Utility.DeleteFileOrDirectoryHard(wxsFile, throwOnFailure: false);
|
||||
Utility.DeleteFileOrDirectoryHard(objFile, throwOnFailure: false);
|
||||
}
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public void SetExeIcon(string exePath, string iconPath)
|
||||
{
|
||||
|
||||
@@ -85,11 +85,13 @@ software, even if advised of the possibility of such damage.
|
||||
|
||||
#endregion
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Squirrel.Packaging;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class MarkdownOptions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -128,6 +130,7 @@ public class MarkdownOptions
|
||||
/// Markdown allows you to write using an easy-to-read, easy-to-write plain text format,
|
||||
/// then convert it to structurally valid XHTML (or HTML).
|
||||
/// </summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class Markdown
|
||||
{
|
||||
private const string _version = "1.13";
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
using INugetLogger = NuGet.Common.ILogger;
|
||||
using NugetLogLevel = NuGet.Common.LogLevel;
|
||||
using INugetLogMessage = NuGet.Common.ILogMessage;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Squirrel.Packaging;
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class NugetLoggingWrapper : INugetLogger
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Squirrel.Packaging
|
||||
{
|
||||
// https://stackoverflow.com/a/43229358/184746
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class StringFileInfo
|
||||
{
|
||||
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern int GetFileVersionInfoSize(string lptstrFilename, out int lpdwHandle);
|
||||
|
||||
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool GetFileVersionInfo(string lptstrFilename, int dwHandle, int dwLen, byte[] lpData);
|
||||
|
||||
[DllImport("version.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool VerQueryValue(byte[] pBlock, string lpSubBlock, out IntPtr lplpBuffer, out int puLen);
|
||||
|
||||
public readonly Version FileVersion;
|
||||
public readonly Version ProductVersion;
|
||||
public readonly uint FileFlagsMask;
|
||||
public readonly uint FileFlags;
|
||||
public readonly uint FileOS;
|
||||
public readonly uint FileType;
|
||||
public readonly uint FileSubtype;
|
||||
// Always null
|
||||
public readonly DateTime? FileDate;
|
||||
|
||||
protected StringFileInfo(Version fileVersion, Version productVersion, uint fileFlagsMask, uint fileFlags, uint fileOS, uint fileType, uint fileSubtype, DateTime? fileDate)
|
||||
{
|
||||
FileVersion = fileVersion;
|
||||
ProductVersion = productVersion;
|
||||
FileFlagsMask = fileFlagsMask;
|
||||
FileFlags = fileFlags;
|
||||
FileOS = fileOS;
|
||||
FileType = fileType;
|
||||
FileSubtype = fileSubtype;
|
||||
FileDate = fileDate;
|
||||
}
|
||||
|
||||
public class VersionInfoItem
|
||||
{
|
||||
public uint CodePage { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
|
||||
public VersionInfoItem(uint codePage, string key, string value)
|
||||
{
|
||||
CodePage = codePage;
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// vi can be null on exit
|
||||
// Item1 = language | codepage
|
||||
// Item2 = Key
|
||||
// Item3 = Value
|
||||
public static IEnumerable<VersionInfoItem> ReadVersionInfo(string fileName, out StringFileInfo vi)
|
||||
{
|
||||
int num;
|
||||
int size = GetFileVersionInfoSize(fileName, out num);
|
||||
|
||||
if (size == 0) {
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
var buffer = new byte[size];
|
||||
bool success = GetFileVersionInfo(fileName, 0, size, buffer);
|
||||
|
||||
if (!success) {
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
return ReadVersionInfo(buffer, out vi);
|
||||
|
||||
}
|
||||
|
||||
// vi can be null on exit
|
||||
// Item1 = language | codepage
|
||||
// Item2 = Key
|
||||
// Item3 = Value
|
||||
public static IEnumerable<VersionInfoItem> ReadVersionInfo(byte[] buffer, out StringFileInfo vi)
|
||||
{
|
||||
int offset;
|
||||
// The offset calculated here is unused
|
||||
var fibs = ReadFileInfoBaseStruct(buffer, 0, out offset);
|
||||
|
||||
if (fibs.Key != "VS_VERSION_INFO") {
|
||||
throw new Exception(fibs.Key);
|
||||
}
|
||||
|
||||
// Value = VS_FIXEDFILEINFO
|
||||
if (fibs.ValueLength != 0) {
|
||||
uint signature = BitConverter.ToUInt32(buffer, fibs.ValueOffset);
|
||||
|
||||
if (signature != 0xFEEF04BD) {
|
||||
throw new Exception(signature.ToString("X8"));
|
||||
}
|
||||
|
||||
uint strucVersion = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 4);
|
||||
|
||||
var fileVersion = new Version(BitConverter.ToUInt16(buffer, fibs.ValueOffset + 10), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 8), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 14), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 12));
|
||||
var productVersion = new Version(BitConverter.ToUInt16(buffer, fibs.ValueOffset + 18), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 16), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 22), BitConverter.ToUInt16(buffer, fibs.ValueOffset + 20));
|
||||
|
||||
uint fileFlagsMask = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 24);
|
||||
uint fileFlags = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 28);
|
||||
uint fileOS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 32);
|
||||
uint fileType = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 36);
|
||||
uint fileSubtype = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 40);
|
||||
|
||||
uint fileDateMS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 44);
|
||||
uint fileDateLS = BitConverter.ToUInt32(buffer, fibs.ValueOffset + 48);
|
||||
DateTime? fileDate = fileDateMS != 0 || fileDateLS != 0 ?
|
||||
(DateTime?) DateTime.FromFileTime((long) fileDateMS << 32 | fileDateLS) :
|
||||
null;
|
||||
|
||||
vi = new StringFileInfo(fileVersion, productVersion, fileFlagsMask, fileFlags, fileOS, fileType, fileSubtype, fileDate);
|
||||
} else {
|
||||
vi = null;
|
||||
}
|
||||
|
||||
return ReadVersionInfoInternal(buffer, fibs);
|
||||
}
|
||||
|
||||
protected static IEnumerable<VersionInfoItem> ReadVersionInfoInternal(byte[] buffer, FileInfoBaseStruct fibs)
|
||||
{
|
||||
int sfiOrValOffset = (fibs.ValueOffset + fibs.ValueLength + 3) & (~3);
|
||||
|
||||
while (sfiOrValOffset < fibs.Length) {
|
||||
int nextSfiOrValOffset;
|
||||
|
||||
var sfiOrVal = ReadFileInfoBaseStruct(buffer, sfiOrValOffset, out nextSfiOrValOffset);
|
||||
|
||||
if (sfiOrVal.Key == "StringFileInfo") {
|
||||
int stOffset = sfiOrVal.ValueOffset;
|
||||
|
||||
while (stOffset < sfiOrVal.EndOffset) {
|
||||
int nextStOffset;
|
||||
|
||||
var st = ReadFileInfoBaseStruct(buffer, stOffset, out nextStOffset);
|
||||
|
||||
uint langCharset = uint.Parse(st.Key, NumberStyles.HexNumber);
|
||||
|
||||
int striOffset = st.ValueOffset;
|
||||
|
||||
while (striOffset < st.EndOffset) {
|
||||
int nextStriOffset;
|
||||
|
||||
var stri = ReadFileInfoBaseStruct(buffer, striOffset, out nextStriOffset);
|
||||
|
||||
// Here stri.ValueLength is in words!
|
||||
int len = FindLengthUnicodeSZ(buffer, stri.ValueOffset, stri.ValueOffset + (stri.ValueLength * 2));
|
||||
string value = Encoding.Unicode.GetString(buffer, stri.ValueOffset, len * 2);
|
||||
|
||||
yield return new VersionInfoItem(langCharset, stri.Key, value);
|
||||
|
||||
striOffset = nextStriOffset;
|
||||
}
|
||||
|
||||
stOffset = nextStOffset;
|
||||
}
|
||||
} else if (sfiOrVal.Key == "VarFileInfo") {
|
||||
int varOffset = sfiOrVal.ValueOffset;
|
||||
|
||||
while (varOffset < sfiOrVal.EndOffset) {
|
||||
int nextVarOffset;
|
||||
|
||||
var var = ReadFileInfoBaseStruct(buffer, varOffset, out nextVarOffset);
|
||||
|
||||
if (var.Key != "Translation") {
|
||||
throw new Exception(var.Key);
|
||||
}
|
||||
|
||||
int langOffset = var.ValueOffset;
|
||||
|
||||
while (langOffset < var.EndOffset) {
|
||||
unchecked {
|
||||
// We invert the order suggested by the Var description!
|
||||
uint high = (uint) BitConverter.ToInt16(buffer, langOffset);
|
||||
uint low = (uint) BitConverter.ToInt16(buffer, langOffset + 2);
|
||||
uint lang = (high << 16) | low;
|
||||
|
||||
langOffset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
varOffset = nextVarOffset;
|
||||
}
|
||||
} else {
|
||||
Debug.WriteLine("Unrecognized " + sfiOrVal.Key);
|
||||
}
|
||||
|
||||
sfiOrValOffset = nextSfiOrValOffset;
|
||||
}
|
||||
}
|
||||
|
||||
protected static FileInfoBaseStruct ReadFileInfoBaseStruct(byte[] buffer, int offset, out int nextOffset)
|
||||
{
|
||||
var fibs = new FileInfoBaseStruct {
|
||||
Length = BitConverter.ToInt16(buffer, offset),
|
||||
ValueLength = BitConverter.ToInt16(buffer, offset + 2),
|
||||
Type = BitConverter.ToInt16(buffer, offset + 4)
|
||||
};
|
||||
|
||||
int len = FindLengthUnicodeSZ(buffer, offset + 6, offset + fibs.Length);
|
||||
fibs.Key = Encoding.Unicode.GetString(buffer, offset + 6, len * 2);
|
||||
|
||||
// Padding
|
||||
fibs.ValueOffset = ((offset + 6 + (len + 1) * 2) + 3) & (~3);
|
||||
|
||||
fibs.EndOffset = offset + fibs.Length;
|
||||
nextOffset = (fibs.EndOffset + 3) & (~3);
|
||||
|
||||
return fibs;
|
||||
}
|
||||
|
||||
protected static int FindLengthUnicodeSZ(byte[] buffer, int offset, int endOffset)
|
||||
{
|
||||
int offset2 = offset;
|
||||
while (offset2 < endOffset && BitConverter.ToInt16(buffer, offset2) != 0) {
|
||||
offset2 += 2;
|
||||
}
|
||||
|
||||
// In chars
|
||||
return (offset2 - offset) / 2;
|
||||
}
|
||||
|
||||
// Used internally
|
||||
protected class FileInfoBaseStruct
|
||||
{
|
||||
public short Length { get; set; }
|
||||
public short ValueLength { get; set; }
|
||||
public short Type { get; set; }
|
||||
public string Key { get; set; }
|
||||
public int ValueOffset { get; set; }
|
||||
public int EndOffset { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Squirrel.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an error that occurs when a package does not match it's expected SHA checksum
|
||||
/// </summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class ChecksumFailedException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Squirrel.Compression
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
[SupportedOSPlatform("windows")]
|
||||
internal class MsDeltaCompression
|
||||
{
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Squirrel
|
||||
{
|
||||
/// <summary>
|
||||
/// Useful enumerable extensions used by Squirrel
|
||||
/// </summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal static class EnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Squirrel
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal static class LoggerExtensions
|
||||
{
|
||||
public static void Trace(this ILogger logger, string message)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Squirrel
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal static class ProcessArgumentListPolyfill
|
||||
{
|
||||
|
||||
|
||||
@@ -66,7 +66,26 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
#if !NET5_0_OR_GREATER
|
||||
using Squirrel.Json.Reflection;
|
||||
#endif
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
namespace Squirrel.Json
|
||||
{
|
||||
[ExcludeFromCodeCoverage]
|
||||
internal static class SimpleJson
|
||||
{
|
||||
public static T DeserializeObject<T>(string json)
|
||||
{
|
||||
return System.Text.Json.JsonSerializer.Deserialize<T>(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !NET5_0_OR_GREATER
|
||||
|
||||
// ReSharper disable LoopCanBeConvertedToQuery
|
||||
// ReSharper disable RedundantExplicitArrayCreation
|
||||
@@ -79,6 +98,7 @@ namespace Squirrel.Json
|
||||
[GeneratedCode("simple-json", "1.0.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
|
||||
[ExcludeFromCodeCoverage]
|
||||
#if SIMPLE_JSON_OBJARRAYINTERNAL
|
||||
internal
|
||||
#else
|
||||
@@ -113,6 +133,7 @@ namespace Squirrel.Json
|
||||
[GeneratedCode("simple-json", "1.0.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
|
||||
[ExcludeFromCodeCoverage]
|
||||
#if SIMPLE_JSON_OBJARRAYINTERNAL
|
||||
internal
|
||||
#else
|
||||
@@ -493,6 +514,7 @@ namespace Squirrel.Json
|
||||
/// JSON uses Arrays and Objects. These correspond here to the datatypes JsonArray(IList<object>) and JsonObject(IDictionary<string,object>).
|
||||
/// All numbers are parsed to doubles.
|
||||
/// </summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
[GeneratedCode("simple-json", "1.0.0")]
|
||||
#if SIMPLE_JSON_INTERNAL
|
||||
internal
|
||||
@@ -1236,6 +1258,7 @@ namespace Squirrel.Json
|
||||
object DeserializeObject(object value, Type type);
|
||||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
[GeneratedCode("simple-json", "1.0.0")]
|
||||
#if SIMPLE_JSON_INTERNAL
|
||||
internal
|
||||
@@ -1514,6 +1537,7 @@ namespace Squirrel.Json
|
||||
}
|
||||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
#if SIMPLE_JSON_DATACONTRACT
|
||||
[GeneratedCode("simple-json", "1.0.0")]
|
||||
#if SIMPLE_JSON_INTERNAL
|
||||
@@ -1597,6 +1621,7 @@ namespace Squirrel.Json
|
||||
{
|
||||
// This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules
|
||||
// that might be in place in the target project.
|
||||
[ExcludeFromCodeCoverage]
|
||||
[GeneratedCode("reflection-utils", "1.0.0")]
|
||||
#if SIMPLE_JSON_REFLECTION_UTILS_PUBLIC
|
||||
public
|
||||
@@ -2125,3 +2150,4 @@ namespace Squirrel.Json
|
||||
// ReSharper restore LoopCanBeConvertedToQuery
|
||||
// ReSharper restore RedundantExplicitArrayCreation
|
||||
// ReSharper restore SuggestUseVarKeywordEvident
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -13,6 +14,7 @@ namespace Squirrel.Locators
|
||||
/// your application is able to find and prepare updates from your chosen update source without actually
|
||||
/// having an installed Squirrel application. This could be used in a CI/CD pipeline, or unit tests etc.
|
||||
/// </summary>
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class TestSquirrelLocator : SquirrelLocator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<CoverletOutputFormat>cobertura</CoverletOutputFormat>
|
||||
<CoverletOutput>..\coverage.$(MSBuildProjectName).xml</CoverletOutput>
|
||||
<Include>[Squirrel*]*</Include>
|
||||
<Exclude>[Squirrel.*.Tests]*</Exclude>
|
||||
<Exclude>[Squirrel.*.Tests]*,[*]Microsoft*</Exclude>
|
||||
<CollectCoverage>true</CollectCoverage>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user