// 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 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. /// Index of the embedded file to extract. /// Path where temporary files should be placed. /// The extract path for the embedded file. public string AddEmbeddedFileIndex(Uri uri, int embeddedFileIndex, string tempPath) { string extractPath; SortedList extracts; // 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 (!filesWithEmbeddedFiles.TryGetValue(uri, out extracts)) { extracts = new SortedList(); filesWithEmbeddedFiles.Add(uri, extracts); } // If the embedded file is not already tracked in the dictionary of extracts, add it. if (!extracts.TryGetValue(embeddedFileIndex, out extractPath)) { string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(uri.LocalPath); string unique = this.HashUri(uri.AbsoluteUri); string extractedName = String.Format(CultureInfo.InvariantCulture, @"{0}_{1}\{2}", localFileNameWithoutExtension, unique, embeddedFileIndex); extractPath = Path.Combine(tempPath, extractedName); extracts.Add(embeddedFileIndex, extractPath); } return extractPath; } public IEnumerable GetExpectedEmbeddedFiles() { foreach (var uriWithExtracts in filesWithEmbeddedFiles) { foreach (var extracts in uriWithExtracts.Value) { yield return new ExpectedExtractFile { Uri = uriWithExtracts.Key, EmbeddedFileIndex = extracts.Key, OutputPath = extracts.Value, }; } } } public IEnumerable GetExtractFilesForUri(Uri uri) { if (!filesWithEmbeddedFiles.TryGetValue(uri, out var extracts)) { extracts = new SortedList(); } return extracts.Select(e => new ExpectedExtractFile() { Uri = uri, EmbeddedFileIndex = e.Key, OutputPath = e.Value }); } private string HashUri(string uri) { using (SHA1 sha1 = new SHA1CryptoServiceProvider()) { byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(uri)); return Convert.ToBase64String(hash).TrimEnd('=').Replace('+', '-').Replace('/', '_'); } } } }