From a95fdb4b420076ee788864ae990e79f9f5afa0b5 Mon Sep 17 00:00:00 2001 From: Rylov Roman Date: Mon, 12 Jan 2015 17:20:07 +0300 Subject: [PATCH] Init V1.0 The first commit. Source to to article http://plumsail.com/blog/2015/01/deploy-sharepoint-2013-workflow-via-site-template/ --- README.md | 27 +- TemplatePackageFix/Fixer.cs | 222 ++ TemplatePackageFix/Helpers/Extensions.cs | 33 + TemplatePackageFix/Models/Solution.cs | 28 + TemplatePackageFix/Packer.cs | 39 + TemplatePackageFix/Program.cs | 34 + TemplatePackageFix/Properties/AssemblyInfo.cs | 38 + .../Microsoft.Deployment.Compression.Cab.dll | Bin 0 -> 49152 bytes .../Microsoft.Deployment.Compression.Cab.xml | 490 +++++ .../Microsoft.Deployment.Compression.dll | Bin 0 -> 40960 bytes .../Microsoft.Deployment.Compression.xml | 1960 +++++++++++++++++ TemplatePackageFix/TemplatePackageFix.csproj | 114 + TemplatePackageFixSolution.sln | 22 + 13 files changed, 3005 insertions(+), 2 deletions(-) create mode 100644 TemplatePackageFix/Fixer.cs create mode 100644 TemplatePackageFix/Helpers/Extensions.cs create mode 100644 TemplatePackageFix/Models/Solution.cs create mode 100644 TemplatePackageFix/Packer.cs create mode 100644 TemplatePackageFix/Program.cs create mode 100644 TemplatePackageFix/Properties/AssemblyInfo.cs create mode 100644 TemplatePackageFix/Reference/Microsoft.Deployment.Compression.Cab.dll create mode 100644 TemplatePackageFix/Reference/Microsoft.Deployment.Compression.Cab.xml create mode 100644 TemplatePackageFix/Reference/Microsoft.Deployment.Compression.dll create mode 100644 TemplatePackageFix/Reference/Microsoft.Deployment.Compression.xml create mode 100644 TemplatePackageFix/TemplatePackageFix.csproj create mode 100644 TemplatePackageFixSolution.sln diff --git a/README.md b/README.md index 4a6ac0f..43649af 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,25 @@ -# TemplatePackageFix -Fix SharePoint site template template saved in WSP package + +TemplatePackageFix by [Plumsail team](http://plumsail.com) +========= + +## Synopsis + +This project present a small utility which can move all your workflows inside the package to another feature. + +It can be useful if you create a site template from the SharePoint site where was deployed [Workflow Actions Pack](http://plumsail.com/workflow-actions-pack/). + +## How to use + +[Download](https://github.com/RFlipper/TemplatePackageFix/releases) the utility and extract it to any directory. + +Start TemplatePackageFix.exe from command line with specifying the path to your WSP package. +Example: ```TemplatePackageFix.exe C:\temp\HelpDeskTemplate.wsp``` + + +## Contributors + +Currently only I'm, but you're welcome. + +## Post Scriptum + +To know more please check out the article [Deploy SharePoint 2013 Workflow via Site Template](http://plumsail.com/blog/2015/01/deploy-sharepoint-2013-workflow-via-site-template/) diff --git a/TemplatePackageFix/Fixer.cs b/TemplatePackageFix/Fixer.cs new file mode 100644 index 0000000..fac22a2 --- /dev/null +++ b/TemplatePackageFix/Fixer.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using Plumsail.TemplatePackageFix.Helpers; + +namespace Plumsail.TemplatePackageFix +{ + public sealed class Fixer + { + #region Declarations + readonly XNamespace ns = "http://schemas.microsoft.com/sharepoint/"; + readonly string WFPackSolutionID = "64283c6e-6aea-4a86-a881-042359b3521a"; + readonly string WFFeaturePath = "SP2013Workflows"; + readonly string BasePath; + + private XDocument wfFeature; + private XDocument wfElements; + private string wfFeatureDir; + #endregion + + #region Constructor + public Fixer(string path) + { + BasePath = path; + CreateWorkflowFeature(); + ProcessManifest(); + } + #endregion + + #region Control methods + internal void ProcessManifest() + { + var manifestFilePath = Path.Combine(BasePath, "manifest.xml"); + + //Load features + var manifest = XDocument.Load(manifestFilePath); + var features = manifest.Descendants(ns + "FeatureManifest"); + + //Process features list defined in manifest.xml + foreach (var featureDef in features) + { + var featureFile = Path.Combine(BasePath, featureDef.Attribute("Location").Value); + ProcessFeature(featureFile); + } + + //Add additional workflow nodes to manifest.xml + manifest.Descendants(ns + "FeatureManifests").Single().Add( + new XElement(ns + "FeatureManifest", + new XAttribute("Location", Path.Combine(WFFeaturePath, "Feature.xml")))); + + wfElements.SaveToFile(Path.Combine(BasePath, WFFeaturePath, "Elements.xml")); + wfFeature.SaveToFile(Path.Combine(BasePath, WFFeaturePath, "Feature.xml")); + + RemovePackageDependency(manifest); + + manifest.SaveToFile(manifestFilePath); + } + + internal void ProcessFeature(string featureFile) + { + var featureDir = Path.GetDirectoryName(featureFile); + var elementsFile = Path.Combine(featureDir, "Elements.xml"); + + var feature = XDocument.Load(featureFile); + var elements = XDocument.Load(elementsFile); + + RemoveCustomActions(feature, elements, featureDir); + RemoveModules(feature, elements, featureDir); + RemoveDependentFeatures(feature, elements, featureDir); + MoveWorkflowModules(feature, elements, featureDir); + + //Save files + elements.SaveToFile(elementsFile); + feature.SaveToFile(featureFile); + } + #endregion + + #region Service methods + + internal void CreateWorkflowFeature() + { + wfFeatureDir = Path.Combine(BasePath, WFFeaturePath); + System.IO.Directory.CreateDirectory(wfFeatureDir); + wfFeature = new XDocument( + new XElement(ns + "Feature", + new XAttribute("Id", Guid.NewGuid().ToString()), + new XAttribute("Title", "Template workflows"), + new XAttribute("Description", "Template workflows"), + new XAttribute("Scope", "Web"), + new XAttribute("Version", "1.0.0.0"), + new XElement(ns + "ElementManifests", + new XElement(ns + "ElementManifest", new XAttribute("Location", "Elements.xml"))) + )); + + wfElements = new XDocument(new XElement(ns + "Elements")); + } + + private void MoveWorkflowModules(XDocument feature, XDocument elements, string featureDir) + { + Expression> ex = el => el.Attribute("Location").Value.Contains("\\wfsvc\\"); + var apNodes = + feature.Descendants(ns + "ElementFile") + .Where(el => el.Attribute("Location").Value.Contains("\\wfsvc\\") + && !el.Attribute("Location").Value.Contains("Schema.xml")); + + if (apNodes.Count() < 1) + return; + + var paths = new HashSet(); + foreach (var elementFile in apNodes) + { + var fileRelativePath = elementFile.Attribute("Location").Value; + var fileName = Path.GetFileName(fileRelativePath); + var filePath = Path.GetDirectoryName(fileRelativePath); + paths.Add(filePath); + + Directory.CreateDirectory(Path.Combine(wfFeatureDir, filePath)); + File.Move(Path.Combine(featureDir, fileRelativePath), Path.Combine(wfFeatureDir, fileRelativePath)); + } + + wfFeature.Descendants(ns + "ElementManifests").Single().Add(apNodes); + apNodes.Remove(); + + var elNodes = elements.Descendants(ns + "Module").Where(el => paths.Contains(el.Attribute("Path").Value)); + wfElements.Root.Add(elNodes); + elNodes.Remove(); + } + + private void RemoveDependentFeatures(XDocument feature, XDocument elements, string featureDir) + { + var onet = feature.Descendants(ns + "ElementFile").SingleOrDefault(el => el.Attribute("Location").Value.Contains("\\ONet.xml")); + if (onet == null) + return; + + var onetFilePath = Path.Combine(featureDir, onet.Attribute("Location").Value); + var onetDocument = XDocument.Load(onetFilePath); + var features = onetDocument.Descendants(ns + "Feature") + .Where(el => el.Attribute("ID").Value == "{9a5d1295-65c0-4c8e-a926-968da90d2ef9}" + || el.Attribute("ID").Value == "{d7891031-e7f5-4734-8077-9189dd35551c}"); + + if (features.Count() < 1) + return; + + features.Remove(); + onetDocument.SaveToFile(onetFilePath); + } + + private void RemoveCustomActions(XDocument feature, XDocument elements, string featureDir) + { + var nodes = elements.Descendants(ns + "CustomAction") + .Where(el => el.Attribute("Id").Value.Contains("WFPackAdminPage") + || (el.Attribute("ScriptSrc") != null && el.Attribute("ScriptSrc").Value.Contains("Plumsail"))); + + if (nodes.Count() < 1) + return; + + nodes.Remove(); + } + + private void RemoveModules(XDocument feature, XDocument elements, string featureDir) + { + var workflowFiles = + feature.Descendants(ns + "ElementFile") + .Where(el => el.Attribute("Location").Value.Contains("\\Workflows\\")); + + if (workflowFiles.Count() < 1) + return; + + //Get list of nodes to remove from Elements.xml + var filesToRemove = new List(); + foreach (var elementFile in workflowFiles) + { + var fileRelativePath = elementFile.Attribute("Location").Value; + var fileName = Path.GetFileName(fileRelativePath); + var filePath = Path.GetDirectoryName(fileRelativePath); + + var fileNode = elements.Descendants(ns + "File").FirstOrDefault( + el => el.Parent.Attribute("Path").Value == filePath + && el.Attribute("Path").Value == fileName); + + if (fileNode != null) + filesToRemove.Add(fileNode); + + //Delete physical file + File.Delete(Path.Combine(featureDir, fileRelativePath)); + } + + //Remove nodes from Elements.xml + filesToRemove.ForEach(el => el.Remove()); + //Remove empty module elements + elements.Descendants(ns + "Module").Where(el => !el.HasElements).Remove(); + + //Remove nodes from Feature.xml + workflowFiles.Remove(); + } + + private void RemovePackageDependency(XDocument manifest) + { + var dependencyNode = manifest.Descendants(ns + "ActivationDependency") + .SingleOrDefault(el => el.Attribute("SolutionId").Value == WFPackSolutionID); + + if (dependencyNode == null) + return; + + var parent = dependencyNode.Parent; + + dependencyNode.Remove(); + + //remove empty ActivationDependencies node + if (!parent.HasElements) + parent.Remove(); + } + #endregion + + } +} diff --git a/TemplatePackageFix/Helpers/Extensions.cs b/TemplatePackageFix/Helpers/Extensions.cs new file mode 100644 index 0000000..8a29d8a --- /dev/null +++ b/TemplatePackageFix/Helpers/Extensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; + +namespace Plumsail.TemplatePackageFix.Helpers +{ + public static class Extensions + { + public static void SaveToFile(this XDocument doc, string path) + { + var settings = new XmlWriterSettings() + { + OmitXmlDeclaration = true + , Indent = true + , IndentChars = "\t" + , NewLineChars = Environment.NewLine + , NewLineHandling = NewLineHandling.Replace + }; + using (var stream = System.IO.File.Create(path)) + { + using (var writer = XmlWriter.Create(stream, settings)) + { + doc.Save(writer); + } + } + } + + } +} diff --git a/TemplatePackageFix/Models/Solution.cs b/TemplatePackageFix/Models/Solution.cs new file mode 100644 index 0000000..d407155 --- /dev/null +++ b/TemplatePackageFix/Models/Solution.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Plumsail.TemplatePackageFix.Models +{ + public class Solution + { + public class FeatureManifest + { + public string Location { get; set; } + } + + public class ActivationDependency + { + public Guid SolutionId { get; set; } + public string SolutionName { get; set; } + } + + public Guid SolutionId { get; set; } + public string SharePointProductVersion { get; set; } + + public List FeatureManifests { get; set; } + public List ActivationDependencies { get; set; } + } +} diff --git a/TemplatePackageFix/Packer.cs b/TemplatePackageFix/Packer.cs new file mode 100644 index 0000000..3a2ce5b --- /dev/null +++ b/TemplatePackageFix/Packer.cs @@ -0,0 +1,39 @@ +using Microsoft.Deployment.Compression; +using Microsoft.Deployment.Compression.Cab; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Plumsail.TemplatePackageFix +{ + /// + /// Wrap pack/unpack functionality + /// + public class Packer : IDisposable + { + public readonly string OriginalPath; + public readonly string TempFolder = Path.GetTempPath() + Guid.NewGuid(); + + public Packer(string path) + { + OriginalPath = path; + + Directory.CreateDirectory(TempFolder); + if (File.Exists(OriginalPath)) + { + var cab = new CabInfo(OriginalPath); + cab.Unpack(TempFolder); + } + } + public void Dispose() + { + var cab = new CabInfo(OriginalPath); + cab.Pack(TempFolder, true, CompressionLevel.Normal, (sender, args) => { }); + + Directory.Delete(TempFolder, true); + } + } +} diff --git a/TemplatePackageFix/Program.cs b/TemplatePackageFix/Program.cs new file mode 100644 index 0000000..63f16fa --- /dev/null +++ b/TemplatePackageFix/Program.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Plumsail.TemplatePackageFix +{ + class Program + { + static void Main(string[] args) + { + if (args.Length < 1) + { + var message = @"Example: TemplatePackageFix.exe C:\temp\HelpDeskTemplate.wsp" + + "\nThe program will remove any Plumsail Dependencies from the web template package."; + + Console.WriteLine(message); + return; + } + + var path = args[0]; + Console.Write("Processing file {0} ", path); + using (var packer = new Packer(path)) + { + var baseTempFolder = packer.TempFolder; + new Fixer(baseTempFolder); + } + + Console.WriteLine(" - fixed"); + } + } +} diff --git a/TemplatePackageFix/Properties/AssemblyInfo.cs b/TemplatePackageFix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d5dced0 --- /dev/null +++ b/TemplatePackageFix/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TemplatePackageFix")] +[assembly: AssemblyDescription("The utility moves workflows from WSP package to separate feature")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Plumsail.com")] +[assembly: AssemblyProduct("TemplatePackageFix")] +[assembly: AssemblyCopyright("Copyright Plumsail © 2015")] +[assembly: AssemblyTrademark("Plumsail.com")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7436d9f8-545b-4b9e-8dd8-af48673676b0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("TemplatePackageFix.Tests")] \ No newline at end of file diff --git a/TemplatePackageFix/Reference/Microsoft.Deployment.Compression.Cab.dll b/TemplatePackageFix/Reference/Microsoft.Deployment.Compression.Cab.dll new file mode 100644 index 0000000000000000000000000000000000000000..8f944321400eddb73002ab15bec41aeb319b9f31 GIT binary patch literal 49152 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 + + + Microsoft.Deployment.Compression.Cab + + + + + Disposes of resources allocated by the cabinet engine. + + If true, the method has been called directly or indirectly by a user's code, + so managed and unmanaged resources will be disposed. If false, the method has been called by the + runtime from inside the finalizer, and only unmanaged resources will be disposed. + + + + Disposes of resources allocated by the cabinet engine. + + If true, the method has been called directly or indirectly by a user's code, + so managed and unmanaged resources will be disposed. If false, the method has been called by the + runtime from inside the finalizer, and only unmanaged resources will be disposed. + + + + Engine capable of packing and unpacking archives in the cabinet format. + + + + + Creates a new instance of the cabinet engine. + + + + + Disposes of resources allocated by the cabinet engine. + + If true, the method has been called directly + or indirectly by a user's code, so managed and unmanaged resources + will be disposed. If false, the method has been called by the runtime + from inside the finalizer, and only unmanaged resources will be + disposed. + + + + Creates a cabinet or chain of cabinets. + + A context interface to handle opening + and closing of cabinet and file streams. + The paths of the files in the archive (not + external file paths). + The maximum number of bytes for one + cabinet before the contents are chained to the next cabinet, or zero + for unlimited cabinet size. + The cabinet could not be + created. + + The stream context implementation may provide a mapping from the + file paths within the cabinet to the external file paths. + Smaller folder sizes can make it more efficient to extract + individual files out of large cabinet packages. + + + + + Checks whether a Stream begins with a header that indicates + it is a valid cabinet file. + + Stream for reading the cabinet file. + True if the stream is a valid cabinet file + (with no offset); false otherwise. + + + + Gets information about files in a cabinet or cabinet chain. + + A context interface to handle opening + and closing of cabinet and file streams. + A predicate that can determine + which files to process, optional. + Information about files in the cabinet stream. + The cabinet provided + by the stream context is not valid. + + The predicate takes an internal file + path and returns true to include the file or false to exclude it. + + + + + Extracts files from a cabinet or cabinet chain. + + A context interface to handle opening + and closing of cabinet and file streams. + An optional predicate that can determine + which files to process. + The cabinet provided + by the stream context is not valid. + + The predicate takes an internal file + path and returns true to include the file or false to exclude it. + + + + + Exception class for cabinet operations. + + + + + Creates a new CabException with a specified error message and a reference to the + inner exception that is the cause of this exception. + + The message that describes the error. + The exception that is the cause of the current exception. If the + innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + is raised in a catch block that handles the inner exception. + + + + Creates a new CabException with a specified error message. + + The message that describes the error. + + + + Creates a new CabException. + + + + + Initializes a new instance of the CabException class with serialized data. + + The SerializationInfo that holds the serialized object data about the exception being thrown. + The StreamingContext that contains contextual information about the source or destination. + + + + Sets the SerializationInfo with information about the exception. + + The SerializationInfo that holds the serialized object data about the exception being thrown. + The StreamingContext that contains contextual information about the source or destination. + + + + Gets the FCI or FDI cabinet engine error number. + + A cabinet engine error number, or 0 if the exception was + not related to a cabinet engine error number. + + + + Gets the Win32 error code. + + A Win32 error code, or 0 if the exception was + not related to a Win32 error. + + + + Disposes of resources allocated by the cabinet engine. + + If true, the method has been called directly or indirectly by a user's code, + so managed and unmanaged resources will be disposed. If false, the method has been called by the + runtime from inside the finalizer, and only unmanaged resources will be disposed. + + + + Object representing a compressed file within a cabinet package; provides operations for getting + the file properties and extracting the file. + + + + + Creates a new CabinetFileInfo object representing a file within a cabinet in a specified path. + + An object representing the cabinet containing the file. + The path to the file within the cabinet. Usually, this is a simple file + name, but if the cabinet contains a directory structure this may include the directory. + + + + Creates a new CabinetFileInfo object with all parameters specified, + used internally when reading the metadata out of a cab. + + The internal path and name of the file in the cab. + The folder number containing the file. + The cabinet number where the file starts. + The stored attributes of the file. + The stored last write time of the file. + The uncompressed size of the file. + + + + Initializes a new instance of the CabinetFileInfo class with serialized data. + + The SerializationInfo that holds the serialized object data about the exception being thrown. + The StreamingContext that contains contextual information about the source or destination. + + + + Sets the SerializationInfo with information about the archive. + + The SerializationInfo that holds the serialized object data. + The StreamingContext that contains contextual information + about the source or destination. + + + + Refreshes the information in this object with new data retrieved + from an archive. + + Fresh instance for the same file just + read from the archive. + + This implementation refreshes the . + + + + + Gets or sets the cabinet that contains this file. + + + The CabinetInfo instance that retrieved this file information -- this + may be null if the CabinetFileInfo object was returned directly from a + stream. + + + + + Gets the full path of the cabinet that contains this file. + + The full path of the cabinet that contains this file. + + + + Gets the number of the folder containing this file. + + The number of the cabinet folder containing this file. + A single folder or the first folder of a cabinet + (or chain of cabinets) is numbered 0. + + + + Object representing a cabinet file on disk; provides access to + file-based operations on the cabinet file. + + + Generally, the methods on this class are much easier to use than the + stream-based interfaces provided by the class. + + + + + Creates a new CabinetInfo object representing a cabinet file in a specified path. + + The path to the cabinet file. When creating a cabinet file, this file does not + necessarily exist yet. + + + + Initializes a new instance of the CabinetInfo class with serialized data. + + The SerializationInfo that holds the serialized object data about the exception being thrown. + The StreamingContext that contains contextual information about the source or destination. + + + + Creates a compression engine that does the low-level work for + this object. + + A new instance. + + Each instance will be d + immediately after use. + + + + + Gets information about the files contained in the archive. + + A list of objects, each + containing information about a file in the archive. + + + + Gets information about the certain files contained in the archive file. + + The search string, such as + "*.txt". + A list of objects, each containing + information about a file in the archive. + + + + Generic class for managing allocations of integer handles + for objects of a certain type. + + The type of objects the handles refer to. + + + + Auto-resizing list of objects for which handles have been allocated. + Each handle is just an index into this list. When a handle is freed, + the list item at that index is set to null. + + + + + Creates a new HandleManager instance. + + + + + Allocates a new handle for an object. + + Object that the handle will refer to. + New handle that can be later used to retrieve the object. + + + + Frees a handle that was previously allocated. Afterward the handle + will be invalid and the object it referred to can no longer retrieved. + + Handle to be freed. + + + + Gets the object of a handle, or null if the handle is invalid. + + The integer handle previously allocated + for the desired object. + The object for which the handle was allocated. + + + + Native DllImport methods and related structures and constants used for + cabinet creation and extraction via cabinet.dll. + + + + + A direct import of constants, enums, structures, delegates, and functions from fci.h. + Refer to comments in fci.h for documentation. + + + + + Error codes that can be returned by FCI. + + + + + FCI compression algorithm types and parameters. + + + + + Reason for FCI status callback. + + + + + Cabinet information structure used for FCI initialization and GetNextCabinet callback. + + + + + Ensures that the FCI handle is safely released. + + + + + Creates a new unintialized handle. The handle will be initialized + when it is marshalled back from native code. + + + + + Releases the handle by calling FDIDestroy(). + + True if the release succeeded. + + + + Checks if the handle is invalid. An FCI handle is invalid when it is zero. + + + + + A direct import of constants, enums, structures, delegates, and functions from fdi.h. + Refer to comments in fdi.h for documentation. + + + + + Error codes that can be returned by FDI. + + + + + Type of notification message for the FDI Notify callback. + + + + + Cabinet information structure filled in by FDI IsCabinet. + + + + + Cabinet notification details passed to the FDI Notify callback. + + + + + Ensures that the FDI handle is safely released. + + + + + Creates a new unintialized handle. The handle will be initialized + when it is marshalled back from native code. + + + + + Releases the handle by calling FDIDestroy(). + + True if the release succeeded. + + + + Checks if the handle is invalid. An FDI handle is invalid when it is zero. + + + + + Error info structure for FCI and FDI. + + Before being passed to FCI or FDI, this structure is + pinned in memory via a GCHandle. The pinning is necessary + to be able to read the results, since the ERF structure doesn't + get marshalled back out after an error. + + + + Clears the error information. + + + + + Gets or sets the cabinet error code. + + + + + Gets or sets the Win32 error code. + + + + + GCHandle doesn't like the bool type, so use an int underneath. + + + + + Distribution specific strings. + + + + + News URL for the distribution. + + + + + Short product name for the distribution. + + + + + Support URL for the distribution. + + + + + Telemetry URL format for the distribution. + + + + diff --git a/TemplatePackageFix/Reference/Microsoft.Deployment.Compression.dll b/TemplatePackageFix/Reference/Microsoft.Deployment.Compression.dll new file mode 100644 index 0000000000000000000000000000000000000000..81da5f5ca8f76725e186cddcc172b278826b22d2 GIT binary patch literal 40960 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 + + + Microsoft.Deployment.Compression + + + + + Base exception class for compression operations. Compression libraries should + derive subclass exceptions with more specific error information relevent to the + file format. + + + + + Creates a new ArchiveException with a specified error message and a reference to the + inner exception that is the cause of this exception. + + The message that describes the error. + The exception that is the cause of the current exception. If the + innerException parameter is not a null reference (Nothing in Visual Basic), the current exception + is raised in a catch block that handles the inner exception. + + + + Creates a new ArchiveException with a specified error message. + + The message that describes the error. + + + + Creates a new ArchiveException. + + + + + Initializes a new instance of the ArchiveException class with serialized data. + + The SerializationInfo that holds the serialized object data about the exception being thrown. + The StreamingContext that contains contextual information about the source or destination. + + + + Abstract object representing a compressed file within an archive; + provides operations for getting the file properties and unpacking + the file. + + + + + Creates a new ArchiveFileInfo object representing a file within + an archive in a specified path. + + An object representing the archive + containing the file. + The path to the file within the archive. + Usually, this is a simple file name, but if the archive contains + a directory structure this may include the directory. + + + + Creates a new ArchiveFileInfo object with all parameters specified; + used by subclasses when reading the metadata out of an archive. + + The internal path and name of the file in + the archive. + The archive number where the file + starts. + The stored attributes of the file. + The stored last write time of the + file. + The uncompressed size of the file. + + + + Initializes a new instance of the ArchiveFileInfo class with + serialized data. + + The SerializationInfo that holds the serialized + object data about the exception being thrown. + The StreamingContext that contains contextual + information about the source or destination. + + + + Sets the SerializationInfo with information about the archive. + + The SerializationInfo that holds the serialized + object data. + The StreamingContext that contains contextual + information about the source or destination. + + + + Gets the full path to the file. + + The same as + + + + Deletes the file. NOT SUPPORTED. + + Files cannot be deleted + from an existing archive. + + + + Refreshes the attributes and other cached information about the file, + by re-reading the information from the archive. + + + + + Extracts the file. + + The destination path where the file + will be extracted. + + + + Extracts the file, optionally overwriting any existing file. + + The destination path where the file + will be extracted. + If true, + will be overwritten if it exists. + is false + and exists. + + + + Opens the archive file for reading without actually extracting the + file to disk. + + + A stream for reading directly from the packed file. Like any stream + this should be closed/disposed as soon as it is no longer needed. + + + + + Opens the archive file reading text with UTF-8 encoding without + actually extracting the file to disk. + + + A reader for reading text directly from the packed file. Like any reader + this should be closed/disposed as soon as it is no longer needed. + + + To open an archived text file with different encoding, use the + method and pass the returned stream to one of + the constructor overloads. + + + + + Refreshes the information in this object with new data retrieved + from an archive. + + Fresh instance for the same file just + read from the archive. + + Subclasses may override this method to refresh sublcass fields. + However they should always call the base implementation first. + + + + + Gets the name of the file. + + The name of the file, not including any path. + + + + Gets the internal path of the file in the archive. + + The internal path of the file in the archive, not including + the file name. + + + + Gets the full path to the file. + + The full path to the file, including the full path to the + archive, the internal path in the archive, and the file name. + + For example, the path "C:\archive.cab\file.txt" refers to + a file "file.txt" inside the archive "archive.cab". + + + + + Gets or sets the archive that contains this file. + + + The ArchiveInfo instance that retrieved this file information -- this + may be null if the ArchiveFileInfo object was returned directly from + a stream. + + + + + Gets the full path of the archive that contains this file. + + The full path of the archive that contains this file. + + + + Gets the number of the archive where this file starts. + + The number of the archive where this file starts. + A single archive or the first archive in a chain is + numbered 0. + + + + Checks if the file exists within the archive. + + True if the file exists, false otherwise. + + + + Gets the uncompressed size of the file. + + The uncompressed size of the file in bytes. + + + + Gets the attributes of the file. + + The attributes of the file as stored in the archive. + + + + Gets the last modification time of the file. + + The last modification time of the file as stored in the + archive. + + + + Abstract object representing a compressed archive on disk; + provides access to file-based operations on the archive. + + + + + Creates a new ArchiveInfo object representing an archive in a + specified path. + + The path to the archive. When creating an archive, + this file does not necessarily exist yet. + + + + Initializes a new instance of the ArchiveInfo class with serialized data. + + The SerializationInfo that holds the serialized object + data about the exception being thrown. + The StreamingContext that contains contextual + information about the source or destination. + + + + Gets the full path of the archive. + + The full path of the archive. + + + + Deletes the archive. + + + + + Copies an existing archive to another location. + + The destination file path. + + + + Copies an existing archive to another location, optionally + overwriting the destination file. + + The destination file path. + If true, the destination file will be + overwritten if it exists. + + + + Moves an existing archive to another location. + + The destination file path. + + + + Checks if the archive contains a valid archive header. + + True if the file is a valid archive; false otherwise. + + + + Gets information about the files contained in the archive. + + A list of objects, each + containing information about a file in the archive. + + + + Gets information about the certain files contained in the archive file. + + The search string, such as + "*.txt". + A list of objects, each containing + information about a file in the archive. + + + + Extracts all files from an archive to a destination directory. + + Directory where the files are to be + extracted. + + + + Extracts all files from an archive to a destination directory, + optionally extracting only newer files. + + Directory where the files are to be + extracted. + Handler for receiving progress + information; this may be null if progress is not desired. + + + + Extracts a single file from the archive. + + The name of the file in the archive. Also + includes the internal path of the file, if any. File name matching + is case-insensitive. + The path where the file is to be + extracted on disk. + If already exists, + it will be overwritten. + + + + Extracts multiple files from the archive. + + The names of the files in the archive. + Each name includes the internal path of the file, if any. File name + matching is case-insensitive. + This parameter may be null, but if + specified it is the root directory for any relative paths in + . + The paths where the files are to be + extracted on disk. If this parameter is null, the files will be + extracted with the names from the archive. + + If any extracted files already exist on disk, they will be overwritten. +

