// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset.Core.Bind { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; /// /// Internal helper class used to extract embedded files. /// internal class ExtractEmbeddedFiles { private readonly Dictionary> filesWithEmbeddedFiles = new Dictionary>(); public IEnumerable Uris => this.filesWithEmbeddedFiles.Keys; /// /// Adds an embedded file index to track and returns the path where the embedded file will be extracted. Duplicates will return the same extract path. /// /// Uri to file containing the embedded files. /// Id of the embedded file to extract. /// Folder where extracted files should be placed. /// The extract path for the embedded file. public string AddEmbeddedFileToExtract(Uri uri, string embeddedFileId, string extractFolder) { // If the uri to the file that contains the embedded file does not already have embedded files // being extracted, create the dictionary to track that. if (!this.filesWithEmbeddedFiles.TryGetValue(uri, out var extracts)) { extracts = new SortedList(StringComparer.OrdinalIgnoreCase); this.filesWithEmbeddedFiles.Add(uri, extracts); } // If the embedded file is not already tracked in the dictionary of extracts, add it. if (!extracts.TryGetValue(embeddedFileId, out var extractPath)) { var localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(uri.LocalPath); var unique = this.HashUri(uri.AbsoluteUri); var extractedName = String.Format(CultureInfo.InvariantCulture, @"{0}_{1}\{2}", localFileNameWithoutExtension, unique, embeddedFileId); extractPath = Path.GetFullPath(Path.Combine(extractFolder, extractedName)); extracts.Add(embeddedFileId, extractPath); } return extractPath; } public IEnumerable GetExpectedEmbeddedFiles() { var files = new List(); foreach (var uriWithExtracts in this.filesWithEmbeddedFiles) { foreach (var extracts in uriWithExtracts.Value) { files.Add(new ExpectedExtractFile { Uri = uriWithExtracts.Key, EmbeddedFileId = extracts.Key, OutputPath = extracts.Value, }); } } return files; } public IEnumerable GetExtractFilesForUri(Uri uri) { if (!this.filesWithEmbeddedFiles.TryGetValue(uri, out var extracts)) { extracts = new SortedList(StringComparer.OrdinalIgnoreCase); } return extracts.Select(e => new ExpectedExtractFile { Uri = uri, EmbeddedFileId = e.Key, OutputPath = e.Value }); } private string HashUri(string uri) { using (SHA1 sha1 = new SHA1CryptoServiceProvider()) { var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(uri)); return Convert.ToBase64String(hash).TrimEnd('=').Replace('+', '-').Replace('/', '_'); } } } }