1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
// 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.Harvesters.Extensibility
{
using System;
using System.Collections.Generic;
using System.Text;
using Wix = WixToolset.Harvesters.Serialize;
/// <summary>
/// The base mutator extension. Any of these methods can be overridden to change
/// the behavior of the mutator.
/// </summary>
public abstract class BaseMutatorExtension : IMutatorExtension
{
/// <summary>
/// Gets or sets the mutator core for the extension.
/// </summary>
/// <value>The mutator core for the extension.</value>
public IHarvesterCore Core { get; set; }
/// <summary>
/// Gets the sequence of the extension.
/// </summary>
/// <value>The sequence of the extension.</value>
public abstract int Sequence { get; }
/// <summary>
/// Mutate a WiX document.
/// </summary>
/// <param name="wix">The Wix document element.</param>
public virtual void Mutate(Wix.Wix wix)
{
}
/// <summary>
/// Mutate a WiX document as a string.
/// </summary>
/// <param name="wixString">The Wix document element as a string.</param>
/// <returns>The mutated Wix document as a string.</returns>
public virtual string Mutate(string wixString)
{
return wixString;
}
/// <summary>
/// Generate unique MSI identifiers.
/// </summary>
protected class IdentifierGenerator
{
/// <summary>
///
/// </summary>
public const int MaxProductIdentifierLength = 72;
/// <summary>
///
/// </summary>
public const int MaxModuleIdentifierLength = 35;
private string baseName;
private int maxLength;
private Dictionary<string, object> existingIdentifiers;
private Dictionary<string, object> possibleIdentifiers;
private IHarvesterCore harvesterCore;
/// <summary>
/// Instantiate a new IdentifierGenerator.
/// </summary>
/// <param name="baseName">The base resource name to use if a resource name contains no usable characters.</param>
/// <param name="harvesterCore"></param>
public IdentifierGenerator(string baseName, IHarvesterCore harvesterCore)
{
this.baseName = baseName;
this.maxLength = IdentifierGenerator.MaxProductIdentifierLength;
this.existingIdentifiers = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
this.possibleIdentifiers = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
this.harvesterCore = harvesterCore;
}
/// <summary>
/// Gets or sets the maximum length for generated identifiers.
/// </summary>
/// <value>Maximum length for generated identifiers. (Default is 72.)</value>
public int MaxIdentifierLength
{
get { return this.maxLength; }
set { this.maxLength = value; }
}
/// <summary>
/// Index an existing identifier for collision detection.
/// </summary>
/// <param name="identifier">The identifier.</param>
public void IndexExistingIdentifier(string identifier)
{
if (null == identifier)
{
throw new ArgumentNullException("identifier");
}
this.existingIdentifiers[identifier] = null;
}
/// <summary>
/// Index a resource name for collision detection.
/// </summary>
/// <param name="name">The resource name.</param>
public void IndexName(string name)
{
if (null == name)
{
throw new ArgumentNullException("name");
}
string identifier = this.CreateIdentifier(name, 0);
if (this.possibleIdentifiers.ContainsKey(identifier))
{
this.possibleIdentifiers[identifier] = String.Empty;
}
else
{
this.possibleIdentifiers.Add(identifier, null);
}
}
/// <summary>
/// Get the identifier for the given resource name.
/// </summary>
/// <param name="name">The resource name.</param>
/// <returns>A legal MSI identifier.</returns>
public string GetIdentifier(string name)
{
if (null == name)
{
throw new ArgumentNullException("name");
}
for (int i = 0; i <= Int32.MaxValue; i++)
{
string identifier = this.CreateIdentifier(name, i);
if (this.existingIdentifiers.ContainsKey(identifier) || // already used
(0 == i && 0 != this.possibleIdentifiers.Count && null != this.possibleIdentifiers[identifier]) || // needs an index because its duplicated
(0 != i && this.possibleIdentifiers.ContainsKey(identifier))) // collides with another possible identifier
{
continue;
}
else // use this identifier
{
this.existingIdentifiers.Add(identifier, null);
return identifier;
}
}
throw new InvalidOperationException("Could not find a unique identifier for the given resource name.");
}
/// <summary>
/// Create a legal MSI identifier from a resource name and an index.
/// </summary>
/// <param name="name">The name of the resource for which an identifier should be created.</param>
/// <param name="index">An index to append to the end of the identifier to make it unique.</param>
/// <returns>A legal MSI identifier.</returns>
public string CreateIdentifier(string name, int index)
{
if (null == name)
{
throw new ArgumentNullException("name");
}
StringBuilder identifier = new StringBuilder();
// Convert the name to a standard MSI identifier
identifier.Append(this.harvesterCore.CreateIdentifierFromFilename(name));
// no legal identifier characters were found, use the base id instead
if (0 == identifier.Length)
{
identifier.Append(this.baseName);
}
// truncate the identifier if it's too long (reserve 3 characters for up to 99 collisions)
int adjustedMaxLength = this.MaxIdentifierLength - (index != 0 ? 3 : 0);
if (adjustedMaxLength < identifier.Length)
{
identifier.Length = adjustedMaxLength;
}
// if the index is not zero, then append it to the identifier name
if (0 != index)
{
identifier.AppendFormat("_{0}", index);
}
return identifier.ToString();
}
}
}
}
|