The and + parameters cannot both be null.

+
+
+ + + Extracts multiple files from the archive, optionally extracting + only newer files. + + The names of the files in the archive. + Each name includes the internal path of the file, if any. File name + matching is case-insensitive. + This parameter may be null, but if + specified it is the root directory for any relative paths in + . + The paths where the files are to be + extracted on disk. If this parameter is null, the files will be + extracted with the names from the archive. + Handler for receiving progress information; + this may be null if progress is not desired. + + If any extracted files already exist on disk, they will be overwritten. +

The and + parameters cannot both be null.

+
+
+ + + Extracts multiple files from the archive. + + A mapping from internal file paths to + external file paths. Case-senstivity when matching internal paths + depends on the IDictionary implementation. + This parameter may be null, but if + specified it is the root directory for any relative external paths + in . + + If any extracted files already exist on disk, they will be overwritten. + + + + + Extracts multiple files from the archive. + + A mapping from internal file paths to + external file paths. Case-senstivity when matching internal + paths depends on the IDictionary implementation. + This parameter may be null, but if + specified it is the root directory for any relative external + paths in . + Handler for receiving progress + information; this may be null if progress is not desired. + + If any extracted files already exist on disk, they will be overwritten. + + + + + Opens a file inside the archive for reading without actually + extracting the file to disk. + + The name of the file in the archive. Also + includes the internal path of the file, if any. File name matching + is case-insensitive. + + A stream for reading directly from the packed file. Like any stream + this should be closed/disposed as soon as it is no longer needed. + + + + + Opens a file inside the archive for reading text with UTF-8 encoding + without actually extracting the file to disk. + + The name of the file in the archive. Also + includes the internal path of the file, if any. File name matching + is case-insensitive. + + A reader for reading text directly from the packed file. Like any reader + this should be closed/disposed as soon as it is no longer needed. + + + To open an archived text file with different encoding, use the + method and pass the returned stream to one of + the constructor overloads. + + + + + Compresses all files in a directory into the archive. + Does not include subdirectories. + + The directory containing the + files to be included. + + Uses maximum compression level. + + + + + Compresses all files in a directory into the archive, optionally + including subdirectories. + + This is the root directory + for to pack all files. + If true, recursively include + files in subdirectories. + The compression level used when creating + the archive. + Handler for receiving progress information; + this may be null if progress is not desired. + + The files are stored in the archive using their relative file paths in + the directory tree, if supported by the archive file format. + + + + + Compresses files into the archive, specifying the names used to + store the files in the archive. + + This parameter may be null, but + if specified it is the root directory + for any relative paths in . + The list of files to be included in + the archive. + The names of the files as they are stored + in the archive. Each name + includes the internal path of the file, if any. This parameter may + be null, in which case the files are stored in the archive with their + source file names and no path information. + + Uses maximum compression level. +

