// 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('/', '_');
}
}
}
}