// 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.Data
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
///
/// Object that represents a library file.
///
public sealed class Library
{
public const string XmlNamespaceUri = "http://wixtoolset.org/schemas/v4/wixlib";
private static readonly Version CurrentVersion = new Version("4.0.0.0");
#if false
private string id;
private List embedFilePaths;
private Dictionary localizations;
private List sections;
///
/// Instantiates a new empty library which is only useful from static creating methods.
///
private Library()
{
this.embedFilePaths = new List();
this.localizations = new Dictionary();
this.sections = new List();
}
///
/// Instantiate a new library populated with sections.
///
/// Sections to add to the library.
///
public Library(IEnumerable sections, IDictionary localizationsByCulture, IEnumerable embedFilePaths)
{
this.id = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_');
this.embedFilePaths = new List(embedFilePaths);
this.localizations = new Dictionary(localizationsByCulture);
this.sections = new List(sections);
foreach (Section section in this.sections)
{
section.LibraryId = this.id;
}
}
///
/// Get the sections contained in this library.
///
/// Sections contained in this library.
public IEnumerable Sections => this.sections;
///
/// Gets localization files from this library that match the cultures passed in, in the order of the array of cultures.
///
/// The list of cultures to get localizations for.
/// All localizations contained in this library that match the set of cultures provided, in the same order.
public IEnumerable GetLocalizations(string[] cultures)
{
foreach (string culture in cultures ?? new string[0])
{
if (this.localizations.TryGetValue(culture, out var localization))
{
yield return localization;
}
}
}
///
/// Loads a library from a path on disk.
///
/// Path to library file saved on disk.
/// Collection containing TableDefinitions to use when reconstituting the intermediates.
/// Suppresses wix.dll version mismatch check.
/// Returns the loaded library.
public static Library Load(string path, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
{
using (FileStream stream = File.OpenRead(path))
{
return Load(stream, new Uri(Path.GetFullPath(path)), tableDefinitions, suppressVersionCheck);
}
}
///
/// Loads a library from a stream.
///
/// Stream containing the library file.
/// Uri for finding this stream.
/// Collection containing TableDefinitions to use when reconstituting the intermediates.
/// Suppresses wix.dll version mismatch check.
/// Returns the loaded library.
public static Library Load(Stream stream, Uri uri, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
{
using (FileStructure fs = FileStructure.Read(stream))
{
if (FileFormat.Wixlib != fs.FileFormat)
{
throw new WixUnexpectedFileFormatException(uri.LocalPath, FileFormat.Wixlib, fs.FileFormat);
}
using (XmlReader reader = XmlReader.Create(fs.GetDataStream(), null, uri.AbsoluteUri))
{
try
{
reader.MoveToContent();
return Library.Read(reader, tableDefinitions, suppressVersionCheck);
}
catch (XmlException xe)
{
throw new WixCorruptFileException(uri.LocalPath, fs.FileFormat, xe);
}
}
}
}
///
/// Saves a library to a path on disk.
///
/// Path to save library file to on disk.
/// The WiX path resolver.
public void Save(string path)
{
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
using (FileStream stream = File.Create(path))
using (FileStructure fs = FileStructure.Create(stream, FileFormat.Wixlib, embedFilePaths))
using (XmlWriter writer = XmlWriter.Create(fs.GetDataStream()))
{
writer.WriteStartDocument();
this.Write(writer);
writer.WriteEndDocument();
}
}
///
/// Parse the root library element.
///
/// XmlReader with library persisted as Xml.
/// Collection containing TableDefinitions to use when reconstituting the intermediates.
/// Suppresses check for wix.dll version mismatch.
/// The parsed Library.
private static Library Read(XmlReader reader, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
{
if (!reader.LocalName.Equals("wixLibrary"))
{
throw new XmlException();
}
bool empty = reader.IsEmptyElement;
Library library = new Library();
Version version = null;
while (reader.MoveToNextAttribute())
{
switch (reader.LocalName)
{
case "version":
version = new Version(reader.Value);
break;
case "id":
library.id = reader.Value;
break;
}
}
if (!suppressVersionCheck && null != version && !Library.CurrentVersion.Equals(version))
{
throw new WixException(WixDataErrors.VersionMismatch(SourceLineNumber.CreateFromUri(reader.BaseURI), "library", version.ToString(), Library.CurrentVersion.ToString()));
}
if (!empty)
{
bool done = false;
while (!done && (XmlNodeType.Element == reader.NodeType || reader.Read()))
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
switch (reader.LocalName)
{
case "localization":
Localization localization = Localization.Read(reader);
library.localizations.Add(localization.Culture, localization);
break;
case "section":
Section section = Section.Read(reader, tableDefinitions);
section.LibraryId = library.id;
library.sections.Add(section);
break;
default:
throw new XmlException();
}
break;
case XmlNodeType.EndElement:
done = true;
break;
}
}
if (!done)
{
throw new XmlException();
}
}
return library;
}
///
/// Persists a library in an XML format.
///
/// XmlWriter where the library should persist itself as XML.
private void Write(XmlWriter writer)
{
writer.WriteStartElement("wixLibrary", XmlNamespaceUri);
writer.WriteAttributeString("version", CurrentVersion.ToString());
writer.WriteAttributeString("id", this.id);
foreach (Localization localization in this.localizations.Values)
{
localization.Write(writer);
}
foreach (Section section in this.sections)
{
section.Write(writer);
}
writer.WriteEndElement();
}
#endif
}
}