Duplicate items in the array will cause + an .

+
+
+ + + Compresses files into the archive, specifying the names used to + store the files in the archive. + + This parameter may be null, but if + specified it is the root directory + for any relative paths in . + The list of files to be included in + the archive. + The names of the files as they are stored in + the archive. Each name includes the internal path of the file, if any. + This parameter may be null, in which case the files are stored in the + archive with their source file names and no path information. + The compression level used when creating the + archive. + Handler for receiving progress information; + this may be null if progress is not desired. + + Duplicate items in the array will cause + an . + + + + + Compresses files into the archive, specifying the names used + to store the files in the archive. + + This parameter may be null, but if + specified it is the root directory + for any relative paths in . + A mapping from internal file paths to + external file paths. + + Uses maximum compression level. + + + + + Compresses files into the archive, specifying the names used to + store the files in the archive. + + This parameter may be null, but if + specified it is the root directory + for any relative paths in . + A mapping from internal file paths to + external file paths. + The compression level used when creating + the archive. + Handler for receiving progress information; + this may be null if progress is not desired. + + + + Given a directory, gets the relative paths of all files in the + directory, optionally including all subdirectories. + + The directory to search. + True to include subdirectories + in the search. + A list of file paths relative to the directory. + + + + Retrieves information about one file from this archive. + + Path of the file in the archive. + File information, or null if the file was not found + in the archive. + + + + Creates a compression engine that does the low-level work for + this object. + + A new compression engine instance that matches the specific + subclass of archive. + + Each instance will be d + immediately after use. + + + + + Creates a case-insensitive dictionary mapping from one list of + strings to the other. + + List of keys. + List of values that are mapped 1-to-1 to + the keys. + A filled dictionary of the strings. + + + + Recursive-descent helper function for + GetRelativeFilePathsInDirectoryTree. + + The root directory of the search. + The relative directory to be + processed now. + True to descend into + subdirectories. + List of files found so far. + + + + Uses a CompressionEngine to get ArchiveFileInfo objects from this + archive, and then associates them with this ArchiveInfo instance. + + Optional predicate that can determine + which files to process. + A list of objects, each + containing information about a file in the archive. + + + + Gets the directory that contains the archive. + + A DirectoryInfo object representing the parent directory of the + archive. + + + + Gets the full path of the directory that contains the archive. + + The full path of the directory that contains the archive. + + + + Gets the size of the archive. + + The size of the archive in bytes. + + + + Gets the file name of the archive. + + The file name of the archive, not including any path. + + + + Checks if the archive exists. + + True if the archive exists; else false. + + + + Contains the data reported in an archive progress event. + + + + + Creates a new ArchiveProgressEventArgs object from specified event parameters. + + type of status message + name of the file being processed + number of the current file being processed + total number of files to be processed + number of bytes processed so far when compressing or extracting a file + total number of bytes in the current file + name of the current Archive + current Archive number, when processing a chained set of Archives + total number of Archives in a chained set + number of compressed bytes processed so far during an extraction + total number of compressed bytes to be processed during an extraction + number of uncompressed file bytes processed so far + total number of uncompressed file bytes to be processed + + + + Gets the type of status message. + + A value indicating what type of progress event occurred. + + The handler may choose to ignore some types of progress events. + For example, if the handler will only list each file as it is + compressed/extracted, it can ignore events that + are not of type . + + + + + Gets the name of the file being processed. (The name of the file within the Archive; not the external + file path.) Also includes the internal path of the file, if any. Valid for + , , + and messages. + + The name of the file currently being processed, or null if processing + is currently at the stream or archive level. + + + + Gets the number of the current file being processed. The first file is number 0, and the last file + is -1. Valid for , + , and messages. + + The number of the file currently being processed, or the most recent + file processed if processing is currently at the stream or archive level. + + + + Gets the total number of files to be processed. Valid for all message types. + + The total number of files to be processed that are known so far. + + + + Gets the number of bytes processed so far when compressing or extracting a file. Valid for + , , + and messages. + + The number of uncompressed bytes processed so far for the current file, + or 0 if processing is currently at the stream or archive level. + + + + Gets the total number of bytes in the current file. Valid for , + , and messages. + + The uncompressed size of the current file being processed, + or 0 if processing is currently at the stream or archive level. + + + + Gets the name of the current archive. Not necessarily the name of the archive on disk. + Valid for all message types. + + The name of the current archive, or an empty string if no name was specified. + + + + Gets the current archive number, when processing a chained set of archives. Valid for all message types. + + The number of the current archive. + The first archive is number 0, and the last archive is + -1. + + + + Gets the total number of known archives in a chained set. Valid for all message types. + + The total number of known archives in a chained set. + + When using the compression option to auto-split into multiple archives based on data size, + this value will not be accurate until the end. + + + + + Gets the number of compressed bytes processed so far during extraction + of the current archive. Valid for all extraction messages. + + The number of compressed bytes processed so far during extraction + of the current archive. + + + + Gets the total number of compressed bytes to be processed during extraction + of the current archive. Valid for all extraction messages. + + The total number of compressed bytes to be processed during extraction + of the current archive. + + + + Gets the number of uncompressed bytes processed so far among all files. Valid for all message types. + + The number of uncompressed file bytes processed so far among all files. + + When compared to , this can be used as a measure of overall progress. + + + + + Gets the total number of uncompressed file bytes to be processed. Valid for all message types. + + The total number of uncompressed bytes to be processed among all files. + + + + The type of progress event. + + +

