// 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.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 sealed class ExtractEmbeddedFiles
{
private Dictionary> filesWithEmbeddedFiles = new Dictionary>();
public IEnumerable Uris { get { return 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 GetExtractFilesForUri(Uri uri)
{
SortedList extracts;
if (!filesWithEmbeddedFiles.TryGetValue(uri, out extracts))
{
extracts = new SortedList();
}
return extracts.Select(e => new ExtractFile() { 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('/', '_');
}
}
internal struct ExtractFile
{
public int EmbeddedFileIndex { get; set; }
public string OutputPath { get; set; }
}
}
}