Remove dead code
Rob Mensching committed
Jun 10, 2020 at 07:44 UTC
052cc1fac3bf9b6ff2b1cb264410d76d9f35f21e
2 files changed
-1510
src/WixToolset.Core.WindowsInstaller/Patch.cs
deleted
-1239
@@ -1,1239 +0,0 @@
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
-
3
-#if DELETE
4
-
5
-namespace WixToolset.Data
6
-{
7
- using System;
8
- using System.Collections.Generic;
9
- using System.Diagnostics.CodeAnalysis;
10
- using WixToolset.Core.WindowsInstaller;
11
- using WixToolset.Data.WindowsInstaller;
12
- using WixToolset.Extensibility;
13
-
14
- /// <summary>
15
- /// Contains output tables and logic for building an MSP package.
16
- /// </summary>
17
- public class Patch
18
- {
19
- private List<IInspectorExtension> inspectorExtensions;
20
- private WindowsInstallerData patch;
21
- private TableDefinitionCollection tableDefinitions;
22
-
23
- public WindowsInstallerData PatchOutput
24
- {
25
- get { return this.patch; }
26
- }
27
-
28
- public Patch()
29
- {
30
- this.inspectorExtensions = new List<IInspectorExtension>();
31
- this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandardInternal.GetTableDefinitions());
32
- }
33
-
34
- /// <summary>
35
- /// Adds an extension.
36
- /// </summary>
37
- /// <param name="extension">The extension to add.</param>
38
- public void AddExtension(IInspectorExtension extension)
39
- {
40
- this.inspectorExtensions.Add(extension);
41
- }
42
-
43
- public void Load(string patchPath)
44
- {
45
- this.patch = WindowsInstallerData.Load(patchPath, false);
46
- }
47
-
48
- /// <summary>
49
- /// Include transforms in a patch.
50
- /// </summary>
51
- /// <param name="transforms">List of transforms to attach.</param>
52
- [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")]
53
- public void AttachTransforms(List<PatchTransform> transforms)
54
- {
55
- // Track if at least one transform gets attached.
56
- bool attachedTransform = false;
57
-
58
- if (transforms == null || transforms.Count == 0)
59
- {
60
- throw new WixException(WixErrors.PatchWithoutTransforms());
61
- }
62
-
63
- // Get the patch id from the WixPatchId table.
64
- string patchId = null;
65
- string clientPatchId = null;
66
- Table wixPatchIdTable = this.patch.Tables["WixPatchId"];
67
- if (null != wixPatchIdTable && 0 < wixPatchIdTable.Rows.Count)
68
- {
69
- Row patchIdRow = wixPatchIdTable.Rows[0];
70
- if (null != patchIdRow)
71
- {
72
- patchId = patchIdRow[0].ToString();
73
- clientPatchId = patchIdRow[1].ToString();
74
- }
75
- }
76
-
77
- if (null == patchId)
78
- {
79
- throw new WixException(WixErrors.ExpectedPatchIdInWixMsp());
80
- }
81
- if (null == clientPatchId)
82
- {
83
- throw new WixException(WixErrors.ExpectedClientPatchIdInWixMsp());
84
- }
85
-
86
- // enumerate patch.Media to map diskId to Media row
87
- Table patchMediaTable = patch.Tables["Media"];
88
-
89
- if (null == patchMediaTable || patchMediaTable.Rows.Count == 0)
90
- {
91
- throw new WixException(WixErrors.ExpectedMediaRowsInWixMsp());
92
- }
93
-
94
- Hashtable mediaRows = new Hashtable(patchMediaTable.Rows.Count);
95
- foreach (MediaRow row in patchMediaTable.Rows)
96
- {
97
- int media = row.DiskId;
98
- mediaRows[media] = row;
99
- }
100
-
101
- // enumerate patch.WixPatchBaseline to map baseline to diskId
102
- Table patchBaselineTable = patch.Tables["WixPatchBaseline"];
103
-
104
- int numPatchBaselineRows = (null != patchBaselineTable) ? patchBaselineTable.Rows.Count : 0;
105
-
106
- Hashtable baselineMedia = new Hashtable(numPatchBaselineRows);
107
- if (patchBaselineTable != null)
108
- {
109
- foreach (Row row in patchBaselineTable.Rows)
110
- {
111
- string baseline = (string)row[0];
112
- int media = (int)row[1];
113
- int validationFlags = (int)row[2];
114
- if (baselineMedia.Contains(baseline))
115
- {
116
- this.OnMessage(WixErrors.SamePatchBaselineId(row.SourceLineNumbers, baseline));
117
- }
118
- baselineMedia[baseline] = new int[] { media, validationFlags };
119
- }
120
- }
121
-
122
- // populate MSP summary information
123
- Table patchSummaryInfo = patch.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
124
-
125
- // Remove properties that will be calculated or are reserved.
126
- for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--)
127
- {
128
- Row row = patchSummaryInfo.Rows[i];
129
- switch ((SummaryInformation.Patch)row[0])
130
- {
131
- case SummaryInformation.Patch.ProductCodes:
132
- case SummaryInformation.Patch.TransformNames:
133
- case SummaryInformation.Patch.PatchCode:
134
- case SummaryInformation.Patch.InstallerRequirement:
135
- case SummaryInformation.Patch.Reserved11:
136
- case SummaryInformation.Patch.Reserved14:
137
- case SummaryInformation.Patch.Reserved16:
138
- patchSummaryInfo.Rows.RemoveAt(i);
139
- break;
140
- }
141
- }
142
-
143
- // Index remaining summary properties.
144
- SummaryInfoRowCollection summaryInfo = new SummaryInfoRowCollection(patchSummaryInfo);
145
-
146
- // PID_CODEPAGE
147
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.CodePage))
148
- {
149
- // set the code page by default to the same code page for the
150
- // string pool in the database.
151
- Row codePage = patchSummaryInfo.CreateRow(null);
152
- codePage[0] = (int)SummaryInformation.Patch.CodePage;
153
- codePage[1] = this.patch.Codepage.ToString(CultureInfo.InvariantCulture);
154
- }
155
-
156
- // GUID patch code for the patch.
157
- Row revisionRow = patchSummaryInfo.CreateRow(null);
158
- revisionRow[0] = (int)SummaryInformation.Patch.PatchCode;
159
- revisionRow[1] = patchId;
160
-
161
- // Indicates the minimum Windows Installer version that is required to install the patch.
162
- Row wordsRow = patchSummaryInfo.CreateRow(null);
163
- wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement;
164
- wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString(CultureInfo.InvariantCulture);
165
-
166
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.Security))
167
- {
168
- Row security = patchSummaryInfo.CreateRow(null);
169
- security[0] = (int)SummaryInformation.Patch.Security;
170
- security[1] = "4"; // Read-only enforced
171
- }
172
-
173
- // use authored comments or default to DisplayName (required)
174
- string comments = null;
175
-
176
- Table msiPatchMetadataTable = patch.Tables["MsiPatchMetadata"];
177
- Hashtable metadataTable = new Hashtable();
178
- if (null != msiPatchMetadataTable)
179
- {
180
- foreach (Row row in msiPatchMetadataTable.Rows)
181
- {
182
- metadataTable.Add(row.Fields[1].Data.ToString(), row.Fields[2].Data.ToString());
183
- }
184
-
185
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.Title) && metadataTable.Contains("DisplayName"))
186
- {
187
- string displayName = (string)metadataTable["DisplayName"];
188
-
189
- Row title = patchSummaryInfo.CreateRow(null);
190
- title[0] = (int)SummaryInformation.Patch.Title;
191
- title[1] = displayName;
192
-
193
- // default comments use DisplayName as-is (no loc)
194
- comments = displayName;
195
- }
196
-
197
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.CodePage) && metadataTable.Contains("CodePage"))
198
- {
199
- Row codePage = patchSummaryInfo.CreateRow(null);
200
- codePage[0] = (int)SummaryInformation.Patch.CodePage;
201
- codePage[1] = metadataTable["CodePage"];
202
- }
203
-
204
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.PackageName) && metadataTable.Contains("Description"))
205
- {
206
- Row subject = patchSummaryInfo.CreateRow(null);
207
- subject[0] = (int)SummaryInformation.Patch.PackageName;
208
- subject[1] = metadataTable["Description"];
209
- }
210
-
211
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.Manufacturer) && metadataTable.Contains("ManufacturerName"))
212
- {
213
- Row author = patchSummaryInfo.CreateRow(null);
214
- author[0] = (int)SummaryInformation.Patch.Manufacturer;
215
- author[1] = metadataTable["ManufacturerName"];
216
- }
217
- }
218
-
219
- // special metadata marshalled through the build
220
- Table wixPatchMetadataTable = patch.Tables["WixPatchMetadata"];
221
- Hashtable wixMetadataTable = new Hashtable();
222
- if (null != wixPatchMetadataTable)
223
- {
224
- foreach (Row row in wixPatchMetadataTable.Rows)
225
- {
226
- wixMetadataTable.Add(row.Fields[0].Data.ToString(), row.Fields[1].Data.ToString());
227
- }
228
-
229
- if (wixMetadataTable.Contains("Comments"))
230
- {
231
- comments = (string)wixMetadataTable["Comments"];
232
- }
233
- }
234
-
235
- // write the package comments to summary info
236
- if (!summaryInfo.Contains((int)SummaryInformation.Patch.Comments) && null != comments)
237
- {
238
- Row commentsRow = patchSummaryInfo.CreateRow(null);
239
- commentsRow[0] = (int)SummaryInformation.Patch.Comments;
240
- commentsRow[1] = comments;
241
- }
242
-
243
- // enumerate transforms
244
- Dictionary<string, object> productCodes = new Dictionary<string, object>();
245
- ArrayList transformNames = new ArrayList();
246
- ArrayList validTransform = new ArrayList();
247
- int transformCount = 0;
248
- foreach (PatchTransform mainTransform in transforms)
249
- {
250
- string baseline = null;
251
- int media = -1;
252
- int validationFlags = 0;
253
-
254
- if (baselineMedia.Contains(mainTransform.Baseline))
255
- {
256
- int[] baselineData = (int[])baselineMedia[mainTransform.Baseline];
257
- int newMedia = baselineData[0];
258
- if (media != -1 && media != newMedia)
259
- {
260
- throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_TransformAuthoredIntoMultipleMedia, media, newMedia));
261
- }
262
- baseline = mainTransform.Baseline;
263
- media = newMedia;
264
- validationFlags = baselineData[1];
265
- }
266
-
267
- if (media == -1)
268
- {
269
- // transform's baseline not attached to any Media
270
- continue;
271
- }
272
-
273
- Table patchRefTable = patch.Tables["WixPatchRef"];
274
- if (patchRefTable != null && patchRefTable.Rows.Count > 0)
275
- {
276
- if (!Patch.ReduceTransform(mainTransform.Transform, patchRefTable))
277
- {
278
- // transform has none of the content authored into this patch
279
- continue;
280
- }
281
- }
282
-
283
- // Validate the transform doesn't break any patch specific rules.
284
- mainTransform.Validate();
285
-
286
- // ensure consistent File.Sequence within each Media
287
- MediaRow mediaRow = (MediaRow)mediaRows[media];
288
-
289
- // Ensure that files are sequenced after the last file in any transform.
290
- Table transformMediaTable = mainTransform.Transform.Tables["Media"];
291
- if (null != transformMediaTable && 0 < transformMediaTable.Rows.Count)
292
- {
293
- foreach (MediaRow transformMediaRow in transformMediaTable.Rows)
294
- {
295
- if (mediaRow.LastSequence < transformMediaRow.LastSequence)
296
- {
297
- // The Binder will pre-increment the sequence.
298
- mediaRow.LastSequence = transformMediaRow.LastSequence;
299
- }
300
- }
301
- }
302
-
303
- // Use the Media/@DiskId if greater for backward compatibility.
304
- if (mediaRow.LastSequence < mediaRow.DiskId)
305
- {
306
- mediaRow.LastSequence = mediaRow.DiskId;
307
- }
308
-
309
- // ignore media table from transform.
310
- mainTransform.Transform.Tables.Remove("Media");
311
- mainTransform.Transform.Tables.Remove("WixMedia");
312
- mainTransform.Transform.Tables.Remove("MsiDigitalSignature");
313
-
314
- string productCode;
315
- Output pairedTransform = this.BuildPairedTransform(patchId, clientPatchId, mainTransform.Transform, mediaRow, validationFlags, out productCode);
316
- productCodes[productCode] = null;
317
- DictionaryEntry entry = new DictionaryEntry();
318
- entry.Key = productCode;
319
- entry.Value = mainTransform.Transform;
320
- validTransform.Add(entry);
321
-
322
- // attach these transforms to the patch object
323
- // TODO: is this an acceptable way to auto-generate transform stream names?
324
- string transformName = baseline + "." + (++transformCount).ToString(CultureInfo.InvariantCulture);
325
- patch.SubStorages.Add(new SubStorage(transformName, mainTransform.Transform));
326
- patch.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform));
327
- transformNames.Add(":" + transformName);
328
- transformNames.Add(":#" + transformName);
329
- attachedTransform = true;
330
- }
331
-
332
- if (!attachedTransform)
333
- {
334
- throw new WixException(WixErrors.PatchWithoutValidTransforms());
335
- }
336
-
337
- // Validate that a patch authored as removable is actually removable
338
- if (metadataTable.Contains("AllowRemoval"))
339
- {
340
- if ("1" == metadataTable["AllowRemoval"].ToString())
341
- {
342
- ArrayList tables = Patch.GetPatchUninstallBreakingTables();
343
- bool result = true;
344
- foreach (DictionaryEntry entry in validTransform)
345
- {
346
- result &= this.CheckUninstallableTransform(entry.Key.ToString(), (Output)entry.Value, tables);
347
- }
348
-
349
- if (!result)
350
- {
351
- throw new WixException(WixErrors.PatchNotRemovable());
352
- }
353
- }
354
- }
355
-
356
- // Finish filling tables with transform-dependent data.
357
- // Semicolon delimited list of the product codes that can accept the patch.
358
- Table wixPatchTargetTable = patch.Tables["WixPatchTarget"];
359
- if (null != wixPatchTargetTable)
360
- {
361
- Dictionary<string, object> targets = new Dictionary<string, object>();
362
- bool replace = true;
363
- foreach (Row wixPatchTargetRow in wixPatchTargetTable.Rows)
364
- {
365
- string target = wixPatchTargetRow[0].ToString();
366
- if (0 == String.CompareOrdinal("*", target))
367
- {
368
- replace = false;
369
- }
370
- else
371
- {
372
- targets[target] = null;
373
- }
374
- }
375
-
376
- // Replace the target ProductCodes with the authored list.
377
- if (replace)
378
- {
379
- productCodes = targets;
380
- }
381
- else
382
- {
383
- // Copy the authored target ProductCodes into the list.
384
- foreach (string target in targets.Keys)
385
- {
386
- productCodes[target] = null;
387
- }
388
- }
389
- }
390
-
391
- string[] uniqueProductCodes = new string[productCodes.Keys.Count];
392
- productCodes.Keys.CopyTo(uniqueProductCodes, 0);
393
-
394
- Row templateRow = patchSummaryInfo.CreateRow(null);
395
- templateRow[0] = (int)SummaryInformation.Patch.ProductCodes;
396
- templateRow[1] = String.Join(";", uniqueProductCodes);
397
-
398
- // Semicolon delimited list of transform substorage names in the order they are applied.
399
- Row savedbyRow = patchSummaryInfo.CreateRow(null);
400
- savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames;
401
- savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string)));
402
- }
403
-
404
- /// <summary>
405
- /// Ensure transform is uninstallable.
406
- /// </summary>
407
- /// <param name="productCode">Product code in transform.</param>
408
- /// <param name="transform">Transform generated by torch.</param>
409
- /// <param name="tables">Tables to be checked</param>
410
- /// <returns>True if the transform is uninstallable</returns>
411
- private bool CheckUninstallableTransform(string productCode, Output transform, ArrayList tables)
412
- {
413
- bool ret = true;
414
- foreach (string table in tables)
415
- {
416
- Table wixTable = transform.Tables[table];
417
- if (null != wixTable)
418
- {
419
- foreach (Row row in wixTable.Rows)
420
- {
421
- if (row.Operation == RowOperation.Add)
422
- {
423
- ret = false;
424
- string primaryKey = row.GetPrimaryKey('/');
425
- if (null == primaryKey)
426
- {
427
- primaryKey = string.Empty;
428
- }
429
- this.OnMessage(WixErrors.NewRowAddedInTable(row.SourceLineNumbers, productCode, wixTable.Name, primaryKey));
430
- }
431
- }
432
- }
433
- }
434
-
435
- return ret;
436
- }
437
-
438
- /// <summary>
439
- /// Tables affect patch uninstall.
440
- /// </summary>
441
- /// <returns>list of tables to be checked</returns>
442
- private static ArrayList GetPatchUninstallBreakingTables()
443
- {
444
- ArrayList tables = new ArrayList();
445
- tables.Add("AppId");
446
- tables.Add("BindImage");
447
- tables.Add("Class");
448
- tables.Add("Complus");
449
- tables.Add("CreateFolder");
450
- tables.Add("DuplicateFile");
451
- tables.Add("Environment");
452
- tables.Add("Extension");
453
- tables.Add("Font");
454
- tables.Add("IniFile");
455
- tables.Add("IsolatedComponent");
456
- tables.Add("LockPermissions");
457
- tables.Add("MIME");
458
- tables.Add("MoveFile");
459
- tables.Add("MsiLockPermissionsEx");
460
- tables.Add("MsiServiceConfig");
461
- tables.Add("MsiServiceConfigFailureActions");
462
- tables.Add("ODBCAttribute");
463
- tables.Add("ODBCDataSource");
464
- tables.Add("ODBCDriver");
465
- tables.Add("ODBCSourceAttribute");
466
- tables.Add("ODBCTranslator");
467
- tables.Add("ProgId");
468
- tables.Add("PublishComponent");
469
- tables.Add("RemoveIniFile");
470
- tables.Add("SelfReg");
471
- tables.Add("ServiceControl");
472
- tables.Add("ServiceInstall");
473
- tables.Add("TypeLib");
474
- tables.Add("Verb");
475
-
476
- return tables;
477
- }
478
-
479
- /// <summary>
480
- /// Reduce the transform according to the patch references.
481
- /// </summary>
482
- /// <param name="transform">transform generated by torch.</param>
483
- /// <param name="patchRefTable">Table contains patch family filter.</param>
484
- /// <returns>true if the transform is not empty</returns>
485
- public static bool ReduceTransform(Output transform, Table patchRefTable)
486
- {
487
- // identify sections to keep
488
- Hashtable oldSections = new Hashtable(patchRefTable.Rows.Count);
489
- Hashtable newSections = new Hashtable(patchRefTable.Rows.Count);
490
- Hashtable tableKeyRows = new Hashtable();
491
- ArrayList sequenceList = new ArrayList();
492
- Hashtable componentFeatureAddsIndex = new Hashtable();
493
- Hashtable customActionTable = new Hashtable();
494
- Hashtable directoryTableAdds = new Hashtable();
495
- Hashtable featureTableAdds = new Hashtable();
496
- Hashtable keptComponents = new Hashtable();
497
- Hashtable keptDirectories = new Hashtable();
498
- Hashtable keptFeatures = new Hashtable();
499
- Hashtable keptLockPermissions = new Hashtable();
500
- Hashtable keptMsiLockPermissionExs = new Hashtable();
501
-
502
- Dictionary<string, List<string>> componentCreateFolderIndex = new Dictionary<string, List<string>>();
503
- Dictionary<string, List<Row>> directoryLockPermissionsIndex = new Dictionary<string, List<Row>>();
504
- Dictionary<string, List<Row>> directoryMsiLockPermissionsExIndex = new Dictionary<string, List<Row>>();
505
-
506
- foreach (Row patchRefRow in patchRefTable.Rows)
507
- {
508
- string tableName = (string)patchRefRow[0];
509
- string key = (string)patchRefRow[1];
510
-
511
- // Short circuit filtering if all changes should be included.
512
- if ("*" == tableName && "*" == key)
513
- {
514
- Patch.RemoveProductCodeFromTransform(transform);
515
- return true;
516
- }
517
-
518
- Table table = transform.Tables[tableName];
519
- if (table == null)
520
- {
521
- // table not found
522
- continue;
523
- }
524
-
525
- // index this table
526
- if (!tableKeyRows.Contains(tableName))
527
- {
528
- Hashtable newKeyRows = new Hashtable();
529
- foreach (Row newRow in table.Rows)
530
- {
531
- newKeyRows[newRow.GetPrimaryKey('/')] = newRow;
532
- }
533
- tableKeyRows[tableName] = newKeyRows;
534
- }
535
- Hashtable keyRows = (Hashtable)tableKeyRows[tableName];
536
-
537
- Row row = (Row)keyRows[key];
538
- if (row == null)
539
- {
540
- // row not found
541
- continue;
542
- }
543
-
544
- // Differ.sectionDelimiter
545
- string[] sections = row.SectionId.Split('/');
546
- oldSections[sections[0]] = row;
547
- newSections[sections[1]] = row;
548
- }
549
-
550
- // throw away sections not referenced
551
- int keptRows = 0;
552
- Table directoryTable = null;
553
- Table featureTable = null;
554
- Table lockPermissionsTable = null;
555
- Table msiLockPermissionsTable = null;
556
-
557
- foreach (Table table in transform.Tables)
558
- {
559
- if ("_SummaryInformation" == table.Name)
560
- {
561
- continue;
562
- }
563
-
564
- if (table.Name == "AdminExecuteSequence"
565
- || table.Name == "AdminUISequence"
566
- || table.Name == "AdvtExecuteSequence"
567
- || table.Name == "InstallUISequence"
568
- || table.Name == "InstallExecuteSequence")
569
- {
570
- sequenceList.Add(table);
571
- continue;
572
- }
573
-
574
- for (int i = 0; i < table.Rows.Count; i++)
575
- {
576
- Row row = table.Rows[i];
577
-
578
- if (table.Name == "CreateFolder")
579
- {
580
- string createFolderComponentId = (string)row[1];
581
-
582
- List<string> directoryList;
583
- if (!componentCreateFolderIndex.TryGetValue(createFolderComponentId, out directoryList))
584
- {
585
- directoryList = new List<string>();
586
- componentCreateFolderIndex.Add(createFolderComponentId, directoryList);
587
- }
588
-
589
- directoryList.Add((string)row[0]);
590
- }
591
-
592
- if (table.Name == "CustomAction")
593
- {
594
- customActionTable.Add(row[0], row);
595
- }
596
-
597
- if (table.Name == "Directory")
598
- {
599
- directoryTable = table;
600
- if (RowOperation.Add == row.Operation)
601
- {
602
- directoryTableAdds.Add(row[0], row);
603
- }
604
- }
605
-
606
- if (table.Name == "Feature")
607
- {
608
- featureTable = table;
609
- if (RowOperation.Add == row.Operation)
610
- {
611
- featureTableAdds.Add(row[0], row);
612
- }
613
- }
614
-
615
- if (table.Name == "FeatureComponents")
616
- {
617
- if (RowOperation.Add == row.Operation)
618
- {
619
- string featureId = (string)row[0];
620
- string componentId = (string)row[1];
621
-
622
- if (componentFeatureAddsIndex.ContainsKey(componentId))
623
- {
624
- ArrayList featureList = (ArrayList)componentFeatureAddsIndex[componentId];
625
- featureList.Add(featureId);
626
- }
627
- else
628
- {
629
- ArrayList featureList = new ArrayList();
630
- componentFeatureAddsIndex.Add(componentId, featureList);
631
- featureList.Add(featureId);
632
- }
633
- }
634
- }
635
-
636
- if (table.Name == "LockPermissions")
637
- {
638
- lockPermissionsTable = table;
639
- if ("CreateFolder" == (string)row[1])
640
- {
641
- string directoryId = (string)row[0];
642
-
643
- List<Row> rowList;
644
- if (!directoryLockPermissionsIndex.TryGetValue(directoryId, out rowList))
645
- {
646
- rowList = new List<Row>();
647
- directoryLockPermissionsIndex.Add(directoryId, rowList);
648
- }
649
-
650
- rowList.Add(row);
651
- }
652
- }
653
-
654
- if (table.Name == "MsiLockPermissionsEx")
655
- {
656
- msiLockPermissionsTable = table;
657
- if ("CreateFolder" == (string)row[1])
658
- {
659
- string directoryId = (string)row[0];
660
-
661
- List<Row> rowList;
662
- if (!directoryMsiLockPermissionsExIndex.TryGetValue(directoryId, out rowList))
663
- {
664
- rowList = new List<Row>();
665
- directoryMsiLockPermissionsExIndex.Add(directoryId, rowList);
666
- }
667
-
668
- rowList.Add(row);
669
- }
670
- }
671
-
672
- if (null == row.SectionId)
673
- {
674
- table.Rows.RemoveAt(i);
675
- i--;
676
- }
677
- else
678
- {
679
- string[] sections = row.SectionId.Split('/');
680
- // ignore the row without section id.
681
- if (0 == sections[0].Length && 0 == sections[1].Length)
682
- {
683
- table.Rows.RemoveAt(i);
684
- i--;
685
- }
686
- else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
687
- {
688
- if ("Component" == table.Name)
689
- {
690
- keptComponents.Add((string)row[0], row);
691
- }
692
-
693
- if ("Directory" == table.Name)
694
- {
695
- keptDirectories.Add(row[0], row);
696
- }
697
-
698
- if ("Feature" == table.Name)
699
- {
700
- keptFeatures.Add(row[0], row);
701
- }
702
-
703
- keptRows++;
704
- }
705
- else
706
- {
707
- table.Rows.RemoveAt(i);
708
- i--;
709
- }
710
- }
711
- }
712
- }
713
-
714
- keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable);
715
-
716
- if (null != directoryTable)
717
- {
718
- foreach (Row componentRow in keptComponents.Values)
719
- {
720
- string componentId = (string)componentRow[0];
721
-
722
- if (RowOperation.Add == componentRow.Operation)
723
- {
724
- // make sure each added component has its required directory and feature heirarchy.
725
- string directoryId = (string)componentRow[2];
726
- while (null != directoryId && directoryTableAdds.ContainsKey(directoryId))
727
- {
728
- Row directoryRow = (Row)directoryTableAdds[directoryId];
729
-
730
- if (!keptDirectories.ContainsKey(directoryId))
731
- {
732
- directoryTable.Rows.Add(directoryRow);
733
- keptDirectories.Add(directoryRow[0], null);
734
- keptRows++;
735
- }
736
-
737
- directoryId = (string)directoryRow[1];
738
- }
739
-
740
- if (componentFeatureAddsIndex.ContainsKey(componentId))
741
- {
742
- foreach (string featureId in (ArrayList)componentFeatureAddsIndex[componentId])
743
- {
744
- string currentFeatureId = featureId;
745
- while (null != currentFeatureId && featureTableAdds.ContainsKey(currentFeatureId))
746
- {
747
- Row featureRow = (Row)featureTableAdds[currentFeatureId];
748
-
749
- if (!keptFeatures.ContainsKey(currentFeatureId))
750
- {
751
- featureTable.Rows.Add(featureRow);
752
- keptFeatures.Add(featureRow[0], null);
753
- keptRows++;
754
- }
755
-
756
- currentFeatureId = (string)featureRow[1];
757
- }
758
- }
759
- }
760
- }
761
-
762
- // Hook in changes LockPermissions and MsiLockPermissions for folders for each component that has been kept.
763
- foreach (string keptComponentId in keptComponents.Keys)
764
- {
765
- List<string> directoryList;
766
- if (componentCreateFolderIndex.TryGetValue(keptComponentId, out directoryList))
767
- {
768
- foreach (string directoryId in directoryList)
769
- {
770
- List<Row> lockPermissionsRowList;
771
- if (directoryLockPermissionsIndex.TryGetValue(directoryId, out lockPermissionsRowList))
772
- {
773
- foreach (Row lockPermissionsRow in lockPermissionsRowList)
774
- {
775
- string key = lockPermissionsRow.GetPrimaryKey('/');
776
- if (!keptLockPermissions.ContainsKey(key))
777
- {
778
- lockPermissionsTable.Rows.Add(lockPermissionsRow);
779
- keptLockPermissions.Add(key, null);
780
- keptRows++;
781
- }
782
- }
783
- }
784
-
785
- List<Row> msiLockPermissionsExRowList;
786
- if (directoryMsiLockPermissionsExIndex.TryGetValue(directoryId, out msiLockPermissionsExRowList))
787
- {
788
- foreach (Row msiLockPermissionsExRow in msiLockPermissionsExRowList)
789
- {
790
- string key = msiLockPermissionsExRow.GetPrimaryKey('/');
791
- if (!keptMsiLockPermissionExs.ContainsKey(key))
792
- {
793
- msiLockPermissionsTable.Rows.Add(msiLockPermissionsExRow);
794
- keptMsiLockPermissionExs.Add(key, null);
795
- keptRows++;
796
- }
797
- }
798
- }
799
- }
800
- }
801
- }
802
- }
803
- }
804
-
805
- keptRows += ReduceTransformSequenceTable(sequenceList, oldSections, newSections, customActionTable);
806
-
807
- // Delete tables that are empty.
808
- ArrayList tablesToDelete = new ArrayList();
809
- foreach (Table table in transform.Tables)
810
- {
811
- if (0 == table.Rows.Count)
812
- {
813
- tablesToDelete.Add(table.Name);
814
- }
815
- }
816
-
817
- // delete separately to avoid messing up enumeration
818
- foreach (string tableName in tablesToDelete)
819
- {
820
- transform.Tables.Remove(tableName);
821
- }
822
-
823
- return keptRows > 0;
824
- }
825
-
826
- /// <summary>
827
- /// Remove the ProductCode property from the transform.
828
- /// </summary>
829
- /// <param name="transform">The transform.</param>
830
- /// <remarks>
831
- /// Changing the ProductCode is not supported in a patch.
832
- /// </remarks>
833
- private static void RemoveProductCodeFromTransform(Output transform)
834
- {
835
- Table propertyTable = transform.Tables["Property"];
836
- if (null != propertyTable)
837
- {
838
- for (int i = 0; i < propertyTable.Rows.Count; ++i)
839
- {
840
- Row propertyRow = propertyTable.Rows[i];
841
- string property = (string)propertyRow[0];
842
-
843
- if ("ProductCode" == property)
844
- {
845
- propertyTable.Rows.RemoveAt(i);
846
- break;
847
- }
848
- }
849
- }
850
- }
851
-
852
- /// <summary>
853
- /// Check if the section is in a PatchFamily.
854
- /// </summary>
855
- /// <param name="oldSection">Section id in target wixout</param>
856
- /// <param name="newSection">Section id in upgrade wixout</param>
857
- /// <param name="oldSections">Hashtable contains section id should be kept in the baseline wixout.</param>
858
- /// <param name="newSections">Hashtable contains section id should be kept in the upgrade wixout.</param>
859
- /// <returns>true if section in patch family</returns>
860
- private static bool IsInPatchFamily(string oldSection, string newSection, Hashtable oldSections, Hashtable newSections)
861
- {
862
- bool result = false;
863
-
864
- if ((String.IsNullOrEmpty(oldSection) && newSections.Contains(newSection)) || (String.IsNullOrEmpty(newSection) && oldSections.Contains(oldSection)))
865
- {
866
- result = true;
867
- }
868
- else if (!String.IsNullOrEmpty(oldSection) && !String.IsNullOrEmpty(newSection) && (oldSections.Contains(oldSection) || newSections.Contains(newSection)))
869
- {
870
- result = true;
871
- }
872
-
873
- return result;
874
- }
875
-
876
- /// <summary>
877
- /// Reduce the transform sequence tables.
878
- /// </summary>
879
- /// <param name="sequenceList">ArrayList of tables to be reduced</param>
880
- /// <param name="oldSections">Hashtable contains section id should be kept in the baseline wixout.</param>
881
- /// <param name="newSections">Hashtable contains section id should be kept in the target wixout.</param>
882
- /// <param name="customAction">Hashtable contains all the rows in the CustomAction table.</param>
883
- /// <returns>Number of rows left</returns>
884
- private static int ReduceTransformSequenceTable(ArrayList sequenceList, Hashtable oldSections, Hashtable newSections, Hashtable customAction)
885
- {
886
- int keptRows = 0;
887
-
888
- foreach (Table currentTable in sequenceList)
889
- {
890
- for (int i = 0; i < currentTable.Rows.Count; i++)
891
- {
892
- Row row = currentTable.Rows[i];
893
- string actionName = row.Fields[0].Data.ToString();
894
- string[] sections = row.SectionId.Split('/');
895
- bool isSectionIdEmpty = (sections[0].Length == 0 && sections[1].Length == 0);
896
-
897
- if (row.Operation == RowOperation.None)
898
- {
899
- // ignore the rows without section id.
900
- if (isSectionIdEmpty)
901
- {
902
- currentTable.Rows.RemoveAt(i);
903
- i--;
904
- }
905
- else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
906
- {
907
- keptRows++;
908
- }
909
- else
910
- {
911
- currentTable.Rows.RemoveAt(i);
912
- i--;
913
- }
914
- }
915
- else if (row.Operation == RowOperation.Modify)
916
- {
917
- bool sequenceChanged = row.Fields[2].Modified;
918
- bool conditionChanged = row.Fields[1].Modified;
919
-
920
- if (sequenceChanged && !conditionChanged)
921
- {
922
- keptRows++;
923
- }
924
- else if (!sequenceChanged && conditionChanged)
925
- {
926
- if (isSectionIdEmpty)
927
- {
928
- currentTable.Rows.RemoveAt(i);
929
- i--;
930
- }
931
- else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
932
- {
933
- keptRows++;
934
- }
935
- else
936
- {
937
- currentTable.Rows.RemoveAt(i);
938
- i--;
939
- }
940
- }
941
- else if (sequenceChanged && conditionChanged)
942
- {
943
- if (isSectionIdEmpty)
944
- {
945
- row.Fields[1].Modified = false;
946
- keptRows++;
947
- }
948
- else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
949
- {
950
- keptRows++;
951
- }
952
- else
953
- {
954
- row.Fields[1].Modified = false;
955
- keptRows++;
956
- }
957
- }
958
- }
959
- else if (row.Operation == RowOperation.Delete)
960
- {
961
- if (isSectionIdEmpty)
962
- {
963
- // it is a stardard action which is added by wix, we should keep this action.
964
- row.Operation = RowOperation.None;
965
- keptRows++;
966
- }
967
- else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
968
- {
969
- keptRows++;
970
- }
971
- else
972
- {
973
- if (customAction.ContainsKey(actionName))
974
- {
975
- currentTable.Rows.RemoveAt(i);
976
- i--;
977
- }
978
- else
979
- {
980
- // it is a stardard action, we should keep this action.
981
- row.Operation = RowOperation.None;
982
- keptRows++;
983
- }
984
- }
985
- }
986
- else if (row.Operation == RowOperation.Add)
987
- {
988
- if (isSectionIdEmpty)
989
- {
990
- keptRows++;
991
- }
992
- else if (IsInPatchFamily(sections[0], sections[1], oldSections, newSections))
993
- {
994
- keptRows++;
995
- }
996
- else
997
- {
998
- if (customAction.ContainsKey(actionName))
999
- {
1000
- currentTable.Rows.RemoveAt(i);
1001
- i--;
1002
- }
1003
- else
1004
- {
1005
- keptRows++;
1006
- }
1007
- }
1008
- }
1009
- }
1010
- }
1011
-
1012
- return keptRows;
1013
- }
1014
-
1015
- /// <summary>
1016
- /// Create the #transform for the given main transform.
1017
- /// </summary>
1018
- /// <param name="patchId">Patch GUID from patch authoring.</param>
1019
- /// <param name="clientPatchId">Easily referenced identity for this patch.</param>
1020
- /// <param name="mainTransform">Transform generated by torch.</param>
1021
- /// <param name="mediaRow">Media authored into patch.</param>
1022
- /// <param name="validationFlags">Transform validation flags for the summary information stream.</param>
1023
- /// <param name="productCode">Output string to receive ProductCode.</param>
1024
- [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")]
1025
- public Output BuildPairedTransform(string patchId, string clientPatchId, Output mainTransform, MediaRow mediaRow, int validationFlags, out string productCode)
1026
- {
1027
- productCode = null;
1028
- Output pairedTransform = new Output(null);
1029
- pairedTransform.Type = OutputType.Transform;
1030
- pairedTransform.Codepage = mainTransform.Codepage;
1031
-
1032
- // lookup productVersion property to correct summaryInformation
1033
- string newProductVersion = null;
1034
- Table mainPropertyTable = mainTransform.Tables["Property"];
1035
- if (null != mainPropertyTable)
1036
- {
1037
- foreach (Row row in mainPropertyTable.Rows)
1038
- {
1039
- if ("ProductVersion" == (string)row[0])
1040
- {
1041
- newProductVersion = (string)row[1];
1042
- }
1043
- }
1044
- }
1045
-
1046
- // TODO: build class for manipulating SummaryInformation table
1047
- Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"];
1048
- // add required properties
1049
- Hashtable mainSummaryRows = new Hashtable();
1050
- foreach (Row mainSummaryRow in mainSummaryTable.Rows)
1051
- {
1052
- mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow;
1053
- }
1054
- if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
1055
- {
1056
- Row mainSummaryRow = mainSummaryTable.CreateRow(null);
1057
- mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
1058
- mainSummaryRow[1] = validationFlags.ToString(CultureInfo.InvariantCulture);
1059
- }
1060
-
1061
- // copy summary information from core transform
1062
- Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
1063
- foreach (Row mainSummaryRow in mainSummaryTable.Rows)
1064
- {
1065
- string value = (string)mainSummaryRow[1];
1066
- switch ((SummaryInformation.Transform)mainSummaryRow[0])
1067
- {
1068
- case SummaryInformation.Transform.ProductCodes:
1069
- string[] propertyData = value.Split(';');
1070
- string oldProductVersion = propertyData[0].Substring(38);
1071
- string upgradeCode = propertyData[2];
1072
- productCode = propertyData[0].Substring(0, 38);
1073
- if (newProductVersion == null)
1074
- {
1075
- newProductVersion = oldProductVersion;
1076
- }
1077
-
1078
- // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade
1079
- mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
1080
- value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
1081
- break;
1082
- case SummaryInformation.Transform.ValidationFlags:
1083
- // use validation flags authored into the patch XML
1084
- mainSummaryRow[1] = value = validationFlags.ToString(CultureInfo.InvariantCulture);
1085
- break;
1086
- }
1087
- Row pairedSummaryRow = pairedSummaryTable.CreateRow(null);
1088
- pairedSummaryRow[0] = mainSummaryRow[0];
1089
- pairedSummaryRow[1] = value;
1090
- }
1091
-
1092
- if (productCode == null)
1093
- {
1094
- throw new InvalidOperationException(WixStrings.EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo);
1095
- }
1096
-
1097
- // copy File table
1098
- Table mainFileTable = mainTransform.Tables["File"];
1099
- if (null != mainFileTable && 0 < mainFileTable.Rows.Count)
1100
- {
1101
- // We require file source information.
1102
- Table mainWixFileTable = mainTransform.Tables["WixFile"];
1103
- if (null == mainWixFileTable)
1104
- {
1105
- throw new WixException(WixErrors.AdminImageRequired(productCode));
1106
- }
1107
-
1108
- RowDictionary<FileRow> mainFileRows = new RowDictionary<FileRow>(mainFileTable);
1109
-
1110
- Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition);
1111
- foreach (WixFileRow mainWixFileRow in mainWixFileTable.Rows)
1112
- {
1113
- FileRow mainFileRow = mainFileRows[mainWixFileRow.File];
1114
-
1115
- // set File.Sequence to non null to satisfy transform bind
1116
- mainFileRow.Sequence = 1;
1117
-
1118
- // delete's don't need rows in the paired transform
1119
- if (mainFileRow.Operation == RowOperation.Delete)
1120
- {
1121
- continue;
1122
- }
1123
-
1124
- FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null);
1125
- pairedFileRow.Operation = RowOperation.Modify;
1126
- for (int i = 0; i < mainFileRow.Fields.Length; i++)
1127
- {
1128
- pairedFileRow[i] = mainFileRow[i];
1129
- }
1130
-
1131
- // override authored media for patch bind
1132
- mainWixFileRow.DiskId = mediaRow.DiskId;
1133
-
1134
- // suppress any change to File.Sequence to avoid bloat
1135
- mainFileRow.Fields[7].Modified = false;
1136
-
1137
- // force File row to appear in the transform
1138
- switch (mainFileRow.Operation)
1139
- {
1140
- case RowOperation.Modify:
1141
- case RowOperation.Add:
1142
- // set msidbFileAttributesPatchAdded
1143
- pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded;
1144
- pairedFileRow.Fields[6].Modified = true;
1145
- pairedFileRow.Operation = mainFileRow.Operation;
1146
- break;
1147
- default:
1148
- pairedFileRow.Fields[6].Modified = false;
1149
- break;
1150
- }
1151
- }
1152
- }
1153
-
1154
- // add Media row to pairedTransform
1155
- Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]);
1156
- Row pairedMediaRow = pairedMediaTable.CreateRow(null);
1157
- pairedMediaRow.Operation = RowOperation.Add;
1158
- for (int i = 0; i < mediaRow.Fields.Length; i++)
1159
- {
1160
- pairedMediaRow[i] = mediaRow[i];
1161
- }
1162
-
1163
- // add PatchPackage for this Media
1164
- Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]);
1165
- pairedPackageTable.Operation = TableOperation.Add;
1166
- Row pairedPackageRow = pairedPackageTable.CreateRow(null);
1167
- pairedPackageRow.Operation = RowOperation.Add;
1168
- pairedPackageRow[0] = patchId;
1169
- pairedPackageRow[1] = mediaRow.DiskId;
1170
-
1171
- // add property to both identify client patches and whether those patches are removable or not
1172
- int allowRemoval = 0;
1173
- Table msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"];
1174
- if (null != msiPatchMetadataTable)
1175
- {
1176
- foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows)
1177
- {
1178
- // get the value of the standard AllowRemoval property, if present
1179
- string company = (string)msiPatchMetadataRow[0];
1180
- if ((null == company || 0 == company.Length) && "AllowRemoval" == (string)msiPatchMetadataRow[1])
1181
- {
1182
- allowRemoval = Int32.Parse((string)msiPatchMetadataRow[2], CultureInfo.InvariantCulture);
1183
- }
1184
- }
1185
- }
1186
-
1187
- // add the property to the patch transform's Property table
1188
- Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]);
1189
- pairedPropertyTable.Operation = TableOperation.Add;
1190
- Row pairedPropertyRow = pairedPropertyTable.CreateRow(null);
1191
- pairedPropertyRow.Operation = RowOperation.Add;
1192
- pairedPropertyRow[0] = string.Concat(clientPatchId, ".AllowRemoval");
1193
- pairedPropertyRow[1] = allowRemoval.ToString(CultureInfo.InvariantCulture);
1194
-
1195
- // add this patch code GUID to the patch transform to identify
1196
- // which patches are installed, including in multi-patch
1197
- // installations.
1198
- pairedPropertyRow = pairedPropertyTable.CreateRow(null);
1199
- pairedPropertyRow.Operation = RowOperation.Add;
1200
- pairedPropertyRow[0] = string.Concat(clientPatchId, ".PatchCode");
1201
- pairedPropertyRow[1] = patchId;
1202
-
1203
- // add PATCHNEWPACKAGECODE to apply to admin layouts
1204
- pairedPropertyRow = pairedPropertyTable.CreateRow(null);
1205
- pairedPropertyRow.Operation = RowOperation.Add;
1206
- pairedPropertyRow[0] = "PATCHNEWPACKAGECODE";
1207
- pairedPropertyRow[1] = patchId;
1208
-
1209
- // add PATCHNEWSUMMARYCOMMENTS and PATCHNEWSUMMARYSUBJECT to apply to admin layouts
1210
- Table _summaryInformationTable = this.patch.Tables["_SummaryInformation"];
1211
- if (null != _summaryInformationTable)
1212
- {
1213
- foreach (Row row in _summaryInformationTable.Rows)
1214
- {
1215
- if (3 == (int)row[0]) // PID_SUBJECT
1216
- {
1217
- pairedPropertyRow = pairedPropertyTable.CreateRow(null);
1218
- pairedPropertyRow.Operation = RowOperation.Add;
1219
- pairedPropertyRow[0] = "PATCHNEWSUMMARYSUBJECT";
1220
- pairedPropertyRow[1] = row[1];
1221
- }
1222
- else if (6 == (int)row[0]) // PID_COMMENTS
1223
- {
1224
- pairedPropertyRow = pairedPropertyTable.CreateRow(null);
1225
- pairedPropertyRow.Operation = RowOperation.Add;
1226
- pairedPropertyRow[0] = "PATCHNEWSUMMARYCOMMENTS";
1227
- pairedPropertyRow[1] = row[1];
1228
- }
1229
- }
1230
- }
1231
-
1232
- return pairedTransform;
1233
-
1234
- throw new NotImplementedException();
1235
- }
1236
- }
1237
-}
1238
-
1239
-#endif
src/WixToolset.Core.WindowsInstaller/PatchTransform.cs
deleted
-271
@@ -1,271 +0,0 @@
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
-
3
-#if DELETE
4
-
5
-namespace WixToolset
6
-{
7
- using System;
8
- using System.Collections;
9
- using System.Globalization;
10
- using System.Text;
11
- using System.Text.RegularExpressions;
12
- using WixToolset.Data;
13
- using WixToolset.Extensibility;
14
-
15
- public class PatchTransform
16
- {
17
- private string baseline;
18
- private Intermediate transform;
19
- private string transformPath;
20
-
21
- public string Baseline
22
- {
23
- get { return this.baseline; }
24
- }
25
-
26
- public Intermediate Transform
27
- {
28
- get
29
- {
30
- if (null == this.transform)
31
- {
32
- this.transform = Intermediate.Load(this.transformPath, false);
33
- }
34
-
35
- return this.transform;
36
- }
37
- }
38
-
39
- public string TransformPath
40
- {
41
- get { return this.transformPath; }
42
- }
43
-
44
- public PatchTransform(string transformPath, string baseline)
45
- {
46
- this.transformPath = transformPath;
47
- this.baseline = baseline;
48
- }
49
-
50
- /// <summary>
51
- /// Validates that the differences in the transform are valid for patch transforms.
52
- /// </summary>
53
- public void Validate()
54
- {
55
- // Changing the ProdocutCode in a patch transform is not recommended.
56
- Table propertyTable = this.Transform.Tables["Property"];
57
- if (null != propertyTable)
58
- {
59
- foreach (Row row in propertyTable.Rows)
60
- {
61
- // Only interested in modified rows; fast check.
62
- if (RowOperation.Modify == row.Operation)
63
- {
64
- if (0 == String.CompareOrdinal("ProductCode", (string)row[0]))
65
- {
66
- this.OnMessage(WixWarnings.MajorUpgradePatchNotRecommended());
67
- }
68
- }
69
- }
70
- }
71
-
72
- // If there is nothing in the component table we can return early because the remaining checks are component based.
73
- Table componentTable = this.Transform.Tables["Component"];
74
- if (null == componentTable)
75
- {
76
- return;
77
- }
78
-
79
- // Index Feature table row operations
80
- Table featureTable = this.Transform.Tables["Feature"];
81
- Table featureComponentsTable = this.Transform.Tables["FeatureComponents"];
82
- Hashtable featureOps = null;
83
- if (null != featureTable)
84
- {
85
- int capacity = featureTable.Rows.Count;
86
- featureOps = new Hashtable(capacity);
87
-
88
- foreach (Row row in featureTable.Rows)
89
- {
90
- featureOps[(string)row[0]] = row.Operation;
91
- }
92
- }
93
- else
94
- {
95
- featureOps = new Hashtable();
96
- }
97
-
98
- // Index Component table and check for keypath modifications
99
- Hashtable deletedComponent = new Hashtable();
100
- Hashtable componentKeyPath = new Hashtable();
101
- foreach (Row row in componentTable.Rows)
102
- {
103
- string id = row.Fields[0].Data.ToString();
104
- string keypath = (null == row.Fields[5].Data) ? String.Empty : row.Fields[5].Data.ToString();
105
-
106
- componentKeyPath.Add(id, keypath);
107
- if (RowOperation.Delete == row.Operation)
108
- {
109
- deletedComponent.Add(id, row);
110
- }
111
- else if (RowOperation.Modify == row.Operation)
112
- {
113
- if (row.Fields[1].Modified)
114
- {
115
- // Changing the guid of a component is equal to deleting the old one and adding a new one.
116
- deletedComponent.Add(id, row);
117
- }
118
-
119
- // If the keypath is modified its an error
120
- if (row.Fields[5].Modified)
121
- {
122
- this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, id, this.transformPath));
123
- }
124
- }
125
- }
126
-
127
- // Verify changes in the file table
128
- Table fileTable = this.Transform.Tables["File"];
129
- if (null != fileTable)
130
- {
131
- Hashtable componentWithChangedKeyPath = new Hashtable();
132
- foreach (Row row in fileTable.Rows)
133
- {
134
- if (RowOperation.None != row.Operation)
135
- {
136
- string fileId = row.Fields[0].Data.ToString();
137
- string componentId = row.Fields[1].Data.ToString();
138
-
139
- // If this file is the keypath of a component
140
- if (String.Equals((string)componentKeyPath[componentId], fileId, StringComparison.Ordinal))
141
- {
142
- if (row.Fields[2].Modified)
143
- {
144
- // You cant change the filename of a file that is the keypath of a component.
145
- this.OnMessage(WixErrors.InvalidKeypathChange(row.SourceLineNumbers, componentId, this.transformPath));
146
- }
147
-
148
- if (!componentWithChangedKeyPath.ContainsKey(componentId))
149
- {
150
- componentWithChangedKeyPath.Add(componentId, fileId);
151
- }
152
- }
153
-
154
- if (RowOperation.Delete == row.Operation)
155
- {
156
- // If the file is removed from a component that is not deleted.
157
- if (!deletedComponent.ContainsKey(componentId))
158
- {
159
- bool foundRemoveFileEntry = false;
160
- string filename = Common.GetName((string)row[2], false, true);
161
-
162
- Table removeFileTable = this.Transform.Tables["RemoveFile"];
163
- if (null != removeFileTable)
164
- {
165
- foreach (Row removeFileRow in removeFileTable.Rows)
166
- {
167
- if (RowOperation.Delete == removeFileRow.Operation)
168
- {
169
- continue;
170
- }
171
-
172
- if (componentId == (string)removeFileRow[1])
173
- {
174
- // Check if there is a RemoveFile entry for this file
175
- if (null != removeFileRow[2])
176
- {
177
- string removeFileName = Common.GetName((string)removeFileRow[2], false, true);
178
-
179
- // Convert the MSI format for a wildcard string to Regex format.
180
- removeFileName = removeFileName.Replace('.', '|').Replace('?', '.').Replace("*", ".*").Replace("|", "\\.");
181
-
182
- Regex regex = new Regex(removeFileName, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
183
- if (regex.IsMatch(filename))
184
- {
185
- foundRemoveFileEntry = true;
186
- break;
187
- }
188
- }
189
- }
190
- }
191
- }
192
-
193
- if (!foundRemoveFileEntry)
194
- {
195
- this.OnMessage(WixWarnings.InvalidRemoveFile(row.SourceLineNumbers, fileId, componentId));
196
- }
197
- }
198
- }
199
- }
200
- }
201
- }
202
-
203
- if (0 < deletedComponent.Count)
204
- {
205
- // Index FeatureComponents table.
206
- Hashtable featureComponents = new Hashtable();
207
-
208
- if (null != featureComponentsTable)
209
- {
210
- foreach (Row row in featureComponentsTable.Rows)
211
- {
212
- ArrayList features;
213
- string componentId = row.Fields[1].Data.ToString();
214
-
215
- if (featureComponents.Contains(componentId))
216
- {
217
- features = (ArrayList)featureComponents[componentId];
218
- }
219
- else
220
- {
221
- features = new ArrayList();
222
- featureComponents.Add(componentId, features);
223
- }
224
- features.Add(row.Fields[0].Data.ToString());
225
- }
226
- }
227
-
228
- // Check to make sure if a component was deleted, the feature was too.
229
- foreach (DictionaryEntry entry in deletedComponent)
230
- {
231
- if (featureComponents.Contains(entry.Key.ToString()))
232
- {
233
- ArrayList features = (ArrayList)featureComponents[entry.Key.ToString()];
234
- foreach (string featureId in features)
235
- {
236
- if (!featureOps.ContainsKey(featureId) || RowOperation.Delete != (RowOperation)featureOps[featureId])
237
- {
238
- // The feature was not deleted.
239
- this.OnMessage(WixErrors.InvalidRemoveComponent(((Row)entry.Value).SourceLineNumbers, entry.Key.ToString(), featureId, this.transformPath));
240
- }
241
- }
242
- }
243
- }
244
- }
245
-
246
- // Warn if new components are added to existing features
247
- if (null != featureComponentsTable)
248
- {
249
- foreach (Row row in featureComponentsTable.Rows)
250
- {
251
- if (RowOperation.Add == row.Operation)
252
- {
253
- // Check if the feature is in the Feature table
254
- string feature_ = (string)row[0];
255
- string component_ = (string)row[1];
256
-
257
- // Features may not be present if not referenced
258
- if (!featureOps.ContainsKey(feature_) || RowOperation.Add != (RowOperation)featureOps[feature_])
259
- {
260
- this.OnMessage(WixWarnings.NewComponentAddedToExistingFeature(row.SourceLineNumbers, component_, feature_, this.transformPath));
261
- }
262
- }
263
- }
264
- }
265
-
266
- throw new NotImplementedException();
267
- }
268
- }
269
-}
270
-
271
-#endif
\ No newline at end of file