PACKING EXAMPLE: The following sequence of events might be received when + extracting a simple archive file with 2 files.

+ + Message TypeDescription + StartArchive Begin extracting archive + StartFile Begin extracting first file + PartialFile Extracting first file + PartialFile Extracting first file + FinishFile Finished extracting first file + StartFile Begin extracting second file + PartialFile Extracting second file + FinishFile Finished extracting second file + FinishArchiveFinished extracting archive + +

+

UNPACKING EXAMPLE: Packing 3 files into 2 archive chunks, where the second file is + continued to the second archive chunk.

+ + Message TypeDescription + StartFile Begin compressing first file + FinishFile Finished compressing first file + StartFile Begin compressing second file + PartialFile Compressing second file + PartialFile Compressing second file + FinishFile Finished compressing second file + StartArchive Begin writing first archive + PartialArchiveWriting first archive + FinishArchive Finished writing first archive + StartFile Begin compressing third file + PartialFile Compressing third file + FinishFile Finished compressing third file + StartArchive Begin writing second archive + PartialArchiveWriting second archive + FinishArchive Finished writing second archive + +
+
+ + Status message before beginning the packing or unpacking an individual file. + + + Status message (possibly reported multiple times) during the process of packing or unpacking a file. + + + Status message after completion of the packing or unpacking an individual file. + + + Status message before beginning the packing or unpacking an archive. + + + Status message (possibly reported multiple times) during the process of packing or unpacking an archiv. + + + Status message after completion of the packing or unpacking of an archive. + + + + Provides a basic implementation of the archive pack and unpack stream context + interfaces, based on a list of archive files, a default directory, and an + optional mapping from internal to external file paths. + + + This class can also handle creating or extracting chained archive packages. + + + + + This interface provides the methods necessary for the + to open and close streams for archives + and files. The implementor of this interface can use any kind of logic + to determine what kind of streams to open and where. + + + + + Gets the name of the archive with a specified number. + + The 0-based index of the archive + within the chain. + The name of the requested archive. May be an empty string + for non-chained archives, but may never be null. + The archive name is the name stored within the archive, used for + identification of the archive especially among archive chains. That + name is often, but not necessarily the same as the filename of the + archive package. + + + + Opens a stream for writing an archive package. + + The 0-based index of the archive within + the chain. + The name of the archive that was returned + by . + True if the stream should be truncated when + opened (if it already exists); false if an existing stream is being + re-opened for writing additional data. + Instance of the compression engine + doing the operations. + A writable Stream where the compressed archive bytes will be + written, or null to cancel the archive creation. + + If this method returns null, the archive engine will throw a + FileNotFoundException. + + + + + Closes a stream where an archive package was written. + + The 0-based index of the archive within + the chain. + The name of the archive that was previously + returned by + . + A stream that was previously returned by + and is now ready to be closed. + + If there is another archive package in the chain, then after this stream + is closed a new stream will be opened. + + + + + Opens a stream to read a file that is to be included in an archive. + + The path of the file within the archive. This is often, + but not necessarily, the same as the relative path of the file outside + the archive. + Returned attributes of the opened file, to be + stored in the archive. + Returned last-modified time of the opened file, + to be stored in the archive. + A readable Stream where the file bytes will be read from before + they are compressed, or null to skip inclusion of the file and continue to + the next file. + + + + Closes a stream that has been used to read a file. + + The path of the file within the archive; the same as + the path provided + when the stream was opened. + A stream that was previously returned by + and is now ready to be closed. + + + + Gets extended parameter information specific to the compression + format being used. + + Name of the option being requested. + Parameters for the option; for per-file options, + the first parameter is typically the internal file path. + Option value, or null to use the default behavior. + + This method provides a way to set uncommon options during packaging, or a + way to handle aspects of compression formats not supported by the base library. + For example, this may be used by the zip compression library to + specify different compression methods/levels on a per-file basis. + The available option names, parameters, and expected return values + should be documented by each compression library. + + + + + This interface provides the methods necessary for the to open + and close streams for archives and files. The implementor of this interface can use any + kind of logic to determine what kind of streams to open and where + + + + + Opens the archive stream for reading. + + The zero-based index of the archive to open. + The name of the archive being opened. + Instance of the compression engine doing the operations. + A stream from which archive bytes are read, or null to cancel extraction + of the archive. + + When the first archive in a chain is opened, the name is not yet known, so the + provided value will be an empty string. When opening further archives, the + provided value is the next-archive name stored in the previous archive. This + name is often, but not necessarily, the same as the filename of the archive + package to be opened. + If this method returns null, the archive engine will throw a + FileNotFoundException. + + + + + Closes a stream where an archive package was read. + + The archive number of the stream to close. + The name of the archive being closed. + The stream that was previously returned by + and is now ready to be closed. + + + + Opens a stream for writing extracted file bytes. + + The path of the file within the archive. This is often, but + not necessarily, the same as the relative path of the file outside the archive. + The uncompressed size of the file to be extracted. + The last write time of the file to be extracted. + A stream where extracted file bytes are to be written, or null to skip + extraction of the file and continue to the next file. + + The implementor may use the path, size and date information to dynamically + decide whether or not the file should be extracted. + + + + + Closes a stream where an extracted file was written. + + The path of the file within the archive. + The stream that was previously returned by + and is now ready to be closed. + The attributes of the extracted file. + The last write time of the file. + + The implementor may wish to apply the attributes and date to the newly-extracted file. + + + + + Creates a new ArchiveFileStreamContext with a archive file and + no default directory or file mapping. + + The path to a archive file that will be + created or extracted. + + + + Creates a new ArchiveFileStreamContext with a archive file, default + directory and mapping from internal to external file paths. + + The path to a archive file that will be + created or extracted. + The default root directory where files will be + located, optional. + A mapping from internal file paths to external file + paths, optional. + + If the mapping is not null and a file is not included in the mapping, + the file will be skipped. + If the external path in the mapping is a simple file name or + relative file path, it will be concatenated onto the default directory, + if one was specified. + For more about how the default directory and files mapping are + used, see and + . + + + + + Creates a new ArchiveFileStreamContext with a list of archive files, + a default directory and a mapping from internal to external file paths. + + A list of paths to archive files that will be + created or extracted. + The default root directory where files will be + located, optional. + A mapping from internal file paths to external file + paths, optional. + + When creating chained archives, the list + should include at least enough archives to handle the entire set of + input files, based on the maximum archive size that is passed to the + .. + If the mapping is not null and a file is not included in the mapping, + the file will be skipped. + If the external path in the mapping is a simple file name or + relative file path, it will be concatenated onto the default directory, + if one was specified. + For more about how the default directory and files mapping are used, + see and + . + + + + + Gets the name of the archive with a specified number. + + The 0-based index of the archive within + the chain. + The name of the requested archive. May be an empty string + for non-chained archives, but may never be null. + This method returns the file name of the archive from the + list with the specified index, or an empty + string if the archive number is outside the bounds of the list. The + file name should not include any directory path. + + + + Opens a stream for writing an archive. + + The 0-based index of the archive within + the chain. + The name of the archive that was returned + by . + True if the stream should be truncated when + opened (if it already exists); false if an existing stream is being + re-opened for writing additional data. + Instance of the compression engine + doing the operations. + A writable Stream where the compressed archive bytes will be + written, or null to cancel the archive creation. + + This method opens the file from the list + with the specified index. If the archive number is outside the bounds + of the list, this method returns null. + If the flag is set, this method + will seek to the start of any existing archive in the file, or to the + end of the file if the existing file is not an archive. + + + + + Closes a stream where an archive package was written. + + The 0-based index of the archive within + the chain. + The name of the archive that was previously + returned by . + A stream that was previously returned by + and is now ready to be closed. + + + + Opens a stream to read a file that is to be included in an archive. + + The path of the file within the archive. + The returned attributes of the opened file, + to be stored in the archive. + The returned last-modified time of the + opened file, to be stored in the archive. + A readable Stream where the file bytes will be read from + before they are compressed, or null to skip inclusion of the file and + continue to the next file. + + This method opens a file using the following logic: + + If the and the mapping + are both null, the path is treated as relative to the current directory, + and that file is opened. + If the is not null but the + mapping is null, the path is treated as relative to that directory, and + that file is opened. + If the is null but the + mapping is not null, the path parameter is used as a key into the mapping, + and the resulting value is the file path that is opened, relative to the + current directory (or it may be an absolute path). If no mapping exists, + the file is skipped. + If both the and the + mapping are specified, the path parameter is used as a key into the + mapping, and the resulting value is the file path that is opened, relative + to the specified directory (or it may be an absolute path). If no mapping + exists, the file is skipped. + + + + + + Closes a stream that has been used to read a file. + + The path of the file within the archive; the same as + the path provided when the stream was opened. + A stream that was previously returned by + and is now ready to be closed. + + + + Gets extended parameter information specific to the compression format + being used. + + Name of the option being requested. + Parameters for the option; for per-file options, + the first parameter is typically the internal file path. + Option value, or null to use the default behavior. + + This implementation does not handle any options. Subclasses may override + this method to allow for non-default behavior. + + + + + Opens the archive stream for reading. + + The zero-based index of the archive to + open. + The name of the archive being opened. + Instance of the compression engine + doing the operations. + A stream from which archive bytes are read, or null to cancel + extraction of the archive. + + This method opens the file from the list with + the specified index. If the archive number is outside the bounds of the + list, this method returns null. + If the flag is set, this method will + seek to the start of any existing archive in the file, or to the end of + the file if the existing file is not an archive. + + + + + Closes a stream where an archive was read. + + The archive number of the stream + to close. + The name of the archive being closed. + The stream that was previously returned by + and is now ready to be closed. + + + + Opens a stream for writing extracted file bytes. + + The path of the file within the archive. + The uncompressed size of the file to be + extracted. + The last write time of the file to be + extracted. + A stream where extracted file bytes are to be written, or null + to skip extraction of the file and continue to the next file. + + This method opens a file using the following logic: + + If the and the mapping + are both null, the path is treated as relative to the current directory, + and that file is opened. + If the is not null but the + mapping is null, the path is treated as relative to that directory, and + that file is opened. + If the is null but the + mapping is not null, the path parameter is used as a key into the mapping, + and the resulting value is the file path that is opened, relative to the + current directory (or it may be an absolute path). If no mapping exists, + the file is skipped. + If both the and the + mapping are specified, the path parameter is used as a key into the + mapping, and the resulting value is the file path that is opened, + relative to the specified directory (or it may be an absolute path). + If no mapping exists, the file is skipped. + + If the flag is set, the file + is skipped if a file currently exists in the same path with an equal + or newer write time. + + + + + Closes a stream where an extracted file was written. + + The path of the file within the archive. + The stream that was previously returned by + and is now ready to be closed. + The attributes of the extracted file. + The last write time of the file. + + After closing the extracted file stream, this method applies the date + and attributes to that file. + + + + + Translates an internal file path to an external file path using the + and the mapping, according to + rules documented in and + . + + The path of the file with the archive. + The external path of the file, or null if there is no + valid translation. + + + + Gets or sets the list of archive files that are created or extracted. + + The list of archive files that are created or extracted. + + + + Gets or sets the default root directory where files are located. + + The default root directory where files are located. + + For details about how the default directory is used, + see and . + + + + + Gets or sets the mapping from internal file paths to external file paths. + + A mapping from internal file paths to external file paths. + + For details about how the files mapping is used, + see and . + + + + + Gets or sets a flag that can prevent extracted files from overwriting + newer files that already exist. + + True to prevent overwriting newer files that already exist + during extraction; false to always extract from the archive regardless + of existing files. + + + + Gets or sets a flag that enables creating or extracting an archive + at an offset within an existing file. (This is typically used to open + archive-based self-extracting packages.) + + True to search an existing package file for an archive offset + or the end of the file;/ false to always create or open a plain + archive file. + + + + Stream context used to extract a single file from an archive into a memory stream. + + + + + Creates a new BasicExtractStreamContext that reads from the specified archive stream. + + Archive stream to read from. + + + + Opens the archive stream for reading. Returns a DuplicateStream instance, + so the stream may be virtually opened multiple times. + + The archive number to open (ignored; 0 is assumed). + The name of the archive being opened. + Instance of the compression engine doing the operations. + A stream from which archive bytes are read. + + + + Does *not* close the stream. The archive stream should be managed by + the code that invokes the archive extraction. + + The archive number of the stream to close. + The name of the archive being closed. + The stream being closed. + + + + Opens a stream for writing extracted file bytes. The returned stream is a MemoryStream + instance, so the file is extracted straight into memory. + + Path of the file within the archive. + The uncompressed size of the file to be extracted. + The last write time of the file. + A stream where extracted file bytes are to be written. + + + + Does *not* close the file stream. The file stream is saved in memory so it can + be read later. + + Path of the file within the archive. + The file stream to be closed. + The attributes of the extracted file. + The last write time of the file. + + + + Gets the stream for the extracted file, or null if no file was extracted. + + + + + Base class for an engine capable of packing and unpacking a particular + compressed file format. + + + + + Creates a new instance of the compression engine base class. + + + + + Disposes the compression engine. + + + + + Disposes of resources allocated by the compression engine. + + + + + Creates an archive. + + A context interface to handle opening + and closing of archive and file streams. + The paths of the files in the archive + (not external file paths). + The archive could not be + created. + + The stream context implementation may provide a mapping from the + file paths within the archive to the external file paths. + + + + + Creates an archive or chain of archives. + + A context interface to handle opening + and closing of archive and file streams. + The paths of the files in the archive (not + external file paths). + The maximum number of bytes for one + archive before the contents are chained to the next archive, or zero + for unlimited archive size. + The archive could not be + created. + + The stream context implementation may provide a mapping from the file + paths within the archive to the external file paths. + + + + + Checks whether a Stream begins with a header that indicates + it is a valid archive. + + Stream for reading the archive file. + True if the stream is a valid archive + (with no offset); false otherwise. + + + + Gets the offset of an archive that is positioned 0 or more bytes + from the start of the Stream. + + A stream for reading the archive. + The offset in bytes of the archive, + or -1 if no archive is found in the Stream. + The archive must begin on a 4-byte boundary. + + + + Gets information about all files in an archive stream. + + A stream for reading the archive. + Information about all files in the archive stream. + The stream is not a valid + archive. + + + + Gets information about files in an archive or archive chain. + + A context interface to handle opening + and closing of archive and file streams. + A predicate that can determine + which files to process, optional. + Information about files in the archive stream. + The archive provided + by the stream context is not valid. + + The predicate takes an internal file + path and returns true to include the file or false to exclude it. + + + + + Gets the list of files in an archive Stream. + + A stream for reading the archive. + A list of the paths of all files contained in the + archive. + The stream is not a valid + archive. + + + + Gets the list of files in an archive or archive chain. + + A context interface to handle opening + and closing of archive and file streams. + A predicate that can determine + which files to process, optional. + An array containing the names of all files contained in + the archive or archive chain. + The archive provided + by the stream context is not valid. + + The predicate takes an internal file + path and returns true to include the file or false to exclude it. + + + + + Reads a single file from an archive stream. + + A stream for reading the archive. + The path of the file within the archive + (not the external file path). + A stream for reading the extracted file, or null + if the file does not exist in the archive. + The stream is not a valid + archive. + The entire extracted file is cached in memory, so this + method requires enough free memory to hold the file. + + + + Extracts files from an archive or archive chain. + + A context interface to handle opening + and closing of archive and file streams. + An optional predicate that can determine + which files to process. + The archive provided + by the stream context is not valid. + + The predicate takes an internal file + path and returns true to include the file or false to exclude it. + + + + + Called by sublcasses to distribute a packing or unpacking progress + event to listeners. + + Event details. + + + + Disposes of resources allocated by the compression engine. + + If true, the method has been called + directly or indirectly by a user's code, so managed and unmanaged + resources will be disposed. If false, the method has been called by + the runtime from inside the finalizer, and only unmanaged resources + will be disposed. + + + + Compresion utility function for converting old-style + date and time values to a DateTime structure. + + + + + Compresion utility function for converting a DateTime structure + to old-style date and time values. + + + + + Occurs when the compression engine reports progress in packing + or unpacking an archive. + + + + + + Gets or sets a flag indicating whether temporary files are created + and used during compression. + + True if temporary files are used; false if compression is done + entirely in-memory. + The value of this property is true by default. Using temporary + files can greatly reduce the memory requirement of compression, + especially when compressing large archives. However, setting this property + to false may yield slightly better performance when creating small + archives. Or it may be necessary if the process does not have sufficient + privileges to create temporary files. + + + + Compression level to use when compressing files. + + A compression level ranging from minimum to maximum compression, + or no compression. + + + + Specifies the compression level ranging from minimum compresion to + maximum compression, or no compression at all. + + + Although only four values are enumerated, any integral value between + and can also be used. + + + + Do not compress files, only store. + + + Minimum compression; fastest. + + + A compromize between speed and compression efficiency. + + + Maximum compression; slowest. + + + + Wraps a source stream and carries additional items that are disposed when the stream is closed. + + + + + Creates a new a cargo stream. + + source of the stream + List of additional items that are disposed when the stream is closed. + The order of the list is the order in which the items are disposed. + + + + Flushes the source stream. + + + + + Sets the length of the source stream. + + The desired length of the stream in bytes. + + + + Closes the source stream and also closes the additional objects that are carried. + + + + + Reads from the source stream. + + An array of bytes. When this method returns, the buffer + contains the specified byte array with the values between offset and + (offset + count - 1) replaced by the bytes read from the source. + The zero-based byte offset in buffer at which to begin + storing the data read from the stream. + The maximum number of bytes to be read from the stream. + The total number of bytes read into the buffer. This can be less + than the number of bytes requested if that many bytes are not currently available, + or zero (0) if the end of the stream has been reached. + + + + Writes to the source stream. + + An array of bytes. This method copies count + bytes from buffer to the stream. + The zero-based byte offset in buffer at which + to begin copying bytes to the stream. + The number of bytes to be written to the stream. + + + + Changes the position of the source stream. + + A byte offset relative to the origin parameter. + A value of type SeekOrigin indicating the reference + point used to obtain the new position. + The new position within the stream. + + + + Gets the source stream of the cargo stream. + + + + + Gets the list of additional items that are disposed when the stream is closed. + The order of the list is the order in which the items are disposed. The contents can be modified any time. + + + + + Gets a value indicating whether the source stream supports reading. + + true if the stream supports reading; otherwise, false. + + + + Gets a value indicating whether the source stream supports writing. + + true if the stream supports writing; otherwise, false. + + + + Gets a value indicating whether the source stream supports seeking. + + true if the stream supports seeking; otherwise, false. + + + + Gets the length of the source stream. + + + + + Gets or sets the position of the source stream. + + + + + Duplicates a source stream by maintaining a separate position. + + + WARNING: duplicate streams are not thread-safe with respect to each other or the original stream. + If multiple threads use duplicate copies of the same stream, they must synchronize for any operations. + + + + + Creates a new duplicate of a stream. + + source of the duplicate + + + + Retrieves the original stream from a possible duplicate stream. + + Possible duplicate stream. + If the stream is a DuplicateStream, returns + the duplicate's source; otherwise returns the same stream. + + + + Flushes the source stream. + + + + + Sets the length of the source stream. + + The desired length of the stream in bytes. + + + + Closes the underlying stream, effectively closing ALL duplicates. + + + + + Reads from the source stream while maintaining a separate position + and not impacting the source stream's position. + + An array of bytes. When this method returns, the buffer + contains the specified byte array with the values between offset and + (offset + count - 1) replaced by the bytes read from the current source. + The zero-based byte offset in buffer at which to begin + storing the data read from the current stream. + The maximum number of bytes to be read from the current stream. + The total number of bytes read into the buffer. This can be less + than the number of bytes requested if that many bytes are not currently available, + or zero (0) if the end of the stream has been reached. + + + + Writes to the source stream while maintaining a separate position + and not impacting the source stream's position. + + An array of bytes. This method copies count + bytes from buffer to the current stream. + The zero-based byte offset in buffer at which + to begin copying bytes to the current stream. + The number of bytes to be written to the + current stream. + + + + Changes the position of this stream without impacting the + source stream's position. + + A byte offset relative to the origin parameter. + A value of type SeekOrigin indicating the reference + point used to obtain the new position. + The new position within the current stream. + + + + Gets the original stream that was used to create the duplicate. + + + + + Gets a value indicating whether the source stream supports reading. + + true if the stream supports reading; otherwise, false. + + + + Gets a value indicating whether the source stream supports writing. + + true if the stream supports writing; otherwise, false. + + + + Gets a value indicating whether the source stream supports seeking. + + true if the stream supports seeking; otherwise, false. + + + + Gets the length of the source stream. + + + + + Gets or sets the position of the current stream, + ignoring the position of the source stream. + + + + + Wraps a source stream and offsets all read/write/seek calls by a given value. + + + This class is used to trick archive an packing or unpacking process + into reading or writing at an offset into a file, primarily for + self-extracting packages. + + + + + Creates a new OffsetStream instance from a source stream + and using a specified offset. + + Underlying stream for which all calls will be offset. + Positive or negative number of bytes to offset. + + + + Reads a sequence of bytes from the source stream and advances + the position within the stream by the number of bytes read. + + An array of bytes. When this method returns, the buffer + contains the specified byte array with the values between offset and + (offset + count - 1) replaced by the bytes read from the current source. + The zero-based byte offset in buffer at which to begin + storing the data read from the current stream. + The maximum number of bytes to be read from the current stream. + The total number of bytes read into the buffer. This can be less + than the number of bytes requested if that many bytes are not currently available, + or zero (0) if the end of the stream has been reached. + + + + Writes a sequence of bytes to the source stream and advances the + current position within this stream by the number of bytes written. + + An array of bytes. This method copies count + bytes from buffer to the current stream. + The zero-based byte offset in buffer at which + to begin copying bytes to the current stream. + The number of bytes to be written to the + current stream. + + + + Reads a byte from the stream and advances the position within the + source stream by one byte, or returns -1 if at the end of the stream. + + The unsigned byte cast to an Int32, or -1 if at the + end of the stream. + + + + Writes a byte to the current position in the source stream and + advances the position within the stream by one byte. + + The byte to write to the stream. + + + + Flushes the source stream. + + + + + Sets the position within the current stream, which is + equal to the position within the source stream minus the offset. + + A byte offset relative to the origin parameter. + A value of type SeekOrigin indicating + the reference point used to obtain the new position. + The new position within the current stream. + + + + Sets the effective length of the stream, which is equal to + the length of the source stream minus the offset. + + The desired length of the + current stream in bytes. + + + + Closes the underlying stream. + + + + + Gets the underlying stream that this OffsetStream calls into. + + + + + Gets the number of bytes to offset all calls before + redirecting to the underlying stream. + + + + + Gets a value indicating whether the source stream supports reading. + + true if the stream supports reading; otherwise, false. + + + + Gets a value indicating whether the source stream supports writing. + + true if the stream supports writing; otherwise, false. + + + + Gets a value indicating whether the source stream supports seeking. + + true if the stream supports seeking; otherwise, false. + + + + Gets the effective length of the stream, which is equal to + the length of the source stream minus the offset. + + + + + Gets or sets the effective position of the stream, which + is equal to the position of the source stream minus the offset. + + + + + Distribution specific strings. + + + + + News URL for the distribution. + + + + + Short product name for the distribution. + + + + + Support URL for the distribution. + + + + + Telemetry URL format for the distribution. + + +
+
diff --git a/TemplatePackageFix/TemplatePackageFix.csproj b/TemplatePackageFix/TemplatePackageFix.csproj new file mode 100644 index 0000000..3c1ec03 --- /dev/null +++ b/TemplatePackageFix/TemplatePackageFix.csproj @@ -0,0 +1,114 @@ + + + + + Debug + AnyCPU + {71E359DE-5694-43B6-BB0A-F64E796E1655} + Exe + Properties + Plumsail.TemplatePackageFix + TemplatePackageFix + v4.5 + 512 + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 1 + 1.0.0.%2a + false + true + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Plumsail.TemplatePackageFix.Program + + + 7E2FE55F33810568A0571C1C9C199196AEF24CA9 + + + TemplatePackageFix_TemporaryKey.pfx + + + true + + + true + + + + Reference\Microsoft.Deployment.Compression.dll + + + Reference\Microsoft.Deployment.Compression.Cab.dll + + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + \ No newline at end of file diff --git a/TemplatePackageFixSolution.sln b/TemplatePackageFixSolution.sln new file mode 100644 index 0000000..423990b --- /dev/null +++ b/TemplatePackageFixSolution.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplatePackageFix", "TemplatePackageFix\TemplatePackageFix.csproj", "{71E359DE-5694-43B6-BB0A-F64E796E1655}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71E359DE-5694-43B6-BB0A-F64E796E1655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71E359DE-5694-43B6-BB0A-F64E796E1655}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71E359DE-5694-43B6-BB0A-F64E796E1655}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71E359DE-5694-43B6-BB0A-F64E796E1655}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal