aboutsummaryrefslogtreecommitdiff
path: root/src/tools/Dtf/WiFile/WiFile.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/Dtf/WiFile/WiFile.cs')
-rw-r--r--src/tools/Dtf/WiFile/WiFile.cs147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/tools/Dtf/WiFile/WiFile.cs b/src/tools/Dtf/WiFile/WiFile.cs
new file mode 100644
index 00000000..1e5c80df
--- /dev/null
+++ b/src/tools/Dtf/WiFile/WiFile.cs
@@ -0,0 +1,147 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Reflection;
6using System.Collections;
7using System.Collections.Generic;
8using System.Diagnostics.CodeAnalysis;
9using System.Globalization;
10using System.Text.RegularExpressions;
11using WixToolset.Dtf.WindowsInstaller;
12using WixToolset.Dtf.WindowsInstaller.Package;
13
14[assembly: AssemblyDescription("Windows Installer package file extraction and update tool")]
15
16
17/// <summary>
18/// Shows sample use of the InstallPackage class.
19/// </summary>
20public class WiFile
21{
22 public static void Usage(TextWriter w)
23 {
24 w.WriteLine("Usage: WiFile.exe package.msi /l [filename,filename2,...]");
25 w.WriteLine("Usage: WiFile.exe package.msi /x [filename,filename2,...]");
26 w.WriteLine("Usage: WiFile.exe package.msi /u [filename,filename2,...]");
27 w.WriteLine();
28 w.WriteLine("Lists (/l), extracts (/x) or updates (/u) files in an MSI or MSM.");
29 w.WriteLine("Files are extracted using their source path relative to the package.");
30 w.WriteLine("Specified filenames do not include paths.");
31 w.WriteLine("Filenames may be a pattern such as *.exe or file?.dll");
32 }
33
34 [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
35 public static int Main(string[] args)
36 {
37 if(!(args.Length == 2 || args.Length == 3))
38 {
39 Usage(Console.Out);
40 return -1;
41 }
42
43 string msiFile = args[0];
44
45 string option = args[1].ToLowerInvariant();
46 if(option.StartsWith("-", StringComparison.Ordinal)) option = "/" + option.Substring(1);
47
48 string[] fileNames = null;
49 if(args.Length == 3)
50 {
51 fileNames = args[2].Split(',');
52 }
53
54 try
55 {
56 switch(option)
57 {
58 case "/l":
59 using(InstallPackage pkg = new InstallPackage(msiFile, DatabaseOpenMode.ReadOnly))
60 {
61 pkg.Message += new InstallPackageMessageHandler(Console.WriteLine);
62 IEnumerable<string> fileKeys = (fileNames != null ? FindFileKeys(pkg, fileNames) : pkg.Files.Keys);
63
64 foreach(string fileKey in fileKeys)
65 {
66 Console.WriteLine(pkg.Files[fileKey]);
67 }
68 }
69 break;
70
71 case "/x":
72 using(InstallPackage pkg = new InstallPackage(msiFile, DatabaseOpenMode.ReadOnly))
73 {
74 pkg.Message += new InstallPackageMessageHandler(Console.WriteLine);
75 ICollection<string> fileKeys = FindFileKeys(pkg, fileNames);
76
77 pkg.ExtractFiles(fileKeys);
78 }
79 break;
80
81 case "/u":
82 using(InstallPackage pkg = new InstallPackage(msiFile, DatabaseOpenMode.Transact))
83 {
84 pkg.Message += new InstallPackageMessageHandler(Console.WriteLine);
85 ICollection<string> fileKeys = FindFileKeys(pkg, fileNames);
86
87 pkg.UpdateFiles(fileKeys);
88 pkg.Commit();
89 }
90 break;
91
92 default:
93 Usage(Console.Out);
94 return -1;
95 }
96 }
97 catch(InstallerException iex)
98 {
99 Console.WriteLine("Error: " + iex.Message);
100 return iex.ErrorCode != 0 ? iex.ErrorCode : 1;
101 }
102 catch(FileNotFoundException fnfex)
103 {
104 Console.WriteLine(fnfex.Message);
105 return 2;
106 }
107 catch(Exception ex)
108 {
109 Console.WriteLine("Error: " + ex.Message);
110 return 1;
111 }
112 return 0;
113 }
114
115 static ICollection<string> FindFileKeys(InstallPackage pkg, ICollection<string> fileNames)
116 {
117 List<string> fileKeys = null;
118 if(fileNames != null)
119 {
120 fileKeys = new List<string>();
121 foreach(string fileName in fileNames)
122 {
123 string[] foundFileKeys = null;
124 if(fileName.IndexOfAny(new char[] { '*', '?' }) >= 0)
125 {
126 foundFileKeys = pkg.FindFiles(FilePatternToRegex(fileName));
127 }
128 else
129 {
130 foundFileKeys = pkg.FindFiles(fileName);
131 }
132 fileKeys.AddRange(foundFileKeys);
133 }
134 if(fileKeys.Count == 0)
135 {
136 throw new FileNotFoundException("Files not found in package.");
137 }
138 }
139 return fileKeys;
140 }
141
142 static Regex FilePatternToRegex(string pattern)
143 {
144 return new Regex("^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$",
145 RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
146 }
147}