diff options
author | Rob Mensching <rob@firegiant.com> | 2019-05-08 14:13:31 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2019-05-08 14:44:43 -0700 |
commit | 75fd55d5a71c492c6ea904768858c51aa97da29f (patch) | |
tree | 610047db1d5759a726ce88277bb2dfddcd01da45 /src/WixToolset.Core | |
parent | d1dbe29f3856d012acf5f96e8e66c43b74ab490d (diff) | |
download | wix-75fd55d5a71c492c6ea904768858c51aa97da29f.tar.gz wix-75fd55d5a71c492c6ea904768858c51aa97da29f.tar.bz2 wix-75fd55d5a71c492c6ea904768858c51aa97da29f.zip |
Use new strongly typed tuples
Diffstat (limited to 'src/WixToolset.Core')
-rw-r--r-- | src/WixToolset.Core/Compiler.cs | 12371 | ||||
-rw-r--r-- | src/WixToolset.Core/CompilerCore.cs | 16 | ||||
-rw-r--r-- | src/WixToolset.Core/Compiler_2.cs | 5615 | ||||
-rw-r--r-- | src/WixToolset.Core/Compiler_Bundle.cs | 2727 | ||||
-rw-r--r-- | src/WixToolset.Core/Compiler_EmbeddedUI.cs | 417 | ||||
-rw-r--r-- | src/WixToolset.Core/Compiler_Module.cs | 650 | ||||
-rw-r--r-- | src/WixToolset.Core/Compiler_UI.cs | 1730 | ||||
-rw-r--r-- | src/WixToolset.Core/ComponentKeyPath.cs | 3 | ||||
-rw-r--r-- | src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs | 135 | ||||
-rw-r--r-- | src/WixToolset.Core/Linker.cs | 5 | ||||
-rw-r--r-- | src/WixToolset.Core/LocalizationParser.cs | 69 | ||||
-rw-r--r-- | src/WixToolset.Core/Resolver.cs | 41 | ||||
-rw-r--r-- | src/WixToolset.Core/WixToolset.Core.csproj | 3 |
13 files changed, 12152 insertions, 11630 deletions
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs index ef8d68fd..8eff4aac 100644 --- a/src/WixToolset.Core/Compiler.cs +++ b/src/WixToolset.Core/Compiler.cs | |||
@@ -3,7 +3,6 @@ | |||
3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
8 | using System.Diagnostics; | 7 | using System.Diagnostics; |
9 | using System.Diagnostics.CodeAnalysis; | 8 | using System.Diagnostics.CodeAnalysis; |
@@ -11,30 +10,19 @@ namespace WixToolset.Core | |||
11 | using System.IO; | 10 | using System.IO; |
12 | using System.Text.RegularExpressions; | 11 | using System.Text.RegularExpressions; |
13 | using System.Xml.Linq; | 12 | using System.Xml.Linq; |
14 | using WixToolset.Core.Native; | ||
15 | using WixToolset.Data; | 13 | using WixToolset.Data; |
16 | using WixToolset.Data.Tuples; | 14 | using WixToolset.Data.Tuples; |
17 | using WixToolset.Extensibility; | 15 | using WixToolset.Extensibility; |
18 | using WixToolset.Extensibility.Data; | 16 | using WixToolset.Extensibility.Data; |
19 | using WixToolset.Extensibility.Services; | 17 | using WixToolset.Extensibility.Services; |
20 | using Wix = WixToolset.Data.Serialize; | ||
21 | 18 | ||
22 | /// <summary> | 19 | /// <summary> |
23 | /// Compiler of the WiX toolset. | 20 | /// Compiler of the WiX toolset. |
24 | /// </summary> | 21 | /// </summary> |
25 | internal class Compiler : ICompiler | 22 | internal partial class Compiler : ICompiler |
26 | { | 23 | { |
27 | public const string DefaultComponentIdPlaceholderFormat = "WixComponentIdPlaceholder{0}"; | 24 | public const string DefaultComponentIdPlaceholderFormat = "WixComponentIdPlaceholder{0}"; |
28 | public const string DefaultComponentIdPlaceholderWixVariableFormat = "!(wix.{0})"; | 25 | public const string DefaultComponentIdPlaceholderWixVariableFormat = "!(wix.{0})"; |
29 | public const string BurnUXContainerId = "WixUXContainer"; | ||
30 | public const string BurnDefaultAttachedContainerId = "WixAttachedContainer"; | ||
31 | |||
32 | // The following constants must stay in sync with src\burn\engine\core.h | ||
33 | private const string BURN_BUNDLE_NAME = "WixBundleName"; | ||
34 | private const string BURN_BUNDLE_ORIGINAL_SOURCE = "WixBundleOriginalSource"; | ||
35 | private const string BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER = "WixBundleOriginalSourceFolder"; | ||
36 | private const string BURN_BUNDLE_LAST_USED_SOURCE = "WixBundleLastUsedSource"; | ||
37 | |||
38 | // If these are true you know you are building a module or product | 26 | // If these are true you know you are building a module or product |
39 | // but if they are false you cannot not be sure they will not end | 27 | // but if they are false you cannot not be sure they will not end |
40 | // up a product or module. Use these flags carefully. | 28 | // up a product or module. Use these flags carefully. |
@@ -367,7 +355,7 @@ namespace WixToolset.Core | |||
367 | /// <param name="componentId">Identifier of parent component.</param> | 355 | /// <param name="componentId">Identifier of parent component.</param> |
368 | private void RegisterImplementedCategories(SourceLineNumber sourceLineNumbers, string categoryId, string classId, string componentId) | 356 | private void RegisterImplementedCategories(SourceLineNumber sourceLineNumbers, string categoryId, string classId, string componentId) |
369 | { | 357 | { |
370 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Implemented Categories\\", categoryId), "*", null, componentId); | 358 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\Implemented Categories\\", categoryId), "*", null, componentId); |
371 | } | 359 | } |
372 | 360 | ||
373 | /// <summary> | 361 | /// <summary> |
@@ -506,41 +494,41 @@ namespace WixToolset.Core | |||
506 | { | 494 | { |
507 | if (null != description) | 495 | if (null != description) |
508 | { | 496 | { |
509 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), null, description, componentId); | 497 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), null, description, componentId); |
510 | } | 498 | } |
511 | else | 499 | else |
512 | { | 500 | { |
513 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "+", null, componentId); | 501 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "+", null, componentId); |
514 | } | 502 | } |
515 | 503 | ||
516 | if (null != remoteServerName) | 504 | if (null != remoteServerName) |
517 | { | 505 | { |
518 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "RemoteServerName", remoteServerName, componentId); | 506 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "RemoteServerName", remoteServerName, componentId); |
519 | } | 507 | } |
520 | 508 | ||
521 | if (null != localService) | 509 | if (null != localService) |
522 | { | 510 | { |
523 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "LocalService", localService, componentId); | 511 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "LocalService", localService, componentId); |
524 | } | 512 | } |
525 | 513 | ||
526 | if (null != serviceParameters) | 514 | if (null != serviceParameters) |
527 | { | 515 | { |
528 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "ServiceParameters", serviceParameters, componentId); | 516 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "ServiceParameters", serviceParameters, componentId); |
529 | } | 517 | } |
530 | 518 | ||
531 | if (null != dllSurrogate) | 519 | if (null != dllSurrogate) |
532 | { | 520 | { |
533 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "DllSurrogate", dllSurrogate, componentId); | 521 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "DllSurrogate", dllSurrogate, componentId); |
534 | } | 522 | } |
535 | 523 | ||
536 | if (YesNoType.Yes == activateAtStorage) | 524 | if (YesNoType.Yes == activateAtStorage) |
537 | { | 525 | { |
538 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "ActivateAtStorage", "Y", componentId); | 526 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "ActivateAtStorage", "Y", componentId); |
539 | } | 527 | } |
540 | 528 | ||
541 | if (YesNoType.Yes == runAsInteractiveUser) | 529 | if (YesNoType.Yes == runAsInteractiveUser) |
542 | { | 530 | { |
543 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "RunAs", "Interactive User", componentId); | 531 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("AppID\\", appId), "RunAs", "Interactive User", componentId); |
544 | } | 532 | } |
545 | } | 533 | } |
546 | } | 534 | } |
@@ -1150,7 +1138,7 @@ namespace WixToolset.Core | |||
1150 | else if (YesNoType.No == advertise) | 1138 | else if (YesNoType.No == advertise) |
1151 | { | 1139 | { |
1152 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | 1140 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); |
1153 | this.Core.CreateRegistryRow(childSourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("FileType\\", classId, "\\", fileTypeMaskIndex.ToString()), String.Empty, this.ParseFileTypeMaskElement(child), componentId); | 1141 | this.Core.CreateRegistryRow(childSourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("FileType\\", classId, "\\", fileTypeMaskIndex.ToString()), String.Empty, this.ParseFileTypeMaskElement(child), componentId); |
1154 | fileTypeMaskIndex++; | 1142 | fileTypeMaskIndex++; |
1155 | } | 1143 | } |
1156 | break; | 1144 | break; |
@@ -1202,34 +1190,38 @@ namespace WixToolset.Core | |||
1202 | { | 1190 | { |
1203 | foreach (var context in contexts) | 1191 | foreach (var context in contexts) |
1204 | { | 1192 | { |
1205 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Class); | 1193 | var tuple = new ClassTuple(sourceLineNumbers) |
1206 | row.Set(0, classId); | 1194 | { |
1207 | row.Set(1, context); | 1195 | CLSID = classId, |
1208 | row.Set(2, componentId); | 1196 | Context = context, |
1209 | row.Set(3, defaultProgId); | 1197 | Component_ = componentId, |
1210 | row.Set(4, description); | 1198 | ProgId_Default = defaultProgId, |
1199 | Description = description, | ||
1200 | FileTypeMask = fileTypeMask, | ||
1201 | DefInprocHandler = defaultInprocHandler, | ||
1202 | Argument = argument, | ||
1203 | Feature_ = Guid.Empty.ToString("B"), | ||
1204 | RelativePath = YesNoType.Yes == relativePath, | ||
1205 | }; | ||
1206 | |||
1211 | if (null != appId) | 1207 | if (null != appId) |
1212 | { | 1208 | { |
1213 | row.Set(5, appId); | 1209 | tuple.AppId_ = appId; |
1214 | this.Core.CreateSimpleReference(sourceLineNumbers, "AppId", appId); | 1210 | this.Core.CreateSimpleReference(sourceLineNumbers, "AppId", appId); |
1215 | } | 1211 | } |
1216 | row.Set(6, fileTypeMask); | 1212 | |
1217 | if (null != icon) | 1213 | if (null != icon) |
1218 | { | 1214 | { |
1219 | row.Set(7, icon); | 1215 | tuple.Icon_ = icon; |
1220 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | 1216 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); |
1221 | } | 1217 | } |
1218 | |||
1222 | if (CompilerConstants.IntegerNotSet != iconIndex) | 1219 | if (CompilerConstants.IntegerNotSet != iconIndex) |
1223 | { | 1220 | { |
1224 | row.Set(8, iconIndex); | 1221 | tuple.IconIndex = iconIndex; |
1225 | } | ||
1226 | row.Set(9, defaultInprocHandler); | ||
1227 | row.Set(10, argument); | ||
1228 | row.Set(11, Guid.Empty.ToString("B")); | ||
1229 | if (YesNoType.Yes == relativePath) | ||
1230 | { | ||
1231 | row.Set(12, MsiInterop.MsidbClassAttributesRelativePath); | ||
1232 | } | 1222 | } |
1223 | |||
1224 | this.Core.AddTuple(tuple); | ||
1233 | } | 1225 | } |
1234 | } | 1226 | } |
1235 | } | 1227 | } |
@@ -1305,7 +1297,7 @@ namespace WixToolset.Core | |||
1305 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Context", context, "InprocServer", "InprocServer32", "LocalServer", "LocalServer32")); | 1297 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Context", context, "InprocServer", "InprocServer32", "LocalServer", "LocalServer32")); |
1306 | } | 1298 | } |
1307 | 1299 | ||
1308 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", context), String.Empty, formattedContextString, componentId); // ClassId context | 1300 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\", context), String.Empty, formattedContextString, componentId); // ClassId context |
1309 | 1301 | ||
1310 | if (null != icon) // ClassId default icon | 1302 | if (null != icon) // ClassId default icon |
1311 | { | 1303 | { |
@@ -1317,18 +1309,18 @@ namespace WixToolset.Core | |||
1317 | { | 1309 | { |
1318 | icon = String.Concat(icon, ",", iconIndex); | 1310 | icon = String.Concat(icon, ",", iconIndex); |
1319 | } | 1311 | } |
1320 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\DefaultIcon"), String.Empty, icon, componentId); | 1312 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\DefaultIcon"), String.Empty, icon, componentId); |
1321 | } | 1313 | } |
1322 | } | 1314 | } |
1323 | 1315 | ||
1324 | if (null != parentAppId) // ClassId AppId (must be specified via nesting, not with the AppId attribute) | 1316 | if (null != parentAppId) // ClassId AppId (must be specified via nesting, not with the AppId attribute) |
1325 | { | 1317 | { |
1326 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId), "AppID", parentAppId, componentId); | 1318 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId), "AppID", parentAppId, componentId); |
1327 | } | 1319 | } |
1328 | 1320 | ||
1329 | if (null != description) // ClassId description | 1321 | if (null != description) // ClassId description |
1330 | { | 1322 | { |
1331 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId), String.Empty, description, componentId); | 1323 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId), String.Empty, description, componentId); |
1332 | } | 1324 | } |
1333 | 1325 | ||
1334 | if (null != defaultInprocHandler) | 1326 | if (null != defaultInprocHandler) |
@@ -1336,17 +1328,17 @@ namespace WixToolset.Core | |||
1336 | switch (defaultInprocHandler) // ClassId Default Inproc Handler | 1328 | switch (defaultInprocHandler) // ClassId Default Inproc Handler |
1337 | { | 1329 | { |
1338 | case "1": | 1330 | case "1": |
1339 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler"), String.Empty, "ole2.dll", componentId); | 1331 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler"), String.Empty, "ole2.dll", componentId); |
1340 | break; | 1332 | break; |
1341 | case "2": | 1333 | case "2": |
1342 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, "ole32.dll", componentId); | 1334 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, "ole32.dll", componentId); |
1343 | break; | 1335 | break; |
1344 | case "3": | 1336 | case "3": |
1345 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler"), String.Empty, "ole2.dll", componentId); | 1337 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler"), String.Empty, "ole2.dll", componentId); |
1346 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, "ole32.dll", componentId); | 1338 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, "ole32.dll", componentId); |
1347 | break; | 1339 | break; |
1348 | default: | 1340 | default: |
1349 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, defaultInprocHandler, componentId); | 1341 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, defaultInprocHandler, componentId); |
1350 | break; | 1342 | break; |
1351 | } | 1343 | } |
1352 | } | 1344 | } |
@@ -1364,36 +1356,36 @@ namespace WixToolset.Core | |||
1364 | // add a threading model for each context in the class | 1356 | // add a threading model for each context in the class |
1365 | foreach (var context in contexts) | 1357 | foreach (var context in contexts) |
1366 | { | 1358 | { |
1367 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", context), "ThreadingModel", threadingModel, componentId); | 1359 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\", context), "ThreadingModel", threadingModel, componentId); |
1368 | } | 1360 | } |
1369 | } | 1361 | } |
1370 | 1362 | ||
1371 | if (null != typeLibId) | 1363 | if (null != typeLibId) |
1372 | { | 1364 | { |
1373 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\TypeLib"), null, typeLibId, componentId); | 1365 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\TypeLib"), null, typeLibId, componentId); |
1374 | } | 1366 | } |
1375 | 1367 | ||
1376 | if (null != version) | 1368 | if (null != version) |
1377 | { | 1369 | { |
1378 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Version"), null, version, componentId); | 1370 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\Version"), null, version, componentId); |
1379 | } | 1371 | } |
1380 | 1372 | ||
1381 | if (null != insertable) | 1373 | if (null != insertable) |
1382 | { | 1374 | { |
1383 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. | 1375 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. |
1384 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", insertable), "*", null, componentId); | 1376 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\", insertable), "*", null, componentId); |
1385 | } | 1377 | } |
1386 | 1378 | ||
1387 | if (control) | 1379 | if (control) |
1388 | { | 1380 | { |
1389 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. | 1381 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. |
1390 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Control"), "*", null, componentId); | 1382 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\Control"), "*", null, componentId); |
1391 | } | 1383 | } |
1392 | 1384 | ||
1393 | if (programmable) | 1385 | if (programmable) |
1394 | { | 1386 | { |
1395 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. | 1387 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. |
1396 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Programmable"), "*", null, componentId); | 1388 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\Programmable"), "*", null, componentId); |
1397 | } | 1389 | } |
1398 | 1390 | ||
1399 | if (safeForInit) | 1391 | if (safeForInit) |
@@ -1475,34 +1467,34 @@ namespace WixToolset.Core | |||
1475 | 1467 | ||
1476 | this.Core.ParseForExtensionElements(node); | 1468 | this.Core.ParseForExtensionElements(node); |
1477 | 1469 | ||
1478 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId), null, name, componentId); | 1470 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId), null, name, componentId); |
1479 | if (null != typeLibId) | 1471 | if (null != typeLibId) |
1480 | { | 1472 | { |
1481 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\TypeLib"), null, typeLibId, componentId); | 1473 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId, "\\TypeLib"), null, typeLibId, componentId); |
1482 | if (versioned) | 1474 | if (versioned) |
1483 | { | 1475 | { |
1484 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\TypeLib"), "Version", typelibVersion, componentId); | 1476 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId, "\\TypeLib"), "Version", typelibVersion, componentId); |
1485 | } | 1477 | } |
1486 | } | 1478 | } |
1487 | 1479 | ||
1488 | if (null != baseInterface) | 1480 | if (null != baseInterface) |
1489 | { | 1481 | { |
1490 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\BaseInterface"), null, baseInterface, componentId); | 1482 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId, "\\BaseInterface"), null, baseInterface, componentId); |
1491 | } | 1483 | } |
1492 | 1484 | ||
1493 | if (CompilerConstants.IntegerNotSet != numMethods) | 1485 | if (CompilerConstants.IntegerNotSet != numMethods) |
1494 | { | 1486 | { |
1495 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\NumMethods"), null, numMethods.ToString(), componentId); | 1487 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId, "\\NumMethods"), null, numMethods.ToString(), componentId); |
1496 | } | 1488 | } |
1497 | 1489 | ||
1498 | if (null != proxyId) | 1490 | if (null != proxyId) |
1499 | { | 1491 | { |
1500 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\ProxyStubClsid"), null, proxyId, componentId); | 1492 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId, "\\ProxyStubClsid"), null, proxyId, componentId); |
1501 | } | 1493 | } |
1502 | 1494 | ||
1503 | if (null != proxyId32) | 1495 | if (null != proxyId32) |
1504 | { | 1496 | { |
1505 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\ProxyStubClsid32"), null, proxyId32, componentId); | 1497 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("Interface\\", interfaceId, "\\ProxyStubClsid32"), null, proxyId32, componentId); |
1506 | } | 1498 | } |
1507 | } | 1499 | } |
1508 | 1500 | ||
@@ -1588,7 +1580,9 @@ namespace WixToolset.Core | |||
1588 | string language = null; | 1580 | string language = null; |
1589 | string maximum = null; | 1581 | string maximum = null; |
1590 | string minimum = null; | 1582 | string minimum = null; |
1591 | var options = MsiInterop.MsidbUpgradeAttributesVersionMinInclusive | MsiInterop.MsidbUpgradeAttributesOnlyDetect; | 1583 | var excludeLanguages = false; |
1584 | var maxInclusive = false; | ||
1585 | var minInclusive = true; | ||
1592 | 1586 | ||
1593 | foreach (var attrib in node.Attributes()) | 1587 | foreach (var attrib in node.Attributes()) |
1594 | { | 1588 | { |
@@ -1597,22 +1591,13 @@ namespace WixToolset.Core | |||
1597 | switch (attrib.Name.LocalName) | 1591 | switch (attrib.Name.LocalName) |
1598 | { | 1592 | { |
1599 | case "ExcludeLanguages": | 1593 | case "ExcludeLanguages": |
1600 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 1594 | excludeLanguages = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
1601 | { | ||
1602 | options |= MsiInterop.MsidbUpgradeAttributesLanguagesExclusive; | ||
1603 | } | ||
1604 | break; | 1595 | break; |
1605 | case "IncludeMaximum": | 1596 | case "IncludeMaximum": |
1606 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 1597 | maxInclusive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
1607 | { | ||
1608 | options |= MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive; | ||
1609 | } | ||
1610 | break; | 1598 | break; |
1611 | case "IncludeMinimum": // this is "yes" by default | 1599 | case "IncludeMinimum": |
1612 | if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 1600 | minInclusive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
1613 | { | ||
1614 | options &= ~MsiInterop.MsidbUpgradeAttributesVersionMinInclusive; | ||
1615 | } | ||
1616 | break; | 1601 | break; |
1617 | case "Language": | 1602 | case "Language": |
1618 | language = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 1603 | language = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
@@ -1646,13 +1631,20 @@ namespace WixToolset.Core | |||
1646 | 1631 | ||
1647 | if (!this.Core.EncounteredError) | 1632 | if (!this.Core.EncounteredError) |
1648 | { | 1633 | { |
1649 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Upgrade); | 1634 | var tuple = new UpgradeTuple(sourceLineNumbers) |
1650 | row.Set(0, upgradeCode); | 1635 | { |
1651 | row.Set(1, minimum); | 1636 | UpgradeCode = upgradeCode, |
1652 | row.Set(2, maximum); | 1637 | VersionMin = minimum, |
1653 | row.Set(3, language); | 1638 | VersionMax = maximum, |
1654 | row.Set(4, options); | 1639 | Language = language, |
1655 | row.Set(6, propertyId); | 1640 | ActionProperty = propertyId, |
1641 | OnlyDetect = true, | ||
1642 | ExcludeLanguages = excludeLanguages, | ||
1643 | VersionMaxInclusive = maxInclusive, | ||
1644 | VersionMinInclusive = minInclusive, | ||
1645 | }; | ||
1646 | |||
1647 | this.Core.AddTuple(tuple); | ||
1656 | } | 1648 | } |
1657 | } | 1649 | } |
1658 | 1650 | ||
@@ -1669,7 +1661,7 @@ namespace WixToolset.Core | |||
1669 | string key = null; | 1661 | string key = null; |
1670 | string name = null; | 1662 | string name = null; |
1671 | string signature = null; | 1663 | string signature = null; |
1672 | var root = CompilerConstants.IntegerNotSet; | 1664 | RegistryRootType? root = null; |
1673 | var type = CompilerConstants.IntegerNotSet; | 1665 | var type = CompilerConstants.IntegerNotSet; |
1674 | var search64bit = false; | 1666 | var search64bit = false; |
1675 | 1667 | ||
@@ -1689,28 +1681,26 @@ namespace WixToolset.Core | |||
1689 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 1681 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
1690 | break; | 1682 | break; |
1691 | case "Root": | 1683 | case "Root": |
1692 | root = this.Core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, false); | 1684 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, false); |
1693 | break; | 1685 | break; |
1694 | case "Type": | 1686 | case "Type": |
1695 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 1687 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
1696 | if (0 < typeValue.Length) | 1688 | switch (typeValue) |
1697 | { | 1689 | { |
1698 | var typeType = Wix.RegistrySearch.ParseTypeType(typeValue); | 1690 | case "directory": |
1699 | switch (typeType) | 1691 | type = 0; |
1700 | { | 1692 | break; |
1701 | case Wix.RegistrySearch.TypeType.directory: | 1693 | case "file": |
1702 | type = 0; | 1694 | type = 1; |
1703 | break; | 1695 | break; |
1704 | case Wix.RegistrySearch.TypeType.file: | 1696 | case "raw": |
1705 | type = 1; | 1697 | type = 2; |
1706 | break; | 1698 | break; |
1707 | case Wix.RegistrySearch.TypeType.raw: | 1699 | case "": |
1708 | type = 2; | 1700 | break; |
1709 | break; | 1701 | default: |
1710 | default: | 1702 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Type", typeValue, "directory", "file", "raw")); |
1711 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Type", typeValue, "directory", "file", "raw")); | 1703 | break; |
1712 | break; | ||
1713 | } | ||
1714 | } | 1704 | } |
1715 | break; | 1705 | break; |
1716 | case "Win64": | 1706 | case "Win64": |
@@ -1743,7 +1733,7 @@ namespace WixToolset.Core | |||
1743 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | 1733 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); |
1744 | } | 1734 | } |
1745 | 1735 | ||
1746 | if (CompilerConstants.IntegerNotSet == root) | 1736 | if (!root.HasValue) |
1747 | { | 1737 | { |
1748 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | 1738 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); |
1749 | } | 1739 | } |
@@ -1813,7 +1803,7 @@ namespace WixToolset.Core | |||
1813 | if (!this.Core.EncounteredError) | 1803 | if (!this.Core.EncounteredError) |
1814 | { | 1804 | { |
1815 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RegLocator, id); | 1805 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RegLocator, id); |
1816 | row.Set(1, root); | 1806 | row.Set(1, (int)root); |
1817 | row.Set(2, key); | 1807 | row.Set(2, key); |
1818 | row.Set(3, name); | 1808 | row.Set(3, name); |
1819 | row.Set(4, search64bit ? (type | 16) : type); | 1809 | row.Set(4, search64bit ? (type | 16) : type); |
@@ -2047,21 +2037,31 @@ namespace WixToolset.Core | |||
2047 | { | 2037 | { |
2048 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 2038 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
2049 | 2039 | ||
2050 | var bits = 0; | ||
2051 | var comPlusBits = CompilerConstants.IntegerNotSet; | 2040 | var comPlusBits = CompilerConstants.IntegerNotSet; |
2052 | string condition = null; | 2041 | string condition = null; |
2053 | var encounteredODBCDataSource = false; | 2042 | var encounteredODBCDataSource = false; |
2054 | var explicitWin64 = false; | ||
2055 | var files = 0; | 2043 | var files = 0; |
2056 | var guid = "*"; | 2044 | var guid = "*"; |
2057 | var componentIdPlaceholder = String.Format(Compiler.DefaultComponentIdPlaceholderFormat, this.componentIdPlaceholdersResolver.VariableCount); // placeholder id for defaulting Component/@Id to keypath id. | 2045 | var componentIdPlaceholder = String.Format(Compiler.DefaultComponentIdPlaceholderFormat, this.componentIdPlaceholdersResolver.VariableCount); // placeholder id for defaulting Component/@Id to keypath id. |
2058 | var componentIdPlaceholderWixVariable = String.Format(Compiler.DefaultComponentIdPlaceholderWixVariableFormat, componentIdPlaceholder); | 2046 | var componentIdPlaceholderWixVariable = String.Format(Compiler.DefaultComponentIdPlaceholderWixVariableFormat, componentIdPlaceholder); |
2059 | var id = new Identifier(componentIdPlaceholderWixVariable, AccessModifier.Private); | 2047 | var id = new Identifier(componentIdPlaceholderWixVariable, AccessModifier.Private); |
2060 | var keyBits = 0; | ||
2061 | var keyFound = false; | 2048 | var keyFound = false; |
2062 | string keyPath = null; | 2049 | string keyPath = null; |
2063 | var shouldAddCreateFolder = false; | 2050 | var shouldAddCreateFolder = false; |
2051 | |||
2052 | var keyPathType = ComponentKeyPathType.Directory; | ||
2053 | var location = ComponentLocation.LocalOnly; | ||
2054 | var disableRegistryReflection = false; | ||
2055 | |||
2056 | var neverOverwrite = false; | ||
2057 | var permanent = false; | ||
2058 | var shared = false; | ||
2059 | var sharedDllRefCount = false; | ||
2060 | var transitive = false; | ||
2061 | var uninstallWhenSuperseded = false; | ||
2062 | var explicitWin64 = false; | ||
2064 | var win64 = false; | 2063 | var win64 = false; |
2064 | |||
2065 | var multiInstance = false; | 2065 | var multiInstance = false; |
2066 | var symbols = new List<string>(); | 2066 | var symbols = new List<string>(); |
2067 | string feature = null; | 2067 | string feature = null; |
@@ -2079,10 +2079,11 @@ namespace WixToolset.Core | |||
2079 | comPlusBits = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | 2079 | comPlusBits = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); |
2080 | break; | 2080 | break; |
2081 | case "DisableRegistryReflection": | 2081 | case "DisableRegistryReflection": |
2082 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2082 | disableRegistryReflection = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2083 | { | 2083 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2084 | bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection; | 2084 | //{ |
2085 | } | 2085 | // bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection; |
2086 | //} | ||
2086 | break; | 2087 | break; |
2087 | case "Directory": | 2088 | case "Directory": |
2088 | directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | 2089 | directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); |
@@ -2101,77 +2102,84 @@ namespace WixToolset.Core | |||
2101 | { | 2102 | { |
2102 | keyFound = true; | 2103 | keyFound = true; |
2103 | keyPath = null; | 2104 | keyPath = null; |
2104 | keyBits = 0; | ||
2105 | shouldAddCreateFolder = true; | 2105 | shouldAddCreateFolder = true; |
2106 | } | 2106 | } |
2107 | break; | 2107 | break; |
2108 | case "Location": | 2108 | case "Location": |
2109 | var location = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 2109 | var locationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
2110 | if (0 < location.Length) | 2110 | switch (locationValue) |
2111 | { | 2111 | { |
2112 | var locationType = Wix.Component.ParseLocationType(location); | 2112 | case "either": |
2113 | switch (locationType) | 2113 | location = ComponentLocation.Either; |
2114 | { | 2114 | //bits |= MsiInterop.MsidbComponentAttributesOptional; |
2115 | case Wix.Component.LocationType.either: | 2115 | break; |
2116 | bits |= MsiInterop.MsidbComponentAttributesOptional; | 2116 | case "local": // this is the default |
2117 | break; | 2117 | location = ComponentLocation.LocalOnly; |
2118 | case Wix.Component.LocationType.local: // this is the default | 2118 | break; |
2119 | break; | 2119 | case "source": |
2120 | case Wix.Component.LocationType.source: | 2120 | location = ComponentLocation.SourceOnly; |
2121 | bits |= MsiInterop.MsidbComponentAttributesSourceOnly; | 2121 | //bits |= MsiInterop.MsidbComponentAttributesSourceOnly; |
2122 | break; | 2122 | break; |
2123 | default: | 2123 | case "": |
2124 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "either", "local", "source")); | 2124 | break; |
2125 | break; | 2125 | default: |
2126 | } | 2126 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, locationValue, "either", "local", "source")); |
2127 | break; | ||
2127 | } | 2128 | } |
2128 | break; | 2129 | break; |
2129 | case "MultiInstance": | 2130 | case "MultiInstance": |
2130 | multiInstance = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 2131 | multiInstance = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2131 | break; | 2132 | break; |
2132 | case "NeverOverwrite": | 2133 | case "NeverOverwrite": |
2133 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2134 | neverOverwrite = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2134 | { | 2135 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2135 | bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite; | 2136 | //{ |
2136 | } | 2137 | // bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite; |
2138 | //} | ||
2137 | break; | 2139 | break; |
2138 | case "Permanent": | 2140 | case "Permanent": |
2139 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2141 | permanent = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2140 | { | 2142 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2141 | bits |= MsiInterop.MsidbComponentAttributesPermanent; | 2143 | //{ |
2142 | } | 2144 | // bits |= MsiInterop.MsidbComponentAttributesPermanent; |
2145 | //} | ||
2143 | break; | 2146 | break; |
2144 | case "Shared": | 2147 | case "Shared": |
2145 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2148 | shared = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2146 | { | 2149 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2147 | bits |= MsiInterop.MsidbComponentAttributesShared; | 2150 | //{ |
2148 | } | 2151 | // bits |= MsiInterop.MsidbComponentAttributesShared; |
2152 | //} | ||
2149 | break; | 2153 | break; |
2150 | case "SharedDllRefCount": | 2154 | case "SharedDllRefCount": |
2151 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2155 | sharedDllRefCount = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2152 | { | 2156 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2153 | bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount; | 2157 | //{ |
2154 | } | 2158 | // bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount; |
2159 | //} | ||
2155 | break; | 2160 | break; |
2156 | case "Transitive": | 2161 | case "Transitive": |
2157 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2162 | transitive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2158 | { | 2163 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2159 | bits |= MsiInterop.MsidbComponentAttributesTransitive; | 2164 | //{ |
2160 | } | 2165 | // bits |= MsiInterop.MsidbComponentAttributesTransitive; |
2166 | //} | ||
2161 | break; | 2167 | break; |
2162 | case "UninstallWhenSuperseded": | 2168 | case "UninstallWhenSuperseded": |
2163 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2169 | uninstallWhenSuperseded = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2164 | { | 2170 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2165 | bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence; | 2171 | //{ |
2166 | } | 2172 | // bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence; |
2173 | //} | ||
2167 | break; | 2174 | break; |
2168 | case "Win64": | 2175 | case "Win64": |
2169 | explicitWin64 = true; | 2176 | explicitWin64 = true; |
2170 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 2177 | win64 = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
2171 | { | 2178 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
2172 | bits |= MsiInterop.MsidbComponentAttributes64bit; | 2179 | //{ |
2173 | win64 = true; | 2180 | // bits |= MsiInterop.MsidbComponentAttributes64bit; |
2174 | } | 2181 | // win64 = true; |
2182 | //} | ||
2175 | break; | 2183 | break; |
2176 | default: | 2184 | default: |
2177 | this.Core.UnexpectedAttribute(node, attrib); | 2185 | this.Core.UnexpectedAttribute(node, attrib); |
@@ -2186,7 +2194,7 @@ namespace WixToolset.Core | |||
2186 | 2194 | ||
2187 | if (!explicitWin64 && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) | 2195 | if (!explicitWin64 && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) |
2188 | { | 2196 | { |
2189 | bits |= MsiInterop.MsidbComponentAttributes64bit; | 2197 | //bits |= MsiInterop.MsidbComponentAttributes64bit; |
2190 | win64 = true; | 2198 | win64 = true; |
2191 | } | 2199 | } |
2192 | 2200 | ||
@@ -2195,12 +2203,12 @@ namespace WixToolset.Core | |||
2195 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); | 2203 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); |
2196 | } | 2204 | } |
2197 | 2205 | ||
2198 | if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)) | 2206 | if (String.IsNullOrEmpty(guid) && shared /*MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)*/) |
2199 | { | 2207 | { |
2200 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Shared", "yes", "Guid", "")); | 2208 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Shared", "yes", "Guid", "")); |
2201 | } | 2209 | } |
2202 | 2210 | ||
2203 | if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)) | 2211 | if (String.IsNullOrEmpty(guid) && permanent /*MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)*/) |
2204 | { | 2212 | { |
2205 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Permanent", "yes", "Guid", "")); | 2213 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Permanent", "yes", "Guid", "")); |
2206 | } | 2214 | } |
@@ -2228,7 +2236,7 @@ namespace WixToolset.Core | |||
2228 | { | 2236 | { |
2229 | var keyPathSet = YesNoType.NotSet; | 2237 | var keyPathSet = YesNoType.NotSet; |
2230 | string keyPossible = null; | 2238 | string keyPossible = null; |
2231 | var keyBit = 0; | 2239 | ComponentKeyPathType? keyBit = null; |
2232 | 2240 | ||
2233 | if (CompilerCore.WixNamespace == child.Name.Namespace) | 2241 | if (CompilerCore.WixNamespace == child.Name.Namespace) |
2234 | { | 2242 | { |
@@ -2269,10 +2277,7 @@ namespace WixToolset.Core | |||
2269 | break; | 2277 | break; |
2270 | case "File": | 2278 | case "File": |
2271 | keyPathSet = this.ParseFileElement(child, id.Id, directoryId, diskId, srcPath, out keyPossible, win64, guid); | 2279 | keyPathSet = this.ParseFileElement(child, id.Id, directoryId, diskId, srcPath, out keyPossible, win64, guid); |
2272 | if (null != keyPossible) | 2280 | keyBit = ComponentKeyPathType.File; |
2273 | { | ||
2274 | keyBit = 0; | ||
2275 | } | ||
2276 | files++; | 2281 | files++; |
2277 | break; | 2282 | break; |
2278 | case "IniFile": | 2283 | case "IniFile": |
@@ -2286,7 +2291,7 @@ namespace WixToolset.Core | |||
2286 | break; | 2291 | break; |
2287 | case "ODBCDataSource": | 2292 | case "ODBCDataSource": |
2288 | keyPathSet = this.ParseODBCDataSource(child, id.Id, null, out keyPossible); | 2293 | keyPathSet = this.ParseODBCDataSource(child, id.Id, null, out keyPossible); |
2289 | keyBit = MsiInterop.MsidbComponentAttributesODBCDataSource; | 2294 | keyBit = ComponentKeyPathType.OdbcDataSource; |
2290 | encounteredODBCDataSource = true; | 2295 | encounteredODBCDataSource = true; |
2291 | break; | 2296 | break; |
2292 | case "ODBCDriver": | 2297 | case "ODBCDriver": |
@@ -2300,12 +2305,12 @@ namespace WixToolset.Core | |||
2300 | this.ParseProgIdElement(child, id.Id, YesNoType.NotSet, null, null, null, ref foundExtension, YesNoType.NotSet); | 2305 | this.ParseProgIdElement(child, id.Id, YesNoType.NotSet, null, null, null, ref foundExtension, YesNoType.NotSet); |
2301 | break; | 2306 | break; |
2302 | case "RegistryKey": | 2307 | case "RegistryKey": |
2303 | keyPathSet = this.ParseRegistryKeyElement(child, id.Id, CompilerConstants.IntegerNotSet, null, win64, out keyPossible); | 2308 | keyPathSet = this.ParseRegistryKeyElement(child, id.Id, null, null, win64, out keyPossible); |
2304 | keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; | 2309 | keyBit = ComponentKeyPathType.Registry; |
2305 | break; | 2310 | break; |
2306 | case "RegistryValue": | 2311 | case "RegistryValue": |
2307 | keyPathSet = this.ParseRegistryValueElement(child, id.Id, CompilerConstants.IntegerNotSet, null, win64, out keyPossible); | 2312 | keyPathSet = this.ParseRegistryValueElement(child, id.Id, null, null, win64, out keyPossible); |
2308 | keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; | 2313 | keyBit = ComponentKeyPathType.Registry; |
2309 | break; | 2314 | break; |
2310 | case "RemoveFile": | 2315 | case "RemoveFile": |
2311 | this.ParseRemoveFileElement(child, id.Id, directoryId); | 2316 | this.ParseRemoveFileElement(child, id.Id, directoryId); |
@@ -2354,7 +2359,7 @@ namespace WixToolset.Core | |||
2354 | var possibleKeyPath = this.Core.ParsePossibleKeyPathExtensionElement(node, child, context); | 2359 | var possibleKeyPath = this.Core.ParsePossibleKeyPathExtensionElement(node, child, context); |
2355 | if (null != possibleKeyPath) | 2360 | if (null != possibleKeyPath) |
2356 | { | 2361 | { |
2357 | if (ComponentKeyPathType.None == possibleKeyPath.Type) | 2362 | if (PossibleKeyPathType.None == possibleKeyPath.Type) |
2358 | { | 2363 | { |
2359 | keyPathSet = YesNoType.No; | 2364 | keyPathSet = YesNoType.No; |
2360 | } | 2365 | } |
@@ -2367,9 +2372,9 @@ namespace WixToolset.Core | |||
2367 | keyPossible = possibleKeyPath.Id; | 2372 | keyPossible = possibleKeyPath.Id; |
2368 | } | 2373 | } |
2369 | 2374 | ||
2370 | if (ComponentKeyPathType.Registry == possibleKeyPath.Type || ComponentKeyPathType.RegistryFormatted == possibleKeyPath.Type) | 2375 | if (PossibleKeyPathType.Registry == possibleKeyPath.Type || PossibleKeyPathType.RegistryFormatted == possibleKeyPath.Type) |
2371 | { | 2376 | { |
2372 | keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; | 2377 | keyBit = ComponentKeyPathType.Registry; //MsiInterop.MsidbComponentAttributesRegistryKeyPath; |
2373 | } | 2378 | } |
2374 | } | 2379 | } |
2375 | } | 2380 | } |
@@ -2391,11 +2396,10 @@ namespace WixToolset.Core | |||
2391 | { | 2396 | { |
2392 | keyFound = YesNoType.Yes == keyPathSet; | 2397 | keyFound = YesNoType.Yes == keyPathSet; |
2393 | keyPath = keyPossible; | 2398 | keyPath = keyPossible; |
2394 | keyBits = keyBit; | 2399 | keyPathType = keyBit.Value; |
2395 | } | 2400 | } |
2396 | } | 2401 | } |
2397 | 2402 | ||
2398 | |||
2399 | if (shouldAddCreateFolder) | 2403 | if (shouldAddCreateFolder) |
2400 | { | 2404 | { |
2401 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CreateFolder, new Identifier(AccessModifier.Public, directoryId, id.Id)); | 2405 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CreateFolder, new Identifier(AccessModifier.Public, directoryId, id.Id)); |
@@ -2413,7 +2417,7 @@ namespace WixToolset.Core | |||
2413 | isGeneratableGuidOk = false; | 2417 | isGeneratableGuidOk = false; |
2414 | } | 2418 | } |
2415 | 2419 | ||
2416 | if (0 != files && MsiInterop.MsidbComponentAttributesRegistryKeyPath == keyBits) | 2420 | if (0 < files && ComponentKeyPathType.Registry == keyPathType) |
2417 | { | 2421 | { |
2418 | this.Core.Write(ErrorMessages.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers, true)); | 2422 | this.Core.Write(ErrorMessages.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers, true)); |
2419 | isGeneratableGuidOk = false; | 2423 | isGeneratableGuidOk = false; |
@@ -2452,16 +2456,43 @@ namespace WixToolset.Core | |||
2452 | // finally add the Component table row | 2456 | // finally add the Component table row |
2453 | if (!this.Core.EncounteredError) | 2457 | if (!this.Core.EncounteredError) |
2454 | { | 2458 | { |
2455 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Component, id); | 2459 | var tuple = new ComponentTuple(sourceLineNumbers, id) |
2456 | row.Set(1, guid); | 2460 | { |
2457 | row.Set(2, directoryId); | 2461 | Component = id.Id, |
2458 | row.Set(3, bits | keyBits); | 2462 | ComponentId = guid, |
2459 | row.Set(4, condition); | 2463 | Directory_ = directoryId, |
2460 | row.Set(5, keyPath); | 2464 | Location = location, |
2465 | Condition = condition, | ||
2466 | KeyPath = keyPath, | ||
2467 | KeyPathType = keyPathType, | ||
2468 | DisableRegistryReflection = disableRegistryReflection, | ||
2469 | NeverOverwrite = neverOverwrite, | ||
2470 | Permanent = permanent, | ||
2471 | SharedDllRefCount = sharedDllRefCount, | ||
2472 | Transitive = transitive, | ||
2473 | UninstallWhenSuperseded = uninstallWhenSuperseded, | ||
2474 | Win64 = win64, | ||
2475 | }; | ||
2476 | |||
2477 | this.Core.AddTuple(tuple); | ||
2478 | |||
2479 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Component, id); | ||
2480 | //row.Set(1, guid); | ||
2481 | //row.Set(2, directoryId); | ||
2482 | //row.Set(3, bits | keyBits); | ||
2483 | //row.Set(4, condition); | ||
2484 | //row.Set(5, keyPath); | ||
2461 | 2485 | ||
2462 | if (multiInstance) | 2486 | if (multiInstance) |
2463 | { | 2487 | { |
2464 | var instanceComponentRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixInstanceComponent, id); | 2488 | //var instanceComponentRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixInstanceComponent, id); |
2489 | |||
2490 | var instanceComponentTuple = new WixInstanceComponentTuple(sourceLineNumbers, id) | ||
2491 | { | ||
2492 | Component_ = id.Id, | ||
2493 | }; | ||
2494 | |||
2495 | this.Core.AddTuple(instanceComponentTuple); | ||
2465 | } | 2496 | } |
2466 | 2497 | ||
2467 | if (0 < symbols.Count) | 2498 | if (0 < symbols.Count) |
@@ -2474,8 +2505,13 @@ namespace WixToolset.Core | |||
2474 | // Complus | 2505 | // Complus |
2475 | if (CompilerConstants.IntegerNotSet != comPlusBits) | 2506 | if (CompilerConstants.IntegerNotSet != comPlusBits) |
2476 | { | 2507 | { |
2477 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Complus, id); | 2508 | var complusTuple = new ComplusTuple(sourceLineNumbers) |
2478 | row.Set(1, comPlusBits); | 2509 | { |
2510 | Component_ = id.Id, | ||
2511 | ExpType = comPlusBits, | ||
2512 | }; | ||
2513 | |||
2514 | this.Core.AddTuple(complusTuple); | ||
2479 | } | 2515 | } |
2480 | 2516 | ||
2481 | // if this is a module, automatically add this component to the references to ensure it gets in the ModuleComponents table | 2517 | // if this is a module, automatically add this component to the references to ensure it gets in the ModuleComponents table |
@@ -2685,8 +2721,7 @@ namespace WixToolset.Core | |||
2685 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 2721 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
2686 | Identifier id = null; | 2722 | Identifier id = null; |
2687 | string componentId = null; | 2723 | string componentId = null; |
2688 | var type = MsiInterop.MsidbLocatorTypeFileName; | 2724 | var type = LocatorType.Filename; |
2689 | string signature = null; | ||
2690 | 2725 | ||
2691 | foreach (var attrib in node.Attributes()) | 2726 | foreach (var attrib in node.Attributes()) |
2692 | { | 2727 | { |
@@ -2702,21 +2737,19 @@ namespace WixToolset.Core | |||
2702 | break; | 2737 | break; |
2703 | case "Type": | 2738 | case "Type": |
2704 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 2739 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
2705 | if (0 < typeValue.Length) | 2740 | switch (typeValue) |
2706 | { | 2741 | { |
2707 | var typeType = Wix.ComponentSearch.ParseTypeType(typeValue); | 2742 | case "directory": |
2708 | switch (typeType) | 2743 | type = LocatorType.Directory; |
2709 | { | 2744 | break; |
2710 | case Wix.ComponentSearch.TypeType.directory: | 2745 | case "file": |
2711 | type = MsiInterop.MsidbLocatorTypeDirectory; | 2746 | type = LocatorType.Filename; |
2712 | break; | 2747 | break; |
2713 | case Wix.ComponentSearch.TypeType.file: | 2748 | case "": |
2714 | type = MsiInterop.MsidbLocatorTypeFileName; | 2749 | break; |
2715 | break; | 2750 | default: |
2716 | default: | 2751 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "directory", "file")); |
2717 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "directory", "file")); | 2752 | break; |
2718 | break; | ||
2719 | } | ||
2720 | } | 2753 | } |
2721 | break; | 2754 | break; |
2722 | default: | 2755 | default: |
@@ -2735,7 +2768,7 @@ namespace WixToolset.Core | |||
2735 | id = this.Core.CreateIdentifier("cmp", componentId, type.ToString()); | 2768 | id = this.Core.CreateIdentifier("cmp", componentId, type.ToString()); |
2736 | } | 2769 | } |
2737 | 2770 | ||
2738 | signature = id.Id; | 2771 | var signature = id.Id; |
2739 | var oneChild = false; | 2772 | var oneChild = false; |
2740 | foreach (var child in node.Elements()) | 2773 | foreach (var child in node.Elements()) |
2741 | { | 2774 | { |
@@ -2793,9 +2826,17 @@ namespace WixToolset.Core | |||
2793 | 2826 | ||
2794 | if (!this.Core.EncounteredError) | 2827 | if (!this.Core.EncounteredError) |
2795 | { | 2828 | { |
2796 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CompLocator, id); | 2829 | var tuple = new CompLocatorTuple(sourceLineNumbers, id) |
2797 | row.Set(1, componentId); | 2830 | { |
2798 | row.Set(2, type); | 2831 | ComponentId = componentId, |
2832 | Type = type, | ||
2833 | }; | ||
2834 | |||
2835 | this.Core.AddTuple(tuple); | ||
2836 | |||
2837 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CompLocator, id); | ||
2838 | //row.Set(1, componentId); | ||
2839 | //row.Set(2, type); | ||
2799 | } | 2840 | } |
2800 | 2841 | ||
2801 | return signature; | 2842 | return signature; |
@@ -3070,17 +3111,23 @@ namespace WixToolset.Core | |||
3070 | { | 3111 | { |
3071 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 3112 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
3072 | Identifier id = null; | 3113 | Identifier id = null; |
3073 | var bits = 0; | ||
3074 | var extendedBits = 0; | ||
3075 | var inlineScript = false; | 3114 | var inlineScript = false; |
3076 | string innerText = null; | ||
3077 | string source = null; | ||
3078 | var sourceBits = 0; | ||
3079 | var suppressModularization = YesNoType.NotSet; | 3115 | var suppressModularization = YesNoType.NotSet; |
3116 | string source = null; | ||
3080 | string target = null; | 3117 | string target = null; |
3081 | var targetBits = 0; | ||
3082 | var explicitWin64 = false; | 3118 | var explicitWin64 = false; |
3083 | 3119 | ||
3120 | CustomActionSourceType? sourceType = null; | ||
3121 | CustomActionTargetType? targetType = null; | ||
3122 | var executionType = CustomActionExecutionType.Immediate; | ||
3123 | var hidden = false; | ||
3124 | var impersonate = true; | ||
3125 | var patchUninstall = false; | ||
3126 | var tsAware = false; | ||
3127 | var win64 = false; | ||
3128 | var async = false; | ||
3129 | var ignoreResult = false; | ||
3130 | |||
3084 | foreach (var attrib in node.Attributes()) | 3131 | foreach (var attrib in node.Attributes()) |
3085 | { | 3132 | { |
3086 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | 3133 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) |
@@ -3096,7 +3143,8 @@ namespace WixToolset.Core | |||
3096 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | 3143 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); |
3097 | } | 3144 | } |
3098 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | 3145 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); |
3099 | sourceBits = MsiInterop.MsidbCustomActionTypeBinaryData; | 3146 | //sourceBits = MsiInterop.MsidbCustomActionTypeBinaryData; |
3147 | sourceType = CustomActionSourceType.Binary; | ||
3100 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", source); // add a reference to the appropriate Binary | 3148 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", source); // add a reference to the appropriate Binary |
3101 | break; | 3149 | break; |
3102 | case "Directory": | 3150 | case "Directory": |
@@ -3105,7 +3153,8 @@ namespace WixToolset.Core | |||
3105 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | 3153 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); |
3106 | } | 3154 | } |
3107 | source = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | 3155 | source = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); |
3108 | sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; | 3156 | //sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; |
3157 | sourceType = CustomActionSourceType.Directory; | ||
3109 | break; | 3158 | break; |
3110 | case "DllEntry": | 3159 | case "DllEntry": |
3111 | if (null != target) | 3160 | if (null != target) |
@@ -3113,7 +3162,8 @@ namespace WixToolset.Core | |||
3113 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3162 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3114 | } | 3163 | } |
3115 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 3164 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
3116 | targetBits = MsiInterop.MsidbCustomActionTypeDll; | 3165 | //targetBits = MsiInterop.MsidbCustomActionTypeDll; |
3166 | targetType = CustomActionTargetType.Dll; | ||
3117 | break; | 3167 | break; |
3118 | case "Error": | 3168 | case "Error": |
3119 | if (null != target) | 3169 | if (null != target) |
@@ -3121,27 +3171,14 @@ namespace WixToolset.Core | |||
3121 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3171 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3122 | } | 3172 | } |
3123 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 3173 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
3124 | targetBits = MsiInterop.MsidbCustomActionTypeTextData | MsiInterop.MsidbCustomActionTypeSourceFile; | 3174 | //targetBits = MsiInterop.MsidbCustomActionTypeTextData | MsiInterop.MsidbCustomActionTypeSourceFile; |
3175 | sourceType = CustomActionSourceType.File; | ||
3176 | targetType = CustomActionTargetType.TextData; | ||
3125 | 3177 | ||
3126 | var errorReference = true; | 3178 | // The target can be either a formatted error string or a literal |
3127 | 3179 | // error number. Try to convert to error number to determine whether | |
3128 | try | 3180 | // to add a reference. No need to look at the value. |
3129 | { | 3181 | if (Int32.TryParse(target, out var ignored)) |
3130 | // The target can be either a formatted error string or a literal | ||
3131 | // error number. Try to convert to error number to determine whether | ||
3132 | // to add a reference. No need to look at the value. | ||
3133 | Convert.ToInt32(target, CultureInfo.InvariantCulture.NumberFormat); | ||
3134 | } | ||
3135 | catch (FormatException) | ||
3136 | { | ||
3137 | errorReference = false; | ||
3138 | } | ||
3139 | catch (OverflowException) | ||
3140 | { | ||
3141 | errorReference = false; | ||
3142 | } | ||
3143 | |||
3144 | if (errorReference) | ||
3145 | { | 3182 | { |
3146 | this.Core.CreateSimpleReference(sourceLineNumbers, "Error", target); | 3183 | this.Core.CreateSimpleReference(sourceLineNumbers, "Error", target); |
3147 | } | 3184 | } |
@@ -3152,39 +3189,43 @@ namespace WixToolset.Core | |||
3152 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3189 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3153 | } | 3190 | } |
3154 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | 3191 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid |
3155 | targetBits = MsiInterop.MsidbCustomActionTypeExe; | 3192 | //targetBits = MsiInterop.MsidbCustomActionTypeExe; |
3193 | targetType = CustomActionTargetType.Exe; | ||
3156 | break; | 3194 | break; |
3157 | case "Execute": | 3195 | case "Execute": |
3158 | var execute = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 3196 | var execute = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
3159 | if (0 < execute.Length) | 3197 | switch (execute) |
3160 | { | 3198 | { |
3161 | var executeType = Wix.CustomAction.ParseExecuteType(execute); | 3199 | case "commit": |
3162 | switch (executeType) | 3200 | //bits |= MsiInterop.MsidbCustomActionTypeInScript | MsiInterop.MsidbCustomActionTypeCommit; |
3163 | { | 3201 | executionType = CustomActionExecutionType.Commit; |
3164 | case Wix.CustomAction.ExecuteType.commit: | 3202 | break; |
3165 | bits |= MsiInterop.MsidbCustomActionTypeInScript | MsiInterop.MsidbCustomActionTypeCommit; | 3203 | case "deferred": |
3166 | break; | 3204 | //bits |= MsiInterop.MsidbCustomActionTypeInScript; |
3167 | case Wix.CustomAction.ExecuteType.deferred: | 3205 | executionType = CustomActionExecutionType.Deferred; |
3168 | bits |= MsiInterop.MsidbCustomActionTypeInScript; | 3206 | break; |
3169 | break; | 3207 | case "firstSequence": |
3170 | case Wix.CustomAction.ExecuteType.firstSequence: | 3208 | //bits |= MsiInterop.MsidbCustomActionTypeFirstSequence; |
3171 | bits |= MsiInterop.MsidbCustomActionTypeFirstSequence; | 3209 | executionType = CustomActionExecutionType.FirstSequence; |
3172 | break; | 3210 | break; |
3173 | case Wix.CustomAction.ExecuteType.immediate: | 3211 | case "immediate": |
3174 | break; | 3212 | executionType = CustomActionExecutionType.Immediate; |
3175 | case Wix.CustomAction.ExecuteType.oncePerProcess: | 3213 | break; |
3176 | bits |= MsiInterop.MsidbCustomActionTypeOncePerProcess; | 3214 | case "oncePerProcess": |
3177 | break; | 3215 | //bits |= MsiInterop.MsidbCustomActionTypeOncePerProcess; |
3178 | case Wix.CustomAction.ExecuteType.rollback: | 3216 | executionType = CustomActionExecutionType.OncePerProcess; |
3179 | bits |= MsiInterop.MsidbCustomActionTypeInScript | MsiInterop.MsidbCustomActionTypeRollback; | 3217 | break; |
3180 | break; | 3218 | case "rollback": |
3181 | case Wix.CustomAction.ExecuteType.secondSequence: | 3219 | //bits |= MsiInterop.MsidbCustomActionTypeInScript | MsiInterop.MsidbCustomActionTypeRollback; |
3182 | bits |= MsiInterop.MsidbCustomActionTypeClientRepeat; | 3220 | executionType = CustomActionExecutionType.Rollback; |
3183 | break; | 3221 | break; |
3184 | default: | 3222 | case "secondSequence": |
3185 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, execute, "commit", "deferred", "firstSequence", "immediate", "oncePerProcess", "rollback", "secondSequence")); | 3223 | //bits |= MsiInterop.MsidbCustomActionTypeClientRepeat; |
3186 | break; | 3224 | executionType = CustomActionExecutionType.ClientRepeat; |
3187 | } | 3225 | break; |
3226 | default: | ||
3227 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, execute, "commit", "deferred", "firstSequence", "immediate", "oncePerProcess", "rollback", "secondSequence")); | ||
3228 | break; | ||
3188 | } | 3229 | } |
3189 | break; | 3230 | break; |
3190 | case "FileKey": | 3231 | case "FileKey": |
@@ -3193,20 +3234,23 @@ namespace WixToolset.Core | |||
3193 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | 3234 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); |
3194 | } | 3235 | } |
3195 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | 3236 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); |
3196 | sourceBits = MsiInterop.MsidbCustomActionTypeSourceFile; | 3237 | //sourceBits = MsiInterop.MsidbCustomActionTypeSourceFile; |
3238 | sourceType = CustomActionSourceType.File; | ||
3197 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", source); // add a reference to the appropriate File | 3239 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", source); // add a reference to the appropriate File |
3198 | break; | 3240 | break; |
3199 | case "HideTarget": | 3241 | case "HideTarget": |
3200 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 3242 | hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
3201 | { | 3243 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
3202 | bits |= MsiInterop.MsidbCustomActionTypeHideTarget; | 3244 | //{ |
3203 | } | 3245 | // bits |= MsiInterop.MsidbCustomActionTypeHideTarget; |
3246 | //} | ||
3204 | break; | 3247 | break; |
3205 | case "Impersonate": | 3248 | case "Impersonate": |
3206 | if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 3249 | impersonate = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
3207 | { | 3250 | //if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
3208 | bits |= MsiInterop.MsidbCustomActionTypeNoImpersonate; | 3251 | //{ |
3209 | } | 3252 | // bits |= MsiInterop.MsidbCustomActionTypeNoImpersonate; |
3253 | //} | ||
3210 | break; | 3254 | break; |
3211 | case "JScriptCall": | 3255 | case "JScriptCall": |
3212 | if (null != target) | 3256 | if (null != target) |
@@ -3214,13 +3258,15 @@ namespace WixToolset.Core | |||
3214 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3258 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3215 | } | 3259 | } |
3216 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | 3260 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid |
3217 | targetBits = MsiInterop.MsidbCustomActionTypeJScript; | 3261 | //targetBits = MsiInterop.MsidbCustomActionTypeJScript; |
3262 | targetType = CustomActionTargetType.JScript; | ||
3218 | break; | 3263 | break; |
3219 | case "PatchUninstall": | 3264 | case "PatchUninstall": |
3220 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 3265 | patchUninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
3221 | { | 3266 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
3222 | extendedBits |= MsiInterop.MsidbCustomActionTypePatchUninstall; | 3267 | //{ |
3223 | } | 3268 | // extendedBits |= MsiInterop.MsidbCustomActionTypePatchUninstall; |
3269 | //} | ||
3224 | break; | 3270 | break; |
3225 | case "Property": | 3271 | case "Property": |
3226 | if (null != source) | 3272 | if (null != source) |
@@ -3228,30 +3274,33 @@ namespace WixToolset.Core | |||
3228 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | 3274 | this.Core.Write(ErrorMessages.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); |
3229 | } | 3275 | } |
3230 | source = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 3276 | source = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
3231 | sourceBits = MsiInterop.MsidbCustomActionTypeProperty; | 3277 | //sourceBits = MsiInterop.MsidbCustomActionTypeProperty; |
3278 | sourceType = CustomActionSourceType.Property; | ||
3232 | break; | 3279 | break; |
3233 | case "Return": | 3280 | case "Return": |
3234 | var returnValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 3281 | var returnValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
3235 | if (0 < returnValue.Length) | 3282 | switch (returnValue) |
3236 | { | 3283 | { |
3237 | var returnType = Wix.CustomAction.ParseReturnType(returnValue); | 3284 | case "asyncNoWait": |
3238 | switch (returnType) | 3285 | //bits |= MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue; |
3239 | { | 3286 | async = true; |
3240 | case Wix.CustomAction.ReturnType.asyncNoWait: | 3287 | ignoreResult = true; |
3241 | bits |= MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue; | 3288 | break; |
3242 | break; | 3289 | case "asyncWait": |
3243 | case Wix.CustomAction.ReturnType.asyncWait: | 3290 | //bits |= MsiInterop.MsidbCustomActionTypeAsync; |
3244 | bits |= MsiInterop.MsidbCustomActionTypeAsync; | 3291 | async = true; |
3245 | break; | 3292 | break; |
3246 | case Wix.CustomAction.ReturnType.check: | 3293 | case "check": |
3247 | break; | 3294 | break; |
3248 | case Wix.CustomAction.ReturnType.ignore: | 3295 | case "ignore": |
3249 | bits |= MsiInterop.MsidbCustomActionTypeContinue; | 3296 | //bits |= MsiInterop.MsidbCustomActionTypeContinue; |
3250 | break; | 3297 | ignoreResult = true; |
3251 | default: | 3298 | break; |
3252 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, returnValue, "asyncNoWait", "asyncWait", "check", "ignore")); | 3299 | case "": |
3253 | break; | 3300 | break; |
3254 | } | 3301 | default: |
3302 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, returnValue, "asyncNoWait", "asyncWait", "check", "ignore")); | ||
3303 | break; | ||
3255 | } | 3304 | } |
3256 | break; | 3305 | break; |
3257 | case "Script": | 3306 | case "Script": |
@@ -3272,33 +3321,36 @@ namespace WixToolset.Core | |||
3272 | inlineScript = true; | 3321 | inlineScript = true; |
3273 | 3322 | ||
3274 | var script = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 3323 | var script = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
3275 | if (0 < script.Length) | 3324 | switch (script) |
3276 | { | 3325 | { |
3277 | var scriptType = Wix.CustomAction.ParseScriptType(script); | 3326 | case "jscript": |
3278 | switch (scriptType) | 3327 | //sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; |
3279 | { | 3328 | sourceType = CustomActionSourceType.Directory; |
3280 | case Wix.CustomAction.ScriptType.jscript: | 3329 | //targetBits = MsiInterop.MsidbCustomActionTypeJScript; |
3281 | sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; | 3330 | targetType = CustomActionTargetType.JScript; |
3282 | targetBits = MsiInterop.MsidbCustomActionTypeJScript; | 3331 | break; |
3283 | break; | 3332 | case "vbscript": |
3284 | case Wix.CustomAction.ScriptType.vbscript: | 3333 | //sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; |
3285 | sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; | 3334 | sourceType = CustomActionSourceType.Directory; |
3286 | targetBits = MsiInterop.MsidbCustomActionTypeVBScript; | 3335 | //targetBits = MsiInterop.MsidbCustomActionTypeVBScript; |
3287 | break; | 3336 | targetType = CustomActionTargetType.VBScript; |
3288 | default: | 3337 | break; |
3289 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, script, "jscript", "vbscript")); | 3338 | case "": |
3290 | break; | 3339 | break; |
3291 | } | 3340 | default: |
3341 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, script, "jscript", "vbscript")); | ||
3342 | break; | ||
3292 | } | 3343 | } |
3293 | break; | 3344 | break; |
3294 | case "SuppressModularization": | 3345 | case "SuppressModularization": |
3295 | suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 3346 | suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
3296 | break; | 3347 | break; |
3297 | case "TerminalServerAware": | 3348 | case "TerminalServerAware": |
3298 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 3349 | tsAware = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
3299 | { | 3350 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
3300 | bits |= MsiInterop.MsidbCustomActionTypeTSAware; | 3351 | //{ |
3301 | } | 3352 | // bits |= MsiInterop.MsidbCustomActionTypeTSAware; |
3353 | //} | ||
3302 | break; | 3354 | break; |
3303 | case "Value": | 3355 | case "Value": |
3304 | if (null != target) | 3356 | if (null != target) |
@@ -3306,7 +3358,8 @@ namespace WixToolset.Core | |||
3306 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3358 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3307 | } | 3359 | } |
3308 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | 3360 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid |
3309 | targetBits = MsiInterop.MsidbCustomActionTypeTextData; | 3361 | //targetBits = MsiInterop.MsidbCustomActionTypeTextData; |
3362 | targetType = CustomActionTargetType.TextData; | ||
3310 | break; | 3363 | break; |
3311 | case "VBScriptCall": | 3364 | case "VBScriptCall": |
3312 | if (null != target) | 3365 | if (null != target) |
@@ -3314,14 +3367,16 @@ namespace WixToolset.Core | |||
3314 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3367 | this.Core.Write(ErrorMessages.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3315 | } | 3368 | } |
3316 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | 3369 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid |
3317 | targetBits = MsiInterop.MsidbCustomActionTypeVBScript; | 3370 | //targetBits = MsiInterop.MsidbCustomActionTypeVBScript; |
3371 | targetType = CustomActionTargetType.VBScript; | ||
3318 | break; | 3372 | break; |
3319 | case "Win64": | 3373 | case "Win64": |
3320 | explicitWin64 = true; | 3374 | explicitWin64 = true; |
3321 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 3375 | win64 = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
3322 | { | 3376 | //if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
3323 | bits |= MsiInterop.MsidbCustomActionType64BitScript; | 3377 | //{ |
3324 | } | 3378 | // bits |= MsiInterop.MsidbCustomActionType64BitScript; |
3379 | //} | ||
3325 | break; | 3380 | break; |
3326 | default: | 3381 | default: |
3327 | this.Core.UnexpectedAttribute(node, attrib); | 3382 | this.Core.UnexpectedAttribute(node, attrib); |
@@ -3340,49 +3395,49 @@ namespace WixToolset.Core | |||
3340 | id = Identifier.Invalid; | 3395 | id = Identifier.Invalid; |
3341 | } | 3396 | } |
3342 | 3397 | ||
3343 | if (!explicitWin64 && (MsiInterop.MsidbCustomActionTypeVBScript == targetBits || MsiInterop.MsidbCustomActionTypeJScript == targetBits) && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) | 3398 | if (!explicitWin64 && (CustomActionTargetType.VBScript == targetType || CustomActionTargetType.JScript == targetType) && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) |
3344 | { | 3399 | { |
3345 | bits |= MsiInterop.MsidbCustomActionType64BitScript; | 3400 | win64 = true; |
3346 | } | 3401 | } |
3347 | 3402 | ||
3348 | // get the inner text if any exists | 3403 | // get the inner text if any exists |
3349 | innerText = this.Core.GetTrimmedInnerText(node); | 3404 | var innerText = this.Core.GetTrimmedInnerText(node); |
3350 | 3405 | ||
3351 | // if we have an in-lined Script CustomAction ensure no source or target attributes were provided | 3406 | // if we have an in-lined Script CustomAction ensure no source or target attributes were provided |
3352 | if (inlineScript) | 3407 | if (inlineScript) |
3353 | { | 3408 | { |
3354 | target = innerText; | 3409 | target = innerText; |
3355 | } | 3410 | } |
3356 | else if (MsiInterop.MsidbCustomActionTypeVBScript == targetBits) // non-inline vbscript | 3411 | else if (CustomActionTargetType.VBScript == targetType) // non-inline vbscript |
3357 | { | 3412 | { |
3358 | if (null == source) | 3413 | if (null == source) |
3359 | { | 3414 | { |
3360 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "VBScriptCall", "BinaryKey", "FileKey", "Property")); | 3415 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "VBScriptCall", "BinaryKey", "FileKey", "Property")); |
3361 | } | 3416 | } |
3362 | else if (MsiInterop.MsidbCustomActionTypeDirectory == sourceBits) | 3417 | else if (CustomActionSourceType.Directory == sourceType) |
3363 | { | 3418 | { |
3364 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "VBScriptCall", "Directory")); | 3419 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "VBScriptCall", "Directory")); |
3365 | } | 3420 | } |
3366 | } | 3421 | } |
3367 | else if (MsiInterop.MsidbCustomActionTypeJScript == targetBits) // non-inline jscript | 3422 | else if (CustomActionTargetType.JScript == targetType) // non-inline jscript |
3368 | { | 3423 | { |
3369 | if (null == source) | 3424 | if (null == source) |
3370 | { | 3425 | { |
3371 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "JScriptCall", "BinaryKey", "FileKey", "Property")); | 3426 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "JScriptCall", "BinaryKey", "FileKey", "Property")); |
3372 | } | 3427 | } |
3373 | else if (MsiInterop.MsidbCustomActionTypeDirectory == sourceBits) | 3428 | else if (CustomActionSourceType.Directory == sourceType) |
3374 | { | 3429 | { |
3375 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "JScriptCall", "Directory")); | 3430 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "JScriptCall", "Directory")); |
3376 | } | 3431 | } |
3377 | } | 3432 | } |
3378 | else if (MsiInterop.MsidbCustomActionTypeExe == targetBits) // exe-command | 3433 | else if (CustomActionTargetType.Exe == targetType) // exe-command |
3379 | { | 3434 | { |
3380 | if (null == source) | 3435 | if (null == source) |
3381 | { | 3436 | { |
3382 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ExeCommand", "BinaryKey", "Directory", "FileKey", "Property")); | 3437 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ExeCommand", "BinaryKey", "Directory", "FileKey", "Property")); |
3383 | } | 3438 | } |
3384 | } | 3439 | } |
3385 | else if (MsiInterop.MsidbCustomActionTypeTextData == (bits | sourceBits | targetBits)) | 3440 | else if (CustomActionTargetType.TextData == targetType && CustomActionSourceType.Directory != sourceType && CustomActionSourceType.Property != sourceType) |
3386 | { | 3441 | { |
3387 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Value", "Directory", "Property")); | 3442 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Value", "Directory", "Property")); |
3388 | } | 3443 | } |
@@ -3391,34 +3446,36 @@ namespace WixToolset.Core | |||
3391 | this.Core.Write(ErrorMessages.CustomActionIllegalInnerText(sourceLineNumbers, node.Name.LocalName, innerText, "Script")); | 3446 | this.Core.Write(ErrorMessages.CustomActionIllegalInnerText(sourceLineNumbers, node.Name.LocalName, innerText, "Script")); |
3392 | } | 3447 | } |
3393 | 3448 | ||
3394 | if (MsiInterop.MsidbCustomActionType64BitScript == (bits & MsiInterop.MsidbCustomActionType64BitScript) && MsiInterop.MsidbCustomActionTypeVBScript != targetBits && MsiInterop.MsidbCustomActionTypeJScript != targetBits) | 3449 | if (win64 && CustomActionTargetType.VBScript != targetType && CustomActionTargetType.JScript != targetType) |
3395 | { | 3450 | { |
3396 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Win64", "Script", "VBScriptCall", "JScriptCall")); | 3451 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Win64", "Script", "VBScriptCall", "JScriptCall")); |
3397 | } | 3452 | } |
3398 | 3453 | ||
3399 | if ((MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue) == (bits & (MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue)) && MsiInterop.MsidbCustomActionTypeExe != targetBits) | 3454 | if (async && ignoreResult && CustomActionTargetType.Exe != targetType) |
3400 | { | 3455 | { |
3401 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Return", "asyncNoWait", "ExeCommand")); | 3456 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Return", "asyncNoWait", "ExeCommand")); |
3402 | } | 3457 | } |
3403 | 3458 | ||
3404 | if (MsiInterop.MsidbCustomActionTypeTSAware == (bits & MsiInterop.MsidbCustomActionTypeTSAware)) | 3459 | // TS-aware CAs are valid only when deferred. |
3460 | if (tsAware & | ||
3461 | CustomActionExecutionType.Deferred != executionType && | ||
3462 | CustomActionExecutionType.Rollback != executionType && | ||
3463 | CustomActionExecutionType.Commit != executionType) | ||
3405 | { | 3464 | { |
3406 | // TS-aware CAs are valid only when deferred so require the in-script Type bit... | 3465 | this.Core.Write(ErrorMessages.IllegalTerminalServerCustomActionAttributes(sourceLineNumbers)); |
3407 | if (0 == (bits & MsiInterop.MsidbCustomActionTypeInScript)) | ||
3408 | { | ||
3409 | this.Core.Write(ErrorMessages.IllegalTerminalServerCustomActionAttributes(sourceLineNumbers)); | ||
3410 | } | ||
3411 | } | 3466 | } |
3412 | 3467 | ||
3413 | // MSI doesn't support in-script property setting, so disallow it | 3468 | // MSI doesn't support in-script property setting, so disallow it |
3414 | if (MsiInterop.MsidbCustomActionTypeProperty == sourceBits && | 3469 | if (CustomActionSourceType.Property == sourceType && |
3415 | MsiInterop.MsidbCustomActionTypeTextData == targetBits && | 3470 | CustomActionTargetType.TextData == targetType && |
3416 | 0 != (bits & MsiInterop.MsidbCustomActionTypeInScript)) | 3471 | (CustomActionExecutionType.Deferred == executionType || |
3472 | CustomActionExecutionType.Rollback == executionType || | ||
3473 | CustomActionExecutionType.Commit == executionType)) | ||
3417 | { | 3474 | { |
3418 | this.Core.Write(ErrorMessages.IllegalPropertyCustomActionAttributes(sourceLineNumbers)); | 3475 | this.Core.Write(ErrorMessages.IllegalPropertyCustomActionAttributes(sourceLineNumbers)); |
3419 | } | 3476 | } |
3420 | 3477 | ||
3421 | if (0 == targetBits) | 3478 | if (!targetType.HasValue /*0 == targetBits*/) |
3422 | { | 3479 | { |
3423 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | 3480 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); |
3424 | } | 3481 | } |
@@ -3427,14 +3484,30 @@ namespace WixToolset.Core | |||
3427 | 3484 | ||
3428 | if (!this.Core.EncounteredError) | 3485 | if (!this.Core.EncounteredError) |
3429 | { | 3486 | { |
3430 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CustomAction, id); | 3487 | var tuple = new CustomActionTuple(sourceLineNumbers, id) |
3431 | row.Set(1, bits | sourceBits | targetBits); | 3488 | { |
3432 | row.Set(2, source); | 3489 | ExecutionType = executionType, |
3433 | row.Set(3, target); | 3490 | Source = source, |
3434 | if (0 != extendedBits) | 3491 | SourceType = sourceType.Value, |
3435 | { | 3492 | Target = target, |
3436 | row.Set(4, extendedBits); | 3493 | TargetType = targetType.Value, |
3437 | } | 3494 | Async = async, |
3495 | IgnoreResult = ignoreResult, | ||
3496 | Impersonate = impersonate, | ||
3497 | PatchUninstall = patchUninstall, | ||
3498 | TSAware = tsAware, | ||
3499 | Win64 = win64, | ||
3500 | }; | ||
3501 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CustomAction, id); | ||
3502 | //row.Set(1, bits | sourceBits | targetBits); | ||
3503 | //row.Set(2, source); | ||
3504 | //row.Set(3, target); | ||
3505 | //if (0 != extendedBits) | ||
3506 | //{ | ||
3507 | // row.Set(4, extendedBits); | ||
3508 | //} | ||
3509 | |||
3510 | this.Core.AddTuple(tuple); | ||
3438 | 3511 | ||
3439 | if (YesNoType.Yes == suppressModularization) | 3512 | if (YesNoType.Yes == suppressModularization) |
3440 | { | 3513 | { |
@@ -3442,10 +3515,12 @@ namespace WixToolset.Core | |||
3442 | } | 3515 | } |
3443 | 3516 | ||
3444 | // For deferred CAs that specify HideTarget we should also hide the CA data property for the action. | 3517 | // For deferred CAs that specify HideTarget we should also hide the CA data property for the action. |
3445 | if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && | 3518 | if (hidden && |
3446 | MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) | 3519 | (CustomActionExecutionType.Deferred == executionType || |
3520 | CustomActionExecutionType.Commit == executionType || | ||
3521 | CustomActionExecutionType.Rollback == executionType)) | ||
3447 | { | 3522 | { |
3448 | this.AddWixPropertyRow(sourceLineNumbers, id, false, false, true); | 3523 | this.AddWixPropertyRow(sourceLineNumbers, id, false, false, hidden); |
3449 | } | 3524 | } |
3450 | } | 3525 | } |
3451 | } | 3526 | } |
@@ -3827,24 +3902,22 @@ namespace WixToolset.Core | |||
3827 | break; | 3902 | break; |
3828 | case "Type": | 3903 | case "Type": |
3829 | var typeValue = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | 3904 | var typeValue = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); |
3830 | if (0 < typeValue.Length) | 3905 | switch (typeValue) |
3831 | { | 3906 | { |
3832 | var typeType = Wix.Column.ParseTypeType(typeValue); | 3907 | case "binary": |
3833 | switch (typeType) | 3908 | typeName = "OBJECT"; |
3834 | { | 3909 | break; |
3835 | case Wix.Column.TypeType.binary: | 3910 | case "int": |
3836 | typeName = "OBJECT"; | 3911 | typeName = "SHORT"; |
3837 | break; | 3912 | break; |
3838 | case Wix.Column.TypeType.@int: | 3913 | case "string": |
3839 | typeName = "SHORT"; | 3914 | typeName = "CHAR"; |
3840 | break; | 3915 | break; |
3841 | case Wix.Column.TypeType.@string: | 3916 | case "": |
3842 | typeName = "CHAR"; | 3917 | break; |
3843 | break; | 3918 | default: |
3844 | default: | 3919 | this.Core.Write(ErrorMessages.IllegalAttributeValue(childSourceLineNumbers, child.Name.LocalName, "Type", typeValue, "binary", "int", "string")); |
3845 | this.Core.Write(ErrorMessages.IllegalAttributeValue(childSourceLineNumbers, child.Name.LocalName, "Type", typeValue, "binary", "int", "string")); | 3920 | break; |
3846 | break; | ||
3847 | } | ||
3848 | } | 3921 | } |
3849 | break; | 3922 | break; |
3850 | case "Width": | 3923 | case "Width": |
@@ -4615,16 +4688,17 @@ namespace WixToolset.Core | |||
4615 | { | 4688 | { |
4616 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 4689 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
4617 | Identifier id = null; | 4690 | Identifier id = null; |
4618 | string allowAdvertise = null; | ||
4619 | var bits = 0; | ||
4620 | string configurableDirectory = null; | 4691 | string configurableDirectory = null; |
4621 | string description = null; | 4692 | string description = null; |
4622 | var display = "collapse"; | 4693 | var displayValue = "collapse"; |
4623 | var followParent = YesNoType.NotSet; | ||
4624 | string installDefault = null; | ||
4625 | var level = 1; | 4694 | var level = 1; |
4626 | string title = null; | 4695 | string title = null; |
4627 | string typicalDefault = null; | 4696 | |
4697 | var installDefault = FeatureInstallDefault.Local; | ||
4698 | var typicalDefault = FeatureTypicalDefault.Install; | ||
4699 | var disallowAbsent = false; | ||
4700 | var disallowAdvertise = false; | ||
4701 | var display = 0; | ||
4628 | 4702 | ||
4629 | foreach (var attrib in node.Attributes()) | 4703 | foreach (var attrib in node.Attributes()) |
4630 | { | 4704 | { |
@@ -4636,42 +4710,39 @@ namespace WixToolset.Core | |||
4636 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | 4710 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); |
4637 | break; | 4711 | break; |
4638 | case "Absent": | 4712 | case "Absent": |
4639 | var absent = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 4713 | var absentValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
4640 | if (0 < absent.Length) | 4714 | switch (absentValue) |
4641 | { | 4715 | { |
4642 | var absentType = Wix.Feature.ParseAbsentType(absent); | 4716 | case "allow": // this is the default |
4643 | switch (absentType) | 4717 | break; |
4644 | { | 4718 | case "disallow": |
4645 | case Wix.Feature.AbsentType.allow: // this is the default | 4719 | //bits |= MsiInterop.MsidbFeatureAttributesUIDisallowAbsent; |
4646 | break; | 4720 | disallowAbsent = true; |
4647 | case Wix.Feature.AbsentType.disallow: | 4721 | break; |
4648 | bits = bits | MsiInterop.MsidbFeatureAttributesUIDisallowAbsent; | 4722 | case "": |
4649 | break; | 4723 | break; |
4650 | default: | 4724 | default: |
4651 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, absent, "allow", "disallow")); | 4725 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, absentValue, "allow", "disallow")); |
4652 | break; | 4726 | break; |
4653 | } | ||
4654 | } | 4727 | } |
4655 | break; | 4728 | break; |
4656 | case "AllowAdvertise": | 4729 | case "AllowAdvertise": |
4657 | allowAdvertise = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 4730 | var advertiseValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
4658 | if (0 < allowAdvertise.Length) | 4731 | switch (advertiseValue) |
4659 | { | 4732 | { |
4660 | var allowAdvertiseType = Wix.Feature.ParseAllowAdvertiseType(allowAdvertise); | 4733 | case "disallow": |
4661 | switch (allowAdvertiseType) | 4734 | case "no": |
4662 | { | 4735 | //bits |= MsiInterop.MsidbFeatureAttributesDisallowAdvertise; |
4663 | case Wix.Feature.AllowAdvertiseType.no: | 4736 | disallowAdvertise = true; |
4664 | bits |= MsiInterop.MsidbFeatureAttributesDisallowAdvertise; | 4737 | break; |
4665 | break; | 4738 | case "allow": |
4666 | case Wix.Feature.AllowAdvertiseType.system: | 4739 | case "yes": // this is the default |
4667 | bits |= MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise; | 4740 | break; |
4668 | break; | 4741 | case "": |
4669 | case Wix.Feature.AllowAdvertiseType.yes: // this is the default | 4742 | break; |
4670 | break; | 4743 | default: |
4671 | default: | 4744 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, advertiseValue, "no", "system", "yes")); |
4672 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, allowAdvertise, "no", "system", "yes")); | 4745 | break; |
4673 | break; | ||
4674 | } | ||
4675 | } | 4746 | } |
4676 | break; | 4747 | break; |
4677 | case "ConfigurableDirectory": | 4748 | case "ConfigurableDirectory": |
@@ -4681,31 +4752,32 @@ namespace WixToolset.Core | |||
4681 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 4752 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
4682 | break; | 4753 | break; |
4683 | case "Display": | 4754 | case "Display": |
4684 | display = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 4755 | displayValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
4685 | break; | 4756 | break; |
4686 | case "InstallDefault": | 4757 | case "InstallDefault": |
4687 | installDefault = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 4758 | var installDefaultValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
4688 | if (0 < installDefault.Length) | 4759 | switch (installDefaultValue) |
4689 | { | 4760 | { |
4690 | var installDefaultType = Wix.Feature.ParseInstallDefaultType(installDefault); | 4761 | case "followParent": |
4691 | switch (installDefaultType) | 4762 | if (ComplexReferenceParentType.Product == parentType) |
4692 | { | 4763 | { |
4693 | case Wix.Feature.InstallDefaultType.followParent: | 4764 | this.Core.Write(ErrorMessages.RootFeatureCannotFollowParent(sourceLineNumbers)); |
4694 | if (ComplexReferenceParentType.Product == parentType) | ||
4695 | { | ||
4696 | this.Core.Write(ErrorMessages.RootFeatureCannotFollowParent(sourceLineNumbers)); | ||
4697 | } | ||
4698 | bits = bits | MsiInterop.MsidbFeatureAttributesFollowParent; | ||
4699 | break; | ||
4700 | case Wix.Feature.InstallDefaultType.local: // this is the default | ||
4701 | break; | ||
4702 | case Wix.Feature.InstallDefaultType.source: | ||
4703 | bits = bits | MsiInterop.MsidbFeatureAttributesFavorSource; | ||
4704 | break; | ||
4705 | default: | ||
4706 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installDefault, "followParent", "local", "source")); | ||
4707 | break; | ||
4708 | } | 4765 | } |
4766 | //bits = bits | MsiInterop.MsidbFeatureAttributesFollowParent; | ||
4767 | installDefault = FeatureInstallDefault.FollowParent; | ||
4768 | break; | ||
4769 | case "local": // this is the default | ||
4770 | installDefault = FeatureInstallDefault.Local; | ||
4771 | break; | ||
4772 | case "source": | ||
4773 | //bits = bits | MsiInterop.MsidbFeatureAttributesFavorSource; | ||
4774 | installDefault = FeatureInstallDefault.Source; | ||
4775 | break; | ||
4776 | case "": | ||
4777 | break; | ||
4778 | default: | ||
4779 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installDefaultValue, "followParent", "local", "source")); | ||
4780 | break; | ||
4709 | } | 4781 | } |
4710 | break; | 4782 | break; |
4711 | case "Level": | 4783 | case "Level": |
@@ -4719,21 +4791,19 @@ namespace WixToolset.Core | |||
4719 | } | 4791 | } |
4720 | break; | 4792 | break; |
4721 | case "TypicalDefault": | 4793 | case "TypicalDefault": |
4722 | typicalDefault = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 4794 | var typicalValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
4723 | if (0 < typicalDefault.Length) | 4795 | switch (typicalValue) |
4724 | { | 4796 | { |
4725 | var typicalDefaultType = Wix.Feature.ParseTypicalDefaultType(typicalDefault); | 4797 | case "advertise": |
4726 | switch (typicalDefaultType) | 4798 | //bits |= MsiInterop.MsidbFeatureAttributesFavorAdvertise; |
4727 | { | 4799 | typicalDefault = FeatureTypicalDefault.Advertise; |
4728 | case Wix.Feature.TypicalDefaultType.advertise: | 4800 | break; |
4729 | bits = bits | MsiInterop.MsidbFeatureAttributesFavorAdvertise; | 4801 | case "install": // this is the default |
4730 | break; | 4802 | typicalDefault = FeatureTypicalDefault.Install; |
4731 | case Wix.Feature.TypicalDefaultType.install: // this is the default | 4803 | break; |
4732 | break; | 4804 | default: |
4733 | default: | 4805 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typicalValue, "advertise", "install")); |
4734 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typicalDefault, "advertise", "install")); | 4806 | break; |
4735 | break; | ||
4736 | } | ||
4737 | } | 4807 | } |
4738 | break; | 4808 | break; |
4739 | default: | 4809 | default: |
@@ -4762,14 +4832,9 @@ namespace WixToolset.Core | |||
4762 | this.Core.Write(ErrorMessages.FeatureConfigurableDirectoryNotUppercase(sourceLineNumbers, node.Name.LocalName, "ConfigurableDirectory", configurableDirectory)); | 4832 | this.Core.Write(ErrorMessages.FeatureConfigurableDirectoryNotUppercase(sourceLineNumbers, node.Name.LocalName, "ConfigurableDirectory", configurableDirectory)); |
4763 | } | 4833 | } |
4764 | 4834 | ||
4765 | if ("advertise" == typicalDefault && "no" == allowAdvertise) | 4835 | if (FeatureTypicalDefault.Advertise == typicalDefault && disallowAdvertise) |
4766 | { | ||
4767 | this.Core.Write(ErrorMessages.FeatureCannotFavorAndDisallowAdvertise(sourceLineNumbers, node.Name.LocalName, "TypicalDefault", typicalDefault, "AllowAdvertise", allowAdvertise)); | ||
4768 | } | ||
4769 | |||
4770 | if (YesNoType.Yes == followParent && ("local" == installDefault || "source" == installDefault)) | ||
4771 | { | 4836 | { |
4772 | this.Core.Write(ErrorMessages.FeatureCannotFollowParentAndFavorLocalOrSource(sourceLineNumbers, node.Name.LocalName, "InstallDefault", "FollowParent", "yes")); | 4837 | this.Core.Write(ErrorMessages.FeatureCannotFavorAndDisallowAdvertise(sourceLineNumbers, node.Name.LocalName, "TypicalDefault", "advertise", "AllowAdvertise", "no")); |
4773 | } | 4838 | } |
4774 | 4839 | ||
4775 | var childDisplay = 0; | 4840 | var childDisplay = 0; |
@@ -4814,48 +4879,91 @@ namespace WixToolset.Core | |||
4814 | } | 4879 | } |
4815 | } | 4880 | } |
4816 | 4881 | ||
4817 | if (!this.Core.EncounteredError) | 4882 | switch (displayValue) |
4818 | { | 4883 | { |
4819 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Feature, id); | 4884 | case "collapse": |
4820 | // row.Set(1, null); - this column is set in the linker | 4885 | lastDisplay = (lastDisplay | 1) + 1; |
4821 | row.Set(2, title); | 4886 | display = lastDisplay; |
4822 | row.Set(3, description); | 4887 | break; |
4823 | if (0 < display.Length) | 4888 | case "expand": |
4889 | lastDisplay = (lastDisplay + 1) | 1; | ||
4890 | display = lastDisplay; | ||
4891 | break; | ||
4892 | case "hidden": | ||
4893 | display = 0; | ||
4894 | break; | ||
4895 | default: | ||
4896 | if (!Int32.TryParse(displayValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out display)) | ||
4897 | { | ||
4898 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Display", displayValue, "collapse", "expand", "hidden")); | ||
4899 | } | ||
4900 | else | ||
4824 | { | 4901 | { |
4825 | switch (display) | 4902 | // Save the display value (if its not hidden) for subsequent rows |
4903 | if (0 != display) | ||
4826 | { | 4904 | { |
4827 | case "collapse": | 4905 | lastDisplay = display; |
4828 | lastDisplay = (lastDisplay | 1) + 1; | ||
4829 | row.Set(4, lastDisplay); | ||
4830 | break; | ||
4831 | case "expand": | ||
4832 | lastDisplay = (lastDisplay + 1) | 1; | ||
4833 | row.Set(4, lastDisplay); | ||
4834 | break; | ||
4835 | case "hidden": | ||
4836 | row.Set(4, 0); | ||
4837 | break; | ||
4838 | default: | ||
4839 | int value; | ||
4840 | if (!Int32.TryParse(display, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) | ||
4841 | { | ||
4842 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Display", display, "collapse", "expand", "hidden")); | ||
4843 | } | ||
4844 | else | ||
4845 | { | ||
4846 | row.Set(4, value); | ||
4847 | // save the display value of this row (if its not hidden) for subsequent rows | ||
4848 | if (0 != (int)row[4]) | ||
4849 | { | ||
4850 | lastDisplay = (int)row[4]; | ||
4851 | } | ||
4852 | } | ||
4853 | break; | ||
4854 | } | 4906 | } |
4855 | } | 4907 | } |
4856 | row.Set(5, level); | 4908 | break; |
4857 | row.Set(6, configurableDirectory); | 4909 | } |
4858 | row.Set(7, bits); | 4910 | |
4911 | if (!this.Core.EncounteredError) | ||
4912 | { | ||
4913 | var tuple = new FeatureTuple(sourceLineNumbers, id) | ||
4914 | { | ||
4915 | Title = title, | ||
4916 | Description = description, | ||
4917 | Display = display, | ||
4918 | Level = level, | ||
4919 | Directory_ = configurableDirectory, | ||
4920 | DisallowAbsent = disallowAbsent, | ||
4921 | DisallowAdvertise = disallowAdvertise, | ||
4922 | InstallDefault = installDefault, | ||
4923 | TypicalDefault = typicalDefault, | ||
4924 | }; | ||
4925 | |||
4926 | this.Core.AddTuple(tuple); | ||
4927 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Feature, id); | ||
4928 | //// row.Set(1, null); - this column is set in the linker | ||
4929 | //row.Set(2, title); | ||
4930 | //row.Set(3, description); | ||
4931 | //if (0 < display.Length) | ||
4932 | //{ | ||
4933 | // switch (display) | ||
4934 | // { | ||
4935 | // case "collapse": | ||
4936 | // lastDisplay = (lastDisplay | 1) + 1; | ||
4937 | // row.Set(4, lastDisplay); | ||
4938 | // break; | ||
4939 | // case "expand": | ||
4940 | // lastDisplay = (lastDisplay + 1) | 1; | ||
4941 | // row.Set(4, lastDisplay); | ||
4942 | // break; | ||
4943 | // case "hidden": | ||
4944 | // row.Set(4, 0); | ||
4945 | // break; | ||
4946 | // default: | ||
4947 | // int value; | ||
4948 | // if (!Int32.TryParse(display, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) | ||
4949 | // { | ||
4950 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Display", display, "collapse", "expand", "hidden")); | ||
4951 | // } | ||
4952 | // else | ||
4953 | // { | ||
4954 | // row.Set(4, value); | ||
4955 | // // save the display value of this row (if its not hidden) for subsequent rows | ||
4956 | // if (0 != (int)row[4]) | ||
4957 | // { | ||
4958 | // lastDisplay = (int)row[4]; | ||
4959 | // } | ||
4960 | // } | ||
4961 | // break; | ||
4962 | // } | ||
4963 | //} | ||
4964 | //row.Set(5, level); | ||
4965 | //row.Set(6, configurableDirectory); | ||
4966 | //row.Set(7, bits); | ||
4859 | 4967 | ||
4860 | if (ComplexReferenceParentType.Unknown != parentType) | 4968 | if (ComplexReferenceParentType.Unknown != parentType) |
4861 | { | 4969 | { |
@@ -5109,15 +5217,13 @@ namespace WixToolset.Core | |||
5109 | { | 5217 | { |
5110 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 5218 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
5111 | Identifier id = null; | 5219 | Identifier id = null; |
5112 | string action = null; | ||
5113 | string name = null; | 5220 | string name = null; |
5114 | var partType = Wix.Environment.PartType.NotSet; | 5221 | EnvironmentActionType? action = null; |
5115 | string part = null; | 5222 | EnvironmentPartType? part = null; |
5116 | var permanent = false; | 5223 | var permanent = false; |
5117 | var separator = ";"; // default to ';' | 5224 | var separator = ";"; // default to ';' |
5118 | var system = false; | 5225 | var system = false; |
5119 | string text = null; | 5226 | string value = null; |
5120 | var uninstall = "-"; // default to remove at uninstall | ||
5121 | 5227 | ||
5122 | foreach (var attrib in node.Attributes()) | 5228 | foreach (var attrib in node.Attributes()) |
5123 | { | 5229 | { |
@@ -5129,35 +5235,44 @@ namespace WixToolset.Core | |||
5129 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | 5235 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); |
5130 | break; | 5236 | break; |
5131 | case "Action": | 5237 | case "Action": |
5132 | var value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 5238 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
5133 | if (0 < value.Length) | 5239 | switch (actionValue) |
5134 | { | 5240 | { |
5135 | var actionType = Wix.Environment.ParseActionType(value); | 5241 | case "create": |
5136 | switch (actionType) | 5242 | action = EnvironmentActionType.Create; |
5137 | { | 5243 | break; |
5138 | case Wix.Environment.ActionType.create: | 5244 | case "set": |
5139 | action = "+"; | 5245 | action = EnvironmentActionType.Set; |
5140 | break; | 5246 | break; |
5141 | case Wix.Environment.ActionType.set: | 5247 | case "remove": |
5142 | action = "="; | 5248 | action = EnvironmentActionType.Remove; |
5143 | break; | 5249 | break; |
5144 | case Wix.Environment.ActionType.remove: | 5250 | default: |
5145 | action = "!"; | 5251 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "create", "set", "remove")); |
5146 | break; | 5252 | break; |
5147 | default: | ||
5148 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "create", "set", "remove")); | ||
5149 | break; | ||
5150 | } | ||
5151 | } | 5253 | } |
5152 | break; | 5254 | break; |
5153 | case "Name": | 5255 | case "Name": |
5154 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 5256 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
5155 | break; | 5257 | break; |
5156 | case "Part": | 5258 | case "Part": |
5157 | part = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 5259 | var partValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
5158 | if (!Wix.Environment.TryParsePartType(part, out partType)) | 5260 | switch (partValue) |
5159 | { | 5261 | { |
5160 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Part", part, "all", "first", "last")); | 5262 | case "all": |
5263 | part = EnvironmentPartType.All; | ||
5264 | break; | ||
5265 | case "first": | ||
5266 | part = EnvironmentPartType.First; | ||
5267 | break; | ||
5268 | case "last": | ||
5269 | part = EnvironmentPartType.Last; | ||
5270 | break; | ||
5271 | case "": | ||
5272 | break; | ||
5273 | default: | ||
5274 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Part", partValue, "all", "first", "last")); | ||
5275 | break; | ||
5161 | } | 5276 | } |
5162 | break; | 5277 | break; |
5163 | case "Permanent": | 5278 | case "Permanent": |
@@ -5170,7 +5285,7 @@ namespace WixToolset.Core | |||
5170 | system = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 5285 | system = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
5171 | break; | 5286 | break; |
5172 | case "Value": | 5287 | case "Value": |
5173 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 5288 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
5174 | break; | 5289 | break; |
5175 | default: | 5290 | default: |
5176 | this.Core.UnexpectedAttribute(node, attrib); | 5291 | this.Core.UnexpectedAttribute(node, attrib); |
@@ -5185,7 +5300,7 @@ namespace WixToolset.Core | |||
5185 | 5300 | ||
5186 | if (null == id) | 5301 | if (null == id) |
5187 | { | 5302 | { |
5188 | id = this.Core.CreateIdentifier("env", action, name, part, system.ToString()); | 5303 | id = this.Core.CreateIdentifier("env", ((int?)action)?.ToString(), name, ((int?)part)?.ToString(), system.ToString()); |
5189 | } | 5304 | } |
5190 | 5305 | ||
5191 | if (null == name) | 5306 | if (null == name) |
@@ -5193,39 +5308,58 @@ namespace WixToolset.Core | |||
5193 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | 5308 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); |
5194 | } | 5309 | } |
5195 | 5310 | ||
5196 | if (Wix.Environment.PartType.NotSet != partType) | 5311 | if (!part.HasValue && action == EnvironmentActionType.Create) |
5197 | { | 5312 | { |
5198 | if ("+" == action) | 5313 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Part", "Action", "create")); |
5199 | { | ||
5200 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Part", "Action", "create")); | ||
5201 | } | ||
5202 | |||
5203 | switch (partType) | ||
5204 | { | ||
5205 | case Wix.Environment.PartType.all: | ||
5206 | break; | ||
5207 | case Wix.Environment.PartType.first: | ||
5208 | text = String.Concat(text, separator, "[~]"); | ||
5209 | break; | ||
5210 | case Wix.Environment.PartType.last: | ||
5211 | text = String.Concat("[~]", separator, text); | ||
5212 | break; | ||
5213 | } | ||
5214 | } | 5314 | } |
5215 | 5315 | ||
5216 | if (permanent) | 5316 | //if (Wix.Environment.PartType.NotSet != partType) |
5217 | { | 5317 | //{ |
5218 | uninstall = null; | 5318 | // if ("+" == action) |
5219 | } | 5319 | // { |
5320 | // this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Part", "Action", "create")); | ||
5321 | // } | ||
5322 | |||
5323 | // switch (partType) | ||
5324 | // { | ||
5325 | // case Wix.Environment.PartType.all: | ||
5326 | // break; | ||
5327 | // case Wix.Environment.PartType.first: | ||
5328 | // text = String.Concat(text, separator, "[~]"); | ||
5329 | // break; | ||
5330 | // case Wix.Environment.PartType.last: | ||
5331 | // text = String.Concat("[~]", separator, text); | ||
5332 | // break; | ||
5333 | // } | ||
5334 | //} | ||
5335 | |||
5336 | //if (permanent) | ||
5337 | //{ | ||
5338 | // uninstall = null; | ||
5339 | //} | ||
5220 | 5340 | ||
5221 | this.Core.ParseForExtensionElements(node); | 5341 | this.Core.ParseForExtensionElements(node); |
5222 | 5342 | ||
5223 | if (!this.Core.EncounteredError) | 5343 | if (!this.Core.EncounteredError) |
5224 | { | 5344 | { |
5225 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Environment, id); | 5345 | var tuple = new EnvironmentTuple(sourceLineNumbers, id) |
5226 | row.Set(1, String.Concat(action, uninstall, system ? "*" : String.Empty, name)); | 5346 | { |
5227 | row.Set(2, text); | 5347 | Name = name, |
5228 | row.Set(3, componentId); | 5348 | Value = value, |
5349 | Separator = separator, | ||
5350 | Action = action, | ||
5351 | Part = part, | ||
5352 | Permanent = permanent, | ||
5353 | System = system, | ||
5354 | Component_ = componentId | ||
5355 | }; | ||
5356 | |||
5357 | this.Core.AddTuple(tuple); | ||
5358 | |||
5359 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Environment, id); | ||
5360 | //row.Set(1, String.Concat(action, uninstall, system ? "*" : String.Empty, name)); | ||
5361 | //row.Set(2, text); | ||
5362 | //row.Set(3, componentId); | ||
5229 | } | 5363 | } |
5230 | } | 5364 | } |
5231 | 5365 | ||
@@ -5367,10 +5501,10 @@ namespace WixToolset.Core | |||
5367 | } | 5501 | } |
5368 | else if (YesNoType.No == advertise) | 5502 | else if (YesNoType.No == advertise) |
5369 | { | 5503 | { |
5370 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(".", extension), String.Empty, progId, componentId); // Extension | 5504 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(".", extension), String.Empty, progId, componentId); // Extension |
5371 | if (null != mime) | 5505 | if (null != mime) |
5372 | { | 5506 | { |
5373 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(".", extension), "Content Type", mime, componentId); // Extension's MIME ContentType | 5507 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(".", extension), "Content Type", mime, componentId); // Extension's MIME ContentType |
5374 | } | 5508 | } |
5375 | } | 5509 | } |
5376 | } | 5510 | } |
@@ -5387,7 +5521,7 @@ namespace WixToolset.Core | |||
5387 | /// <param name="possibleKeyPath">This will be set with the possible keyPath for the parent component.</param> | 5521 | /// <param name="possibleKeyPath">This will be set with the possible keyPath for the parent component.</param> |
5388 | /// <param name="win64Component">true if the component is 64-bit.</param> | 5522 | /// <param name="win64Component">true if the component is 64-bit.</param> |
5389 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | 5523 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> |
5390 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | 5524 | [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] |
5391 | private YesNoType ParseFileElement(XElement node, string componentId, string directoryId, int diskId, string sourcePath, out string possibleKeyPath, bool win64Component, string componentGuid) | 5525 | private YesNoType ParseFileElement(XElement node, string componentId, string directoryId, int diskId, string sourcePath, out string possibleKeyPath, bool win64Component, string componentGuid) |
5392 | { | 5526 | { |
5393 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 5527 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
@@ -5441,24 +5575,20 @@ namespace WixToolset.Core | |||
5441 | break; | 5575 | break; |
5442 | case "Assembly": | 5576 | case "Assembly": |
5443 | var assemblyValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 5577 | var assemblyValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
5444 | if (0 < assemblyValue.Length) | 5578 | switch (assemblyValue) |
5445 | { | 5579 | { |
5446 | var parsedAssemblyType = Wix.File.ParseAssemblyType(assemblyValue); | 5580 | case ".net": |
5447 | switch (parsedAssemblyType) | 5581 | assemblyType = FileAssemblyType.DotNetAssembly; |
5448 | { | 5582 | break; |
5449 | case Wix.File.AssemblyType.net: | 5583 | case "no": |
5450 | assemblyType = FileAssemblyType.DotNetAssembly; | 5584 | assemblyType = FileAssemblyType.NotAnAssembly; |
5451 | break; | 5585 | break; |
5452 | case Wix.File.AssemblyType.no: | 5586 | case "win32": |
5453 | assemblyType = FileAssemblyType.NotAnAssembly; | 5587 | assemblyType = FileAssemblyType.Win32Assembly; |
5454 | break; | 5588 | break; |
5455 | case Wix.File.AssemblyType.win32: | 5589 | default: |
5456 | assemblyType = FileAssemblyType.Win32Assembly; | 5590 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "File", "Assembly", assemblyValue, "no", "win32", ".net")); |
5457 | break; | 5591 | break; |
5458 | default: | ||
5459 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "File", "Assembly", assemblyValue, "no", "win32", ".net")); | ||
5460 | break; | ||
5461 | } | ||
5462 | } | 5592 | } |
5463 | break; | 5593 | break; |
5464 | case "AssemblyApplication": | 5594 | case "AssemblyApplication": |
@@ -5538,27 +5668,25 @@ namespace WixToolset.Core | |||
5538 | break; | 5668 | break; |
5539 | case "ProcessorArchitecture": | 5669 | case "ProcessorArchitecture": |
5540 | var procArchValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 5670 | var procArchValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
5541 | if (0 < procArchValue.Length) | 5671 | switch (procArchValue) |
5542 | { | 5672 | { |
5543 | var procArchType = Wix.File.ParseProcessorArchitectureType(procArchValue); | 5673 | case "msil": |
5544 | switch (procArchType) | 5674 | procArch = "MSIL"; |
5545 | { | 5675 | break; |
5546 | case Wix.File.ProcessorArchitectureType.msil: | 5676 | case "x86": |
5547 | procArch = "MSIL"; | 5677 | procArch = "x86"; |
5548 | break; | 5678 | break; |
5549 | case Wix.File.ProcessorArchitectureType.x86: | 5679 | case "x64": |
5550 | procArch = "x86"; | 5680 | procArch = "amd64"; |
5551 | break; | 5681 | break; |
5552 | case Wix.File.ProcessorArchitectureType.x64: | 5682 | case "ia64": |
5553 | procArch = "amd64"; | 5683 | procArch = "ia64"; |
5554 | break; | 5684 | break; |
5555 | case Wix.File.ProcessorArchitectureType.ia64: | 5685 | case "": |
5556 | procArch = "ia64"; | 5686 | break; |
5557 | break; | 5687 | default: |
5558 | default: | 5688 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "File", "ProcessorArchitecture", procArchValue, "msil", "x86", "x64", "ia64")); |
5559 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, "File", "ProcessorArchitecture", procArchValue, "msil", "x86", "x64", "ia64")); | 5689 | break; |
5560 | break; | ||
5561 | } | ||
5562 | } | 5690 | } |
5563 | break; | 5691 | break; |
5564 | case "ReadOnly": | 5692 | case "ReadOnly": |
@@ -6287,16 +6415,28 @@ namespace WixToolset.Core | |||
6287 | if ("Control" == parentElementLocalName) | 6415 | if ("Control" == parentElementLocalName) |
6288 | { | 6416 | { |
6289 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 6417 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
6290 | if (0 < action.Length) | 6418 | switch (action) |
6291 | { | 6419 | { |
6292 | if (Wix.Condition.TryParseActionType(action, out var actionType)) | 6420 | case "default": |
6293 | { | 6421 | action = "Default"; |
6294 | action = Compiler.UppercaseFirstChar(action); | 6422 | break; |
6295 | } | 6423 | case "disnable": |
6296 | else | 6424 | action = "Disable"; |
6297 | { | 6425 | break; |
6298 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "default", "disable", "enable", "hide", "show")); | 6426 | case "enable": |
6299 | } | 6427 | action = "Enable"; |
6428 | break; | ||
6429 | case "hide": | ||
6430 | action = "Hide"; | ||
6431 | break; | ||
6432 | case "show": | ||
6433 | action = "Show"; | ||
6434 | break; | ||
6435 | case "": | ||
6436 | break; | ||
6437 | default: | ||
6438 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "default", "disable", "enable", "hide", "show")); | ||
6439 | break; | ||
6300 | } | 6440 | } |
6301 | } | 6441 | } |
6302 | else | 6442 | else |
@@ -6407,13 +6547,12 @@ namespace WixToolset.Core | |||
6407 | { | 6547 | { |
6408 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 6548 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
6409 | Identifier id = null; | 6549 | Identifier id = null; |
6410 | var action = CompilerConstants.IntegerNotSet; | 6550 | InifFileActionType? action = null; |
6411 | string directory = null; | 6551 | string directory = null; |
6412 | string key = null; | 6552 | string key = null; |
6413 | string name = null; | 6553 | string name = null; |
6414 | string section = null; | 6554 | string section = null; |
6415 | string shortName = null; | 6555 | string shortName = null; |
6416 | TupleDefinitionType tableName; | ||
6417 | string value = null; | 6556 | string value = null; |
6418 | 6557 | ||
6419 | foreach (var attrib in node.Attributes()) | 6558 | foreach (var attrib in node.Attributes()) |
@@ -6427,30 +6566,25 @@ namespace WixToolset.Core | |||
6427 | break; | 6566 | break; |
6428 | case "Action": | 6567 | case "Action": |
6429 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 6568 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
6430 | if (0 < actionValue.Length) | 6569 | switch (actionValue) |
6431 | { | 6570 | { |
6432 | var actionType = Wix.IniFile.ParseActionType(actionValue); | 6571 | case "addLine": |
6433 | switch (actionType) | 6572 | action = InifFileActionType.AddLine; |
6434 | { | ||
6435 | case Wix.IniFile.ActionType.addLine: | ||
6436 | action = MsiInterop.MsidbIniFileActionAddLine; | ||
6437 | break; | 6573 | break; |
6438 | case Wix.IniFile.ActionType.addTag: | 6574 | case "addTag": |
6439 | action = MsiInterop.MsidbIniFileActionAddTag; | 6575 | action = InifFileActionType.AddTag; |
6440 | break; | 6576 | break; |
6441 | case Wix.IniFile.ActionType.createLine: | 6577 | case "removeLine": |
6442 | action = MsiInterop.MsidbIniFileActionCreateLine; | 6578 | action = InifFileActionType.RemoveLine; |
6443 | break; | 6579 | break; |
6444 | case Wix.IniFile.ActionType.removeLine: | 6580 | case "removeTag": |
6445 | action = MsiInterop.MsidbIniFileActionRemoveLine; | 6581 | action = InifFileActionType.RemoveTag; |
6446 | break; | 6582 | break; |
6447 | case Wix.IniFile.ActionType.removeTag: | 6583 | case "": // error case handled by GetAttributeValue() |
6448 | action = MsiInterop.MsidbIniFileActionRemoveTag; | ||
6449 | break; | 6584 | break; |
6450 | default: | 6585 | default: |
6451 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", actionValue, "addLine", "addTag", "createLine", "removeLine", "removeTag")); | 6586 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", actionValue, "addLine", "addTag", "createLine", "removeLine", "removeTag")); |
6452 | break; | 6587 | break; |
6453 | } | ||
6454 | } | 6588 | } |
6455 | break; | 6589 | break; |
6456 | case "Directory": | 6590 | case "Directory": |
@@ -6482,10 +6616,16 @@ namespace WixToolset.Core | |||
6482 | } | 6616 | } |
6483 | } | 6617 | } |
6484 | 6618 | ||
6485 | if (CompilerConstants.IntegerNotSet == action) | 6619 | if (!action.HasValue) |
6486 | { | 6620 | { |
6487 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | 6621 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); |
6488 | action = CompilerConstants.IllegalInteger; | 6622 | } |
6623 | else if (InifFileActionType.AddLine == action || InifFileActionType.AddTag == action || InifFileActionType.CreateLine == action) | ||
6624 | { | ||
6625 | if (null == value) | ||
6626 | { | ||
6627 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
6628 | } | ||
6489 | } | 6629 | } |
6490 | 6630 | ||
6491 | if (null == key) | 6631 | if (null == key) |
@@ -6532,30 +6672,20 @@ namespace WixToolset.Core | |||
6532 | 6672 | ||
6533 | this.Core.ParseForExtensionElements(node); | 6673 | this.Core.ParseForExtensionElements(node); |
6534 | 6674 | ||
6535 | if (MsiInterop.MsidbIniFileActionRemoveLine == action || MsiInterop.MsidbIniFileActionRemoveTag == action) | 6675 | if (!this.Core.EncounteredError) |
6536 | { | ||
6537 | tableName = TupleDefinitionType.RemoveIniFile; | ||
6538 | } | ||
6539 | else | ||
6540 | { | 6676 | { |
6541 | if (null == value) | 6677 | var tuple = new IniFileTuple(sourceLineNumbers, id) |
6542 | { | 6678 | { |
6543 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | 6679 | FileName = this.GetMsiFilenameValue(shortName, name), |
6544 | } | 6680 | DirProperty = directory, |
6545 | 6681 | Section = section, | |
6546 | tableName = TupleDefinitionType.IniFile; | 6682 | Key = key, |
6547 | } | 6683 | Value = value, |
6684 | Action = action.Value, | ||
6685 | Component_ = componentId | ||
6686 | }; | ||
6548 | 6687 | ||
6549 | if (!this.Core.EncounteredError) | 6688 | this.Core.AddTuple(tuple); |
6550 | { | ||
6551 | var row = this.Core.CreateRow(sourceLineNumbers, tableName, id); | ||
6552 | row.Set(1, this.GetMsiFilenameValue(shortName, name)); | ||
6553 | row.Set(2, directory); | ||
6554 | row.Set(3, section); | ||
6555 | row.Set(4, key); | ||
6556 | row.Set(5, value); | ||
6557 | row.Set(6, action); | ||
6558 | row.Set(7, componentId); | ||
6559 | } | 6689 | } |
6560 | } | 6690 | } |
6561 | 6691 | ||
@@ -6602,24 +6732,22 @@ namespace WixToolset.Core | |||
6602 | break; | 6732 | break; |
6603 | case "Type": | 6733 | case "Type": |
6604 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 6734 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
6605 | if (0 < typeValue.Length) | 6735 | switch (typeValue) |
6606 | { | 6736 | { |
6607 | var typeType = Wix.IniFileSearch.ParseTypeType(typeValue); | 6737 | case "directory": |
6608 | switch (typeType) | 6738 | type = 0; |
6609 | { | 6739 | break; |
6610 | case Wix.IniFileSearch.TypeType.directory: | 6740 | case "file": |
6611 | type = 0; | 6741 | type = 1; |
6612 | break; | 6742 | break; |
6613 | case Wix.IniFileSearch.TypeType.file: | 6743 | case "raw": |
6614 | type = 1; | 6744 | type = 2; |
6615 | break; | 6745 | break; |
6616 | case Wix.IniFileSearch.TypeType.raw: | 6746 | case "": |
6617 | type = 2; | 6747 | break; |
6618 | break; | 6748 | default: |
6619 | default: | 6749 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Type", typeValue, "directory", "file", "registry")); |
6620 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Type", typeValue, "directory", "file", "registry")); | 6750 | break; |
6621 | break; | ||
6622 | } | ||
6623 | } | 6751 | } |
6624 | break; | 6752 | break; |
6625 | default: | 6753 | default: |
@@ -6984,7 +7112,8 @@ namespace WixToolset.Core | |||
6984 | private void ParseMajorUpgradeElement(XElement node, IDictionary<string, string> contextValues) | 7112 | private void ParseMajorUpgradeElement(XElement node, IDictionary<string, string> contextValues) |
6985 | { | 7113 | { |
6986 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 7114 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
6987 | var options = MsiInterop.MsidbUpgradeAttributesMigrateFeatures; | 7115 | var migrateFeatures = true; |
7116 | var ignoreRemoveFailure = false; | ||
6988 | var allowDowngrades = false; | 7117 | var allowDowngrades = false; |
6989 | var allowSameVersionUpgrades = false; | 7118 | var allowSameVersionUpgrades = false; |
6990 | var blockUpgrades = false; | 7119 | var blockUpgrades = false; |
@@ -7029,10 +7158,7 @@ namespace WixToolset.Core | |||
7029 | disallowUpgradeErrorMessage = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7158 | disallowUpgradeErrorMessage = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
7030 | break; | 7159 | break; |
7031 | case "MigrateFeatures": | 7160 | case "MigrateFeatures": |
7032 | if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 7161 | migrateFeatures = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); |
7033 | { | ||
7034 | options &= ~MsiInterop.MsidbUpgradeAttributesMigrateFeatures; | ||
7035 | } | ||
7036 | break; | 7162 | break; |
7037 | case "IgnoreLanguage": | 7163 | case "IgnoreLanguage": |
7038 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 7164 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) |
@@ -7041,10 +7167,7 @@ namespace WixToolset.Core | |||
7041 | } | 7167 | } |
7042 | break; | 7168 | break; |
7043 | case "IgnoreRemoveFailure": | 7169 | case "IgnoreRemoveFailure": |
7044 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | 7170 | ignoreRemoveFailure = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); |
7045 | { | ||
7046 | options |= MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure; | ||
7047 | } | ||
7048 | break; | 7171 | break; |
7049 | case "RemoveFeatures": | 7172 | case "RemoveFeatures": |
7050 | removeFeatures = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7173 | removeFeatures = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
@@ -7093,25 +7216,29 @@ namespace WixToolset.Core | |||
7093 | if (!this.Core.EncounteredError) | 7216 | if (!this.Core.EncounteredError) |
7094 | { | 7217 | { |
7095 | // create the row that performs the upgrade (or downgrade) | 7218 | // create the row that performs the upgrade (or downgrade) |
7096 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Upgrade); | 7219 | var tuple = new UpgradeTuple(sourceLineNumbers) |
7097 | row.Set(0, upgradeCode); | 7220 | { |
7221 | UpgradeCode = upgradeCode, | ||
7222 | Remove = removeFeatures, | ||
7223 | MigrateFeatures = migrateFeatures, | ||
7224 | IgnoreRemoveFailures = ignoreRemoveFailure, | ||
7225 | ActionProperty = Common.UpgradeDetectedProperty | ||
7226 | }; | ||
7227 | |||
7098 | if (allowDowngrades) | 7228 | if (allowDowngrades) |
7099 | { | 7229 | { |
7100 | row.Set(1, "0"); // let any version satisfy | 7230 | tuple.VersionMin = "0"; |
7101 | // row.Set(2, maximum version; omit so we don't have to fake a version like "255.255.65535"; | 7231 | tuple.Language = productLanguage; |
7102 | row.Set(3, productLanguage); | 7232 | tuple.VersionMinInclusive = true; |
7103 | row.Set(4, options | MsiInterop.MsidbUpgradeAttributesVersionMinInclusive); | ||
7104 | } | 7233 | } |
7105 | else | 7234 | else |
7106 | { | 7235 | { |
7107 | // row.Set(1, minimum version; skip it so we detect all prior versions. | 7236 | tuple.VersionMax = productVersion; |
7108 | row.Set(2, productVersion); | 7237 | tuple.Language = productLanguage; |
7109 | row.Set(3, productLanguage); | 7238 | tuple.VersionMaxInclusive = allowSameVersionUpgrades; |
7110 | row.Set(4, allowSameVersionUpgrades ? (options | MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive) : options); | ||
7111 | } | 7239 | } |
7112 | 7240 | ||
7113 | row.Set(5, removeFeatures); | 7241 | this.Core.AddTuple(tuple); |
7114 | row.Set(6, Common.UpgradeDetectedProperty); | ||
7115 | 7242 | ||
7116 | // Ensure the action property is secure. | 7243 | // Ensure the action property is secure. |
7117 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(Common.UpgradeDetectedProperty, AccessModifier.Public), false, true, false); | 7244 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(Common.UpgradeDetectedProperty, AccessModifier.Public), false, true, false); |
@@ -7119,63 +7246,72 @@ namespace WixToolset.Core | |||
7119 | // Add launch condition that blocks upgrades | 7246 | // Add launch condition that blocks upgrades |
7120 | if (blockUpgrades) | 7247 | if (blockUpgrades) |
7121 | { | 7248 | { |
7122 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.LaunchCondition); | 7249 | var conditionTuple = new LaunchConditionTuple(sourceLineNumbers) |
7123 | row.Set(0, Common.UpgradePreventedCondition); | 7250 | { |
7124 | row.Set(1, disallowUpgradeErrorMessage); | 7251 | Condition = Common.UpgradePreventedCondition, |
7252 | Description = downgradeErrorMessage | ||
7253 | }; | ||
7254 | |||
7255 | this.Core.AddTuple(conditionTuple); | ||
7125 | } | 7256 | } |
7126 | 7257 | ||
7127 | // now create the Upgrade row and launch conditions to prevent downgrades (unless explicitly permitted) | 7258 | // now create the Upgrade row and launch conditions to prevent downgrades (unless explicitly permitted) |
7128 | if (!allowDowngrades) | 7259 | if (!allowDowngrades) |
7129 | { | 7260 | { |
7130 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Upgrade); | 7261 | var upgradeTuple = new UpgradeTuple(sourceLineNumbers) |
7131 | row.Set(0, upgradeCode); | 7262 | { |
7132 | row.Set(1, productVersion); | 7263 | UpgradeCode = upgradeCode, |
7133 | // row.Set(2, maximum version; skip it so we detect all future versions. | 7264 | VersionMin = productVersion, |
7134 | row.Set(3, productLanguage); | 7265 | Language = productLanguage, |
7135 | row.Set(4, MsiInterop.MsidbUpgradeAttributesOnlyDetect); | 7266 | OnlyDetect = true, |
7136 | // row.Set(5, removeFeatures); | 7267 | MigrateFeatures = migrateFeatures, |
7137 | row.Set(6, Common.DowngradeDetectedProperty); | 7268 | IgnoreRemoveFailures = ignoreRemoveFailure, |
7269 | ActionProperty = Common.DowngradeDetectedProperty | ||
7270 | }; | ||
7271 | |||
7272 | this.Core.AddTuple(upgradeTuple); | ||
7138 | 7273 | ||
7139 | // Ensure the action property is secure. | 7274 | // Ensure the action property is secure. |
7140 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(Common.DowngradeDetectedProperty, AccessModifier.Public), false, true, false); | 7275 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(Common.DowngradeDetectedProperty, AccessModifier.Public), false, true, false); |
7141 | 7276 | ||
7142 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.LaunchCondition); | 7277 | var conditionTuple = new LaunchConditionTuple(sourceLineNumbers) |
7143 | row.Set(0, Common.DowngradePreventedCondition); | 7278 | { |
7144 | row.Set(1, downgradeErrorMessage); | 7279 | Condition = Common.DowngradePreventedCondition, |
7280 | Description = downgradeErrorMessage | ||
7281 | }; | ||
7282 | |||
7283 | this.Core.AddTuple(conditionTuple); | ||
7145 | } | 7284 | } |
7146 | 7285 | ||
7147 | // finally, schedule RemoveExistingProducts | 7286 | // finally, schedule RemoveExistingProducts |
7148 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixAction, new Identifier(AccessModifier.Public, "InstallExecuteSequence", "RemoveExistingProducts")); | 7287 | var actionTuple = new WixActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, "InstallExecuteSequence", "RemoveExistingProducts")) |
7149 | row.Set(0, "InstallExecuteSequence"); | 7288 | { |
7150 | row.Set(1, "RemoveExistingProducts"); | 7289 | SequenceTable = SequenceTable.InstallExecuteSequence, |
7151 | // row.Set(2, condition); | 7290 | Action = "RemoveExistingProducts", |
7152 | // row.Set(3, sequence); | 7291 | Overridable = false, |
7153 | row.Set(6, false); // overridable | 7292 | }; |
7154 | 7293 | ||
7155 | switch (schedule) | 7294 | switch (schedule) |
7156 | { | 7295 | { |
7157 | case null: | 7296 | case null: |
7158 | case "afterInstallValidate": | 7297 | case "afterInstallValidate": |
7159 | // row.Set(4, beforeAction; | 7298 | actionTuple.After = "InstallValidate"; |
7160 | row.Set(5, "InstallValidate"); | 7299 | break; |
7161 | break; | 7300 | case "afterInstallInitialize": |
7162 | case "afterInstallInitialize": | 7301 | actionTuple.After = "InstallInitialize"; |
7163 | // row.Set(4, beforeAction; | 7302 | break; |
7164 | row.Set(5, "InstallInitialize"); | 7303 | case "afterInstallExecute": |
7165 | break; | 7304 | actionTuple.After = "InstallExecute"; |
7166 | case "afterInstallExecute": | 7305 | break; |
7167 | // row.Set(4, beforeAction; | 7306 | case "afterInstallExecuteAgain": |
7168 | row.Set(5, "InstallExecute"); | 7307 | actionTuple.After = "InstallExecuteAgain"; |
7169 | break; | 7308 | break; |
7170 | case "afterInstallExecuteAgain": | 7309 | case "afterInstallFinalize": |
7171 | // row.Set(4, beforeAction; | 7310 | actionTuple.After = "InstallFinalize"; |
7172 | row.Set(5, "InstallExecuteAgain"); | 7311 | break; |
7173 | break; | ||
7174 | case "afterInstallFinalize": | ||
7175 | // row.Set(4, beforeAction; | ||
7176 | row.Set(5, "InstallFinalize"); | ||
7177 | break; | ||
7178 | } | 7312 | } |
7313 | |||
7314 | this.Core.AddTuple(actionTuple); | ||
7179 | } | 7315 | } |
7180 | } | 7316 | } |
7181 | 7317 | ||
@@ -7212,18 +7348,7 @@ namespace WixToolset.Core | |||
7212 | cabinet = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7348 | cabinet = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
7213 | break; | 7349 | break; |
7214 | case "CompressionLevel": | 7350 | case "CompressionLevel": |
7215 | var compressionLevelString = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7351 | compressionLevel = this.ParseCompressionLevel(sourceLineNumbers, node, attrib); |
7216 | if (0 < compressionLevelString.Length) | ||
7217 | { | ||
7218 | if (!Wix.Enums.TryParseCompressionLevelType(compressionLevelString, out var compressionLevelType)) | ||
7219 | { | ||
7220 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, compressionLevelString, "high", "low", "medium", "mszip", "none")); | ||
7221 | } | ||
7222 | else | ||
7223 | { | ||
7224 | compressionLevel = (CompressionLevel)Enum.Parse(typeof(CompressionLevel), compressionLevelString, true); | ||
7225 | } | ||
7226 | } | ||
7227 | break; | 7352 | break; |
7228 | case "DiskPrompt": | 7353 | case "DiskPrompt": |
7229 | diskPrompt = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7354 | diskPrompt = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
@@ -7233,16 +7358,6 @@ namespace WixToolset.Core | |||
7233 | embedCab = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | 7358 | embedCab = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); |
7234 | break; | 7359 | break; |
7235 | case "Layout": | 7360 | case "Layout": |
7236 | case "src": | ||
7237 | if (null != layout) | ||
7238 | { | ||
7239 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Layout", "src")); | ||
7240 | } | ||
7241 | |||
7242 | if ("src" == attrib.Name.LocalName) | ||
7243 | { | ||
7244 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Layout")); | ||
7245 | } | ||
7246 | layout = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7361 | layout = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
7247 | break; | 7362 | break; |
7248 | case "VolumeLabel": | 7363 | case "VolumeLabel": |
@@ -7300,7 +7415,7 @@ namespace WixToolset.Core | |||
7300 | } | 7415 | } |
7301 | } | 7416 | } |
7302 | 7417 | ||
7303 | if (null != compressionLevel && null == cabinet) | 7418 | if (!compressionLevel.HasValue && null == cabinet) |
7304 | { | 7419 | { |
7305 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Cabinet", "CompressionLevel")); | 7420 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Cabinet", "CompressionLevel")); |
7306 | } | 7421 | } |
@@ -7366,8 +7481,6 @@ namespace WixToolset.Core | |||
7366 | } | 7481 | } |
7367 | } | 7482 | } |
7368 | 7483 | ||
7369 | |||
7370 | |||
7371 | // add the row to the section | 7484 | // add the row to the section |
7372 | if (!this.Core.EncounteredError) | 7485 | if (!this.Core.EncounteredError) |
7373 | { | 7486 | { |
@@ -7407,13 +7520,12 @@ namespace WixToolset.Core | |||
7407 | { | 7520 | { |
7408 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | 7521 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); |
7409 | var cabinetTemplate = "cab{0}.cab"; | 7522 | var cabinetTemplate = "cab{0}.cab"; |
7410 | string compressionLevel = null; // this defaults to mszip in Binder | ||
7411 | string diskPrompt = null; | 7523 | string diskPrompt = null; |
7412 | var patch = null != patchId; | 7524 | var patch = null != patchId; |
7413 | string volumeLabel = null; | 7525 | string volumeLabel = null; |
7414 | var maximumUncompressedMediaSize = CompilerConstants.IntegerNotSet; | 7526 | var maximumUncompressedMediaSize = CompilerConstants.IntegerNotSet; |
7415 | var maximumCabinetSizeForLargeFileSplitting = CompilerConstants.IntegerNotSet; | 7527 | var maximumCabinetSizeForLargeFileSplitting = CompilerConstants.IntegerNotSet; |
7416 | var compressionLevelType = Wix.CompressionLevelType.NotSet; | 7528 | CompressionLevel? compressionLevel = null; // this defaults to mszip in Binder |
7417 | 7529 | ||
7418 | var embedCab = patch ? YesNoType.Yes : YesNoType.NotSet; | 7530 | var embedCab = patch ? YesNoType.Yes : YesNoType.NotSet; |
7419 | 7531 | ||
@@ -7447,14 +7559,7 @@ namespace WixToolset.Core | |||
7447 | } | 7559 | } |
7448 | break; | 7560 | break; |
7449 | case "CompressionLevel": | 7561 | case "CompressionLevel": |
7450 | compressionLevel = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7562 | compressionLevel = this.ParseCompressionLevel(sourceLineNumbers, node, attrib); |
7451 | if (0 < compressionLevel.Length) | ||
7452 | { | ||
7453 | if (!Wix.Enums.TryParseCompressionLevelType(compressionLevel, out compressionLevelType)) | ||
7454 | { | ||
7455 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, compressionLevel, "high", "low", "medium", "mszip", "none")); | ||
7456 | } | ||
7457 | } | ||
7458 | break; | 7563 | break; |
7459 | case "DiskPrompt": | 7564 | case "DiskPrompt": |
7460 | diskPrompt = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 7565 | diskPrompt = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
@@ -7521,23 +7626,9 @@ namespace WixToolset.Core | |||
7521 | mediaTemplateRow.MaximumCabinetSizeForLargeFileSplitting = 0; // Default value of 0 corresponds to max size of 2048 MB (i.e. 2 GB) | 7626 | mediaTemplateRow.MaximumCabinetSizeForLargeFileSplitting = 0; // Default value of 0 corresponds to max size of 2048 MB (i.e. 2 GB) |
7522 | } | 7627 | } |
7523 | 7628 | ||
7524 | switch (compressionLevelType) | 7629 | if (compressionLevel.HasValue) |
7525 | { | 7630 | { |
7526 | case Wix.CompressionLevelType.high: | 7631 | mediaTemplateRow.CompressionLevel = compressionLevel.Value; |
7527 | mediaTemplateRow.CompressionLevel = CompressionLevel.High; | ||
7528 | break; | ||
7529 | case Wix.CompressionLevelType.low: | ||
7530 | mediaTemplateRow.CompressionLevel = CompressionLevel.Low; | ||
7531 | break; | ||
7532 | case Wix.CompressionLevelType.medium: | ||
7533 | mediaTemplateRow.CompressionLevel = CompressionLevel.Medium; | ||
7534 | break; | ||
7535 | case Wix.CompressionLevelType.none: | ||
7536 | mediaTemplateRow.CompressionLevel = CompressionLevel.None; | ||
7537 | break; | ||
7538 | case Wix.CompressionLevelType.mszip: | ||
7539 | mediaTemplateRow.CompressionLevel = CompressionLevel.Mszip; | ||
7540 | break; | ||
7541 | } | 7632 | } |
7542 | } | 7633 | } |
7543 | } | 7634 | } |
@@ -7849,10 +7940,10 @@ namespace WixToolset.Core | |||
7849 | this.Core.Write(ErrorMessages.CannotDefaultMismatchedAdvertiseStates(sourceLineNumbers)); | 7940 | this.Core.Write(ErrorMessages.CannotDefaultMismatchedAdvertiseStates(sourceLineNumbers)); |
7850 | } | 7941 | } |
7851 | 7942 | ||
7852 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("MIME\\Database\\Content Type\\", contentType), "Extension", String.Concat(".", extension), componentId); | 7943 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("MIME\\Database\\Content Type\\", contentType), "Extension", String.Concat(".", extension), componentId); |
7853 | if (null != classId) | 7944 | if (null != classId) |
7854 | { | 7945 | { |
7855 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("MIME\\Database\\Content Type\\", contentType), "CLSID", classId, componentId); | 7946 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("MIME\\Database\\Content Type\\", contentType), "CLSID", classId, componentId); |
7856 | } | 7947 | } |
7857 | } | 7948 | } |
7858 | 7949 | ||
@@ -7860,212 +7951,6 @@ namespace WixToolset.Core | |||
7860 | } | 7951 | } |
7861 | 7952 | ||
7862 | /// <summary> | 7953 | /// <summary> |
7863 | /// Parses a module element. | ||
7864 | /// </summary> | ||
7865 | /// <param name="node">Element to parse.</param> | ||
7866 | private void ParseModuleElement(XElement node) | ||
7867 | { | ||
7868 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7869 | var codepage = 0; | ||
7870 | string moduleId = null; | ||
7871 | string version = null; | ||
7872 | |||
7873 | this.activeName = null; | ||
7874 | this.activeLanguage = null; | ||
7875 | |||
7876 | foreach (var attrib in node.Attributes()) | ||
7877 | { | ||
7878 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7879 | { | ||
7880 | switch (attrib.Name.LocalName) | ||
7881 | { | ||
7882 | case "Id": | ||
7883 | this.activeName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7884 | if ("PUT-MODULE-NAME-HERE" == this.activeName) | ||
7885 | { | ||
7886 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
7887 | } | ||
7888 | else | ||
7889 | { | ||
7890 | this.activeName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
7891 | } | ||
7892 | break; | ||
7893 | case "Codepage": | ||
7894 | codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
7895 | break; | ||
7896 | case "Guid": | ||
7897 | moduleId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
7898 | this.Core.Write(WarningMessages.DeprecatedModuleGuidAttribute(sourceLineNumbers)); | ||
7899 | break; | ||
7900 | case "Language": | ||
7901 | this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
7902 | break; | ||
7903 | case "Version": | ||
7904 | version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
7905 | break; | ||
7906 | default: | ||
7907 | this.Core.UnexpectedAttribute(node, attrib); | ||
7908 | break; | ||
7909 | } | ||
7910 | } | ||
7911 | else | ||
7912 | { | ||
7913 | this.Core.ParseExtensionAttribute(node, attrib); | ||
7914 | } | ||
7915 | } | ||
7916 | |||
7917 | if (null == this.activeName) | ||
7918 | { | ||
7919 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
7920 | } | ||
7921 | |||
7922 | if (null == this.activeLanguage) | ||
7923 | { | ||
7924 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
7925 | } | ||
7926 | |||
7927 | if (null == version) | ||
7928 | { | ||
7929 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
7930 | } | ||
7931 | else if (!CompilerCore.IsValidModuleOrBundleVersion(version)) | ||
7932 | { | ||
7933 | this.Core.Write(WarningMessages.InvalidModuleOrBundleVersion(sourceLineNumbers, "Module", version)); | ||
7934 | } | ||
7935 | |||
7936 | try | ||
7937 | { | ||
7938 | this.compilingModule = true; // notice that we are actually building a Merge Module here | ||
7939 | this.Core.CreateActiveSection(this.activeName, SectionType.Module, codepage, this.Context.CompilationId); | ||
7940 | |||
7941 | foreach (var child in node.Elements()) | ||
7942 | { | ||
7943 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
7944 | { | ||
7945 | switch (child.Name.LocalName) | ||
7946 | { | ||
7947 | case "AdminExecuteSequence": | ||
7948 | case "AdminUISequence": | ||
7949 | case "AdvertiseExecuteSequence": | ||
7950 | case "InstallExecuteSequence": | ||
7951 | case "InstallUISequence": | ||
7952 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
7953 | break; | ||
7954 | case "AppId": | ||
7955 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
7956 | break; | ||
7957 | case "Binary": | ||
7958 | this.ParseBinaryElement(child); | ||
7959 | break; | ||
7960 | case "Component": | ||
7961 | this.ParseComponentElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage, CompilerConstants.IntegerNotSet, null, null); | ||
7962 | break; | ||
7963 | case "ComponentGroupRef": | ||
7964 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage); | ||
7965 | break; | ||
7966 | case "ComponentRef": | ||
7967 | this.ParseComponentRefElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage); | ||
7968 | break; | ||
7969 | case "Configuration": | ||
7970 | this.ParseConfigurationElement(child); | ||
7971 | break; | ||
7972 | case "CustomAction": | ||
7973 | this.ParseCustomActionElement(child); | ||
7974 | break; | ||
7975 | case "CustomActionRef": | ||
7976 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
7977 | break; | ||
7978 | case "CustomTable": | ||
7979 | this.ParseCustomTableElement(child); | ||
7980 | break; | ||
7981 | case "Dependency": | ||
7982 | this.ParseDependencyElement(child); | ||
7983 | break; | ||
7984 | case "Directory": | ||
7985 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
7986 | break; | ||
7987 | case "DirectoryRef": | ||
7988 | this.ParseDirectoryRefElement(child); | ||
7989 | break; | ||
7990 | case "EmbeddedChainer": | ||
7991 | this.ParseEmbeddedChainerElement(child); | ||
7992 | break; | ||
7993 | case "EmbeddedChainerRef": | ||
7994 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
7995 | break; | ||
7996 | case "EnsureTable": | ||
7997 | this.ParseEnsureTableElement(child); | ||
7998 | break; | ||
7999 | case "Exclusion": | ||
8000 | this.ParseExclusionElement(child); | ||
8001 | break; | ||
8002 | case "Icon": | ||
8003 | this.ParseIconElement(child); | ||
8004 | break; | ||
8005 | case "IgnoreModularization": | ||
8006 | this.ParseIgnoreModularizationElement(child); | ||
8007 | break; | ||
8008 | case "IgnoreTable": | ||
8009 | this.ParseIgnoreTableElement(child); | ||
8010 | break; | ||
8011 | case "Package": | ||
8012 | this.ParsePackageElement(child, null, moduleId); | ||
8013 | break; | ||
8014 | case "Property": | ||
8015 | this.ParsePropertyElement(child); | ||
8016 | break; | ||
8017 | case "PropertyRef": | ||
8018 | this.ParseSimpleRefElement(child, "Property"); | ||
8019 | break; | ||
8020 | case "SetDirectory": | ||
8021 | this.ParseSetDirectoryElement(child); | ||
8022 | break; | ||
8023 | case "SetProperty": | ||
8024 | this.ParseSetPropertyElement(child); | ||
8025 | break; | ||
8026 | case "SFPCatalog": | ||
8027 | string parentName = null; | ||
8028 | this.ParseSFPCatalogElement(child, ref parentName); | ||
8029 | break; | ||
8030 | case "Substitution": | ||
8031 | this.ParseSubstitutionElement(child); | ||
8032 | break; | ||
8033 | case "UI": | ||
8034 | this.ParseUIElement(child); | ||
8035 | break; | ||
8036 | case "UIRef": | ||
8037 | this.ParseSimpleRefElement(child, "WixUI"); | ||
8038 | break; | ||
8039 | case "WixVariable": | ||
8040 | this.ParseWixVariableElement(child); | ||
8041 | break; | ||
8042 | default: | ||
8043 | this.Core.UnexpectedElement(node, child); | ||
8044 | break; | ||
8045 | } | ||
8046 | } | ||
8047 | else | ||
8048 | { | ||
8049 | this.Core.ParseExtensionElement(node, child); | ||
8050 | } | ||
8051 | } | ||
8052 | |||
8053 | |||
8054 | if (!this.Core.EncounteredError) | ||
8055 | { | ||
8056 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleSignature); | ||
8057 | row.Set(0, this.activeName); | ||
8058 | row.Set(1, this.activeLanguage); | ||
8059 | row.Set(2, version); | ||
8060 | } | ||
8061 | } | ||
8062 | finally | ||
8063 | { | ||
8064 | this.compilingModule = false; // notice that we are no longer building a Merge Module here | ||
8065 | } | ||
8066 | } | ||
8067 | |||
8068 | /// <summary> | ||
8069 | /// Parses a patch creation element. | 7954 | /// Parses a patch creation element. |
8070 | /// </summary> | 7955 | /// </summary> |
8071 | /// <param name="node">The element to parse.</param> | 7956 | /// <param name="node">The element to parse.</param> |
@@ -9934,18 +9819,22 @@ namespace WixToolset.Core | |||
9934 | case "ProductVersion": | 9819 | case "ProductVersion": |
9935 | var check = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 9820 | var check = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
9936 | validationFlags &= ~TransformFlags.ProductVersionMask; | 9821 | validationFlags &= ~TransformFlags.ProductVersionMask; |
9937 | var productVersionType = Wix.Validate.ParseProductVersionType(check); | 9822 | switch (check) |
9938 | switch (productVersionType) | ||
9939 | { | 9823 | { |
9940 | case Wix.Validate.ProductVersionType.Major: | 9824 | case "Major": |
9825 | case "major": | ||
9941 | validationFlags |= TransformFlags.ValidateMajorVersion; | 9826 | validationFlags |= TransformFlags.ValidateMajorVersion; |
9942 | break; | 9827 | break; |
9943 | case Wix.Validate.ProductVersionType.Minor: | 9828 | case "Minor": |
9829 | case "minor": | ||
9944 | validationFlags |= TransformFlags.ValidateMinorVersion; | 9830 | validationFlags |= TransformFlags.ValidateMinorVersion; |
9945 | break; | 9831 | break; |
9946 | case Wix.Validate.ProductVersionType.Update: | 9832 | case "Update": |
9833 | case "update": | ||
9947 | validationFlags |= TransformFlags.ValidateUpdateVersion; | 9834 | validationFlags |= TransformFlags.ValidateUpdateVersion; |
9948 | break; | 9835 | break; |
9836 | case "": | ||
9837 | break; | ||
9949 | default: | 9838 | default: |
9950 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Version", check, "Major", "Minor", "Update")); | 9839 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Version", check, "Major", "Minor", "Update")); |
9951 | break; | 9840 | break; |
@@ -9954,24 +9843,30 @@ namespace WixToolset.Core | |||
9954 | case "ProductVersionOperator": | 9843 | case "ProductVersionOperator": |
9955 | var op = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | 9844 | var op = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
9956 | validationFlags &= ~TransformFlags.ProductVersionOperatorMask; | 9845 | validationFlags &= ~TransformFlags.ProductVersionOperatorMask; |
9957 | var opType = Wix.Validate.ParseProductVersionOperatorType(op); | 9846 | switch (op) |
9958 | switch (opType) | ||
9959 | { | 9847 | { |
9960 | case Wix.Validate.ProductVersionOperatorType.Lesser: | 9848 | case "Lesser": |
9849 | case "lesser": | ||
9961 | validationFlags |= TransformFlags.ValidateNewLessBaseVersion; | 9850 | validationFlags |= TransformFlags.ValidateNewLessBaseVersion; |
9962 | break; | 9851 | break; |
9963 | case Wix.Validate.ProductVersionOperatorType.LesserOrEqual: | 9852 | case "LesserOrEqual": |
9853 | case "lesserOrEqual": | ||
9964 | validationFlags |= TransformFlags.ValidateNewLessEqualBaseVersion; | 9854 | validationFlags |= TransformFlags.ValidateNewLessEqualBaseVersion; |
9965 | break; | 9855 | break; |
9966 | case Wix.Validate.ProductVersionOperatorType.Equal: | 9856 | case "Equal": |
9857 | case "equal": | ||
9967 | validationFlags |= TransformFlags.ValidateNewEqualBaseVersion; | 9858 | validationFlags |= TransformFlags.ValidateNewEqualBaseVersion; |
9968 | break; | 9859 | break; |
9969 | case Wix.Validate.ProductVersionOperatorType.GreaterOrEqual: | 9860 | case "GreaterOrEqual": |
9861 | case "greaterOrEqual": | ||
9970 | validationFlags |= TransformFlags.ValidateNewGreaterEqualBaseVersion; | 9862 | validationFlags |= TransformFlags.ValidateNewGreaterEqualBaseVersion; |
9971 | break; | 9863 | break; |
9972 | case Wix.Validate.ProductVersionOperatorType.Greater: | 9864 | case "Greater": |
9865 | case "greater": | ||
9973 | validationFlags |= TransformFlags.ValidateNewGreaterBaseVersion; | 9866 | validationFlags |= TransformFlags.ValidateNewGreaterBaseVersion; |
9974 | break; | 9867 | break; |
9868 | case "": | ||
9869 | break; | ||
9975 | default: | 9870 | default: |
9976 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Operator", op, "Lesser", "LesserOrEqual", "Equal", "GreaterOrEqual", "Greater")); | 9871 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Operator", op, "Lesser", "LesserOrEqual", "Equal", "GreaterOrEqual", "Greater")); |
9977 | break; | 9872 | break; |
@@ -10057,7 +9952,6 @@ namespace WixToolset.Core | |||
10057 | this.Core.ParseExtensionAttribute(node, attrib); | 9952 | this.Core.ParseExtensionAttribute(node, attrib); |
10058 | } | 9953 | } |
10059 | } | 9954 | } |
10060 | |||
10061 | } | 9955 | } |
10062 | 9956 | ||
10063 | /// <summary> | 9957 | /// <summary> |
@@ -10075,10520 +9969,5 @@ namespace WixToolset.Core | |||
10075 | row.Set(1, value); | 9969 | row.Set(1, value); |
10076 | } | 9970 | } |
10077 | } | 9971 | } |
10078 | |||
10079 | /// <summary> | ||
10080 | /// Parses a dependency element. | ||
10081 | /// </summary> | ||
10082 | /// <param name="node">Element to parse.</param> | ||
10083 | private void ParseDependencyElement(XElement node) | ||
10084 | { | ||
10085 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10086 | string requiredId = null; | ||
10087 | var requiredLanguage = CompilerConstants.IntegerNotSet; | ||
10088 | string requiredVersion = null; | ||
10089 | |||
10090 | foreach (var attrib in node.Attributes()) | ||
10091 | { | ||
10092 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10093 | { | ||
10094 | switch (attrib.Name.LocalName) | ||
10095 | { | ||
10096 | case "RequiredId": | ||
10097 | requiredId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10098 | break; | ||
10099 | case "RequiredLanguage": | ||
10100 | requiredLanguage = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
10101 | break; | ||
10102 | case "RequiredVersion": | ||
10103 | requiredVersion = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10104 | break; | ||
10105 | default: | ||
10106 | this.Core.UnexpectedAttribute(node, attrib); | ||
10107 | break; | ||
10108 | } | ||
10109 | } | ||
10110 | else | ||
10111 | { | ||
10112 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10113 | } | ||
10114 | } | ||
10115 | |||
10116 | if (null == requiredId) | ||
10117 | { | ||
10118 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RequiredId")); | ||
10119 | requiredId = String.Empty; | ||
10120 | } | ||
10121 | |||
10122 | if (CompilerConstants.IntegerNotSet == requiredLanguage) | ||
10123 | { | ||
10124 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RequiredLanguage")); | ||
10125 | requiredLanguage = CompilerConstants.IllegalInteger; | ||
10126 | } | ||
10127 | |||
10128 | this.Core.ParseForExtensionElements(node); | ||
10129 | |||
10130 | if (!this.Core.EncounteredError) | ||
10131 | { | ||
10132 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleDependency); | ||
10133 | row.Set(0, this.activeName); | ||
10134 | row.Set(1, this.activeLanguage); | ||
10135 | row.Set(2, requiredId); | ||
10136 | row.Set(3, requiredLanguage.ToString(CultureInfo.InvariantCulture)); | ||
10137 | row.Set(4, requiredVersion); | ||
10138 | } | ||
10139 | } | ||
10140 | |||
10141 | /// <summary> | ||
10142 | /// Parses an exclusion element. | ||
10143 | /// </summary> | ||
10144 | /// <param name="node">Element to parse.</param> | ||
10145 | private void ParseExclusionElement(XElement node) | ||
10146 | { | ||
10147 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10148 | string excludedId = null; | ||
10149 | var excludeExceptLanguage = CompilerConstants.IntegerNotSet; | ||
10150 | var excludeLanguage = CompilerConstants.IntegerNotSet; | ||
10151 | var excludedLanguageField = "0"; | ||
10152 | string excludedMaxVersion = null; | ||
10153 | string excludedMinVersion = null; | ||
10154 | |||
10155 | foreach (var attrib in node.Attributes()) | ||
10156 | { | ||
10157 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10158 | { | ||
10159 | switch (attrib.Name.LocalName) | ||
10160 | { | ||
10161 | case "ExcludedId": | ||
10162 | excludedId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10163 | break; | ||
10164 | case "ExcludeExceptLanguage": | ||
10165 | excludeExceptLanguage = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
10166 | break; | ||
10167 | case "ExcludeLanguage": | ||
10168 | excludeLanguage = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
10169 | break; | ||
10170 | case "ExcludedMaxVersion": | ||
10171 | excludedMaxVersion = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10172 | break; | ||
10173 | case "ExcludedMinVersion": | ||
10174 | excludedMinVersion = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10175 | break; | ||
10176 | default: | ||
10177 | this.Core.UnexpectedAttribute(node, attrib); | ||
10178 | break; | ||
10179 | } | ||
10180 | } | ||
10181 | else | ||
10182 | { | ||
10183 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10184 | } | ||
10185 | } | ||
10186 | |||
10187 | if (null == excludedId) | ||
10188 | { | ||
10189 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ExcludedId")); | ||
10190 | excludedId = String.Empty; | ||
10191 | } | ||
10192 | |||
10193 | if (CompilerConstants.IntegerNotSet != excludeExceptLanguage && CompilerConstants.IntegerNotSet != excludeLanguage) | ||
10194 | { | ||
10195 | this.Core.Write(ErrorMessages.IllegalModuleExclusionLanguageAttributes(sourceLineNumbers)); | ||
10196 | } | ||
10197 | else if (CompilerConstants.IntegerNotSet != excludeExceptLanguage) | ||
10198 | { | ||
10199 | excludedLanguageField = Convert.ToString(-excludeExceptLanguage, CultureInfo.InvariantCulture); | ||
10200 | } | ||
10201 | else if (CompilerConstants.IntegerNotSet != excludeLanguage) | ||
10202 | { | ||
10203 | excludedLanguageField = Convert.ToString(excludeLanguage, CultureInfo.InvariantCulture); | ||
10204 | } | ||
10205 | |||
10206 | this.Core.ParseForExtensionElements(node); | ||
10207 | |||
10208 | if (!this.Core.EncounteredError) | ||
10209 | { | ||
10210 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleExclusion); | ||
10211 | row.Set(0, this.activeName); | ||
10212 | row.Set(1, this.activeLanguage); | ||
10213 | row.Set(2, excludedId); | ||
10214 | row.Set(3, excludedLanguageField); | ||
10215 | row.Set(4, excludedMinVersion); | ||
10216 | row.Set(5, excludedMaxVersion); | ||
10217 | } | ||
10218 | } | ||
10219 | |||
10220 | /// <summary> | ||
10221 | /// Parses a configuration element for a configurable merge module. | ||
10222 | /// </summary> | ||
10223 | /// <param name="node">Element to parse.</param> | ||
10224 | private void ParseConfigurationElement(XElement node) | ||
10225 | { | ||
10226 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10227 | var attributes = 0; | ||
10228 | string contextData = null; | ||
10229 | string defaultValue = null; | ||
10230 | string description = null; | ||
10231 | string displayName = null; | ||
10232 | var format = CompilerConstants.IntegerNotSet; | ||
10233 | string helpKeyword = null; | ||
10234 | string helpLocation = null; | ||
10235 | string name = null; | ||
10236 | string type = null; | ||
10237 | |||
10238 | foreach (var attrib in node.Attributes()) | ||
10239 | { | ||
10240 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10241 | { | ||
10242 | switch (attrib.Name.LocalName) | ||
10243 | { | ||
10244 | case "Name": | ||
10245 | name = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10246 | break; | ||
10247 | case "ContextData": | ||
10248 | contextData = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10249 | break; | ||
10250 | case "Description": | ||
10251 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10252 | break; | ||
10253 | case "DefaultValue": | ||
10254 | defaultValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10255 | break; | ||
10256 | case "DisplayName": | ||
10257 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10258 | break; | ||
10259 | case "Format": | ||
10260 | var formatStr = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10261 | if (0 < formatStr.Length) | ||
10262 | { | ||
10263 | var formatType = Wix.Configuration.ParseFormatType(formatStr); | ||
10264 | switch (formatType) | ||
10265 | { | ||
10266 | case Wix.Configuration.FormatType.Text: | ||
10267 | format = 0; | ||
10268 | break; | ||
10269 | case Wix.Configuration.FormatType.Key: | ||
10270 | format = 1; | ||
10271 | break; | ||
10272 | case Wix.Configuration.FormatType.Integer: | ||
10273 | format = 2; | ||
10274 | break; | ||
10275 | case Wix.Configuration.FormatType.Bitfield: | ||
10276 | format = 3; | ||
10277 | break; | ||
10278 | default: | ||
10279 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Format", formatStr, "Text", "Key", "Integer", "Bitfield")); | ||
10280 | break; | ||
10281 | } | ||
10282 | } | ||
10283 | break; | ||
10284 | case "HelpKeyword": | ||
10285 | helpKeyword = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10286 | break; | ||
10287 | case "HelpLocation": | ||
10288 | helpLocation = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10289 | break; | ||
10290 | case "KeyNoOrphan": | ||
10291 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10292 | { | ||
10293 | attributes |= MsiInterop.MsidbMsmConfigurableOptionKeyNoOrphan; | ||
10294 | } | ||
10295 | break; | ||
10296 | case "NonNullable": | ||
10297 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10298 | { | ||
10299 | attributes |= MsiInterop.MsidbMsmConfigurableOptionNonNullable; | ||
10300 | } | ||
10301 | break; | ||
10302 | case "Type": | ||
10303 | type = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10304 | break; | ||
10305 | default: | ||
10306 | this.Core.UnexpectedAttribute(node, attrib); | ||
10307 | break; | ||
10308 | } | ||
10309 | } | ||
10310 | else | ||
10311 | { | ||
10312 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10313 | } | ||
10314 | } | ||
10315 | |||
10316 | if (null == name) | ||
10317 | { | ||
10318 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
10319 | name = String.Empty; | ||
10320 | } | ||
10321 | |||
10322 | if (CompilerConstants.IntegerNotSet == format) | ||
10323 | { | ||
10324 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Format")); | ||
10325 | format = CompilerConstants.IllegalInteger; | ||
10326 | } | ||
10327 | |||
10328 | this.Core.ParseForExtensionElements(node); | ||
10329 | |||
10330 | if (!this.Core.EncounteredError) | ||
10331 | { | ||
10332 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleConfiguration); | ||
10333 | row.Set(0, name); | ||
10334 | row.Set(1, format); | ||
10335 | row.Set(2, type); | ||
10336 | row.Set(3, contextData); | ||
10337 | row.Set(4, defaultValue); | ||
10338 | row.Set(5, attributes); | ||
10339 | row.Set(6, displayName); | ||
10340 | row.Set(7, description); | ||
10341 | row.Set(8, helpLocation); | ||
10342 | row.Set(9, helpKeyword); | ||
10343 | } | ||
10344 | } | ||
10345 | |||
10346 | /// <summary> | ||
10347 | /// Parses a substitution element for a configurable merge module. | ||
10348 | /// </summary> | ||
10349 | /// <param name="node">Element to parse.</param> | ||
10350 | private void ParseSubstitutionElement(XElement node) | ||
10351 | { | ||
10352 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10353 | string column = null; | ||
10354 | string rowKeys = null; | ||
10355 | string table = null; | ||
10356 | string value = null; | ||
10357 | |||
10358 | foreach (var attrib in node.Attributes()) | ||
10359 | { | ||
10360 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10361 | { | ||
10362 | switch (attrib.Name.LocalName) | ||
10363 | { | ||
10364 | case "Column": | ||
10365 | column = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10366 | break; | ||
10367 | case "Row": | ||
10368 | rowKeys = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10369 | break; | ||
10370 | case "Table": | ||
10371 | table = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10372 | break; | ||
10373 | case "Value": | ||
10374 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10375 | break; | ||
10376 | default: | ||
10377 | this.Core.UnexpectedAttribute(node, attrib); | ||
10378 | break; | ||
10379 | } | ||
10380 | } | ||
10381 | else | ||
10382 | { | ||
10383 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10384 | } | ||
10385 | } | ||
10386 | |||
10387 | if (null == column) | ||
10388 | { | ||
10389 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Column")); | ||
10390 | column = String.Empty; | ||
10391 | } | ||
10392 | |||
10393 | if (null == table) | ||
10394 | { | ||
10395 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Table")); | ||
10396 | table = String.Empty; | ||
10397 | } | ||
10398 | |||
10399 | if (null == rowKeys) | ||
10400 | { | ||
10401 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Row")); | ||
10402 | } | ||
10403 | |||
10404 | this.Core.ParseForExtensionElements(node); | ||
10405 | |||
10406 | if (!this.Core.EncounteredError) | ||
10407 | { | ||
10408 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleSubstitution); | ||
10409 | row.Set(0, table); | ||
10410 | row.Set(1, rowKeys); | ||
10411 | row.Set(2, column); | ||
10412 | row.Set(3, value); | ||
10413 | } | ||
10414 | } | ||
10415 | |||
10416 | /// <summary> | ||
10417 | /// Parses an IgnoreTable element. | ||
10418 | /// </summary> | ||
10419 | /// <param name="node">Element to parse.</param> | ||
10420 | private void ParseIgnoreTableElement(XElement node) | ||
10421 | { | ||
10422 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10423 | string id = null; | ||
10424 | |||
10425 | foreach (var attrib in node.Attributes()) | ||
10426 | { | ||
10427 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10428 | { | ||
10429 | switch (attrib.Name.LocalName) | ||
10430 | { | ||
10431 | case "Id": | ||
10432 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10433 | break; | ||
10434 | default: | ||
10435 | this.Core.UnexpectedAttribute(node, attrib); | ||
10436 | break; | ||
10437 | } | ||
10438 | } | ||
10439 | else | ||
10440 | { | ||
10441 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10442 | } | ||
10443 | } | ||
10444 | |||
10445 | if (null == id) | ||
10446 | { | ||
10447 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
10448 | } | ||
10449 | |||
10450 | this.Core.ParseForExtensionElements(node); | ||
10451 | |||
10452 | if (!this.Core.EncounteredError) | ||
10453 | { | ||
10454 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleIgnoreTable); | ||
10455 | row.Set(0, id); | ||
10456 | } | ||
10457 | } | ||
10458 | |||
10459 | /// <summary> | ||
10460 | /// Parses an odbc driver or translator element. | ||
10461 | /// </summary> | ||
10462 | /// <param name="node">Element to parse.</param> | ||
10463 | /// <param name="componentId">Identifier of parent component.</param> | ||
10464 | /// <param name="fileId">Default identifer for driver/translator file.</param> | ||
10465 | /// <param name="table">Table we're processing for.</param> | ||
10466 | private void ParseODBCDriverOrTranslator(XElement node, string componentId, string fileId, TupleDefinitionType tableName) | ||
10467 | { | ||
10468 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10469 | Identifier id = null; | ||
10470 | var driver = fileId; | ||
10471 | string name = null; | ||
10472 | var setup = fileId; | ||
10473 | |||
10474 | foreach (var attrib in node.Attributes()) | ||
10475 | { | ||
10476 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10477 | { | ||
10478 | switch (attrib.Name.LocalName) | ||
10479 | { | ||
10480 | case "Id": | ||
10481 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
10482 | break; | ||
10483 | case "File": | ||
10484 | driver = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10485 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", driver); | ||
10486 | break; | ||
10487 | case "Name": | ||
10488 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10489 | break; | ||
10490 | case "SetupFile": | ||
10491 | setup = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10492 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", setup); | ||
10493 | break; | ||
10494 | default: | ||
10495 | this.Core.UnexpectedAttribute(node, attrib); | ||
10496 | break; | ||
10497 | } | ||
10498 | } | ||
10499 | else | ||
10500 | { | ||
10501 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10502 | } | ||
10503 | } | ||
10504 | |||
10505 | if (null == name) | ||
10506 | { | ||
10507 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
10508 | } | ||
10509 | |||
10510 | if (null == id) | ||
10511 | { | ||
10512 | id = this.Core.CreateIdentifier("odb", name, fileId, setup); | ||
10513 | } | ||
10514 | |||
10515 | // drivers have a few possible children | ||
10516 | if (TupleDefinitionType.ODBCDriver == tableName) | ||
10517 | { | ||
10518 | // process any data sources for the driver | ||
10519 | foreach (var child in node.Elements()) | ||
10520 | { | ||
10521 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
10522 | { | ||
10523 | switch (child.Name.LocalName) | ||
10524 | { | ||
10525 | case "ODBCDataSource": | ||
10526 | string ignoredKeyPath = null; | ||
10527 | this.ParseODBCDataSource(child, componentId, name, out ignoredKeyPath); | ||
10528 | break; | ||
10529 | case "Property": | ||
10530 | this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCAttribute); | ||
10531 | break; | ||
10532 | default: | ||
10533 | this.Core.UnexpectedElement(node, child); | ||
10534 | break; | ||
10535 | } | ||
10536 | } | ||
10537 | else | ||
10538 | { | ||
10539 | this.Core.ParseExtensionElement(node, child); | ||
10540 | } | ||
10541 | } | ||
10542 | } | ||
10543 | else | ||
10544 | { | ||
10545 | this.Core.ParseForExtensionElements(node); | ||
10546 | } | ||
10547 | |||
10548 | if (!this.Core.EncounteredError) | ||
10549 | { | ||
10550 | var row = this.Core.CreateRow(sourceLineNumbers, tableName, id); | ||
10551 | row.Set(1, componentId); | ||
10552 | row.Set(2, name); | ||
10553 | row.Set(3, driver); | ||
10554 | row.Set(4, setup); | ||
10555 | } | ||
10556 | } | ||
10557 | |||
10558 | /// <summary> | ||
10559 | /// Parses a Property element underneath an ODBC driver or translator. | ||
10560 | /// </summary> | ||
10561 | /// <param name="node">Element to parse.</param> | ||
10562 | /// <param name="parentId">Identifier of parent driver or translator.</param> | ||
10563 | /// <param name="tableName">Name of the table to create property in.</param> | ||
10564 | private void ParseODBCProperty(XElement node, string parentId, TupleDefinitionType tableName) | ||
10565 | { | ||
10566 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10567 | string id = null; | ||
10568 | string propertyValue = null; | ||
10569 | |||
10570 | foreach (var attrib in node.Attributes()) | ||
10571 | { | ||
10572 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10573 | { | ||
10574 | switch (attrib.Name.LocalName) | ||
10575 | { | ||
10576 | case "Id": | ||
10577 | id = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10578 | break; | ||
10579 | case "Value": | ||
10580 | propertyValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10581 | break; | ||
10582 | default: | ||
10583 | this.Core.UnexpectedAttribute(node, attrib); | ||
10584 | break; | ||
10585 | } | ||
10586 | } | ||
10587 | else | ||
10588 | { | ||
10589 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10590 | } | ||
10591 | } | ||
10592 | |||
10593 | if (null == id) | ||
10594 | { | ||
10595 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
10596 | } | ||
10597 | |||
10598 | this.Core.ParseForExtensionElements(node); | ||
10599 | |||
10600 | if (!this.Core.EncounteredError) | ||
10601 | { | ||
10602 | var row = this.Core.CreateRow(sourceLineNumbers, tableName); | ||
10603 | row.Set(0, parentId); | ||
10604 | row.Set(1, id); | ||
10605 | row.Set(2, propertyValue); | ||
10606 | } | ||
10607 | } | ||
10608 | |||
10609 | /// <summary> | ||
10610 | /// Parse an odbc data source element. | ||
10611 | /// </summary> | ||
10612 | /// <param name="node">Element to parse.</param> | ||
10613 | /// <param name="componentId">Identifier of parent component.</param> | ||
10614 | /// <param name="driverName">Default name of driver.</param> | ||
10615 | /// <param name="possibleKeyPath">Identifier of this element in case it is a keypath.</param> | ||
10616 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
10617 | private YesNoType ParseODBCDataSource(XElement node, string componentId, string driverName, out string possibleKeyPath) | ||
10618 | { | ||
10619 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10620 | Identifier id = null; | ||
10621 | var keyPath = YesNoType.NotSet; | ||
10622 | string name = null; | ||
10623 | var registration = CompilerConstants.IntegerNotSet; | ||
10624 | |||
10625 | foreach (var attrib in node.Attributes()) | ||
10626 | { | ||
10627 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10628 | { | ||
10629 | switch (attrib.Name.LocalName) | ||
10630 | { | ||
10631 | case "Id": | ||
10632 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
10633 | break; | ||
10634 | case "DriverName": | ||
10635 | driverName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10636 | break; | ||
10637 | case "KeyPath": | ||
10638 | keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
10639 | break; | ||
10640 | case "Name": | ||
10641 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10642 | break; | ||
10643 | case "Registration": | ||
10644 | var registrationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10645 | if (0 < registrationValue.Length) | ||
10646 | { | ||
10647 | var registrationType = Wix.ODBCDataSource.ParseRegistrationType(registrationValue); | ||
10648 | switch (registrationType) | ||
10649 | { | ||
10650 | case Wix.ODBCDataSource.RegistrationType.machine: | ||
10651 | registration = 0; | ||
10652 | break; | ||
10653 | case Wix.ODBCDataSource.RegistrationType.user: | ||
10654 | registration = 1; | ||
10655 | break; | ||
10656 | default: | ||
10657 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Registration", registrationValue, "machine", "user")); | ||
10658 | break; | ||
10659 | } | ||
10660 | } | ||
10661 | break; | ||
10662 | default: | ||
10663 | this.Core.UnexpectedAttribute(node, attrib); | ||
10664 | break; | ||
10665 | } | ||
10666 | } | ||
10667 | else | ||
10668 | { | ||
10669 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10670 | } | ||
10671 | } | ||
10672 | |||
10673 | if (CompilerConstants.IntegerNotSet == registration) | ||
10674 | { | ||
10675 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Registration")); | ||
10676 | registration = CompilerConstants.IllegalInteger; | ||
10677 | } | ||
10678 | |||
10679 | if (null == id) | ||
10680 | { | ||
10681 | id = this.Core.CreateIdentifier("odc", name, driverName, registration.ToString()); | ||
10682 | } | ||
10683 | |||
10684 | foreach (var child in node.Elements()) | ||
10685 | { | ||
10686 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
10687 | { | ||
10688 | switch (child.Name.LocalName) | ||
10689 | { | ||
10690 | case "Property": | ||
10691 | this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCSourceAttribute); | ||
10692 | break; | ||
10693 | default: | ||
10694 | this.Core.UnexpectedElement(node, child); | ||
10695 | break; | ||
10696 | } | ||
10697 | } | ||
10698 | else | ||
10699 | { | ||
10700 | this.Core.ParseExtensionElement(node, child); | ||
10701 | } | ||
10702 | } | ||
10703 | |||
10704 | if (!this.Core.EncounteredError) | ||
10705 | { | ||
10706 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ODBCDataSource, id); | ||
10707 | row.Set(1, componentId); | ||
10708 | row.Set(2, name); | ||
10709 | row.Set(3, driverName); | ||
10710 | row.Set(4, registration); | ||
10711 | } | ||
10712 | |||
10713 | possibleKeyPath = id.Id; | ||
10714 | return keyPath; | ||
10715 | } | ||
10716 | |||
10717 | /// <summary> | ||
10718 | /// Parses a package element. | ||
10719 | /// </summary> | ||
10720 | /// <param name="node">Element to parse.</param> | ||
10721 | /// <param name="productAuthor">Default package author.</param> | ||
10722 | /// <param name="moduleId">The module guid - this is necessary until Module/@Guid is removed.</param> | ||
10723 | private void ParsePackageElement(XElement node, string productAuthor, string moduleId) | ||
10724 | { | ||
10725 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10726 | var codepage = "1252"; | ||
10727 | var comments = String.Format(CultureInfo.InvariantCulture, "This installer database contains the logic and data required to install {0}.", this.activeName); | ||
10728 | var keywords = "Installer"; | ||
10729 | var msiVersion = 100; // lowest released version, really should be specified | ||
10730 | var packageAuthor = productAuthor; | ||
10731 | string packageCode = null; | ||
10732 | var packageLanguages = this.activeLanguage; | ||
10733 | var packageName = this.activeName; | ||
10734 | string platform = null; | ||
10735 | string platformValue = null; | ||
10736 | var security = YesNoDefaultType.Default; | ||
10737 | var sourceBits = (this.compilingModule ? 2 : 0); | ||
10738 | IntermediateTuple row; | ||
10739 | var installPrivilegeSeen = false; | ||
10740 | var installScopeSeen = false; | ||
10741 | |||
10742 | switch (this.CurrentPlatform) | ||
10743 | { | ||
10744 | case Platform.X86: | ||
10745 | platform = "Intel"; | ||
10746 | break; | ||
10747 | case Platform.X64: | ||
10748 | platform = "x64"; | ||
10749 | msiVersion = 200; | ||
10750 | break; | ||
10751 | case Platform.IA64: | ||
10752 | platform = "Intel64"; | ||
10753 | msiVersion = 200; | ||
10754 | break; | ||
10755 | case Platform.ARM: | ||
10756 | platform = "Arm"; | ||
10757 | msiVersion = 500; | ||
10758 | break; | ||
10759 | default: | ||
10760 | throw new ArgumentException("Unknown platform enumeration '{0}' encountered.", this.CurrentPlatform.ToString()); | ||
10761 | } | ||
10762 | |||
10763 | foreach (var attrib in node.Attributes()) | ||
10764 | { | ||
10765 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10766 | { | ||
10767 | switch (attrib.Name.LocalName) | ||
10768 | { | ||
10769 | case "Id": | ||
10770 | packageCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, this.compilingProduct); | ||
10771 | break; | ||
10772 | case "AdminImage": | ||
10773 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10774 | { | ||
10775 | sourceBits = sourceBits | 4; | ||
10776 | } | ||
10777 | break; | ||
10778 | case "Comments": | ||
10779 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10780 | break; | ||
10781 | case "Compressed": | ||
10782 | // merge modules must always be compressed, so this attribute is invalid | ||
10783 | if (this.compilingModule) | ||
10784 | { | ||
10785 | this.Core.Write(WarningMessages.DeprecatedPackageCompressedAttribute(sourceLineNumbers)); | ||
10786 | // this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Compressed", "Module")); | ||
10787 | } | ||
10788 | else if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10789 | { | ||
10790 | sourceBits = sourceBits | 2; | ||
10791 | } | ||
10792 | break; | ||
10793 | case "Description": | ||
10794 | packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10795 | break; | ||
10796 | case "InstallPrivileges": | ||
10797 | var installPrivileges = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10798 | if (0 < installPrivileges.Length) | ||
10799 | { | ||
10800 | installPrivilegeSeen = true; | ||
10801 | var installPrivilegesType = Wix.Package.ParseInstallPrivilegesType(installPrivileges); | ||
10802 | switch (installPrivilegesType) | ||
10803 | { | ||
10804 | case Wix.Package.InstallPrivilegesType.elevated: | ||
10805 | // this is the default setting | ||
10806 | break; | ||
10807 | case Wix.Package.InstallPrivilegesType.limited: | ||
10808 | sourceBits = sourceBits | 8; | ||
10809 | break; | ||
10810 | default: | ||
10811 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installPrivileges, "elevated", "limited")); | ||
10812 | break; | ||
10813 | } | ||
10814 | } | ||
10815 | break; | ||
10816 | case "InstallScope": | ||
10817 | var installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10818 | if (0 < installScope.Length) | ||
10819 | { | ||
10820 | installScopeSeen = true; | ||
10821 | var installScopeType = Wix.Package.ParseInstallScopeType(installScope); | ||
10822 | switch (installScopeType) | ||
10823 | { | ||
10824 | case Wix.Package.InstallScopeType.perMachine: | ||
10825 | { | ||
10826 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Property, new Identifier("ALLUSERS", AccessModifier.Public)); | ||
10827 | row.Set(1, "1"); | ||
10828 | } | ||
10829 | break; | ||
10830 | case Wix.Package.InstallScopeType.perUser: | ||
10831 | sourceBits = sourceBits | 8; | ||
10832 | break; | ||
10833 | default: | ||
10834 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installScope, "perMachine", "perUser")); | ||
10835 | break; | ||
10836 | } | ||
10837 | } | ||
10838 | break; | ||
10839 | case "InstallerVersion": | ||
10840 | msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
10841 | break; | ||
10842 | case "Keywords": | ||
10843 | keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10844 | break; | ||
10845 | case "Languages": | ||
10846 | packageLanguages = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10847 | break; | ||
10848 | case "Manufacturer": | ||
10849 | packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10850 | if ("PUT-COMPANY-NAME-HERE" == packageAuthor) | ||
10851 | { | ||
10852 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, packageAuthor)); | ||
10853 | } | ||
10854 | break; | ||
10855 | case "Platform": | ||
10856 | if (null != platformValue) | ||
10857 | { | ||
10858 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platforms")); | ||
10859 | } | ||
10860 | |||
10861 | platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10862 | var platformType = Wix.Package.ParsePlatformType(platformValue); | ||
10863 | switch (platformType) | ||
10864 | { | ||
10865 | case Wix.Package.PlatformType.intel: | ||
10866 | this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "x86")); | ||
10867 | goto case Wix.Package.PlatformType.x86; | ||
10868 | case Wix.Package.PlatformType.x86: | ||
10869 | platform = "Intel"; | ||
10870 | break; | ||
10871 | case Wix.Package.PlatformType.x64: | ||
10872 | platform = "x64"; | ||
10873 | break; | ||
10874 | case Wix.Package.PlatformType.intel64: | ||
10875 | this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "ia64")); | ||
10876 | goto case Wix.Package.PlatformType.ia64; | ||
10877 | case Wix.Package.PlatformType.ia64: | ||
10878 | platform = "Intel64"; | ||
10879 | break; | ||
10880 | case Wix.Package.PlatformType.arm: | ||
10881 | platform = "Arm"; | ||
10882 | break; | ||
10883 | default: | ||
10884 | this.Core.Write(ErrorMessages.InvalidPlatformValue(sourceLineNumbers, platformValue)); | ||
10885 | break; | ||
10886 | } | ||
10887 | break; | ||
10888 | case "Platforms": | ||
10889 | if (null != platformValue) | ||
10890 | { | ||
10891 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
10892 | } | ||
10893 | |||
10894 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
10895 | platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10896 | platform = platformValue; | ||
10897 | break; | ||
10898 | case "ReadOnly": | ||
10899 | security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
10900 | break; | ||
10901 | case "ShortNames": | ||
10902 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10903 | { | ||
10904 | sourceBits = sourceBits | 1; | ||
10905 | this.useShortFileNames = true; | ||
10906 | } | ||
10907 | break; | ||
10908 | case "SummaryCodepage": | ||
10909 | codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib, true); | ||
10910 | break; | ||
10911 | default: | ||
10912 | this.Core.UnexpectedAttribute(node, attrib); | ||
10913 | break; | ||
10914 | } | ||
10915 | } | ||
10916 | else | ||
10917 | { | ||
10918 | this.Core.ParseExtensionAttribute(node, attrib); | ||
10919 | } | ||
10920 | } | ||
10921 | |||
10922 | if (installPrivilegeSeen && installScopeSeen) | ||
10923 | { | ||
10924 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "InstallPrivileges", "InstallScope")); | ||
10925 | } | ||
10926 | |||
10927 | if ((0 != String.Compare(platform, "Intel", StringComparison.OrdinalIgnoreCase)) && 200 > msiVersion) | ||
10928 | { | ||
10929 | msiVersion = 200; | ||
10930 | this.Core.Write(WarningMessages.RequiresMsi200for64bitPackage(sourceLineNumbers)); | ||
10931 | } | ||
10932 | |||
10933 | if ((0 == String.Compare(platform, "Arm", StringComparison.OrdinalIgnoreCase)) && 500 > msiVersion) | ||
10934 | { | ||
10935 | msiVersion = 500; | ||
10936 | this.Core.Write(WarningMessages.RequiresMsi500forArmPackage(sourceLineNumbers)); | ||
10937 | } | ||
10938 | |||
10939 | if (null == packageAuthor) | ||
10940 | { | ||
10941 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
10942 | } | ||
10943 | |||
10944 | if (this.compilingModule) | ||
10945 | { | ||
10946 | if (null == packageCode) | ||
10947 | { | ||
10948 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
10949 | } | ||
10950 | |||
10951 | // merge modules use the modularization guid as the package code | ||
10952 | if (null != moduleId) | ||
10953 | { | ||
10954 | packageCode = moduleId; | ||
10955 | } | ||
10956 | |||
10957 | // merge modules are always compressed | ||
10958 | sourceBits = 2; | ||
10959 | } | ||
10960 | else // product | ||
10961 | { | ||
10962 | if (null == packageCode) | ||
10963 | { | ||
10964 | packageCode = "*"; | ||
10965 | } | ||
10966 | |||
10967 | if ("*" != packageCode) | ||
10968 | { | ||
10969 | this.Core.Write(WarningMessages.PackageCodeSet(sourceLineNumbers)); | ||
10970 | } | ||
10971 | } | ||
10972 | |||
10973 | this.Core.ParseForExtensionElements(node); | ||
10974 | |||
10975 | if (!this.Core.EncounteredError) | ||
10976 | { | ||
10977 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
10978 | row.Set(0, 1); | ||
10979 | row.Set(1, codepage); | ||
10980 | |||
10981 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
10982 | row.Set(0, 2); | ||
10983 | row.Set(1, "Installation Database"); | ||
10984 | |||
10985 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
10986 | row.Set(0, 3); | ||
10987 | row.Set(1, packageName); | ||
10988 | |||
10989 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
10990 | row.Set(0, 4); | ||
10991 | row.Set(1, packageAuthor); | ||
10992 | |||
10993 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
10994 | row.Set(0, 5); | ||
10995 | row.Set(1, keywords); | ||
10996 | |||
10997 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
10998 | row.Set(0, 6); | ||
10999 | row.Set(1, comments); | ||
11000 | |||
11001 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11002 | row.Set(0, 7); | ||
11003 | row.Set(1, String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, packageLanguages)); | ||
11004 | |||
11005 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11006 | row.Set(0, 9); | ||
11007 | row.Set(1, packageCode); | ||
11008 | |||
11009 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11010 | row.Set(0, 14); | ||
11011 | row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture)); | ||
11012 | |||
11013 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11014 | row.Set(0, 15); | ||
11015 | row.Set(1, sourceBits.ToString(CultureInfo.InvariantCulture)); | ||
11016 | |||
11017 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11018 | row.Set(0, 19); | ||
11019 | switch (security) | ||
11020 | { | ||
11021 | case YesNoDefaultType.No: // no restriction | ||
11022 | row.Set(1, "0"); | ||
11023 | break; | ||
11024 | case YesNoDefaultType.Default: // read-only recommended | ||
11025 | row.Set(1, "2"); | ||
11026 | break; | ||
11027 | case YesNoDefaultType.Yes: // read-only enforced | ||
11028 | row.Set(1, "4"); | ||
11029 | break; | ||
11030 | } | ||
11031 | } | ||
11032 | } | ||
11033 | |||
11034 | /// <summary> | ||
11035 | /// Parses a patch metadata element. | ||
11036 | /// </summary> | ||
11037 | /// <param name="node">Element to parse.</param> | ||
11038 | private void ParsePatchMetadataElement(XElement node) | ||
11039 | { | ||
11040 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11041 | var allowRemoval = YesNoType.NotSet; | ||
11042 | string classification = null; | ||
11043 | string creationTimeUtc = null; | ||
11044 | string description = null; | ||
11045 | string displayName = null; | ||
11046 | string manufacturerName = null; | ||
11047 | string minorUpdateTargetRTM = null; | ||
11048 | string moreInfoUrl = null; | ||
11049 | var optimizeCA = CompilerConstants.IntegerNotSet; | ||
11050 | var optimizedInstallMode = YesNoType.NotSet; | ||
11051 | string targetProductName = null; | ||
11052 | |||
11053 | foreach (var attrib in node.Attributes()) | ||
11054 | { | ||
11055 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11056 | { | ||
11057 | switch (attrib.Name.LocalName) | ||
11058 | { | ||
11059 | case "AllowRemoval": | ||
11060 | allowRemoval = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
11061 | break; | ||
11062 | case "Classification": | ||
11063 | classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11064 | break; | ||
11065 | case "CreationTimeUTC": | ||
11066 | creationTimeUtc = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11067 | break; | ||
11068 | case "Description": | ||
11069 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11070 | break; | ||
11071 | case "DisplayName": | ||
11072 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11073 | break; | ||
11074 | case "ManufacturerName": | ||
11075 | manufacturerName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11076 | break; | ||
11077 | case "MinorUpdateTargetRTM": | ||
11078 | minorUpdateTargetRTM = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11079 | break; | ||
11080 | case "MoreInfoURL": | ||
11081 | moreInfoUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11082 | break; | ||
11083 | case "OptimizedInstallMode": | ||
11084 | optimizedInstallMode = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
11085 | break; | ||
11086 | case "TargetProductName": | ||
11087 | targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11088 | break; | ||
11089 | default: | ||
11090 | this.Core.UnexpectedAttribute(node, attrib); | ||
11091 | break; | ||
11092 | } | ||
11093 | } | ||
11094 | else | ||
11095 | { | ||
11096 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11097 | } | ||
11098 | } | ||
11099 | |||
11100 | if (YesNoType.NotSet == allowRemoval) | ||
11101 | { | ||
11102 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "AllowRemoval")); | ||
11103 | } | ||
11104 | |||
11105 | if (null == classification) | ||
11106 | { | ||
11107 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification")); | ||
11108 | } | ||
11109 | |||
11110 | if (null == description) | ||
11111 | { | ||
11112 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
11113 | } | ||
11114 | |||
11115 | if (null == displayName) | ||
11116 | { | ||
11117 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName")); | ||
11118 | } | ||
11119 | |||
11120 | if (null == manufacturerName) | ||
11121 | { | ||
11122 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManufacturerName")); | ||
11123 | } | ||
11124 | |||
11125 | if (null == moreInfoUrl) | ||
11126 | { | ||
11127 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MoreInfoURL")); | ||
11128 | } | ||
11129 | |||
11130 | if (null == targetProductName) | ||
11131 | { | ||
11132 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetProductName")); | ||
11133 | } | ||
11134 | |||
11135 | foreach (var child in node.Elements()) | ||
11136 | { | ||
11137 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
11138 | { | ||
11139 | switch (child.Name.LocalName) | ||
11140 | { | ||
11141 | case "CustomProperty": | ||
11142 | this.ParseCustomPropertyElement(child); | ||
11143 | break; | ||
11144 | case "OptimizeCustomActions": | ||
11145 | optimizeCA = this.ParseOptimizeCustomActionsElement(child); | ||
11146 | break; | ||
11147 | default: | ||
11148 | this.Core.UnexpectedElement(node, child); | ||
11149 | break; | ||
11150 | } | ||
11151 | } | ||
11152 | else | ||
11153 | { | ||
11154 | this.Core.ParseExtensionElement(node, child); | ||
11155 | } | ||
11156 | } | ||
11157 | |||
11158 | if (!this.Core.EncounteredError) | ||
11159 | { | ||
11160 | if (YesNoType.NotSet != allowRemoval) | ||
11161 | { | ||
11162 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11163 | row.Set(1, "AllowRemoval"); | ||
11164 | row.Set(2, YesNoType.Yes == allowRemoval ? "1" : "0"); | ||
11165 | } | ||
11166 | |||
11167 | if (null != classification) | ||
11168 | { | ||
11169 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11170 | row.Set(1, "Classification"); | ||
11171 | row.Set(2, classification); | ||
11172 | } | ||
11173 | |||
11174 | if (null != creationTimeUtc) | ||
11175 | { | ||
11176 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11177 | row.Set(1, "CreationTimeUTC"); | ||
11178 | row.Set(2, creationTimeUtc); | ||
11179 | } | ||
11180 | |||
11181 | if (null != description) | ||
11182 | { | ||
11183 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11184 | row.Set(1, "Description"); | ||
11185 | row.Set(2, description); | ||
11186 | } | ||
11187 | |||
11188 | if (null != displayName) | ||
11189 | { | ||
11190 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11191 | row.Set(1, "DisplayName"); | ||
11192 | row.Set(2, displayName); | ||
11193 | } | ||
11194 | |||
11195 | if (null != manufacturerName) | ||
11196 | { | ||
11197 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11198 | row.Set(1, "ManufacturerName"); | ||
11199 | row.Set(2, manufacturerName); | ||
11200 | } | ||
11201 | |||
11202 | if (null != minorUpdateTargetRTM) | ||
11203 | { | ||
11204 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11205 | row.Set(1, "MinorUpdateTargetRTM"); | ||
11206 | row.Set(2, minorUpdateTargetRTM); | ||
11207 | } | ||
11208 | |||
11209 | if (null != moreInfoUrl) | ||
11210 | { | ||
11211 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11212 | row.Set(1, "MoreInfoURL"); | ||
11213 | row.Set(2, moreInfoUrl); | ||
11214 | } | ||
11215 | |||
11216 | if (CompilerConstants.IntegerNotSet != optimizeCA) | ||
11217 | { | ||
11218 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11219 | row.Set(1, "OptimizeCA"); | ||
11220 | row.Set(2, optimizeCA.ToString(CultureInfo.InvariantCulture)); | ||
11221 | } | ||
11222 | |||
11223 | if (YesNoType.NotSet != optimizedInstallMode) | ||
11224 | { | ||
11225 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11226 | row.Set(1, "OptimizedInstallMode"); | ||
11227 | row.Set(2, YesNoType.Yes == optimizedInstallMode ? "1" : "0"); | ||
11228 | } | ||
11229 | |||
11230 | if (null != targetProductName) | ||
11231 | { | ||
11232 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11233 | row.Set(1, "TargetProductName"); | ||
11234 | row.Set(2, targetProductName); | ||
11235 | } | ||
11236 | } | ||
11237 | } | ||
11238 | |||
11239 | /// <summary> | ||
11240 | /// Parses a custom property element for the PatchMetadata table. | ||
11241 | /// </summary> | ||
11242 | /// <param name="node">Element to parse.</param> | ||
11243 | private void ParseCustomPropertyElement(XElement node) | ||
11244 | { | ||
11245 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11246 | string company = null; | ||
11247 | string property = null; | ||
11248 | string value = null; | ||
11249 | |||
11250 | foreach (var attrib in node.Attributes()) | ||
11251 | { | ||
11252 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11253 | { | ||
11254 | switch (attrib.Name.LocalName) | ||
11255 | { | ||
11256 | case "Company": | ||
11257 | company = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11258 | break; | ||
11259 | case "Property": | ||
11260 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11261 | break; | ||
11262 | case "Value": | ||
11263 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11264 | break; | ||
11265 | default: | ||
11266 | this.Core.UnexpectedAttribute(node, attrib); | ||
11267 | break; | ||
11268 | } | ||
11269 | } | ||
11270 | else | ||
11271 | { | ||
11272 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11273 | } | ||
11274 | } | ||
11275 | |||
11276 | if (null == company) | ||
11277 | { | ||
11278 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Company")); | ||
11279 | } | ||
11280 | |||
11281 | if (null == property) | ||
11282 | { | ||
11283 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
11284 | } | ||
11285 | |||
11286 | if (null == value) | ||
11287 | { | ||
11288 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
11289 | } | ||
11290 | |||
11291 | this.Core.ParseForExtensionElements(node); | ||
11292 | |||
11293 | if (!this.Core.EncounteredError) | ||
11294 | { | ||
11295 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
11296 | row.Set(0, company); | ||
11297 | row.Set(1, property); | ||
11298 | row.Set(2, value); | ||
11299 | } | ||
11300 | } | ||
11301 | |||
11302 | /// <summary> | ||
11303 | /// Parses the OptimizeCustomActions element. | ||
11304 | /// </summary> | ||
11305 | /// <param name="node">Element to parse.</param> | ||
11306 | /// <returns>The combined integer value for callers to store as appropriate.</returns> | ||
11307 | private int ParseOptimizeCustomActionsElement(XElement node) | ||
11308 | { | ||
11309 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11310 | var optimizeCA = OptimizeCA.None; | ||
11311 | |||
11312 | foreach (var attrib in node.Attributes()) | ||
11313 | { | ||
11314 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11315 | { | ||
11316 | switch (attrib.Name.LocalName) | ||
11317 | { | ||
11318 | case "SkipAssignment": | ||
11319 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
11320 | { | ||
11321 | optimizeCA |= OptimizeCA.SkipAssignment; | ||
11322 | } | ||
11323 | break; | ||
11324 | case "SkipImmediate": | ||
11325 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
11326 | { | ||
11327 | optimizeCA |= OptimizeCA.SkipImmediate; | ||
11328 | } | ||
11329 | break; | ||
11330 | case "SkipDeferred": | ||
11331 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
11332 | { | ||
11333 | optimizeCA |= OptimizeCA.SkipDeferred; | ||
11334 | } | ||
11335 | break; | ||
11336 | default: | ||
11337 | this.Core.UnexpectedAttribute(node, attrib); | ||
11338 | break; | ||
11339 | } | ||
11340 | } | ||
11341 | else | ||
11342 | { | ||
11343 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11344 | } | ||
11345 | } | ||
11346 | |||
11347 | return (int)optimizeCA; | ||
11348 | } | ||
11349 | |||
11350 | /// <summary> | ||
11351 | /// Parses a patch information element. | ||
11352 | /// </summary> | ||
11353 | /// <param name="node">Element to parse.</param> | ||
11354 | private void ParsePatchInformationElement(XElement node) | ||
11355 | { | ||
11356 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11357 | var codepage = "1252"; | ||
11358 | string comments = null; | ||
11359 | var keywords = "Installer,Patching,PCP,Database"; | ||
11360 | var msiVersion = 1; // Should always be 1 for patches | ||
11361 | string packageAuthor = null; | ||
11362 | var packageName = this.activeName; | ||
11363 | var security = YesNoDefaultType.Default; | ||
11364 | |||
11365 | foreach (var attrib in node.Attributes()) | ||
11366 | { | ||
11367 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11368 | { | ||
11369 | switch (attrib.Name.LocalName) | ||
11370 | { | ||
11371 | case "AdminImage": | ||
11372 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11373 | break; | ||
11374 | case "Comments": | ||
11375 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11376 | break; | ||
11377 | case "Compressed": | ||
11378 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11379 | break; | ||
11380 | case "Description": | ||
11381 | packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11382 | break; | ||
11383 | case "Keywords": | ||
11384 | keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11385 | break; | ||
11386 | case "Languages": | ||
11387 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11388 | break; | ||
11389 | case "Manufacturer": | ||
11390 | packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11391 | break; | ||
11392 | case "Platforms": | ||
11393 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11394 | break; | ||
11395 | case "ReadOnly": | ||
11396 | security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
11397 | break; | ||
11398 | case "ShortNames": | ||
11399 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11400 | break; | ||
11401 | case "SummaryCodepage": | ||
11402 | codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib); | ||
11403 | break; | ||
11404 | default: | ||
11405 | this.Core.UnexpectedAttribute(node, attrib); | ||
11406 | break; | ||
11407 | } | ||
11408 | } | ||
11409 | else | ||
11410 | { | ||
11411 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11412 | } | ||
11413 | } | ||
11414 | |||
11415 | this.Core.ParseForExtensionElements(node); | ||
11416 | |||
11417 | if (!this.Core.EncounteredError) | ||
11418 | { | ||
11419 | // PID_CODEPAGE | ||
11420 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11421 | row.Set(0, 1); | ||
11422 | row.Set(1, codepage); | ||
11423 | |||
11424 | // PID_TITLE | ||
11425 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11426 | row.Set(0, 2); | ||
11427 | row.Set(1, "Patch"); | ||
11428 | |||
11429 | // PID_SUBJECT | ||
11430 | if (null != packageName) | ||
11431 | { | ||
11432 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11433 | row.Set(0, 3); | ||
11434 | row.Set(1, packageName); | ||
11435 | } | ||
11436 | |||
11437 | // PID_AUTHOR | ||
11438 | if (null != packageAuthor) | ||
11439 | { | ||
11440 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11441 | row.Set(0, 4); | ||
11442 | row.Set(1, packageAuthor); | ||
11443 | } | ||
11444 | |||
11445 | // PID_KEYWORDS | ||
11446 | if (null != keywords) | ||
11447 | { | ||
11448 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11449 | row.Set(0, 5); | ||
11450 | row.Set(1, keywords); | ||
11451 | } | ||
11452 | |||
11453 | // PID_COMMENTS | ||
11454 | if (null != comments) | ||
11455 | { | ||
11456 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11457 | row.Set(0, 6); | ||
11458 | row.Set(1, comments); | ||
11459 | } | ||
11460 | |||
11461 | // PID_PAGECOUNT | ||
11462 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11463 | row.Set(0, 14); | ||
11464 | row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture)); | ||
11465 | |||
11466 | // PID_WORDCOUNT | ||
11467 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11468 | row.Set(0, 15); | ||
11469 | row.Set(1, "0"); | ||
11470 | |||
11471 | // PID_SECURITY | ||
11472 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
11473 | row.Set(0, 19); | ||
11474 | switch (security) | ||
11475 | { | ||
11476 | case YesNoDefaultType.No: // no restriction | ||
11477 | row.Set(1, "0"); | ||
11478 | break; | ||
11479 | case YesNoDefaultType.Default: // read-only recommended | ||
11480 | row.Set(1, "2"); | ||
11481 | break; | ||
11482 | case YesNoDefaultType.Yes: // read-only enforced | ||
11483 | row.Set(1, "4"); | ||
11484 | break; | ||
11485 | } | ||
11486 | } | ||
11487 | } | ||
11488 | |||
11489 | /// <summary> | ||
11490 | /// Parses an ignore modularization element. | ||
11491 | /// </summary> | ||
11492 | /// <param name="node">XmlNode on an IgnoreModulatization element.</param> | ||
11493 | private void ParseIgnoreModularizationElement(XElement node) | ||
11494 | { | ||
11495 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11496 | string name = null; | ||
11497 | |||
11498 | this.Core.Write(WarningMessages.DeprecatedIgnoreModularizationElement(sourceLineNumbers)); | ||
11499 | |||
11500 | foreach (var attrib in node.Attributes()) | ||
11501 | { | ||
11502 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11503 | { | ||
11504 | switch (attrib.Name.LocalName) | ||
11505 | { | ||
11506 | case "Name": | ||
11507 | name = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
11508 | break; | ||
11509 | case "Type": | ||
11510 | // this is actually not used | ||
11511 | break; | ||
11512 | default: | ||
11513 | this.Core.UnexpectedAttribute(node, attrib); | ||
11514 | break; | ||
11515 | } | ||
11516 | } | ||
11517 | else | ||
11518 | { | ||
11519 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11520 | } | ||
11521 | } | ||
11522 | |||
11523 | if (null == name) | ||
11524 | { | ||
11525 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
11526 | } | ||
11527 | |||
11528 | this.Core.ParseForExtensionElements(node); | ||
11529 | |||
11530 | if (!this.Core.EncounteredError) | ||
11531 | { | ||
11532 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSuppressModularization); | ||
11533 | row.Set(0, name); | ||
11534 | } | ||
11535 | } | ||
11536 | |||
11537 | /// <summary> | ||
11538 | /// Parses a permission element. | ||
11539 | /// </summary> | ||
11540 | /// <param name="node">Element to parse.</param> | ||
11541 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
11542 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
11543 | private void ParsePermissionElement(XElement node, string objectId, string tableName) | ||
11544 | { | ||
11545 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11546 | var bits = new BitArray(32); | ||
11547 | string domain = null; | ||
11548 | var permission = 0; | ||
11549 | string[] specialPermissions = null; | ||
11550 | string user = null; | ||
11551 | |||
11552 | switch (tableName) | ||
11553 | { | ||
11554 | case "CreateFolder": | ||
11555 | specialPermissions = Common.FolderPermissions; | ||
11556 | break; | ||
11557 | case "File": | ||
11558 | specialPermissions = Common.FilePermissions; | ||
11559 | break; | ||
11560 | case "Registry": | ||
11561 | specialPermissions = Common.RegistryPermissions; | ||
11562 | break; | ||
11563 | default: | ||
11564 | this.Core.UnexpectedElement(node.Parent, node); | ||
11565 | return; // stop processing this element since no valid permissions are available | ||
11566 | } | ||
11567 | |||
11568 | foreach (var attrib in node.Attributes()) | ||
11569 | { | ||
11570 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11571 | { | ||
11572 | switch (attrib.Name.LocalName) | ||
11573 | { | ||
11574 | case "Domain": | ||
11575 | domain = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11576 | break; | ||
11577 | case "User": | ||
11578 | user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11579 | break; | ||
11580 | case "FileAllRights": | ||
11581 | // match the WinNT.h mask FILE_ALL_ACCESS for value 0x001F01FF (aka 1 1111 0000 0001 1111 1111 or 2032127) | ||
11582 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[16] = bits[17] = bits[18] = bits[19] = bits[20] = true; | ||
11583 | break; | ||
11584 | case "SpecificRightsAll": | ||
11585 | // match the WinNT.h mask SPECIFIC_RIGHTS_ALL for value 0x0000FFFF (aka 1111 1111 1111 1111) | ||
11586 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[9] = bits[10] = bits[11] = bits[12] = bits[13] = bits[14] = bits[15] = true; | ||
11587 | break; | ||
11588 | default: | ||
11589 | var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
11590 | if (!this.Core.TrySetBitFromName(Common.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) | ||
11591 | { | ||
11592 | if (!this.Core.TrySetBitFromName(Common.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) | ||
11593 | { | ||
11594 | if (!this.Core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | ||
11595 | { | ||
11596 | this.Core.UnexpectedAttribute(node, attrib); | ||
11597 | break; | ||
11598 | } | ||
11599 | } | ||
11600 | } | ||
11601 | break; | ||
11602 | } | ||
11603 | } | ||
11604 | else | ||
11605 | { | ||
11606 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11607 | } | ||
11608 | } | ||
11609 | |||
11610 | permission = this.Core.CreateIntegerFromBitArray(bits); | ||
11611 | |||
11612 | if (null == user) | ||
11613 | { | ||
11614 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "User")); | ||
11615 | } | ||
11616 | |||
11617 | if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL | ||
11618 | { | ||
11619 | this.Core.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); | ||
11620 | } | ||
11621 | |||
11622 | this.Core.ParseForExtensionElements(node); | ||
11623 | |||
11624 | if (!this.Core.EncounteredError) | ||
11625 | { | ||
11626 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.LockPermissions); | ||
11627 | row.Set(0, objectId); | ||
11628 | row.Set(1, tableName); | ||
11629 | row.Set(2, domain); | ||
11630 | row.Set(3, user); | ||
11631 | row.Set(4, permission); | ||
11632 | } | ||
11633 | } | ||
11634 | |||
11635 | /// <summary> | ||
11636 | /// Parses an extended permission element. | ||
11637 | /// </summary> | ||
11638 | /// <param name="node">Element to parse.</param> | ||
11639 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
11640 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
11641 | private void ParsePermissionExElement(XElement node, string objectId, string tableName) | ||
11642 | { | ||
11643 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11644 | string condition = null; | ||
11645 | Identifier id = null; | ||
11646 | string sddl = null; | ||
11647 | |||
11648 | switch (tableName) | ||
11649 | { | ||
11650 | case "CreateFolder": | ||
11651 | case "File": | ||
11652 | case "Registry": | ||
11653 | case "ServiceInstall": | ||
11654 | break; | ||
11655 | default: | ||
11656 | this.Core.UnexpectedElement(node.Parent, node); | ||
11657 | return; // stop processing this element since nothing will be valid. | ||
11658 | } | ||
11659 | |||
11660 | foreach (var attrib in node.Attributes()) | ||
11661 | { | ||
11662 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11663 | { | ||
11664 | switch (attrib.Name.LocalName) | ||
11665 | { | ||
11666 | case "Id": | ||
11667 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
11668 | break; | ||
11669 | case "Sddl": | ||
11670 | sddl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11671 | break; | ||
11672 | default: | ||
11673 | this.Core.UnexpectedAttribute(node, attrib); | ||
11674 | break; | ||
11675 | } | ||
11676 | } | ||
11677 | else | ||
11678 | { | ||
11679 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11680 | } | ||
11681 | } | ||
11682 | |||
11683 | if (null == sddl) | ||
11684 | { | ||
11685 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Sddl")); | ||
11686 | } | ||
11687 | |||
11688 | if (null == id) | ||
11689 | { | ||
11690 | id = this.Core.CreateIdentifier("pme", objectId, tableName, sddl); | ||
11691 | } | ||
11692 | |||
11693 | foreach (var child in node.Elements()) | ||
11694 | { | ||
11695 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
11696 | { | ||
11697 | switch (child.Name.LocalName) | ||
11698 | { | ||
11699 | case "Condition": | ||
11700 | if (null != condition) | ||
11701 | { | ||
11702 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11703 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
11704 | } | ||
11705 | |||
11706 | condition = this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
11707 | break; | ||
11708 | default: | ||
11709 | this.Core.UnexpectedElement(node, child); | ||
11710 | break; | ||
11711 | } | ||
11712 | } | ||
11713 | else | ||
11714 | { | ||
11715 | this.Core.ParseExtensionElement(node, child); | ||
11716 | } | ||
11717 | } | ||
11718 | |||
11719 | if (!this.Core.EncounteredError) | ||
11720 | { | ||
11721 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiLockPermissionsEx, id); | ||
11722 | row.Set(1, objectId); | ||
11723 | row.Set(2, tableName); | ||
11724 | row.Set(3, sddl); | ||
11725 | row.Set(4, condition); | ||
11726 | } | ||
11727 | } | ||
11728 | |||
11729 | /// <summary> | ||
11730 | /// Parses a product element. | ||
11731 | /// </summary> | ||
11732 | /// <param name="node">Element to parse.</param> | ||
11733 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
11734 | private void ParseProductElement(XElement node) | ||
11735 | { | ||
11736 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11737 | var codepage = 65001; | ||
11738 | string productCode = null; | ||
11739 | string upgradeCode = null; | ||
11740 | string manufacturer = null; | ||
11741 | string version = null; | ||
11742 | string symbols = null; | ||
11743 | |||
11744 | this.activeName = null; | ||
11745 | this.activeLanguage = null; | ||
11746 | |||
11747 | foreach (var attrib in node.Attributes()) | ||
11748 | { | ||
11749 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11750 | { | ||
11751 | switch (attrib.Name.LocalName) | ||
11752 | { | ||
11753 | case "Id": | ||
11754 | productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
11755 | break; | ||
11756 | case "Codepage": | ||
11757 | codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
11758 | break; | ||
11759 | case "Language": | ||
11760 | this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
11761 | break; | ||
11762 | case "Manufacturer": | ||
11763 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
11764 | if ("PUT-COMPANY-NAME-HERE" == manufacturer) | ||
11765 | { | ||
11766 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, manufacturer)); | ||
11767 | } | ||
11768 | break; | ||
11769 | case "Name": | ||
11770 | this.activeName = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
11771 | if ("PUT-PRODUCT-NAME-HERE" == this.activeName) | ||
11772 | { | ||
11773 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
11774 | } | ||
11775 | break; | ||
11776 | case "UpgradeCode": | ||
11777 | upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
11778 | break; | ||
11779 | case "Version": // if the attribute is valid version, use the attribute value as is (so "1.0000.01.01" would *not* get translated to "1.0.1.1"). | ||
11780 | var verifiedVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
11781 | if (!String.IsNullOrEmpty(verifiedVersion)) | ||
11782 | { | ||
11783 | version = attrib.Value; | ||
11784 | } | ||
11785 | break; | ||
11786 | default: | ||
11787 | this.Core.UnexpectedAttribute(node, attrib); | ||
11788 | break; | ||
11789 | } | ||
11790 | } | ||
11791 | else | ||
11792 | { | ||
11793 | this.Core.ParseExtensionAttribute(node, attrib); | ||
11794 | } | ||
11795 | } | ||
11796 | |||
11797 | if (null == productCode) | ||
11798 | { | ||
11799 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
11800 | } | ||
11801 | |||
11802 | if (null == this.activeLanguage) | ||
11803 | { | ||
11804 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
11805 | } | ||
11806 | |||
11807 | if (null == manufacturer) | ||
11808 | { | ||
11809 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
11810 | } | ||
11811 | |||
11812 | if (null == this.activeName) | ||
11813 | { | ||
11814 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
11815 | } | ||
11816 | |||
11817 | if (null == upgradeCode) | ||
11818 | { | ||
11819 | this.Core.Write(WarningMessages.MissingUpgradeCode(sourceLineNumbers)); | ||
11820 | } | ||
11821 | |||
11822 | if (null == version) | ||
11823 | { | ||
11824 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
11825 | } | ||
11826 | else if (!CompilerCore.IsValidProductVersion(version)) | ||
11827 | { | ||
11828 | this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version)); | ||
11829 | } | ||
11830 | |||
11831 | if (this.Core.EncounteredError) | ||
11832 | { | ||
11833 | return; | ||
11834 | } | ||
11835 | |||
11836 | try | ||
11837 | { | ||
11838 | this.compilingProduct = true; | ||
11839 | this.Core.CreateActiveSection(productCode, SectionType.Product, codepage, this.Context.CompilationId); | ||
11840 | |||
11841 | this.AddProperty(sourceLineNumbers, new Identifier("Manufacturer", AccessModifier.Public), manufacturer, false, false, false, true); | ||
11842 | this.AddProperty(sourceLineNumbers, new Identifier("ProductCode", AccessModifier.Public), productCode, false, false, false, true); | ||
11843 | this.AddProperty(sourceLineNumbers, new Identifier("ProductLanguage", AccessModifier.Public), this.activeLanguage, false, false, false, true); | ||
11844 | this.AddProperty(sourceLineNumbers, new Identifier("ProductName", AccessModifier.Public), this.activeName, false, false, false, true); | ||
11845 | this.AddProperty(sourceLineNumbers, new Identifier("ProductVersion", AccessModifier.Public), version, false, false, false, true); | ||
11846 | if (null != upgradeCode) | ||
11847 | { | ||
11848 | this.AddProperty(sourceLineNumbers, new Identifier("UpgradeCode", AccessModifier.Public), upgradeCode, false, false, false, true); | ||
11849 | } | ||
11850 | |||
11851 | var contextValues = new Dictionary<string, string> | ||
11852 | { | ||
11853 | ["ProductLanguage"] = this.activeLanguage, | ||
11854 | ["ProductVersion"] = version, | ||
11855 | ["UpgradeCode"] = upgradeCode | ||
11856 | }; | ||
11857 | |||
11858 | var featureDisplay = 0; | ||
11859 | foreach (var child in node.Elements()) | ||
11860 | { | ||
11861 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
11862 | { | ||
11863 | switch (child.Name.LocalName) | ||
11864 | { | ||
11865 | case "_locDefinition": | ||
11866 | break; | ||
11867 | case "AdminExecuteSequence": | ||
11868 | case "AdminUISequence": | ||
11869 | case "AdvertiseExecuteSequence": | ||
11870 | case "InstallExecuteSequence": | ||
11871 | case "InstallUISequence": | ||
11872 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
11873 | break; | ||
11874 | case "AppId": | ||
11875 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
11876 | break; | ||
11877 | case "Binary": | ||
11878 | this.ParseBinaryElement(child); | ||
11879 | break; | ||
11880 | case "ComplianceCheck": | ||
11881 | this.ParseComplianceCheckElement(child); | ||
11882 | break; | ||
11883 | case "Component": | ||
11884 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null); | ||
11885 | break; | ||
11886 | case "ComponentGroup": | ||
11887 | this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, null); | ||
11888 | break; | ||
11889 | case "Condition": | ||
11890 | this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
11891 | break; | ||
11892 | case "CustomAction": | ||
11893 | this.ParseCustomActionElement(child); | ||
11894 | break; | ||
11895 | case "CustomActionRef": | ||
11896 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
11897 | break; | ||
11898 | case "CustomTable": | ||
11899 | this.ParseCustomTableElement(child); | ||
11900 | break; | ||
11901 | case "Directory": | ||
11902 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
11903 | break; | ||
11904 | case "DirectoryRef": | ||
11905 | this.ParseDirectoryRefElement(child); | ||
11906 | break; | ||
11907 | case "EmbeddedChainer": | ||
11908 | this.ParseEmbeddedChainerElement(child); | ||
11909 | break; | ||
11910 | case "EmbeddedChainerRef": | ||
11911 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
11912 | break; | ||
11913 | case "EnsureTable": | ||
11914 | this.ParseEnsureTableElement(child); | ||
11915 | break; | ||
11916 | case "Feature": | ||
11917 | this.ParseFeatureElement(child, ComplexReferenceParentType.Product, productCode, ref featureDisplay); | ||
11918 | break; | ||
11919 | case "FeatureRef": | ||
11920 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
11921 | break; | ||
11922 | case "FeatureGroupRef": | ||
11923 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
11924 | break; | ||
11925 | case "Icon": | ||
11926 | this.ParseIconElement(child); | ||
11927 | break; | ||
11928 | case "InstanceTransforms": | ||
11929 | this.ParseInstanceTransformsElement(child); | ||
11930 | break; | ||
11931 | case "MajorUpgrade": | ||
11932 | this.ParseMajorUpgradeElement(child, contextValues); | ||
11933 | break; | ||
11934 | case "Media": | ||
11935 | this.ParseMediaElement(child, null); | ||
11936 | break; | ||
11937 | case "MediaTemplate": | ||
11938 | this.ParseMediaTemplateElement(child, null); | ||
11939 | break; | ||
11940 | case "Package": | ||
11941 | this.ParsePackageElement(child, manufacturer, null); | ||
11942 | break; | ||
11943 | case "PackageCertificates": | ||
11944 | case "PatchCertificates": | ||
11945 | this.ParseCertificatesElement(child); | ||
11946 | break; | ||
11947 | case "Property": | ||
11948 | this.ParsePropertyElement(child); | ||
11949 | break; | ||
11950 | case "PropertyRef": | ||
11951 | this.ParseSimpleRefElement(child, "Property"); | ||
11952 | break; | ||
11953 | case "SetDirectory": | ||
11954 | this.ParseSetDirectoryElement(child); | ||
11955 | break; | ||
11956 | case "SetProperty": | ||
11957 | this.ParseSetPropertyElement(child); | ||
11958 | break; | ||
11959 | case "SFPCatalog": | ||
11960 | string parentName = null; | ||
11961 | this.ParseSFPCatalogElement(child, ref parentName); | ||
11962 | break; | ||
11963 | case "SymbolPath": | ||
11964 | if (null != symbols) | ||
11965 | { | ||
11966 | symbols += ";" + this.ParseSymbolPathElement(child); | ||
11967 | } | ||
11968 | else | ||
11969 | { | ||
11970 | symbols = this.ParseSymbolPathElement(child); | ||
11971 | } | ||
11972 | break; | ||
11973 | case "UI": | ||
11974 | this.ParseUIElement(child); | ||
11975 | break; | ||
11976 | case "UIRef": | ||
11977 | this.ParseSimpleRefElement(child, "WixUI"); | ||
11978 | break; | ||
11979 | case "Upgrade": | ||
11980 | this.ParseUpgradeElement(child); | ||
11981 | break; | ||
11982 | case "WixVariable": | ||
11983 | this.ParseWixVariableElement(child); | ||
11984 | break; | ||
11985 | default: | ||
11986 | this.Core.UnexpectedElement(node, child); | ||
11987 | break; | ||
11988 | } | ||
11989 | } | ||
11990 | else | ||
11991 | { | ||
11992 | this.Core.ParseExtensionElement(node, child); | ||
11993 | } | ||
11994 | } | ||
11995 | |||
11996 | if (!this.Core.EncounteredError) | ||
11997 | { | ||
11998 | if (null != symbols) | ||
11999 | { | ||
12000 | var symbolRow = (WixDeltaPatchSymbolPathsTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixDeltaPatchSymbolPaths); | ||
12001 | symbolRow.Id = productCode; | ||
12002 | symbolRow.Type = SymbolPathType.Product; | ||
12003 | symbolRow.SymbolPaths = symbols; | ||
12004 | } | ||
12005 | } | ||
12006 | } | ||
12007 | finally | ||
12008 | { | ||
12009 | this.compilingProduct = false; | ||
12010 | } | ||
12011 | } | ||
12012 | |||
12013 | /// <summary> | ||
12014 | /// Parses a progid element | ||
12015 | /// </summary> | ||
12016 | /// <param name="node">Element to parse.</param> | ||
12017 | /// <param name="componentId">Identifier of parent component.</param> | ||
12018 | /// <param name="advertise">Flag if progid is advertised.</param> | ||
12019 | /// <param name="classId">CLSID related to ProgId.</param> | ||
12020 | /// <param name="description">Default description of ProgId</param> | ||
12021 | /// <param name="parent">Optional parent ProgId</param> | ||
12022 | /// <param name="foundExtension">Set to true if an extension is found; used for error-checking.</param> | ||
12023 | /// <param name="firstProgIdForClass">Whether or not this ProgId is the first one found in the parent class.</param> | ||
12024 | /// <returns>This element's Id.</returns> | ||
12025 | private string ParseProgIdElement(XElement node, string componentId, YesNoType advertise, string classId, string description, string parent, ref bool foundExtension, YesNoType firstProgIdForClass) | ||
12026 | { | ||
12027 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12028 | string icon = null; | ||
12029 | var iconIndex = CompilerConstants.IntegerNotSet; | ||
12030 | string noOpen = null; | ||
12031 | string progId = null; | ||
12032 | var progIdAdvertise = YesNoType.NotSet; | ||
12033 | |||
12034 | foreach (var attrib in node.Attributes()) | ||
12035 | { | ||
12036 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12037 | { | ||
12038 | switch (attrib.Name.LocalName) | ||
12039 | { | ||
12040 | case "Id": | ||
12041 | progId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12042 | break; | ||
12043 | case "Advertise": | ||
12044 | progIdAdvertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12045 | break; | ||
12046 | case "Description": | ||
12047 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
12048 | break; | ||
12049 | case "Icon": | ||
12050 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
12051 | break; | ||
12052 | case "IconIndex": | ||
12053 | iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue); | ||
12054 | break; | ||
12055 | case "NoOpen": | ||
12056 | noOpen = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
12057 | break; | ||
12058 | default: | ||
12059 | this.Core.UnexpectedAttribute(node, attrib); | ||
12060 | break; | ||
12061 | } | ||
12062 | } | ||
12063 | else | ||
12064 | { | ||
12065 | this.Core.ParseExtensionAttribute(node, attrib); | ||
12066 | } | ||
12067 | } | ||
12068 | |||
12069 | if ((YesNoType.No == advertise && YesNoType.Yes == progIdAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == progIdAdvertise)) | ||
12070 | { | ||
12071 | this.Core.Write(ErrorMessages.AdvertiseStateMustMatch(sourceLineNumbers, advertise.ToString(), progIdAdvertise.ToString())); | ||
12072 | } | ||
12073 | else | ||
12074 | { | ||
12075 | advertise = progIdAdvertise; | ||
12076 | } | ||
12077 | |||
12078 | if (YesNoType.NotSet == advertise) | ||
12079 | { | ||
12080 | advertise = YesNoType.No; | ||
12081 | } | ||
12082 | |||
12083 | if (null != parent && (null != icon || CompilerConstants.IntegerNotSet != iconIndex)) | ||
12084 | { | ||
12085 | this.Core.Write(ErrorMessages.VersionIndependentProgIdsCannotHaveIcons(sourceLineNumbers)); | ||
12086 | } | ||
12087 | |||
12088 | var firstProgIdForNestedClass = YesNoType.Yes; | ||
12089 | foreach (var child in node.Elements()) | ||
12090 | { | ||
12091 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12092 | { | ||
12093 | switch (child.Name.LocalName) | ||
12094 | { | ||
12095 | case "Extension": | ||
12096 | this.ParseExtensionElement(child, componentId, advertise, progId); | ||
12097 | foundExtension = true; | ||
12098 | break; | ||
12099 | case "ProgId": | ||
12100 | // Only allow one nested ProgId. If we have a child, we should not have a parent. | ||
12101 | if (null == parent) | ||
12102 | { | ||
12103 | if (YesNoType.Yes == advertise) | ||
12104 | { | ||
12105 | this.ParseProgIdElement(child, componentId, advertise, null, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
12106 | } | ||
12107 | else if (YesNoType.No == advertise) | ||
12108 | { | ||
12109 | this.ParseProgIdElement(child, componentId, advertise, classId, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
12110 | } | ||
12111 | |||
12112 | firstProgIdForNestedClass = YesNoType.No; // any ProgId after this one is definitely not the first. | ||
12113 | } | ||
12114 | else | ||
12115 | { | ||
12116 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
12117 | this.Core.Write(ErrorMessages.ProgIdNestedTooDeep(childSourceLineNumbers)); | ||
12118 | } | ||
12119 | break; | ||
12120 | default: | ||
12121 | this.Core.UnexpectedElement(node, child); | ||
12122 | break; | ||
12123 | } | ||
12124 | } | ||
12125 | else | ||
12126 | { | ||
12127 | this.Core.ParseExtensionElement(node, child); | ||
12128 | } | ||
12129 | } | ||
12130 | |||
12131 | if (YesNoType.Yes == advertise) | ||
12132 | { | ||
12133 | if (!this.Core.EncounteredError) | ||
12134 | { | ||
12135 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ProgId); | ||
12136 | row.Set(0, progId); | ||
12137 | row.Set(1, parent); | ||
12138 | row.Set(2, classId); | ||
12139 | row.Set(3, description); | ||
12140 | if (null != icon) | ||
12141 | { | ||
12142 | row.Set(4, icon); | ||
12143 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
12144 | } | ||
12145 | |||
12146 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
12147 | { | ||
12148 | row.Set(5, iconIndex); | ||
12149 | } | ||
12150 | |||
12151 | this.Core.EnsureTable(sourceLineNumbers, "Class"); | ||
12152 | } | ||
12153 | } | ||
12154 | else if (YesNoType.No == advertise) | ||
12155 | { | ||
12156 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, progId, String.Empty, description, componentId); | ||
12157 | if (null != classId) | ||
12158 | { | ||
12159 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(progId, "\\CLSID"), String.Empty, classId, componentId); | ||
12160 | if (null != parent) // if this is a version independent ProgId | ||
12161 | { | ||
12162 | if (YesNoType.Yes == firstProgIdForClass) | ||
12163 | { | ||
12164 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\VersionIndependentProgID"), String.Empty, progId, componentId); | ||
12165 | } | ||
12166 | |||
12167 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(progId, "\\CurVer"), String.Empty, parent, componentId); | ||
12168 | } | ||
12169 | else | ||
12170 | { | ||
12171 | if (YesNoType.Yes == firstProgIdForClass) | ||
12172 | { | ||
12173 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\ProgID"), String.Empty, progId, componentId); | ||
12174 | } | ||
12175 | } | ||
12176 | } | ||
12177 | |||
12178 | if (null != icon) // ProgId's Default Icon | ||
12179 | { | ||
12180 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", icon); | ||
12181 | |||
12182 | icon = String.Format(CultureInfo.InvariantCulture, "\"[#{0}]\"", icon); | ||
12183 | |||
12184 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
12185 | { | ||
12186 | icon = String.Concat(icon, ",", iconIndex); | ||
12187 | } | ||
12188 | |||
12189 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(progId, "\\DefaultIcon"), String.Empty, icon, componentId); | ||
12190 | } | ||
12191 | } | ||
12192 | |||
12193 | if (null != noOpen) | ||
12194 | { | ||
12195 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, progId, "NoOpen", noOpen, componentId); // ProgId NoOpen name | ||
12196 | } | ||
12197 | |||
12198 | // raise an error for an orphaned ProgId | ||
12199 | if (YesNoType.Yes == advertise && !foundExtension && null == parent && null == classId) | ||
12200 | { | ||
12201 | this.Core.Write(WarningMessages.OrphanedProgId(sourceLineNumbers, progId)); | ||
12202 | } | ||
12203 | |||
12204 | return progId; | ||
12205 | } | ||
12206 | |||
12207 | /// <summary> | ||
12208 | /// Parses a property element. | ||
12209 | /// </summary> | ||
12210 | /// <param name="node">Element to parse.</param> | ||
12211 | private void ParsePropertyElement(XElement node) | ||
12212 | { | ||
12213 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12214 | Identifier id = null; | ||
12215 | var admin = false; | ||
12216 | var complianceCheck = false; | ||
12217 | var hidden = false; | ||
12218 | var secure = false; | ||
12219 | var suppressModularization = YesNoType.NotSet; | ||
12220 | string value = null; | ||
12221 | |||
12222 | foreach (var attrib in node.Attributes()) | ||
12223 | { | ||
12224 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12225 | { | ||
12226 | switch (attrib.Name.LocalName) | ||
12227 | { | ||
12228 | case "Id": | ||
12229 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12230 | break; | ||
12231 | case "Admin": | ||
12232 | admin = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12233 | break; | ||
12234 | case "ComplianceCheck": | ||
12235 | complianceCheck = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12236 | break; | ||
12237 | case "Hidden": | ||
12238 | hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12239 | break; | ||
12240 | case "Secure": | ||
12241 | secure = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12242 | break; | ||
12243 | case "SuppressModularization": | ||
12244 | suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12245 | break; | ||
12246 | case "Value": | ||
12247 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12248 | break; | ||
12249 | default: | ||
12250 | this.Core.UnexpectedAttribute(node, attrib); | ||
12251 | break; | ||
12252 | } | ||
12253 | } | ||
12254 | else | ||
12255 | { | ||
12256 | this.Core.ParseExtensionAttribute(node, attrib); | ||
12257 | } | ||
12258 | } | ||
12259 | |||
12260 | if (null == id) | ||
12261 | { | ||
12262 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
12263 | id = Identifier.Invalid; | ||
12264 | } | ||
12265 | else if ("ProductID" == id.Id) | ||
12266 | { | ||
12267 | this.Core.Write(WarningMessages.ProductIdAuthored(sourceLineNumbers)); | ||
12268 | } | ||
12269 | else if ("SecureCustomProperties" == id.Id || "AdminProperties" == id.Id || "MsiHiddenProperties" == id.Id) | ||
12270 | { | ||
12271 | this.Core.Write(ErrorMessages.CannotAuthorSpecialProperties(sourceLineNumbers, id.Id)); | ||
12272 | } | ||
12273 | |||
12274 | var innerText = this.Core.GetTrimmedInnerText(node); | ||
12275 | if (null != value) | ||
12276 | { | ||
12277 | // cannot specify both the value attribute and inner text | ||
12278 | if (!String.IsNullOrEmpty(innerText)) | ||
12279 | { | ||
12280 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
12281 | } | ||
12282 | } | ||
12283 | else // value attribute not specified, use inner text if any. | ||
12284 | { | ||
12285 | value = innerText; | ||
12286 | } | ||
12287 | |||
12288 | if ("ErrorDialog" == id.Id) | ||
12289 | { | ||
12290 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", value); | ||
12291 | } | ||
12292 | |||
12293 | foreach (var child in node.Elements()) | ||
12294 | { | ||
12295 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12296 | { | ||
12297 | { | ||
12298 | switch (child.Name.LocalName) | ||
12299 | { | ||
12300 | case "ProductSearch": | ||
12301 | this.ParseProductSearchElement(child, id.Id); | ||
12302 | secure = true; | ||
12303 | break; | ||
12304 | default: | ||
12305 | // let ParseSearchSignatures handle standard AppSearch children and unknown elements | ||
12306 | break; | ||
12307 | } | ||
12308 | } | ||
12309 | } | ||
12310 | } | ||
12311 | |||
12312 | // see if this property is used for appSearch | ||
12313 | var signatures = this.ParseSearchSignatures(node); | ||
12314 | |||
12315 | // If we're doing CCP then there must be a signature. | ||
12316 | if (complianceCheck && 0 == signatures.Count) | ||
12317 | { | ||
12318 | this.Core.Write(ErrorMessages.SearchElementRequiredWithAttribute(sourceLineNumbers, node.Name.LocalName, "ComplianceCheck", "yes")); | ||
12319 | } | ||
12320 | |||
12321 | foreach (var sig in signatures) | ||
12322 | { | ||
12323 | if (complianceCheck && !this.Core.EncounteredError) | ||
12324 | { | ||
12325 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CCPSearch, new Identifier(sig, AccessModifier.Private)); | ||
12326 | } | ||
12327 | |||
12328 | this.AddAppSearch(sourceLineNumbers, id, sig); | ||
12329 | } | ||
12330 | |||
12331 | // If we're doing AppSearch get that setup. | ||
12332 | if (0 < signatures.Count) | ||
12333 | { | ||
12334 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
12335 | } | ||
12336 | else // just a normal old property. | ||
12337 | { | ||
12338 | // If the property value is empty and none of the flags are set, print out a warning that we're ignoring | ||
12339 | // the element. | ||
12340 | if (String.IsNullOrEmpty(value) && !admin && !secure && !hidden) | ||
12341 | { | ||
12342 | this.Core.Write(WarningMessages.PropertyUseless(sourceLineNumbers, id.Id)); | ||
12343 | } | ||
12344 | else // there is a value and/or a flag set, do that. | ||
12345 | { | ||
12346 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
12347 | } | ||
12348 | } | ||
12349 | |||
12350 | if (!this.Core.EncounteredError && YesNoType.Yes == suppressModularization) | ||
12351 | { | ||
12352 | this.Core.Write(WarningMessages.PropertyModularizationSuppressed(sourceLineNumbers)); | ||
12353 | |||
12354 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSuppressModularization, id); | ||
12355 | } | ||
12356 | } | ||
12357 | |||
12358 | /// <summary> | ||
12359 | /// Parses a RegistryKey element. | ||
12360 | /// </summary> | ||
12361 | /// <param name="node">Element to parse.</param> | ||
12362 | /// <param name="componentId">Identifier for parent component.</param> | ||
12363 | /// <param name="root">Root specified when element is nested under another Registry element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
12364 | /// <param name="parentKey">Parent key for this Registry element when nested.</param> | ||
12365 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
12366 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
12367 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
12368 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12369 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12370 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12371 | private YesNoType ParseRegistryKeyElement(XElement node, string componentId, int root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
12372 | { | ||
12373 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12374 | Identifier id = null; | ||
12375 | var key = parentKey; // default to parent key path | ||
12376 | string action = null; | ||
12377 | var forceCreateOnInstall = false; | ||
12378 | var forceDeleteOnUninstall = false; | ||
12379 | var actionType = Wix.RegistryKey.ActionType.NotSet; | ||
12380 | var keyPath = YesNoType.NotSet; | ||
12381 | |||
12382 | possibleKeyPath = null; | ||
12383 | |||
12384 | foreach (var attrib in node.Attributes()) | ||
12385 | { | ||
12386 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12387 | { | ||
12388 | switch (attrib.Name.LocalName) | ||
12389 | { | ||
12390 | case "Id": | ||
12391 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12392 | break; | ||
12393 | case "Action": | ||
12394 | this.Core.Write(WarningMessages.DeprecatedRegistryKeyActionAttribute(sourceLineNumbers)); | ||
12395 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12396 | if (0 < action.Length) | ||
12397 | { | ||
12398 | actionType = Wix.RegistryKey.ParseActionType(action); | ||
12399 | switch (actionType) | ||
12400 | { | ||
12401 | case Wix.RegistryKey.ActionType.create: | ||
12402 | forceCreateOnInstall = true; | ||
12403 | break; | ||
12404 | case Wix.RegistryKey.ActionType.createAndRemoveOnUninstall: | ||
12405 | forceCreateOnInstall = true; | ||
12406 | forceDeleteOnUninstall = true; | ||
12407 | break; | ||
12408 | case Wix.RegistryKey.ActionType.none: | ||
12409 | break; | ||
12410 | default: | ||
12411 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "create", "createAndRemoveOnUninstall", "none")); | ||
12412 | break; | ||
12413 | } | ||
12414 | } | ||
12415 | break; | ||
12416 | case "ForceCreateOnInstall": | ||
12417 | forceCreateOnInstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12418 | break; | ||
12419 | case "ForceDeleteOnUninstall": | ||
12420 | forceDeleteOnUninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12421 | break; | ||
12422 | case "Key": | ||
12423 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12424 | if (null != parentKey) | ||
12425 | { | ||
12426 | key = Path.Combine(parentKey, key); | ||
12427 | } | ||
12428 | break; | ||
12429 | case "Root": | ||
12430 | if (CompilerConstants.IntegerNotSet != root) | ||
12431 | { | ||
12432 | this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers)); | ||
12433 | } | ||
12434 | |||
12435 | root = this.Core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12436 | break; | ||
12437 | default: | ||
12438 | this.Core.UnexpectedAttribute(node, attrib); | ||
12439 | break; | ||
12440 | } | ||
12441 | } | ||
12442 | else | ||
12443 | { | ||
12444 | this.Core.ParseExtensionAttribute(node, attrib); | ||
12445 | } | ||
12446 | } | ||
12447 | |||
12448 | var name = forceCreateOnInstall ? (forceDeleteOnUninstall ? "*" : "+") : (forceDeleteOnUninstall ? "-" : null); | ||
12449 | |||
12450 | if (forceCreateOnInstall || forceDeleteOnUninstall) // generates a Registry row, so an Id must be present | ||
12451 | { | ||
12452 | // generate the identifier if it wasn't provided | ||
12453 | if (null == id) | ||
12454 | { | ||
12455 | id = this.Core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12456 | } | ||
12457 | } | ||
12458 | else // does not generate a Registry row, so no Id should be present | ||
12459 | { | ||
12460 | if (null != id) | ||
12461 | { | ||
12462 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Id", "ForceCreateOnInstall", "ForceDeleteOnUninstall", "yes", true)); | ||
12463 | } | ||
12464 | } | ||
12465 | |||
12466 | if (CompilerConstants.IntegerNotSet == root) | ||
12467 | { | ||
12468 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12469 | root = CompilerConstants.IllegalInteger; | ||
12470 | } | ||
12471 | |||
12472 | if (null == key) | ||
12473 | { | ||
12474 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12475 | key = String.Empty; // set the key to something to prevent null reference exceptions | ||
12476 | } | ||
12477 | |||
12478 | foreach (var child in node.Elements()) | ||
12479 | { | ||
12480 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12481 | { | ||
12482 | string possibleChildKeyPath = null; | ||
12483 | |||
12484 | switch (child.Name.LocalName) | ||
12485 | { | ||
12486 | case "RegistryKey": | ||
12487 | if (YesNoType.Yes == this.ParseRegistryKeyElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
12488 | { | ||
12489 | if (YesNoType.Yes == keyPath) | ||
12490 | { | ||
12491 | this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
12492 | } | ||
12493 | |||
12494 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
12495 | keyPath = YesNoType.Yes; | ||
12496 | } | ||
12497 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
12498 | { | ||
12499 | possibleKeyPath = possibleChildKeyPath; | ||
12500 | } | ||
12501 | break; | ||
12502 | case "RegistryValue": | ||
12503 | if (YesNoType.Yes == this.ParseRegistryValueElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
12504 | { | ||
12505 | if (YesNoType.Yes == keyPath) | ||
12506 | { | ||
12507 | this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
12508 | } | ||
12509 | |||
12510 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
12511 | keyPath = YesNoType.Yes; | ||
12512 | } | ||
12513 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
12514 | { | ||
12515 | possibleKeyPath = possibleChildKeyPath; | ||
12516 | } | ||
12517 | break; | ||
12518 | case "Permission": | ||
12519 | if (!forceCreateOnInstall) | ||
12520 | { | ||
12521 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
12522 | } | ||
12523 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
12524 | break; | ||
12525 | case "PermissionEx": | ||
12526 | if (!forceCreateOnInstall) | ||
12527 | { | ||
12528 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
12529 | } | ||
12530 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
12531 | break; | ||
12532 | default: | ||
12533 | this.Core.UnexpectedElement(node, child); | ||
12534 | break; | ||
12535 | } | ||
12536 | } | ||
12537 | else | ||
12538 | { | ||
12539 | var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
12540 | this.Core.ParseExtensionElement(node, child, context); | ||
12541 | } | ||
12542 | } | ||
12543 | |||
12544 | |||
12545 | if (!this.Core.EncounteredError && null != name) | ||
12546 | { | ||
12547 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Registry, id); | ||
12548 | row.Set(1, root); | ||
12549 | row.Set(2, key); | ||
12550 | row.Set(3, name); | ||
12551 | //row.Set(4, null); | ||
12552 | row.Set(5, componentId); | ||
12553 | } | ||
12554 | |||
12555 | return keyPath; | ||
12556 | } | ||
12557 | |||
12558 | /// <summary> | ||
12559 | /// Parses a RegistryValue element. | ||
12560 | /// </summary> | ||
12561 | /// <param name="node">Element to parse.</param> | ||
12562 | /// <param name="componentId">Identifier for parent component.</param> | ||
12563 | /// <param name="root">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
12564 | /// <param name="parentKey">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
12565 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
12566 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
12567 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
12568 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12569 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12570 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12571 | private YesNoType ParseRegistryValueElement(XElement node, string componentId, int root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
12572 | { | ||
12573 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12574 | Identifier id = null; | ||
12575 | var key = parentKey; // default to parent key path | ||
12576 | string name = null; | ||
12577 | string value = null; | ||
12578 | string type = null; | ||
12579 | var typeType = Wix.RegistryValue.TypeType.NotSet; | ||
12580 | string action = null; | ||
12581 | var actionType = Wix.RegistryValue.ActionType.NotSet; | ||
12582 | var keyPath = YesNoType.NotSet; | ||
12583 | var couldBeKeyPath = true; // assume that this is a regular registry key that could become the key path | ||
12584 | |||
12585 | possibleKeyPath = null; | ||
12586 | |||
12587 | foreach (var attrib in node.Attributes()) | ||
12588 | { | ||
12589 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12590 | { | ||
12591 | switch (attrib.Name.LocalName) | ||
12592 | { | ||
12593 | case "Id": | ||
12594 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12595 | break; | ||
12596 | case "Action": | ||
12597 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12598 | if (0 < action.Length) | ||
12599 | { | ||
12600 | if (!Wix.RegistryValue.TryParseActionType(action, out actionType)) | ||
12601 | { | ||
12602 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "append", "prepend", "write")); | ||
12603 | } | ||
12604 | } | ||
12605 | break; | ||
12606 | case "Key": | ||
12607 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12608 | if (null != parentKey) | ||
12609 | { | ||
12610 | if (parentKey.EndsWith("\\", StringComparison.Ordinal)) | ||
12611 | { | ||
12612 | key = String.Concat(parentKey, key); | ||
12613 | } | ||
12614 | else | ||
12615 | { | ||
12616 | key = String.Concat(parentKey, "\\", key); | ||
12617 | } | ||
12618 | } | ||
12619 | break; | ||
12620 | case "KeyPath": | ||
12621 | keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12622 | break; | ||
12623 | case "Name": | ||
12624 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12625 | break; | ||
12626 | case "Root": | ||
12627 | if (CompilerConstants.IntegerNotSet != root) | ||
12628 | { | ||
12629 | this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers)); | ||
12630 | } | ||
12631 | |||
12632 | root = this.Core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12633 | break; | ||
12634 | case "Type": | ||
12635 | type = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12636 | if (0 < type.Length) | ||
12637 | { | ||
12638 | if (!Wix.RegistryValue.TryParseTypeType(type, out typeType)) | ||
12639 | { | ||
12640 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, type, "binary", "expandable", "integer", "multiString", "string")); | ||
12641 | } | ||
12642 | } | ||
12643 | break; | ||
12644 | case "Value": | ||
12645 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
12646 | break; | ||
12647 | default: | ||
12648 | this.Core.UnexpectedAttribute(node, attrib); | ||
12649 | break; | ||
12650 | } | ||
12651 | } | ||
12652 | else | ||
12653 | { | ||
12654 | this.Core.ParseExtensionAttribute(node, attrib); | ||
12655 | } | ||
12656 | } | ||
12657 | |||
12658 | // generate the identifier if it wasn't provided | ||
12659 | if (null == id) | ||
12660 | { | ||
12661 | id = this.Core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12662 | } | ||
12663 | |||
12664 | if ((Wix.RegistryValue.ActionType.append == actionType || Wix.RegistryValue.ActionType.prepend == actionType) && | ||
12665 | Wix.RegistryValue.TypeType.multiString != typeType) | ||
12666 | { | ||
12667 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Action", action, "Type", "multiString")); | ||
12668 | } | ||
12669 | |||
12670 | if (null == key) | ||
12671 | { | ||
12672 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12673 | } | ||
12674 | |||
12675 | if (CompilerConstants.IntegerNotSet == root) | ||
12676 | { | ||
12677 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12678 | } | ||
12679 | |||
12680 | if (null == type) | ||
12681 | { | ||
12682 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type")); | ||
12683 | } | ||
12684 | |||
12685 | foreach (var child in node.Elements()) | ||
12686 | { | ||
12687 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12688 | { | ||
12689 | switch (child.Name.LocalName) | ||
12690 | { | ||
12691 | case "MultiStringValue": | ||
12692 | if (Wix.RegistryValue.TypeType.multiString != typeType && null != value) | ||
12693 | { | ||
12694 | this.Core.Write(ErrorMessages.RegistryMultipleValuesWithoutMultiString(sourceLineNumbers, node.Name.LocalName, "Value", child.Name.LocalName, "Type")); | ||
12695 | } | ||
12696 | else if (null == value) | ||
12697 | { | ||
12698 | value = Common.GetInnerText(child); | ||
12699 | } | ||
12700 | else | ||
12701 | { | ||
12702 | value = String.Concat(value, "[~]", Common.GetInnerText(child)); | ||
12703 | } | ||
12704 | break; | ||
12705 | case "Permission": | ||
12706 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
12707 | break; | ||
12708 | case "PermissionEx": | ||
12709 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
12710 | break; | ||
12711 | default: | ||
12712 | this.Core.UnexpectedElement(node, child); | ||
12713 | break; | ||
12714 | } | ||
12715 | } | ||
12716 | else | ||
12717 | { | ||
12718 | var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
12719 | this.Core.ParseExtensionElement(node, child, context); | ||
12720 | } | ||
12721 | } | ||
12722 | |||
12723 | |||
12724 | switch (typeType) | ||
12725 | { | ||
12726 | case Wix.RegistryValue.TypeType.binary: | ||
12727 | value = String.Concat("#x", value); | ||
12728 | break; | ||
12729 | case Wix.RegistryValue.TypeType.expandable: | ||
12730 | value = String.Concat("#%", value); | ||
12731 | break; | ||
12732 | case Wix.RegistryValue.TypeType.integer: | ||
12733 | value = String.Concat("#", value); | ||
12734 | break; | ||
12735 | case Wix.RegistryValue.TypeType.multiString: | ||
12736 | switch (actionType) | ||
12737 | { | ||
12738 | case Wix.RegistryValue.ActionType.append: | ||
12739 | value = String.Concat("[~]", value); | ||
12740 | break; | ||
12741 | case Wix.RegistryValue.ActionType.prepend: | ||
12742 | value = String.Concat(value, "[~]"); | ||
12743 | break; | ||
12744 | case Wix.RegistryValue.ActionType.write: | ||
12745 | default: | ||
12746 | if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) | ||
12747 | { | ||
12748 | value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value); | ||
12749 | } | ||
12750 | break; | ||
12751 | } | ||
12752 | break; | ||
12753 | case Wix.RegistryValue.TypeType.@string: | ||
12754 | // escape the leading '#' character for string registry keys | ||
12755 | if (null != value && value.StartsWith("#", StringComparison.Ordinal)) | ||
12756 | { | ||
12757 | value = String.Concat("#", value); | ||
12758 | } | ||
12759 | break; | ||
12760 | } | ||
12761 | |||
12762 | // value may be set by child MultiStringValue elements, so it must be checked here | ||
12763 | if (null == value) | ||
12764 | { | ||
12765 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
12766 | } | ||
12767 | else if (0 == value.Length && ("+" == name || "-" == name || "*" == name)) // prevent accidental authoring of special name values | ||
12768 | { | ||
12769 | this.Core.Write(ErrorMessages.RegistryNameValueIncorrect(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
12770 | } | ||
12771 | |||
12772 | if (!this.Core.EncounteredError) | ||
12773 | { | ||
12774 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Registry, id); | ||
12775 | row.Set(1, root); | ||
12776 | row.Set(2, key); | ||
12777 | row.Set(3, name); | ||
12778 | row.Set(4, value); | ||
12779 | row.Set(5, componentId); | ||
12780 | } | ||
12781 | |||
12782 | // If this was just a regular registry key (that could be the key path) | ||
12783 | // and no child registry key set the possible key path, let's make this | ||
12784 | // Registry/@Id a possible key path. | ||
12785 | if (couldBeKeyPath && null == possibleKeyPath) | ||
12786 | { | ||
12787 | possibleKeyPath = id.Id; | ||
12788 | } | ||
12789 | |||
12790 | return keyPath; | ||
12791 | } | ||
12792 | |||
12793 | /// <summary> | ||
12794 | /// Parses a RemoveRegistryKey element. | ||
12795 | /// </summary> | ||
12796 | /// <param name="node">The element to parse.</param> | ||
12797 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
12798 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12799 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12800 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12801 | private void ParseRemoveRegistryKeyElement(XElement node, string componentId) | ||
12802 | { | ||
12803 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12804 | Identifier id = null; | ||
12805 | string action = null; | ||
12806 | var actionType = Wix.RemoveRegistryKey.ActionType.NotSet; | ||
12807 | string key = null; | ||
12808 | var name = "-"; | ||
12809 | var root = CompilerConstants.IntegerNotSet; | ||
12810 | |||
12811 | foreach (var attrib in node.Attributes()) | ||
12812 | { | ||
12813 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12814 | { | ||
12815 | switch (attrib.Name.LocalName) | ||
12816 | { | ||
12817 | case "Id": | ||
12818 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12819 | break; | ||
12820 | case "Action": | ||
12821 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12822 | if (0 < action.Length) | ||
12823 | { | ||
12824 | if (!Wix.RemoveRegistryKey.TryParseActionType(action, out actionType)) | ||
12825 | { | ||
12826 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "removeOnInstall", "removeOnUninstall")); | ||
12827 | } | ||
12828 | } | ||
12829 | break; | ||
12830 | case "Key": | ||
12831 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12832 | break; | ||
12833 | case "Root": | ||
12834 | root = this.Core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12835 | break; | ||
12836 | default: | ||
12837 | this.Core.UnexpectedAttribute(node, attrib); | ||
12838 | break; | ||
12839 | } | ||
12840 | } | ||
12841 | else | ||
12842 | { | ||
12843 | this.Core.ParseExtensionAttribute(node, attrib); | ||
12844 | } | ||
12845 | } | ||
12846 | |||
12847 | // generate the identifier if it wasn't provided | ||
12848 | if (null == id) | ||
12849 | { | ||
12850 | id = this.Core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12851 | } | ||
12852 | |||
12853 | if (null == action) | ||
12854 | { | ||
12855 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
12856 | } | ||
12857 | |||
12858 | if (null == key) | ||
12859 | { | ||
12860 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12861 | } | ||
12862 | |||
12863 | if (CompilerConstants.IntegerNotSet == root) | ||
12864 | { | ||
12865 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12866 | } | ||
12867 | |||
12868 | this.Core.ParseForExtensionElements(node); | ||
12869 | |||
12870 | if (!this.Core.EncounteredError) | ||
12871 | { | ||
12872 | var row = this.Core.CreateRow(sourceLineNumbers, (Wix.RemoveRegistryKey.ActionType.removeOnUninstall == actionType ? TupleDefinitionType.Registry : TupleDefinitionType.RemoveRegistry), id); | ||
12873 | row.Set(1, root); | ||
12874 | row.Set(2, key); | ||
12875 | row.Set(3, name); | ||
12876 | if (Wix.RemoveRegistryKey.ActionType.removeOnUninstall == actionType) // Registry table | ||
12877 | { | ||
12878 | //row.Set(4, null); | ||
12879 | row.Set(5, componentId); | ||
12880 | } | ||
12881 | else // RemoveRegistry table | ||
12882 | { | ||
12883 | row.Set(4, componentId); | ||
12884 | } | ||
12885 | } | ||
12886 | } | ||
12887 | |||
12888 | /// <summary> | ||
12889 | /// Parses a RemoveRegistryValue element. | ||
12890 | /// </summary> | ||
12891 | /// <param name="node">The element to parse.</param> | ||
12892 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
12893 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12894 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12895 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12896 | private void ParseRemoveRegistryValueElement(XElement node, string componentId) | ||
12897 | { | ||
12898 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12899 | Identifier id = null; | ||
12900 | string key = null; | ||
12901 | string name = null; | ||
12902 | var root = CompilerConstants.IntegerNotSet; | ||
12903 | |||
12904 | foreach (var attrib in node.Attributes()) | ||
12905 | { | ||
12906 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12907 | { | ||
12908 | switch (attrib.Name.LocalName) | ||
12909 | { | ||
12910 | case "Id": | ||
12911 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12912 | break; | ||
12913 | case "Key": | ||
12914 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12915 | break; | ||
12916 | case "Name": | ||
12917 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12918 | break; | ||
12919 | case "Root": | ||
12920 | root = this.Core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12921 | break; | ||
12922 | default: | ||
12923 | this.Core.UnexpectedAttribute(node, attrib); | ||
12924 | break; | ||
12925 | } | ||
12926 | } | ||
12927 | else | ||
12928 | { | ||
12929 | this.Core.ParseExtensionAttribute(node, attrib); | ||
12930 | } | ||
12931 | } | ||
12932 | |||
12933 | // generate the identifier if it wasn't provided | ||
12934 | if (null == id) | ||
12935 | { | ||
12936 | id = this.Core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12937 | } | ||
12938 | |||
12939 | if (null == key) | ||
12940 | { | ||
12941 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12942 | } | ||
12943 | |||
12944 | if (CompilerConstants.IntegerNotSet == root) | ||
12945 | { | ||
12946 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12947 | } | ||
12948 | |||
12949 | this.Core.ParseForExtensionElements(node); | ||
12950 | |||
12951 | if (!this.Core.EncounteredError) | ||
12952 | { | ||
12953 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveRegistry, id); | ||
12954 | row.Set(1, root); | ||
12955 | row.Set(2, key); | ||
12956 | row.Set(3, name); | ||
12957 | row.Set(4, componentId); | ||
12958 | } | ||
12959 | } | ||
12960 | |||
12961 | /// <summary> | ||
12962 | /// Parses a remove file element. | ||
12963 | /// </summary> | ||
12964 | /// <param name="node">Element to parse.</param> | ||
12965 | /// <param name="componentId">Identifier of parent component.</param> | ||
12966 | /// <param name="parentDirectory">Identifier of the parent component's directory.</param> | ||
12967 | private void ParseRemoveFileElement(XElement node, string componentId, string parentDirectory) | ||
12968 | { | ||
12969 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12970 | Identifier id = null; | ||
12971 | string directory = null; | ||
12972 | string name = null; | ||
12973 | var on = CompilerConstants.IntegerNotSet; | ||
12974 | string property = null; | ||
12975 | string shortName = null; | ||
12976 | |||
12977 | foreach (var attrib in node.Attributes()) | ||
12978 | { | ||
12979 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12980 | { | ||
12981 | switch (attrib.Name.LocalName) | ||
12982 | { | ||
12983 | case "Id": | ||
12984 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12985 | break; | ||
12986 | case "Directory": | ||
12987 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
12988 | break; | ||
12989 | case "Name": | ||
12990 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true); | ||
12991 | break; | ||
12992 | case "On": | ||
12993 | var onValue = this.Core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
12994 | switch (onValue) | ||
12995 | { | ||
12996 | case Wix.InstallUninstallType.install: | ||
12997 | on = 1; | ||
12998 | break; | ||
12999 | case Wix.InstallUninstallType.uninstall: | ||
13000 | on = 2; | ||
13001 | break; | ||
13002 | case Wix.InstallUninstallType.both: | ||
13003 | on = 3; | ||
13004 | break; | ||
13005 | default: | ||
13006 | on = CompilerConstants.IllegalInteger; | ||
13007 | break; | ||
13008 | } | ||
13009 | break; | ||
13010 | case "Property": | ||
13011 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
13012 | break; | ||
13013 | case "ShortName": | ||
13014 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true); | ||
13015 | break; | ||
13016 | default: | ||
13017 | this.Core.UnexpectedAttribute(node, attrib); | ||
13018 | break; | ||
13019 | } | ||
13020 | } | ||
13021 | else | ||
13022 | { | ||
13023 | this.Core.ParseExtensionAttribute(node, attrib); | ||
13024 | } | ||
13025 | } | ||
13026 | |||
13027 | if (null == name) | ||
13028 | { | ||
13029 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
13030 | } | ||
13031 | else if (0 < name.Length) | ||
13032 | { | ||
13033 | if (this.Core.IsValidShortFilename(name, true)) | ||
13034 | { | ||
13035 | if (null == shortName) | ||
13036 | { | ||
13037 | shortName = name; | ||
13038 | name = null; | ||
13039 | } | ||
13040 | else | ||
13041 | { | ||
13042 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
13043 | } | ||
13044 | } | ||
13045 | else if (null == shortName) // generate a short file name. | ||
13046 | { | ||
13047 | shortName = this.Core.CreateShortName(name, true, true, node.Name.LocalName, componentId); | ||
13048 | } | ||
13049 | } | ||
13050 | |||
13051 | if (CompilerConstants.IntegerNotSet == on) | ||
13052 | { | ||
13053 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
13054 | on = CompilerConstants.IllegalInteger; | ||
13055 | } | ||
13056 | |||
13057 | if (null != directory && null != property) | ||
13058 | { | ||
13059 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
13060 | } | ||
13061 | |||
13062 | if (null == id) | ||
13063 | { | ||
13064 | id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); | ||
13065 | } | ||
13066 | |||
13067 | this.Core.ParseForExtensionElements(node); | ||
13068 | |||
13069 | if (!this.Core.EncounteredError) | ||
13070 | { | ||
13071 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id); | ||
13072 | row.Set(1, componentId); | ||
13073 | row.Set(2, this.GetMsiFilenameValue(shortName, name)); | ||
13074 | if (null != directory) | ||
13075 | { | ||
13076 | row.Set(3, directory); | ||
13077 | } | ||
13078 | else if (null != property) | ||
13079 | { | ||
13080 | row.Set(3, property); | ||
13081 | } | ||
13082 | else | ||
13083 | { | ||
13084 | row.Set(3, parentDirectory); | ||
13085 | } | ||
13086 | row.Set(4, on); | ||
13087 | } | ||
13088 | } | ||
13089 | |||
13090 | /// <summary> | ||
13091 | /// Parses a RemoveFolder element. | ||
13092 | /// </summary> | ||
13093 | /// <param name="node">Element to parse.</param> | ||
13094 | /// <param name="componentId">Identifier of parent component.</param> | ||
13095 | /// <param name="parentDirectory">Identifier of parent component's directory.</param> | ||
13096 | private void ParseRemoveFolderElement(XElement node, string componentId, string parentDirectory) | ||
13097 | { | ||
13098 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13099 | Identifier id = null; | ||
13100 | string directory = null; | ||
13101 | var on = CompilerConstants.IntegerNotSet; | ||
13102 | string property = null; | ||
13103 | |||
13104 | foreach (var attrib in node.Attributes()) | ||
13105 | { | ||
13106 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13107 | { | ||
13108 | switch (attrib.Name.LocalName) | ||
13109 | { | ||
13110 | case "Id": | ||
13111 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13112 | break; | ||
13113 | case "Directory": | ||
13114 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
13115 | break; | ||
13116 | case "On": | ||
13117 | var onValue = this.Core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
13118 | switch (onValue) | ||
13119 | { | ||
13120 | case Wix.InstallUninstallType.install: | ||
13121 | on = 1; | ||
13122 | break; | ||
13123 | case Wix.InstallUninstallType.uninstall: | ||
13124 | on = 2; | ||
13125 | break; | ||
13126 | case Wix.InstallUninstallType.both: | ||
13127 | on = 3; | ||
13128 | break; | ||
13129 | default: | ||
13130 | on = CompilerConstants.IllegalInteger; | ||
13131 | break; | ||
13132 | } | ||
13133 | break; | ||
13134 | case "Property": | ||
13135 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13136 | break; | ||
13137 | default: | ||
13138 | this.Core.UnexpectedAttribute(node, attrib); | ||
13139 | break; | ||
13140 | } | ||
13141 | } | ||
13142 | else | ||
13143 | { | ||
13144 | this.Core.ParseExtensionAttribute(node, attrib); | ||
13145 | } | ||
13146 | } | ||
13147 | |||
13148 | if (CompilerConstants.IntegerNotSet == on) | ||
13149 | { | ||
13150 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
13151 | on = CompilerConstants.IllegalInteger; | ||
13152 | } | ||
13153 | |||
13154 | if (null != directory && null != property) | ||
13155 | { | ||
13156 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
13157 | } | ||
13158 | |||
13159 | if (null == id) | ||
13160 | { | ||
13161 | id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString()); | ||
13162 | } | ||
13163 | |||
13164 | this.Core.ParseForExtensionElements(node); | ||
13165 | |||
13166 | if (!this.Core.EncounteredError) | ||
13167 | { | ||
13168 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id); | ||
13169 | row.Set(1, componentId); | ||
13170 | //row.Set(2, null); | ||
13171 | if (null != directory) | ||
13172 | { | ||
13173 | row.Set(3, directory); | ||
13174 | } | ||
13175 | else if (null != property) | ||
13176 | { | ||
13177 | row.Set(3, property); | ||
13178 | } | ||
13179 | else | ||
13180 | { | ||
13181 | row.Set(3, parentDirectory); | ||
13182 | } | ||
13183 | row.Set(4, on); | ||
13184 | } | ||
13185 | } | ||
13186 | |||
13187 | /// <summary> | ||
13188 | /// Parses a reserve cost element. | ||
13189 | /// </summary> | ||
13190 | /// <param name="node">Element to parse.</param> | ||
13191 | /// <param name="componentId">Identifier of parent component.</param> | ||
13192 | /// <param name="directoryId">Optional and default identifier of referenced directory.</param> | ||
13193 | private void ParseReserveCostElement(XElement node, string componentId, string directoryId) | ||
13194 | { | ||
13195 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13196 | Identifier id = null; | ||
13197 | var runFromSource = CompilerConstants.IntegerNotSet; | ||
13198 | var runLocal = CompilerConstants.IntegerNotSet; | ||
13199 | |||
13200 | foreach (var attrib in node.Attributes()) | ||
13201 | { | ||
13202 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13203 | { | ||
13204 | switch (attrib.Name.LocalName) | ||
13205 | { | ||
13206 | case "Id": | ||
13207 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13208 | break; | ||
13209 | case "Directory": | ||
13210 | directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | ||
13211 | break; | ||
13212 | case "RunFromSource": | ||
13213 | runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
13214 | break; | ||
13215 | case "RunLocal": | ||
13216 | runLocal = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
13217 | break; | ||
13218 | default: | ||
13219 | this.Core.UnexpectedAttribute(node, attrib); | ||
13220 | break; | ||
13221 | } | ||
13222 | } | ||
13223 | else | ||
13224 | { | ||
13225 | this.Core.ParseExtensionAttribute(node, attrib); | ||
13226 | } | ||
13227 | } | ||
13228 | |||
13229 | if (null == id) | ||
13230 | { | ||
13231 | id = this.Core.CreateIdentifier("rc", componentId, directoryId); | ||
13232 | } | ||
13233 | |||
13234 | if (CompilerConstants.IntegerNotSet == runFromSource) | ||
13235 | { | ||
13236 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunFromSource")); | ||
13237 | } | ||
13238 | |||
13239 | if (CompilerConstants.IntegerNotSet == runLocal) | ||
13240 | { | ||
13241 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunLocal")); | ||
13242 | } | ||
13243 | |||
13244 | this.Core.ParseForExtensionElements(node); | ||
13245 | |||
13246 | if (!this.Core.EncounteredError) | ||
13247 | { | ||
13248 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ReserveCost, id); | ||
13249 | row.Set(1, componentId); | ||
13250 | row.Set(2, directoryId); | ||
13251 | row.Set(3, runLocal); | ||
13252 | row.Set(4, runFromSource); | ||
13253 | } | ||
13254 | } | ||
13255 | |||
13256 | /// <summary> | ||
13257 | /// Parses a sequence element. | ||
13258 | /// </summary> | ||
13259 | /// <param name="node">Element to parse.</param> | ||
13260 | /// <param name="sequenceTable">Name of sequence table.</param> | ||
13261 | private void ParseSequenceElement(XElement node, string sequenceTable) | ||
13262 | { | ||
13263 | // use the proper table name internally | ||
13264 | if ("AdvertiseExecuteSequence" == sequenceTable) | ||
13265 | { | ||
13266 | sequenceTable = "AdvtExecuteSequence"; | ||
13267 | } | ||
13268 | |||
13269 | // Parse each action in the sequence. | ||
13270 | foreach (var child in node.Elements()) | ||
13271 | { | ||
13272 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
13273 | var actionName = child.Name.LocalName; | ||
13274 | string afterAction = null; | ||
13275 | string beforeAction = null; | ||
13276 | string condition = null; | ||
13277 | var customAction = "Custom" == actionName; | ||
13278 | var overridable = false; | ||
13279 | var exitSequence = CompilerConstants.IntegerNotSet; | ||
13280 | var sequence = CompilerConstants.IntegerNotSet; | ||
13281 | var showDialog = "Show" == actionName; | ||
13282 | var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName; | ||
13283 | var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName; | ||
13284 | var suppress = false; | ||
13285 | |||
13286 | foreach (var attrib in child.Attributes()) | ||
13287 | { | ||
13288 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13289 | { | ||
13290 | switch (attrib.Name.LocalName) | ||
13291 | { | ||
13292 | case "Action": | ||
13293 | if (customAction) | ||
13294 | { | ||
13295 | actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13296 | this.Core.CreateSimpleReference(childSourceLineNumbers, "CustomAction", actionName); | ||
13297 | } | ||
13298 | else | ||
13299 | { | ||
13300 | this.Core.UnexpectedAttribute(child, attrib); | ||
13301 | } | ||
13302 | break; | ||
13303 | case "After": | ||
13304 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
13305 | { | ||
13306 | afterAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13307 | this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, afterAction); | ||
13308 | } | ||
13309 | else | ||
13310 | { | ||
13311 | this.Core.UnexpectedAttribute(child, attrib); | ||
13312 | } | ||
13313 | break; | ||
13314 | case "Before": | ||
13315 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
13316 | { | ||
13317 | beforeAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13318 | this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, beforeAction); | ||
13319 | } | ||
13320 | else | ||
13321 | { | ||
13322 | this.Core.UnexpectedAttribute(child, attrib); | ||
13323 | } | ||
13324 | break; | ||
13325 | case "Dialog": | ||
13326 | if (showDialog) | ||
13327 | { | ||
13328 | actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13329 | this.Core.CreateSimpleReference(childSourceLineNumbers, "Dialog", actionName); | ||
13330 | } | ||
13331 | else | ||
13332 | { | ||
13333 | this.Core.UnexpectedAttribute(child, attrib); | ||
13334 | } | ||
13335 | break; | ||
13336 | case "OnExit": | ||
13337 | if (customAction || showDialog || specialAction) | ||
13338 | { | ||
13339 | var exitValue = this.Core.GetAttributeExitValue(childSourceLineNumbers, attrib); | ||
13340 | switch (exitValue) | ||
13341 | { | ||
13342 | case Wix.ExitType.success: | ||
13343 | exitSequence = -1; | ||
13344 | break; | ||
13345 | case Wix.ExitType.cancel: | ||
13346 | exitSequence = -2; | ||
13347 | break; | ||
13348 | case Wix.ExitType.error: | ||
13349 | exitSequence = -3; | ||
13350 | break; | ||
13351 | case Wix.ExitType.suspend: | ||
13352 | exitSequence = -4; | ||
13353 | break; | ||
13354 | } | ||
13355 | } | ||
13356 | else | ||
13357 | { | ||
13358 | this.Core.UnexpectedAttribute(child, attrib); | ||
13359 | } | ||
13360 | break; | ||
13361 | case "Overridable": | ||
13362 | overridable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
13363 | break; | ||
13364 | case "Sequence": | ||
13365 | sequence = this.Core.GetAttributeIntegerValue(childSourceLineNumbers, attrib, 1, Int16.MaxValue); | ||
13366 | break; | ||
13367 | case "Suppress": | ||
13368 | suppress = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
13369 | break; | ||
13370 | default: | ||
13371 | this.Core.UnexpectedAttribute(node, attrib); | ||
13372 | break; | ||
13373 | } | ||
13374 | } | ||
13375 | else | ||
13376 | { | ||
13377 | this.Core.ParseExtensionAttribute(node, attrib); | ||
13378 | } | ||
13379 | } | ||
13380 | |||
13381 | |||
13382 | // Get the condition from the inner text of the element. | ||
13383 | condition = this.Core.GetConditionInnerText(child); | ||
13384 | |||
13385 | if (customAction && "Custom" == actionName) | ||
13386 | { | ||
13387 | this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action")); | ||
13388 | } | ||
13389 | else if (showDialog && "Show" == actionName) | ||
13390 | { | ||
13391 | this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Dialog")); | ||
13392 | } | ||
13393 | |||
13394 | if (CompilerConstants.IntegerNotSet != sequence) | ||
13395 | { | ||
13396 | if (CompilerConstants.IntegerNotSet != exitSequence) | ||
13397 | { | ||
13398 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "OnExit")); | ||
13399 | } | ||
13400 | else if (null != beforeAction || null != afterAction) | ||
13401 | { | ||
13402 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "Before", "After")); | ||
13403 | } | ||
13404 | } | ||
13405 | else // sequence not specified use OnExit (which may also be not set). | ||
13406 | { | ||
13407 | sequence = exitSequence; | ||
13408 | } | ||
13409 | |||
13410 | if (null != beforeAction && null != afterAction) | ||
13411 | { | ||
13412 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "After", "Before")); | ||
13413 | } | ||
13414 | else if ((customAction || showDialog || specialAction) && !suppress && CompilerConstants.IntegerNotSet == sequence && null == beforeAction && null == afterAction) | ||
13415 | { | ||
13416 | this.Core.Write(ErrorMessages.NeedSequenceBeforeOrAfter(childSourceLineNumbers, child.Name.LocalName)); | ||
13417 | } | ||
13418 | |||
13419 | // action that is scheduled to occur before/after itself | ||
13420 | if (beforeAction == actionName) | ||
13421 | { | ||
13422 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "Before", beforeAction)); | ||
13423 | } | ||
13424 | else if (afterAction == actionName) | ||
13425 | { | ||
13426 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "After", afterAction)); | ||
13427 | } | ||
13428 | |||
13429 | // normal standard actions cannot be set overridable by the user (since they are overridable by default) | ||
13430 | if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction) | ||
13431 | { | ||
13432 | this.Core.Write(ErrorMessages.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable")); | ||
13433 | } | ||
13434 | |||
13435 | // suppress cannot be specified at the same time as Before, After, or Sequence | ||
13436 | if (suppress && (null != afterAction || null != beforeAction || CompilerConstants.IntegerNotSet != sequence || overridable)) | ||
13437 | { | ||
13438 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(childSourceLineNumbers, child.Name.LocalName, "Suppress", "Before", "After", "Sequence", "Overridable")); | ||
13439 | } | ||
13440 | |||
13441 | this.Core.ParseForExtensionElements(child); | ||
13442 | |||
13443 | // add the row and any references needed | ||
13444 | if (!this.Core.EncounteredError) | ||
13445 | { | ||
13446 | if (suppress) | ||
13447 | { | ||
13448 | var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixSuppressAction, new Identifier(AccessModifier.Public, sequenceTable, actionName)); | ||
13449 | row.Set(0, sequenceTable); | ||
13450 | row.Set(1, actionName); | ||
13451 | } | ||
13452 | else | ||
13453 | { | ||
13454 | var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixAction, new Identifier(AccessModifier.Public, sequenceTable, actionName)); | ||
13455 | row.Set(0, sequenceTable); | ||
13456 | row.Set(1, actionName); | ||
13457 | row.Set(2, condition); | ||
13458 | if (CompilerConstants.IntegerNotSet != sequence) | ||
13459 | { | ||
13460 | row.Set(3, sequence); | ||
13461 | } | ||
13462 | row.Set(4, beforeAction); | ||
13463 | row.Set(5, afterAction); | ||
13464 | row.Set(6, overridable ? 1 : 0); | ||
13465 | } | ||
13466 | } | ||
13467 | } | ||
13468 | } | ||
13469 | |||
13470 | |||
13471 | /// <summary> | ||
13472 | /// Parses a service config element. | ||
13473 | /// </summary> | ||
13474 | /// <param name="node">Element to parse.</param> | ||
13475 | /// <param name="componentId">Identifier of parent component.</param> | ||
13476 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
13477 | private void ParseServiceConfigElement(XElement node, string componentId, string serviceName) | ||
13478 | { | ||
13479 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13480 | Identifier id = null; | ||
13481 | string delayedAutoStart = null; | ||
13482 | string failureActionsWhen = null; | ||
13483 | var events = 0; | ||
13484 | var name = serviceName; | ||
13485 | string preShutdownDelay = null; | ||
13486 | string requiredPrivileges = null; | ||
13487 | string sid = null; | ||
13488 | |||
13489 | this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
13490 | |||
13491 | foreach (var attrib in node.Attributes()) | ||
13492 | { | ||
13493 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13494 | { | ||
13495 | switch (attrib.Name.LocalName) | ||
13496 | { | ||
13497 | case "Id": | ||
13498 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13499 | break; | ||
13500 | case "DelayedAutoStart": | ||
13501 | delayedAutoStart = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13502 | if (0 < delayedAutoStart.Length) | ||
13503 | { | ||
13504 | switch (delayedAutoStart) | ||
13505 | { | ||
13506 | case "no": | ||
13507 | delayedAutoStart = "0"; | ||
13508 | break; | ||
13509 | case "yes": | ||
13510 | delayedAutoStart = "1"; | ||
13511 | break; | ||
13512 | default: | ||
13513 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13514 | break; | ||
13515 | } | ||
13516 | } | ||
13517 | break; | ||
13518 | case "FailureActionsWhen": | ||
13519 | failureActionsWhen = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13520 | if (0 < failureActionsWhen.Length) | ||
13521 | { | ||
13522 | switch (failureActionsWhen) | ||
13523 | { | ||
13524 | case "failedToStop": | ||
13525 | failureActionsWhen = "0"; | ||
13526 | break; | ||
13527 | case "failedToStopOrReturnedError": | ||
13528 | failureActionsWhen = "1"; | ||
13529 | break; | ||
13530 | default: | ||
13531 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13532 | break; | ||
13533 | } | ||
13534 | } | ||
13535 | break; | ||
13536 | case "OnInstall": | ||
13537 | var install = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13538 | if (YesNoType.Yes == install) | ||
13539 | { | ||
13540 | events |= MsiInterop.MsidbServiceConfigEventInstall; | ||
13541 | } | ||
13542 | break; | ||
13543 | case "OnReinstall": | ||
13544 | var reinstall = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13545 | if (YesNoType.Yes == reinstall) | ||
13546 | { | ||
13547 | events |= MsiInterop.MsidbServiceConfigEventReinstall; | ||
13548 | } | ||
13549 | break; | ||
13550 | case "OnUninstall": | ||
13551 | var uninstall = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13552 | if (YesNoType.Yes == uninstall) | ||
13553 | { | ||
13554 | events |= MsiInterop.MsidbServiceConfigEventUninstall; | ||
13555 | } | ||
13556 | break; | ||
13557 | default: | ||
13558 | this.Core.UnexpectedAttribute(node, attrib); | ||
13559 | break; | ||
13560 | case "PreShutdownDelay": | ||
13561 | preShutdownDelay = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
13562 | break; | ||
13563 | case "ServiceName": | ||
13564 | if (!String.IsNullOrEmpty(serviceName)) | ||
13565 | { | ||
13566 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
13567 | } | ||
13568 | |||
13569 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13570 | break; | ||
13571 | case "ServiceSid": | ||
13572 | sid = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13573 | if (0 < sid.Length) | ||
13574 | { | ||
13575 | switch (sid) | ||
13576 | { | ||
13577 | case "none": | ||
13578 | sid = "0"; | ||
13579 | break; | ||
13580 | case "restricted": | ||
13581 | sid = "3"; | ||
13582 | break; | ||
13583 | case "unrestricted": | ||
13584 | sid = "1"; | ||
13585 | break; | ||
13586 | default: | ||
13587 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13588 | break; | ||
13589 | } | ||
13590 | } | ||
13591 | break; | ||
13592 | } | ||
13593 | } | ||
13594 | else | ||
13595 | { | ||
13596 | this.Core.ParseExtensionAttribute(node, attrib); | ||
13597 | } | ||
13598 | } | ||
13599 | |||
13600 | // Get the ServiceConfig required privilegs. | ||
13601 | foreach (var child in node.Elements()) | ||
13602 | { | ||
13603 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
13604 | { | ||
13605 | switch (child.Name.LocalName) | ||
13606 | { | ||
13607 | case "RequiredPrivilege": | ||
13608 | var privilege = this.Core.GetTrimmedInnerText(child); | ||
13609 | switch (privilege) | ||
13610 | { | ||
13611 | case "assignPrimaryToken": | ||
13612 | privilege = "SeAssignPrimaryTokenPrivilege"; | ||
13613 | break; | ||
13614 | case "audit": | ||
13615 | privilege = "SeAuditPrivilege"; | ||
13616 | break; | ||
13617 | case "backup": | ||
13618 | privilege = "SeBackupPrivilege"; | ||
13619 | break; | ||
13620 | case "changeNotify": | ||
13621 | privilege = "SeChangeNotifyPrivilege"; | ||
13622 | break; | ||
13623 | case "createGlobal": | ||
13624 | privilege = "SeCreateGlobalPrivilege"; | ||
13625 | break; | ||
13626 | case "createPagefile": | ||
13627 | privilege = "SeCreatePagefilePrivilege"; | ||
13628 | break; | ||
13629 | case "createPermanent": | ||
13630 | privilege = "SeCreatePermanentPrivilege"; | ||
13631 | break; | ||
13632 | case "createSymbolicLink": | ||
13633 | privilege = "SeCreateSymbolicLinkPrivilege"; | ||
13634 | break; | ||
13635 | case "createToken": | ||
13636 | privilege = "SeCreateTokenPrivilege"; | ||
13637 | break; | ||
13638 | case "debug": | ||
13639 | privilege = "SeDebugPrivilege"; | ||
13640 | break; | ||
13641 | case "enableDelegation": | ||
13642 | privilege = "SeEnableDelegationPrivilege"; | ||
13643 | break; | ||
13644 | case "impersonate": | ||
13645 | privilege = "SeImpersonatePrivilege"; | ||
13646 | break; | ||
13647 | case "increaseBasePriority": | ||
13648 | privilege = "SeIncreaseBasePriorityPrivilege"; | ||
13649 | break; | ||
13650 | case "increaseQuota": | ||
13651 | privilege = "SeIncreaseQuotaPrivilege"; | ||
13652 | break; | ||
13653 | case "increaseWorkingSet": | ||
13654 | privilege = "SeIncreaseWorkingSetPrivilege"; | ||
13655 | break; | ||
13656 | case "loadDriver": | ||
13657 | privilege = "SeLoadDriverPrivilege"; | ||
13658 | break; | ||
13659 | case "lockMemory": | ||
13660 | privilege = "SeLockMemoryPrivilege"; | ||
13661 | break; | ||
13662 | case "machineAccount": | ||
13663 | privilege = "SeMachineAccountPrivilege"; | ||
13664 | break; | ||
13665 | case "manageVolume": | ||
13666 | privilege = "SeManageVolumePrivilege"; | ||
13667 | break; | ||
13668 | case "profileSingleProcess": | ||
13669 | privilege = "SeProfileSingleProcessPrivilege"; | ||
13670 | break; | ||
13671 | case "relabel": | ||
13672 | privilege = "SeRelabelPrivilege"; | ||
13673 | break; | ||
13674 | case "remoteShutdown": | ||
13675 | privilege = "SeRemoteShutdownPrivilege"; | ||
13676 | break; | ||
13677 | case "restore": | ||
13678 | privilege = "SeRestorePrivilege"; | ||
13679 | break; | ||
13680 | case "security": | ||
13681 | privilege = "SeSecurityPrivilege"; | ||
13682 | break; | ||
13683 | case "shutdown": | ||
13684 | privilege = "SeShutdownPrivilege"; | ||
13685 | break; | ||
13686 | case "syncAgent": | ||
13687 | privilege = "SeSyncAgentPrivilege"; | ||
13688 | break; | ||
13689 | case "systemEnvironment": | ||
13690 | privilege = "SeSystemEnvironmentPrivilege"; | ||
13691 | break; | ||
13692 | case "systemProfile": | ||
13693 | privilege = "SeSystemProfilePrivilege"; | ||
13694 | break; | ||
13695 | case "systemTime": | ||
13696 | case "modifySystemTime": | ||
13697 | privilege = "SeSystemtimePrivilege"; | ||
13698 | break; | ||
13699 | case "takeOwnership": | ||
13700 | privilege = "SeTakeOwnershipPrivilege"; | ||
13701 | break; | ||
13702 | case "tcb": | ||
13703 | case "trustedComputerBase": | ||
13704 | privilege = "SeTcbPrivilege"; | ||
13705 | break; | ||
13706 | case "timeZone": | ||
13707 | case "modifyTimeZone": | ||
13708 | privilege = "SeTimeZonePrivilege"; | ||
13709 | break; | ||
13710 | case "trustedCredManAccess": | ||
13711 | case "trustedCredentialManagerAccess": | ||
13712 | privilege = "SeTrustedCredManAccessPrivilege"; | ||
13713 | break; | ||
13714 | case "undock": | ||
13715 | privilege = "SeUndockPrivilege"; | ||
13716 | break; | ||
13717 | case "unsolicitedInput": | ||
13718 | privilege = "SeUnsolicitedInputPrivilege"; | ||
13719 | break; | ||
13720 | default: | ||
13721 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13722 | break; | ||
13723 | } | ||
13724 | |||
13725 | if (null != requiredPrivileges) | ||
13726 | { | ||
13727 | requiredPrivileges = String.Concat(requiredPrivileges, "[~]"); | ||
13728 | } | ||
13729 | requiredPrivileges = String.Concat(requiredPrivileges, privilege); | ||
13730 | break; | ||
13731 | default: | ||
13732 | this.Core.UnexpectedElement(node, child); | ||
13733 | break; | ||
13734 | } | ||
13735 | } | ||
13736 | else | ||
13737 | { | ||
13738 | this.Core.ParseExtensionElement(node, child); | ||
13739 | } | ||
13740 | } | ||
13741 | |||
13742 | if (String.IsNullOrEmpty(name)) | ||
13743 | { | ||
13744 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
13745 | } | ||
13746 | else if (null == id) | ||
13747 | { | ||
13748 | id = this.Core.CreateIdentifierFromFilename(name); | ||
13749 | } | ||
13750 | |||
13751 | if (0 == events) | ||
13752 | { | ||
13753 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
13754 | } | ||
13755 | |||
13756 | if (String.IsNullOrEmpty(delayedAutoStart) && String.IsNullOrEmpty(failureActionsWhen) && String.IsNullOrEmpty(preShutdownDelay) && String.IsNullOrEmpty(requiredPrivileges) && String.IsNullOrEmpty(sid)) | ||
13757 | { | ||
13758 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DelayedAutoStart", "FailureActionsWhen", "PreShutdownDelay", "ServiceSid", "RequiredPrivilege")); | ||
13759 | } | ||
13760 | |||
13761 | if (!this.Core.EncounteredError) | ||
13762 | { | ||
13763 | if (!String.IsNullOrEmpty(delayedAutoStart)) | ||
13764 | { | ||
13765 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".DS"), id.Access)); | ||
13766 | row.Set(1, name); | ||
13767 | row.Set(2, events); | ||
13768 | row.Set(3, 3); | ||
13769 | row.Set(4, delayedAutoStart); | ||
13770 | row.Set(5, componentId); | ||
13771 | } | ||
13772 | |||
13773 | if (!String.IsNullOrEmpty(failureActionsWhen)) | ||
13774 | { | ||
13775 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".FA"), id.Access)); | ||
13776 | row.Set(1, name); | ||
13777 | row.Set(2, events); | ||
13778 | row.Set(3, 4); | ||
13779 | row.Set(4, failureActionsWhen); | ||
13780 | row.Set(5, componentId); | ||
13781 | } | ||
13782 | |||
13783 | if (!String.IsNullOrEmpty(sid)) | ||
13784 | { | ||
13785 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".SS"), id.Access)); | ||
13786 | row.Set(1, name); | ||
13787 | row.Set(2, events); | ||
13788 | row.Set(3, 5); | ||
13789 | row.Set(4, sid); | ||
13790 | row.Set(5, componentId); | ||
13791 | } | ||
13792 | |||
13793 | if (!String.IsNullOrEmpty(requiredPrivileges)) | ||
13794 | { | ||
13795 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".RP"), id.Access)); | ||
13796 | row.Set(1, name); | ||
13797 | row.Set(2, events); | ||
13798 | row.Set(3, 6); | ||
13799 | row.Set(4, requiredPrivileges); | ||
13800 | row.Set(5, componentId); | ||
13801 | } | ||
13802 | |||
13803 | if (!String.IsNullOrEmpty(preShutdownDelay)) | ||
13804 | { | ||
13805 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".PD"), id.Access)); | ||
13806 | row.Set(1, name); | ||
13807 | row.Set(2, events); | ||
13808 | row.Set(3, 7); | ||
13809 | row.Set(4, preShutdownDelay); | ||
13810 | row.Set(5, componentId); | ||
13811 | } | ||
13812 | } | ||
13813 | } | ||
13814 | |||
13815 | /// <summary> | ||
13816 | /// Parses a service config failure actions element. | ||
13817 | /// </summary> | ||
13818 | /// <param name="node">Element to parse.</param> | ||
13819 | /// <param name="componentId">Identifier of parent component.</param> | ||
13820 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
13821 | private void ParseServiceConfigFailureActionsElement(XElement node, string componentId, string serviceName) | ||
13822 | { | ||
13823 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13824 | Identifier id = null; | ||
13825 | var events = 0; | ||
13826 | var name = serviceName; | ||
13827 | var resetPeriod = CompilerConstants.IntegerNotSet; | ||
13828 | string rebootMessage = null; | ||
13829 | string command = null; | ||
13830 | string actions = null; | ||
13831 | string actionsDelays = null; | ||
13832 | |||
13833 | this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
13834 | |||
13835 | foreach (var attrib in node.Attributes()) | ||
13836 | { | ||
13837 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13838 | { | ||
13839 | switch (attrib.Name.LocalName) | ||
13840 | { | ||
13841 | case "Id": | ||
13842 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13843 | break; | ||
13844 | case "Command": | ||
13845 | command = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
13846 | break; | ||
13847 | case "OnInstall": | ||
13848 | var install = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13849 | if (YesNoType.Yes == install) | ||
13850 | { | ||
13851 | events |= MsiInterop.MsidbServiceConfigEventInstall; | ||
13852 | } | ||
13853 | break; | ||
13854 | case "OnReinstall": | ||
13855 | var reinstall = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13856 | if (YesNoType.Yes == reinstall) | ||
13857 | { | ||
13858 | events |= MsiInterop.MsidbServiceConfigEventReinstall; | ||
13859 | } | ||
13860 | break; | ||
13861 | case "OnUninstall": | ||
13862 | var uninstall = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13863 | if (YesNoType.Yes == uninstall) | ||
13864 | { | ||
13865 | events |= MsiInterop.MsidbServiceConfigEventUninstall; | ||
13866 | } | ||
13867 | break; | ||
13868 | case "RebootMessage": | ||
13869 | rebootMessage = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
13870 | break; | ||
13871 | case "ResetPeriod": | ||
13872 | resetPeriod = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
13873 | break; | ||
13874 | case "ServiceName": | ||
13875 | if (!String.IsNullOrEmpty(serviceName)) | ||
13876 | { | ||
13877 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
13878 | } | ||
13879 | |||
13880 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13881 | break; | ||
13882 | default: | ||
13883 | this.Core.UnexpectedAttribute(node, attrib); | ||
13884 | break; | ||
13885 | } | ||
13886 | } | ||
13887 | else | ||
13888 | { | ||
13889 | this.Core.ParseExtensionAttribute(node, attrib); | ||
13890 | } | ||
13891 | } | ||
13892 | |||
13893 | // Get the ServiceConfigFailureActions actions. | ||
13894 | foreach (var child in node.Elements()) | ||
13895 | { | ||
13896 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
13897 | { | ||
13898 | switch (child.Name.LocalName) | ||
13899 | { | ||
13900 | case "Failure": | ||
13901 | string action = null; | ||
13902 | string delay = null; | ||
13903 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
13904 | |||
13905 | foreach (var childAttrib in child.Attributes()) | ||
13906 | { | ||
13907 | if (String.IsNullOrEmpty(childAttrib.Name.NamespaceName) || CompilerCore.WixNamespace == childAttrib.Name.Namespace) | ||
13908 | { | ||
13909 | switch (childAttrib.Name.LocalName) | ||
13910 | { | ||
13911 | case "Action": | ||
13912 | action = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
13913 | switch (action) | ||
13914 | { | ||
13915 | case "none": | ||
13916 | action = "0"; | ||
13917 | break; | ||
13918 | case "restartComputer": | ||
13919 | action = "2"; | ||
13920 | break; | ||
13921 | case "restartService": | ||
13922 | action = "1"; | ||
13923 | break; | ||
13924 | case "runCommand": | ||
13925 | action = "3"; | ||
13926 | break; | ||
13927 | default: | ||
13928 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13929 | break; | ||
13930 | } | ||
13931 | break; | ||
13932 | case "Delay": | ||
13933 | delay = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
13934 | break; | ||
13935 | default: | ||
13936 | this.Core.UnexpectedAttribute(child, childAttrib); | ||
13937 | break; | ||
13938 | } | ||
13939 | } | ||
13940 | } | ||
13941 | |||
13942 | if (String.IsNullOrEmpty(action)) | ||
13943 | { | ||
13944 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Action")); | ||
13945 | } | ||
13946 | |||
13947 | if (String.IsNullOrEmpty(delay)) | ||
13948 | { | ||
13949 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Delay")); | ||
13950 | } | ||
13951 | |||
13952 | if (!String.IsNullOrEmpty(actions)) | ||
13953 | { | ||
13954 | actions = String.Concat(actions, "[~]"); | ||
13955 | } | ||
13956 | actions = String.Concat(actions, action); | ||
13957 | |||
13958 | if (!String.IsNullOrEmpty(actionsDelays)) | ||
13959 | { | ||
13960 | actionsDelays = String.Concat(actionsDelays, "[~]"); | ||
13961 | } | ||
13962 | actionsDelays = String.Concat(actionsDelays, delay); | ||
13963 | break; | ||
13964 | default: | ||
13965 | this.Core.UnexpectedElement(node, child); | ||
13966 | break; | ||
13967 | } | ||
13968 | } | ||
13969 | else | ||
13970 | { | ||
13971 | this.Core.ParseExtensionElement(node, child); | ||
13972 | } | ||
13973 | } | ||
13974 | |||
13975 | if (String.IsNullOrEmpty(name)) | ||
13976 | { | ||
13977 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
13978 | } | ||
13979 | else if (null == id) | ||
13980 | { | ||
13981 | id = this.Core.CreateIdentifierFromFilename(name); | ||
13982 | } | ||
13983 | |||
13984 | if (0 == events) | ||
13985 | { | ||
13986 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
13987 | } | ||
13988 | |||
13989 | if (!this.Core.EncounteredError) | ||
13990 | { | ||
13991 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfigFailureActions, id); | ||
13992 | row.Set(1, name); | ||
13993 | row.Set(2, events); | ||
13994 | if (CompilerConstants.IntegerNotSet != resetPeriod) | ||
13995 | { | ||
13996 | row.Set(3, resetPeriod); | ||
13997 | } | ||
13998 | row.Set(4, rebootMessage ?? "[~]"); | ||
13999 | row.Set(5, command ?? "[~]"); | ||
14000 | row.Set(6, actions); | ||
14001 | row.Set(7, actionsDelays); | ||
14002 | row.Set(8, componentId); | ||
14003 | } | ||
14004 | } | ||
14005 | |||
14006 | /// <summary> | ||
14007 | /// Parses a service control element. | ||
14008 | /// </summary> | ||
14009 | /// <param name="node">Element to parse.</param> | ||
14010 | /// <param name="componentId">Identifier of parent component.</param> | ||
14011 | private void ParseServiceControlElement(XElement node, string componentId) | ||
14012 | { | ||
14013 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14014 | string arguments = null; | ||
14015 | var events = 0; // default is to do nothing | ||
14016 | Identifier id = null; | ||
14017 | string name = null; | ||
14018 | var wait = YesNoType.NotSet; | ||
14019 | |||
14020 | foreach (var attrib in node.Attributes()) | ||
14021 | { | ||
14022 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14023 | { | ||
14024 | switch (attrib.Name.LocalName) | ||
14025 | { | ||
14026 | case "Id": | ||
14027 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
14028 | break; | ||
14029 | case "Name": | ||
14030 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14031 | break; | ||
14032 | case "Remove": | ||
14033 | var removeValue = this.Core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
14034 | switch (removeValue) | ||
14035 | { | ||
14036 | case Wix.InstallUninstallType.install: | ||
14037 | events |= MsiInterop.MsidbServiceControlEventDelete; | ||
14038 | break; | ||
14039 | case Wix.InstallUninstallType.uninstall: | ||
14040 | events |= MsiInterop.MsidbServiceControlEventUninstallDelete; | ||
14041 | break; | ||
14042 | case Wix.InstallUninstallType.both: | ||
14043 | events |= MsiInterop.MsidbServiceControlEventDelete | MsiInterop.MsidbServiceControlEventUninstallDelete; | ||
14044 | break; | ||
14045 | } | ||
14046 | break; | ||
14047 | case "Start": | ||
14048 | var startValue = this.Core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
14049 | switch (startValue) | ||
14050 | { | ||
14051 | case Wix.InstallUninstallType.install: | ||
14052 | events |= MsiInterop.MsidbServiceControlEventStart; | ||
14053 | break; | ||
14054 | case Wix.InstallUninstallType.uninstall: | ||
14055 | events |= MsiInterop.MsidbServiceControlEventUninstallStart; | ||
14056 | break; | ||
14057 | case Wix.InstallUninstallType.both: | ||
14058 | events |= MsiInterop.MsidbServiceControlEventStart | MsiInterop.MsidbServiceControlEventUninstallStart; | ||
14059 | break; | ||
14060 | } | ||
14061 | break; | ||
14062 | case "Stop": | ||
14063 | var stopValue = this.Core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
14064 | switch (stopValue) | ||
14065 | { | ||
14066 | case Wix.InstallUninstallType.install: | ||
14067 | events |= MsiInterop.MsidbServiceControlEventStop; | ||
14068 | break; | ||
14069 | case Wix.InstallUninstallType.uninstall: | ||
14070 | events |= MsiInterop.MsidbServiceControlEventUninstallStop; | ||
14071 | break; | ||
14072 | case Wix.InstallUninstallType.both: | ||
14073 | events |= MsiInterop.MsidbServiceControlEventStop | MsiInterop.MsidbServiceControlEventUninstallStop; | ||
14074 | break; | ||
14075 | } | ||
14076 | break; | ||
14077 | case "Wait": | ||
14078 | wait = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14079 | break; | ||
14080 | default: | ||
14081 | this.Core.UnexpectedAttribute(node, attrib); | ||
14082 | break; | ||
14083 | } | ||
14084 | } | ||
14085 | else | ||
14086 | { | ||
14087 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14088 | } | ||
14089 | } | ||
14090 | |||
14091 | if (null == id) | ||
14092 | { | ||
14093 | id = this.Core.CreateIdentifierFromFilename(name); | ||
14094 | } | ||
14095 | |||
14096 | if (null == name) | ||
14097 | { | ||
14098 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14099 | } | ||
14100 | |||
14101 | // get the ServiceControl arguments | ||
14102 | foreach (var child in node.Elements()) | ||
14103 | { | ||
14104 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
14105 | { | ||
14106 | switch (child.Name.LocalName) | ||
14107 | { | ||
14108 | case "ServiceArgument": | ||
14109 | if (null != arguments) | ||
14110 | { | ||
14111 | arguments = String.Concat(arguments, "[~]"); | ||
14112 | } | ||
14113 | arguments = String.Concat(arguments, this.Core.GetTrimmedInnerText(child)); | ||
14114 | break; | ||
14115 | default: | ||
14116 | this.Core.UnexpectedElement(node, child); | ||
14117 | break; | ||
14118 | } | ||
14119 | } | ||
14120 | else | ||
14121 | { | ||
14122 | this.Core.ParseExtensionElement(node, child); | ||
14123 | } | ||
14124 | } | ||
14125 | |||
14126 | if (!this.Core.EncounteredError) | ||
14127 | { | ||
14128 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ServiceControl, id); | ||
14129 | row.Set(1, name); | ||
14130 | row.Set(2, events); | ||
14131 | row.Set(3, arguments); | ||
14132 | if (YesNoType.NotSet != wait) | ||
14133 | { | ||
14134 | row.Set(4, YesNoType.Yes == wait ? 1 : 0); | ||
14135 | } | ||
14136 | row.Set(5, componentId); | ||
14137 | } | ||
14138 | } | ||
14139 | |||
14140 | /// <summary> | ||
14141 | /// Parses a service dependency element. | ||
14142 | /// </summary> | ||
14143 | /// <param name="node">Element to parse.</param> | ||
14144 | /// <returns>Parsed sevice dependency name.</returns> | ||
14145 | private string ParseServiceDependencyElement(XElement node) | ||
14146 | { | ||
14147 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14148 | string dependency = null; | ||
14149 | var group = false; | ||
14150 | |||
14151 | foreach (var attrib in node.Attributes()) | ||
14152 | { | ||
14153 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14154 | { | ||
14155 | switch (attrib.Name.LocalName) | ||
14156 | { | ||
14157 | case "Id": | ||
14158 | dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14159 | break; | ||
14160 | case "Group": | ||
14161 | group = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14162 | break; | ||
14163 | default: | ||
14164 | this.Core.UnexpectedAttribute(node, attrib); | ||
14165 | break; | ||
14166 | } | ||
14167 | } | ||
14168 | else | ||
14169 | { | ||
14170 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14171 | } | ||
14172 | } | ||
14173 | |||
14174 | if (null == dependency) | ||
14175 | { | ||
14176 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14177 | } | ||
14178 | |||
14179 | this.Core.ParseForExtensionElements(node); | ||
14180 | |||
14181 | return group ? String.Concat("+", dependency) : dependency; | ||
14182 | } | ||
14183 | |||
14184 | /// <summary> | ||
14185 | /// Parses a service install element. | ||
14186 | /// </summary> | ||
14187 | /// <param name="node">Element to parse.</param> | ||
14188 | /// <param name="componentId">Identifier of parent component.</param> | ||
14189 | private void ParseServiceInstallElement(XElement node, string componentId, bool win64Component) | ||
14190 | { | ||
14191 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14192 | Identifier id = null; | ||
14193 | string account = null; | ||
14194 | string arguments = null; | ||
14195 | string dependencies = null; | ||
14196 | string description = null; | ||
14197 | string displayName = null; | ||
14198 | var eraseDescription = false; | ||
14199 | var errorbits = 0; | ||
14200 | string loadOrderGroup = null; | ||
14201 | string name = null; | ||
14202 | string password = null; | ||
14203 | var startType = 0; | ||
14204 | var typebits = 0; | ||
14205 | |||
14206 | foreach (var attrib in node.Attributes()) | ||
14207 | { | ||
14208 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14209 | { | ||
14210 | switch (attrib.Name.LocalName) | ||
14211 | { | ||
14212 | case "Id": | ||
14213 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
14214 | break; | ||
14215 | case "Account": | ||
14216 | account = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14217 | break; | ||
14218 | case "Arguments": | ||
14219 | arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14220 | break; | ||
14221 | case "Description": | ||
14222 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14223 | break; | ||
14224 | case "DisplayName": | ||
14225 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14226 | break; | ||
14227 | case "EraseDescription": | ||
14228 | eraseDescription = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14229 | break; | ||
14230 | case "ErrorControl": | ||
14231 | var errorControlValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14232 | if (0 < errorControlValue.Length) | ||
14233 | { | ||
14234 | var errorControlType = Wix.ServiceInstall.ParseErrorControlType(errorControlValue); | ||
14235 | switch (errorControlType) | ||
14236 | { | ||
14237 | case Wix.ServiceInstall.ErrorControlType.ignore: | ||
14238 | errorbits |= MsiInterop.MsidbServiceInstallErrorIgnore; | ||
14239 | break; | ||
14240 | case Wix.ServiceInstall.ErrorControlType.normal: | ||
14241 | errorbits |= MsiInterop.MsidbServiceInstallErrorNormal; | ||
14242 | break; | ||
14243 | case Wix.ServiceInstall.ErrorControlType.critical: | ||
14244 | errorbits |= MsiInterop.MsidbServiceInstallErrorCritical; | ||
14245 | break; | ||
14246 | default: | ||
14247 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, errorControlValue, "ignore", "normal", "critical")); | ||
14248 | break; | ||
14249 | } | ||
14250 | } | ||
14251 | break; | ||
14252 | case "Interactive": | ||
14253 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
14254 | { | ||
14255 | typebits |= MsiInterop.MsidbServiceInstallInteractive; | ||
14256 | } | ||
14257 | break; | ||
14258 | case "LoadOrderGroup": | ||
14259 | loadOrderGroup = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14260 | break; | ||
14261 | case "Name": | ||
14262 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14263 | break; | ||
14264 | case "Password": | ||
14265 | password = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14266 | break; | ||
14267 | case "Start": | ||
14268 | var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14269 | if (0 < startValue.Length) | ||
14270 | { | ||
14271 | var start = Wix.ServiceInstall.ParseStartType(startValue); | ||
14272 | switch (start) | ||
14273 | { | ||
14274 | case Wix.ServiceInstall.StartType.auto: | ||
14275 | startType = MsiInterop.MsidbServiceInstallAutoStart; | ||
14276 | break; | ||
14277 | case Wix.ServiceInstall.StartType.demand: | ||
14278 | startType = MsiInterop.MsidbServiceInstallDemandStart; | ||
14279 | break; | ||
14280 | case Wix.ServiceInstall.StartType.disabled: | ||
14281 | startType = MsiInterop.MsidbServiceInstallDisabled; | ||
14282 | break; | ||
14283 | case Wix.ServiceInstall.StartType.boot: | ||
14284 | case Wix.ServiceInstall.StartType.system: | ||
14285 | this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue)); | ||
14286 | break; | ||
14287 | default: | ||
14288 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue, "auto", "demand", "disabled")); | ||
14289 | break; | ||
14290 | } | ||
14291 | } | ||
14292 | break; | ||
14293 | case "Type": | ||
14294 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14295 | if (0 < typeValue.Length) | ||
14296 | { | ||
14297 | var typeType = Wix.ServiceInstall.ParseTypeType(typeValue); | ||
14298 | switch (typeType) | ||
14299 | { | ||
14300 | case Wix.ServiceInstall.TypeType.ownProcess: | ||
14301 | typebits |= MsiInterop.MsidbServiceInstallOwnProcess; | ||
14302 | break; | ||
14303 | case Wix.ServiceInstall.TypeType.shareProcess: | ||
14304 | typebits |= MsiInterop.MsidbServiceInstallShareProcess; | ||
14305 | break; | ||
14306 | case Wix.ServiceInstall.TypeType.kernelDriver: | ||
14307 | case Wix.ServiceInstall.TypeType.systemDriver: | ||
14308 | this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue)); | ||
14309 | break; | ||
14310 | default: | ||
14311 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, node.Name.LocalName, typeValue, "ownProcess", "shareProcess")); | ||
14312 | break; | ||
14313 | } | ||
14314 | } | ||
14315 | break; | ||
14316 | case "Vital": | ||
14317 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
14318 | { | ||
14319 | errorbits |= MsiInterop.MsidbServiceInstallErrorControlVital; | ||
14320 | } | ||
14321 | break; | ||
14322 | default: | ||
14323 | this.Core.UnexpectedAttribute(node, attrib); | ||
14324 | break; | ||
14325 | } | ||
14326 | } | ||
14327 | else | ||
14328 | { | ||
14329 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14330 | } | ||
14331 | } | ||
14332 | |||
14333 | if (String.IsNullOrEmpty(name)) | ||
14334 | { | ||
14335 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14336 | } | ||
14337 | else if (null == id) | ||
14338 | { | ||
14339 | id = this.Core.CreateIdentifierFromFilename(name); | ||
14340 | } | ||
14341 | |||
14342 | if (0 == startType) | ||
14343 | { | ||
14344 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Start")); | ||
14345 | } | ||
14346 | |||
14347 | if (eraseDescription) | ||
14348 | { | ||
14349 | description = "[~]"; | ||
14350 | } | ||
14351 | |||
14352 | // get the ServiceInstall dependencies and config | ||
14353 | foreach (var child in node.Elements()) | ||
14354 | { | ||
14355 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
14356 | { | ||
14357 | switch (child.Name.LocalName) | ||
14358 | { | ||
14359 | case "PermissionEx": | ||
14360 | this.ParsePermissionExElement(child, id.Id, "ServiceInstall"); | ||
14361 | break; | ||
14362 | case "ServiceConfig": | ||
14363 | this.ParseServiceConfigElement(child, componentId, name); | ||
14364 | break; | ||
14365 | case "ServiceConfigFailureActions": | ||
14366 | this.ParseServiceConfigFailureActionsElement(child, componentId, name); | ||
14367 | break; | ||
14368 | case "ServiceDependency": | ||
14369 | dependencies = String.Concat(dependencies, this.ParseServiceDependencyElement(child), "[~]"); | ||
14370 | break; | ||
14371 | default: | ||
14372 | this.Core.UnexpectedElement(node, child); | ||
14373 | break; | ||
14374 | } | ||
14375 | } | ||
14376 | else | ||
14377 | { | ||
14378 | var context = new Dictionary<string, string>() { { "ServiceInstallId", id.Id }, { "ServiceInstallName", name }, { "ServiceInstallComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
14379 | this.Core.ParseExtensionElement(node, child, context); | ||
14380 | } | ||
14381 | } | ||
14382 | |||
14383 | if (null != dependencies) | ||
14384 | { | ||
14385 | dependencies = String.Concat(dependencies, "[~]"); | ||
14386 | } | ||
14387 | |||
14388 | if (!this.Core.EncounteredError) | ||
14389 | { | ||
14390 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ServiceInstall, id); | ||
14391 | row.Set(1, name); | ||
14392 | row.Set(2, displayName); | ||
14393 | row.Set(3, typebits); | ||
14394 | row.Set(4, startType); | ||
14395 | row.Set(5, errorbits); | ||
14396 | row.Set(6, loadOrderGroup); | ||
14397 | row.Set(7, dependencies); | ||
14398 | row.Set(8, account); | ||
14399 | row.Set(9, password); | ||
14400 | row.Set(10, arguments); | ||
14401 | row.Set(11, componentId); | ||
14402 | row.Set(12, description); | ||
14403 | } | ||
14404 | } | ||
14405 | |||
14406 | /// <summary> | ||
14407 | /// Parses a SetDirectory element. | ||
14408 | /// </summary> | ||
14409 | /// <param name="node">Element to parse.</param> | ||
14410 | private void ParseSetDirectoryElement(XElement node) | ||
14411 | { | ||
14412 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14413 | string actionName = null; | ||
14414 | string id = null; | ||
14415 | string condition = null; | ||
14416 | var sequences = new string[] { "InstallUISequence", "InstallExecuteSequence" }; // default to "both" | ||
14417 | var extraBits = 0; | ||
14418 | string value = null; | ||
14419 | |||
14420 | foreach (var attrib in node.Attributes()) | ||
14421 | { | ||
14422 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14423 | { | ||
14424 | switch (attrib.Name.LocalName) | ||
14425 | { | ||
14426 | case "Action": | ||
14427 | actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14428 | break; | ||
14429 | case "Id": | ||
14430 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14431 | this.Core.CreateSimpleReference(sourceLineNumbers, "Directory", id); | ||
14432 | break; | ||
14433 | case "Sequence": | ||
14434 | var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14435 | if (0 < sequenceValue.Length) | ||
14436 | { | ||
14437 | var sequenceType = Wix.Enums.ParseSequenceType(sequenceValue); | ||
14438 | switch (sequenceType) | ||
14439 | { | ||
14440 | case Wix.SequenceType.execute: | ||
14441 | sequences = new string[] { "InstallExecuteSequence" }; | ||
14442 | break; | ||
14443 | case Wix.SequenceType.ui: | ||
14444 | sequences = new string[] { "InstallUISequence" }; | ||
14445 | break; | ||
14446 | case Wix.SequenceType.first: | ||
14447 | extraBits = MsiInterop.MsidbCustomActionTypeFirstSequence; | ||
14448 | // default puts it in both sequence which is what we want | ||
14449 | break; | ||
14450 | case Wix.SequenceType.both: | ||
14451 | // default so no work necessary. | ||
14452 | break; | ||
14453 | default: | ||
14454 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
14455 | break; | ||
14456 | } | ||
14457 | } | ||
14458 | break; | ||
14459 | case "Value": | ||
14460 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14461 | break; | ||
14462 | default: | ||
14463 | this.Core.UnexpectedAttribute(node, attrib); | ||
14464 | break; | ||
14465 | } | ||
14466 | } | ||
14467 | else | ||
14468 | { | ||
14469 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14470 | } | ||
14471 | } | ||
14472 | |||
14473 | condition = this.Core.GetConditionInnerText(node); | ||
14474 | |||
14475 | if (null == id) | ||
14476 | { | ||
14477 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14478 | } | ||
14479 | else if (String.IsNullOrEmpty(actionName)) | ||
14480 | { | ||
14481 | actionName = String.Concat("Set", id); | ||
14482 | } | ||
14483 | |||
14484 | if (null == value) | ||
14485 | { | ||
14486 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
14487 | } | ||
14488 | |||
14489 | this.Core.ParseForExtensionElements(node); | ||
14490 | |||
14491 | // add the row and any references needed | ||
14492 | if (!this.Core.EncounteredError) | ||
14493 | { | ||
14494 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CustomAction, new Identifier(AccessModifier.Public, actionName)); | ||
14495 | row.Set(1, MsiInterop.MsidbCustomActionTypeProperty | MsiInterop.MsidbCustomActionTypeTextData | extraBits); | ||
14496 | row.Set(2, id); | ||
14497 | row.Set(3, value); | ||
14498 | |||
14499 | foreach (var sequence in sequences) | ||
14500 | { | ||
14501 | var sequenceRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixAction); | ||
14502 | sequenceRow.Set(0, sequence); | ||
14503 | sequenceRow.Set(1, actionName); | ||
14504 | sequenceRow.Set(2, condition); | ||
14505 | // no explicit sequence | ||
14506 | // no before action | ||
14507 | sequenceRow.Set(5, "CostInitialize"); | ||
14508 | sequenceRow.Set(6, 0); // not overridable | ||
14509 | } | ||
14510 | } | ||
14511 | } | ||
14512 | |||
14513 | /// <summary> | ||
14514 | /// Parses a SetProperty element. | ||
14515 | /// </summary> | ||
14516 | /// <param name="node">Element to parse.</param> | ||
14517 | private void ParseSetPropertyElement(XElement node) | ||
14518 | { | ||
14519 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14520 | string actionName = null; | ||
14521 | string id = null; | ||
14522 | string afterAction = null; | ||
14523 | string beforeAction = null; | ||
14524 | string condition = null; | ||
14525 | var sequences = new string[] { "InstallUISequence", "InstallExecuteSequence" }; // default to "both" | ||
14526 | var extraBits = 0; | ||
14527 | string value = null; | ||
14528 | |||
14529 | foreach (var attrib in node.Attributes()) | ||
14530 | { | ||
14531 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14532 | { | ||
14533 | switch (attrib.Name.LocalName) | ||
14534 | { | ||
14535 | case "Action": | ||
14536 | actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14537 | break; | ||
14538 | case "Id": | ||
14539 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14540 | break; | ||
14541 | case "After": | ||
14542 | afterAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14543 | break; | ||
14544 | case "Before": | ||
14545 | beforeAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14546 | break; | ||
14547 | case "Sequence": | ||
14548 | var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14549 | if (0 < sequenceValue.Length) | ||
14550 | { | ||
14551 | var sequenceType = Wix.Enums.ParseSequenceType(sequenceValue); | ||
14552 | switch (sequenceType) | ||
14553 | { | ||
14554 | case Wix.SequenceType.execute: | ||
14555 | sequences = new string[] { "InstallExecuteSequence" }; | ||
14556 | break; | ||
14557 | case Wix.SequenceType.ui: | ||
14558 | sequences = new string[] { "InstallUISequence" }; | ||
14559 | break; | ||
14560 | case Wix.SequenceType.first: | ||
14561 | extraBits = MsiInterop.MsidbCustomActionTypeFirstSequence; | ||
14562 | // default puts it in both sequence which is what we want | ||
14563 | break; | ||
14564 | case Wix.SequenceType.both: | ||
14565 | // default so no work necessary. | ||
14566 | break; | ||
14567 | default: | ||
14568 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
14569 | break; | ||
14570 | } | ||
14571 | } | ||
14572 | break; | ||
14573 | case "Value": | ||
14574 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
14575 | break; | ||
14576 | default: | ||
14577 | this.Core.UnexpectedAttribute(node, attrib); | ||
14578 | break; | ||
14579 | } | ||
14580 | } | ||
14581 | else | ||
14582 | { | ||
14583 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14584 | } | ||
14585 | } | ||
14586 | |||
14587 | condition = this.Core.GetConditionInnerText(node); | ||
14588 | |||
14589 | if (null == id) | ||
14590 | { | ||
14591 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14592 | } | ||
14593 | else if (String.IsNullOrEmpty(actionName)) | ||
14594 | { | ||
14595 | actionName = String.Concat("Set", id); | ||
14596 | } | ||
14597 | |||
14598 | if (null == value) | ||
14599 | { | ||
14600 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
14601 | } | ||
14602 | |||
14603 | if (null != beforeAction && null != afterAction) | ||
14604 | { | ||
14605 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before")); | ||
14606 | } | ||
14607 | else if (null == beforeAction && null == afterAction) | ||
14608 | { | ||
14609 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before", "Id")); | ||
14610 | } | ||
14611 | |||
14612 | this.Core.ParseForExtensionElements(node); | ||
14613 | |||
14614 | // add the row and any references needed | ||
14615 | if (!this.Core.EncounteredError) | ||
14616 | { | ||
14617 | // action that is scheduled to occur before/after itself | ||
14618 | if (beforeAction == actionName) | ||
14619 | { | ||
14620 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "Before", beforeAction)); | ||
14621 | } | ||
14622 | else if (afterAction == actionName) | ||
14623 | { | ||
14624 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "After", afterAction)); | ||
14625 | } | ||
14626 | |||
14627 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CustomAction, new Identifier(AccessModifier.Public, actionName)); | ||
14628 | row.Set(1, MsiInterop.MsidbCustomActionTypeProperty | MsiInterop.MsidbCustomActionTypeTextData | extraBits); | ||
14629 | row.Set(2, id); | ||
14630 | row.Set(3, value); | ||
14631 | |||
14632 | foreach (var sequence in sequences) | ||
14633 | { | ||
14634 | var sequenceRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixAction, new Identifier(AccessModifier.Public, sequence, actionName)); | ||
14635 | sequenceRow.Set(0, sequence); | ||
14636 | sequenceRow.Set(1, actionName); | ||
14637 | sequenceRow.Set(2, condition); | ||
14638 | // no explicit sequence | ||
14639 | sequenceRow.Set(4, beforeAction); | ||
14640 | sequenceRow.Set(5, afterAction); | ||
14641 | sequenceRow.Set(6, 0); // not overridable | ||
14642 | |||
14643 | if (null != beforeAction) | ||
14644 | { | ||
14645 | if (WindowsInstallerStandard.IsStandardAction(beforeAction)) | ||
14646 | { | ||
14647 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, beforeAction); | ||
14648 | } | ||
14649 | else | ||
14650 | { | ||
14651 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction); | ||
14652 | } | ||
14653 | } | ||
14654 | |||
14655 | if (null != afterAction) | ||
14656 | { | ||
14657 | if (WindowsInstallerStandard.IsStandardAction(afterAction)) | ||
14658 | { | ||
14659 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, afterAction); | ||
14660 | } | ||
14661 | else | ||
14662 | { | ||
14663 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction); | ||
14664 | } | ||
14665 | } | ||
14666 | } | ||
14667 | } | ||
14668 | } | ||
14669 | |||
14670 | /// <summary> | ||
14671 | /// Parses a SFP catalog element. | ||
14672 | /// </summary> | ||
14673 | /// <param name="node">Element to parse.</param> | ||
14674 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
14675 | private void ParseSFPFileElement(XElement node, string parentSFPCatalog) | ||
14676 | { | ||
14677 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14678 | string id = null; | ||
14679 | |||
14680 | foreach (var attrib in node.Attributes()) | ||
14681 | { | ||
14682 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14683 | { | ||
14684 | switch (attrib.Name.LocalName) | ||
14685 | { | ||
14686 | case "Id": | ||
14687 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14688 | break; | ||
14689 | default: | ||
14690 | this.Core.UnexpectedAttribute(node, attrib); | ||
14691 | break; | ||
14692 | } | ||
14693 | } | ||
14694 | else | ||
14695 | { | ||
14696 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14697 | } | ||
14698 | } | ||
14699 | |||
14700 | if (null == id) | ||
14701 | { | ||
14702 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14703 | } | ||
14704 | |||
14705 | this.Core.ParseForExtensionElements(node); | ||
14706 | |||
14707 | if (!this.Core.EncounteredError) | ||
14708 | { | ||
14709 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.FileSFPCatalog); | ||
14710 | row.Set(0, id); | ||
14711 | row.Set(1, parentSFPCatalog); | ||
14712 | } | ||
14713 | } | ||
14714 | |||
14715 | /// <summary> | ||
14716 | /// Parses a SFP catalog element. | ||
14717 | /// </summary> | ||
14718 | /// <param name="node">Element to parse.</param> | ||
14719 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
14720 | private void ParseSFPCatalogElement(XElement node, ref string parentSFPCatalog) | ||
14721 | { | ||
14722 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14723 | string parentName = null; | ||
14724 | string dependency = null; | ||
14725 | string name = null; | ||
14726 | string sourceFile = null; | ||
14727 | |||
14728 | foreach (var attrib in node.Attributes()) | ||
14729 | { | ||
14730 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14731 | { | ||
14732 | switch (attrib.Name.LocalName) | ||
14733 | { | ||
14734 | case "Dependency": | ||
14735 | dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14736 | break; | ||
14737 | case "Name": | ||
14738 | name = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
14739 | parentSFPCatalog = name; | ||
14740 | break; | ||
14741 | case "SourceFile": | ||
14742 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14743 | break; | ||
14744 | default: | ||
14745 | this.Core.UnexpectedAttribute(node, attrib); | ||
14746 | break; | ||
14747 | } | ||
14748 | } | ||
14749 | else | ||
14750 | { | ||
14751 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14752 | } | ||
14753 | } | ||
14754 | |||
14755 | if (null == name) | ||
14756 | { | ||
14757 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14758 | } | ||
14759 | |||
14760 | if (null == sourceFile) | ||
14761 | { | ||
14762 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
14763 | } | ||
14764 | |||
14765 | foreach (var child in node.Elements()) | ||
14766 | { | ||
14767 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
14768 | { | ||
14769 | switch (child.Name.LocalName) | ||
14770 | { | ||
14771 | case "SFPCatalog": | ||
14772 | this.ParseSFPCatalogElement(child, ref parentName); | ||
14773 | if (null != dependency && parentName == dependency) | ||
14774 | { | ||
14775 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
14776 | } | ||
14777 | dependency = parentName; | ||
14778 | break; | ||
14779 | case "SFPFile": | ||
14780 | this.ParseSFPFileElement(child, name); | ||
14781 | break; | ||
14782 | default: | ||
14783 | this.Core.UnexpectedElement(node, child); | ||
14784 | break; | ||
14785 | } | ||
14786 | } | ||
14787 | else | ||
14788 | { | ||
14789 | this.Core.ParseExtensionElement(node, child); | ||
14790 | } | ||
14791 | } | ||
14792 | |||
14793 | if (null == dependency) | ||
14794 | { | ||
14795 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
14796 | } | ||
14797 | |||
14798 | if (!this.Core.EncounteredError) | ||
14799 | { | ||
14800 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.SFPCatalog); | ||
14801 | row.Set(0, name); | ||
14802 | row.Set(1, sourceFile); | ||
14803 | row.Set(2, dependency); | ||
14804 | } | ||
14805 | } | ||
14806 | |||
14807 | /// <summary> | ||
14808 | /// Parses a shortcut element. | ||
14809 | /// </summary> | ||
14810 | /// <param name="node">Element to parse.</param> | ||
14811 | /// <param name="componentId">Identifer for parent component.</param> | ||
14812 | /// <param name="parentElementLocalName">Local name of parent element.</param> | ||
14813 | /// <param name="defaultTarget">Default identifier of parent (which is usually the target).</param> | ||
14814 | /// <param name="parentKeyPath">Flag to indicate whether the parent element is the keypath of a component or not (will only be true for file parent elements).</param> | ||
14815 | private void ParseShortcutElement(XElement node, string componentId, string parentElementLocalName, string defaultTarget, YesNoType parentKeyPath) | ||
14816 | { | ||
14817 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14818 | Identifier id = null; | ||
14819 | var advertise = false; | ||
14820 | string arguments = null; | ||
14821 | string description = null; | ||
14822 | string descriptionResourceDll = null; | ||
14823 | var descriptionResourceId = CompilerConstants.IntegerNotSet; | ||
14824 | string directory = null; | ||
14825 | string displayResourceDll = null; | ||
14826 | var displayResourceId = CompilerConstants.IntegerNotSet; | ||
14827 | var hotkey = CompilerConstants.IntegerNotSet; | ||
14828 | string icon = null; | ||
14829 | var iconIndex = CompilerConstants.IntegerNotSet; | ||
14830 | string name = null; | ||
14831 | string shortName = null; | ||
14832 | var show = CompilerConstants.IntegerNotSet; | ||
14833 | string target = null; | ||
14834 | string workingDirectory = null; | ||
14835 | |||
14836 | foreach (var attrib in node.Attributes()) | ||
14837 | { | ||
14838 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14839 | { | ||
14840 | switch (attrib.Name.LocalName) | ||
14841 | { | ||
14842 | case "Id": | ||
14843 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
14844 | break; | ||
14845 | case "Advertise": | ||
14846 | advertise = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14847 | break; | ||
14848 | case "Arguments": | ||
14849 | arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14850 | break; | ||
14851 | case "Description": | ||
14852 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14853 | break; | ||
14854 | case "DescriptionResourceDll": | ||
14855 | descriptionResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14856 | break; | ||
14857 | case "DescriptionResourceId": | ||
14858 | descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
14859 | break; | ||
14860 | case "Directory": | ||
14861 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
14862 | break; | ||
14863 | case "DisplayResourceDll": | ||
14864 | displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14865 | break; | ||
14866 | case "DisplayResourceId": | ||
14867 | displayResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
14868 | break; | ||
14869 | case "Hotkey": | ||
14870 | hotkey = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
14871 | break; | ||
14872 | case "Icon": | ||
14873 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14874 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
14875 | break; | ||
14876 | case "IconIndex": | ||
14877 | iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue); | ||
14878 | break; | ||
14879 | case "Name": | ||
14880 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
14881 | break; | ||
14882 | case "ShortName": | ||
14883 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
14884 | break; | ||
14885 | case "Show": | ||
14886 | var showValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14887 | if (showValue.Length == 0) | ||
14888 | { | ||
14889 | show = CompilerConstants.IllegalInteger; | ||
14890 | } | ||
14891 | else | ||
14892 | { | ||
14893 | var showType = Wix.Shortcut.ParseShowType(showValue); | ||
14894 | switch (showType) | ||
14895 | { | ||
14896 | case Wix.Shortcut.ShowType.normal: | ||
14897 | show = 1; | ||
14898 | break; | ||
14899 | case Wix.Shortcut.ShowType.maximized: | ||
14900 | show = 3; | ||
14901 | break; | ||
14902 | case Wix.Shortcut.ShowType.minimized: | ||
14903 | show = 7; | ||
14904 | break; | ||
14905 | default: | ||
14906 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized")); | ||
14907 | show = CompilerConstants.IllegalInteger; | ||
14908 | break; | ||
14909 | } | ||
14910 | } | ||
14911 | break; | ||
14912 | case "Target": | ||
14913 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14914 | break; | ||
14915 | case "WorkingDirectory": | ||
14916 | workingDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14917 | break; | ||
14918 | default: | ||
14919 | this.Core.UnexpectedAttribute(node, attrib); | ||
14920 | break; | ||
14921 | } | ||
14922 | } | ||
14923 | else | ||
14924 | { | ||
14925 | this.Core.ParseExtensionAttribute(node, attrib); | ||
14926 | } | ||
14927 | } | ||
14928 | |||
14929 | if (advertise && null != target) | ||
14930 | { | ||
14931 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes")); | ||
14932 | } | ||
14933 | |||
14934 | if (null == directory) | ||
14935 | { | ||
14936 | if ("Component" == parentElementLocalName) | ||
14937 | { | ||
14938 | directory = defaultTarget; | ||
14939 | } | ||
14940 | else | ||
14941 | { | ||
14942 | this.Core.Write(ErrorMessages.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Directory", "Component")); | ||
14943 | } | ||
14944 | } | ||
14945 | |||
14946 | if (null != descriptionResourceDll) | ||
14947 | { | ||
14948 | if (CompilerConstants.IntegerNotSet == descriptionResourceId) | ||
14949 | { | ||
14950 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceDll", "DescriptionResourceId")); | ||
14951 | } | ||
14952 | } | ||
14953 | else | ||
14954 | { | ||
14955 | if (CompilerConstants.IntegerNotSet != descriptionResourceId) | ||
14956 | { | ||
14957 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceId", "DescriptionResourceDll")); | ||
14958 | } | ||
14959 | } | ||
14960 | |||
14961 | if (null != displayResourceDll) | ||
14962 | { | ||
14963 | if (CompilerConstants.IntegerNotSet == displayResourceId) | ||
14964 | { | ||
14965 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceDll", "DisplayResourceId")); | ||
14966 | } | ||
14967 | } | ||
14968 | else | ||
14969 | { | ||
14970 | if (CompilerConstants.IntegerNotSet != displayResourceId) | ||
14971 | { | ||
14972 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceId", "DisplayResourceDll")); | ||
14973 | } | ||
14974 | } | ||
14975 | |||
14976 | if (null == name) | ||
14977 | { | ||
14978 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14979 | } | ||
14980 | else if (0 < name.Length) | ||
14981 | { | ||
14982 | if (this.Core.IsValidShortFilename(name, false)) | ||
14983 | { | ||
14984 | if (null == shortName) | ||
14985 | { | ||
14986 | shortName = name; | ||
14987 | name = null; | ||
14988 | } | ||
14989 | else | ||
14990 | { | ||
14991 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
14992 | } | ||
14993 | } | ||
14994 | else if (null == shortName) // generate a short file name. | ||
14995 | { | ||
14996 | shortName = this.Core.CreateShortName(name, true, false, node.Name.LocalName, componentId, directory); | ||
14997 | } | ||
14998 | } | ||
14999 | |||
15000 | if ("Component" != parentElementLocalName && null != target) | ||
15001 | { | ||
15002 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName)); | ||
15003 | } | ||
15004 | |||
15005 | if (null == id) | ||
15006 | { | ||
15007 | id = this.Core.CreateIdentifier("sct", directory, LowercaseOrNull(name) ?? LowercaseOrNull(shortName)); | ||
15008 | } | ||
15009 | |||
15010 | foreach (var child in node.Elements()) | ||
15011 | { | ||
15012 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15013 | { | ||
15014 | switch (child.Name.LocalName) | ||
15015 | { | ||
15016 | case "Icon": | ||
15017 | icon = this.ParseIconElement(child); | ||
15018 | break; | ||
15019 | case "ShortcutProperty": | ||
15020 | this.ParseShortcutPropertyElement(child, id.Id); | ||
15021 | break; | ||
15022 | default: | ||
15023 | this.Core.UnexpectedElement(node, child); | ||
15024 | break; | ||
15025 | } | ||
15026 | } | ||
15027 | else | ||
15028 | { | ||
15029 | this.Core.ParseExtensionElement(node, child); | ||
15030 | } | ||
15031 | } | ||
15032 | |||
15033 | if (!this.Core.EncounteredError) | ||
15034 | { | ||
15035 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Shortcut, id); | ||
15036 | row.Set(1, directory); | ||
15037 | row.Set(2, this.GetMsiFilenameValue(shortName, name)); | ||
15038 | row.Set(3, componentId); | ||
15039 | if (advertise) | ||
15040 | { | ||
15041 | if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName) | ||
15042 | { | ||
15043 | this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget)); | ||
15044 | } | ||
15045 | row.Set(4, Guid.Empty.ToString("B")); | ||
15046 | } | ||
15047 | else if (null != target) | ||
15048 | { | ||
15049 | row.Set(4, target); | ||
15050 | } | ||
15051 | else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName) | ||
15052 | { | ||
15053 | row.Set(4, String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget)); | ||
15054 | } | ||
15055 | else if ("File" == parentElementLocalName) | ||
15056 | { | ||
15057 | row.Set(4, String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget)); | ||
15058 | } | ||
15059 | row.Set(5, arguments); | ||
15060 | row.Set(6, description); | ||
15061 | if (CompilerConstants.IntegerNotSet != hotkey) | ||
15062 | { | ||
15063 | row.Set(7, hotkey); | ||
15064 | } | ||
15065 | row.Set(8, icon); | ||
15066 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
15067 | { | ||
15068 | row.Set(9, iconIndex); | ||
15069 | } | ||
15070 | |||
15071 | if (CompilerConstants.IntegerNotSet != show) | ||
15072 | { | ||
15073 | row.Set(10, show); | ||
15074 | } | ||
15075 | row.Set(11, workingDirectory); | ||
15076 | row.Set(12, displayResourceDll); | ||
15077 | if (CompilerConstants.IntegerNotSet != displayResourceId) | ||
15078 | { | ||
15079 | row.Set(13, displayResourceId); | ||
15080 | } | ||
15081 | row.Set(14, descriptionResourceDll); | ||
15082 | if (CompilerConstants.IntegerNotSet != descriptionResourceId) | ||
15083 | { | ||
15084 | row.Set(15, descriptionResourceId); | ||
15085 | } | ||
15086 | } | ||
15087 | } | ||
15088 | |||
15089 | /// <summary> | ||
15090 | /// Parses a shortcut property element. | ||
15091 | /// </summary> | ||
15092 | /// <param name="node">Element to parse.</param> | ||
15093 | private void ParseShortcutPropertyElement(XElement node, string shortcutId) | ||
15094 | { | ||
15095 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15096 | Identifier id = null; | ||
15097 | string key = null; | ||
15098 | string value = null; | ||
15099 | |||
15100 | foreach (var attrib in node.Attributes()) | ||
15101 | { | ||
15102 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15103 | { | ||
15104 | switch (attrib.Name.LocalName) | ||
15105 | { | ||
15106 | case "Id": | ||
15107 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15108 | break; | ||
15109 | case "Key": | ||
15110 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15111 | break; | ||
15112 | case "Value": | ||
15113 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15114 | break; | ||
15115 | default: | ||
15116 | this.Core.UnexpectedAttribute(node, attrib); | ||
15117 | break; | ||
15118 | } | ||
15119 | } | ||
15120 | else | ||
15121 | { | ||
15122 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15123 | } | ||
15124 | } | ||
15125 | |||
15126 | if (String.IsNullOrEmpty(key)) | ||
15127 | { | ||
15128 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
15129 | } | ||
15130 | else if (null == id) | ||
15131 | { | ||
15132 | id = this.Core.CreateIdentifier("scp", shortcutId, key.ToUpperInvariant()); | ||
15133 | } | ||
15134 | |||
15135 | var innerText = this.Core.GetTrimmedInnerText(node); | ||
15136 | if (!String.IsNullOrEmpty(innerText)) | ||
15137 | { | ||
15138 | if (String.IsNullOrEmpty(value)) | ||
15139 | { | ||
15140 | value = innerText; | ||
15141 | } | ||
15142 | else // cannot specify both the value attribute and inner text | ||
15143 | { | ||
15144 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15145 | } | ||
15146 | } | ||
15147 | |||
15148 | if (String.IsNullOrEmpty(value)) | ||
15149 | { | ||
15150 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15151 | } | ||
15152 | |||
15153 | this.Core.ParseForExtensionElements(node); | ||
15154 | |||
15155 | if (!this.Core.EncounteredError) | ||
15156 | { | ||
15157 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiShortcutProperty, id); | ||
15158 | row.Set(1, shortcutId); | ||
15159 | row.Set(2, key); | ||
15160 | row.Set(3, value); | ||
15161 | } | ||
15162 | } | ||
15163 | |||
15164 | /// <summary> | ||
15165 | /// Parses a typelib element. | ||
15166 | /// </summary> | ||
15167 | /// <param name="node">Element to parse.</param> | ||
15168 | /// <param name="componentId">Identifier of parent component.</param> | ||
15169 | /// <param name="fileServer">Identifier of file that acts as typelib server.</param> | ||
15170 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
15171 | private void ParseTypeLibElement(XElement node, string componentId, string fileServer, bool win64Component) | ||
15172 | { | ||
15173 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15174 | string id = null; | ||
15175 | var advertise = YesNoType.NotSet; | ||
15176 | var cost = CompilerConstants.IntegerNotSet; | ||
15177 | string description = null; | ||
15178 | var flags = 0; | ||
15179 | string helpDirectory = null; | ||
15180 | var language = CompilerConstants.IntegerNotSet; | ||
15181 | var majorVersion = CompilerConstants.IntegerNotSet; | ||
15182 | var minorVersion = CompilerConstants.IntegerNotSet; | ||
15183 | var resourceId = CompilerConstants.LongNotSet; | ||
15184 | |||
15185 | foreach (var attrib in node.Attributes()) | ||
15186 | { | ||
15187 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15188 | { | ||
15189 | switch (attrib.Name.LocalName) | ||
15190 | { | ||
15191 | case "Id": | ||
15192 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
15193 | break; | ||
15194 | case "Advertise": | ||
15195 | advertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
15196 | break; | ||
15197 | case "Control": | ||
15198 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15199 | { | ||
15200 | flags |= 2; | ||
15201 | } | ||
15202 | break; | ||
15203 | case "Cost": | ||
15204 | cost = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
15205 | break; | ||
15206 | case "Description": | ||
15207 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15208 | break; | ||
15209 | case "HasDiskImage": | ||
15210 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15211 | { | ||
15212 | flags |= 8; | ||
15213 | } | ||
15214 | break; | ||
15215 | case "HelpDirectory": | ||
15216 | helpDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
15217 | break; | ||
15218 | case "Hidden": | ||
15219 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15220 | { | ||
15221 | flags |= 4; | ||
15222 | } | ||
15223 | break; | ||
15224 | case "Language": | ||
15225 | language = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
15226 | break; | ||
15227 | case "MajorVersion": | ||
15228 | majorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, UInt16.MaxValue); | ||
15229 | break; | ||
15230 | case "MinorVersion": | ||
15231 | minorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
15232 | break; | ||
15233 | case "ResourceId": | ||
15234 | resourceId = this.Core.GetAttributeLongValue(sourceLineNumbers, attrib, Int32.MinValue, Int32.MaxValue); | ||
15235 | break; | ||
15236 | case "Restricted": | ||
15237 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15238 | { | ||
15239 | flags |= 1; | ||
15240 | } | ||
15241 | break; | ||
15242 | default: | ||
15243 | this.Core.UnexpectedAttribute(node, attrib); | ||
15244 | break; | ||
15245 | } | ||
15246 | } | ||
15247 | else | ||
15248 | { | ||
15249 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15250 | } | ||
15251 | } | ||
15252 | |||
15253 | if (null == id) | ||
15254 | { | ||
15255 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
15256 | } | ||
15257 | |||
15258 | if (CompilerConstants.IntegerNotSet == language) | ||
15259 | { | ||
15260 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
15261 | language = CompilerConstants.IllegalInteger; | ||
15262 | } | ||
15263 | |||
15264 | // build up the typelib version string for the registry if the major or minor version was specified | ||
15265 | string registryVersion = null; | ||
15266 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
15267 | { | ||
15268 | if (CompilerConstants.IntegerNotSet != majorVersion) | ||
15269 | { | ||
15270 | registryVersion = majorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat); | ||
15271 | } | ||
15272 | else | ||
15273 | { | ||
15274 | registryVersion = "0"; | ||
15275 | } | ||
15276 | |||
15277 | if (CompilerConstants.IntegerNotSet != minorVersion) | ||
15278 | { | ||
15279 | registryVersion = String.Concat(registryVersion, ".", minorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat)); | ||
15280 | } | ||
15281 | else | ||
15282 | { | ||
15283 | registryVersion = String.Concat(registryVersion, ".0"); | ||
15284 | } | ||
15285 | } | ||
15286 | |||
15287 | // if the advertise state has not been set, default to non-advertised | ||
15288 | if (YesNoType.NotSet == advertise) | ||
15289 | { | ||
15290 | advertise = YesNoType.No; | ||
15291 | } | ||
15292 | |||
15293 | foreach (var child in node.Elements()) | ||
15294 | { | ||
15295 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15296 | { | ||
15297 | switch (child.Name.LocalName) | ||
15298 | { | ||
15299 | case "AppId": | ||
15300 | this.ParseAppIdElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion); | ||
15301 | break; | ||
15302 | case "Class": | ||
15303 | this.ParseClassElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion, null); | ||
15304 | break; | ||
15305 | case "Interface": | ||
15306 | this.ParseInterfaceElement(child, componentId, null, null, id, registryVersion); | ||
15307 | break; | ||
15308 | default: | ||
15309 | this.Core.UnexpectedElement(node, child); | ||
15310 | break; | ||
15311 | } | ||
15312 | } | ||
15313 | else | ||
15314 | { | ||
15315 | this.Core.ParseExtensionElement(node, child); | ||
15316 | } | ||
15317 | } | ||
15318 | |||
15319 | |||
15320 | if (YesNoType.Yes == advertise) | ||
15321 | { | ||
15322 | if (CompilerConstants.LongNotSet != resourceId) | ||
15323 | { | ||
15324 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "ResourceId")); | ||
15325 | } | ||
15326 | |||
15327 | if (0 != flags) | ||
15328 | { | ||
15329 | if (0x1 == (flags & 0x1)) | ||
15330 | { | ||
15331 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Restricted", "Advertise", "yes")); | ||
15332 | } | ||
15333 | |||
15334 | if (0x2 == (flags & 0x2)) | ||
15335 | { | ||
15336 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Control", "Advertise", "yes")); | ||
15337 | } | ||
15338 | |||
15339 | if (0x4 == (flags & 0x4)) | ||
15340 | { | ||
15341 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Hidden", "Advertise", "yes")); | ||
15342 | } | ||
15343 | |||
15344 | if (0x8 == (flags & 0x8)) | ||
15345 | { | ||
15346 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "HasDiskImage", "Advertise", "yes")); | ||
15347 | } | ||
15348 | } | ||
15349 | |||
15350 | if (!this.Core.EncounteredError) | ||
15351 | { | ||
15352 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.TypeLib); | ||
15353 | row.Set(0, id); | ||
15354 | row.Set(1, language); | ||
15355 | row.Set(2, componentId); | ||
15356 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
15357 | { | ||
15358 | row.Set(3, (CompilerConstants.IntegerNotSet != majorVersion ? majorVersion * 256 : 0) + (CompilerConstants.IntegerNotSet != minorVersion ? minorVersion : 0)); | ||
15359 | } | ||
15360 | row.Set(4, description); | ||
15361 | row.Set(5, helpDirectory); | ||
15362 | row.Set(6, Guid.Empty.ToString("B")); | ||
15363 | if (CompilerConstants.IntegerNotSet != cost) | ||
15364 | { | ||
15365 | row.Set(7, cost); | ||
15366 | } | ||
15367 | } | ||
15368 | } | ||
15369 | else if (YesNoType.No == advertise) | ||
15370 | { | ||
15371 | if (CompilerConstants.IntegerNotSet != cost && CompilerConstants.IllegalInteger != cost) | ||
15372 | { | ||
15373 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Cost", "Advertise", "no")); | ||
15374 | } | ||
15375 | |||
15376 | if (null == fileServer) | ||
15377 | { | ||
15378 | this.Core.Write(ErrorMessages.MissingTypeLibFile(sourceLineNumbers, node.Name.LocalName, "File")); | ||
15379 | } | ||
15380 | |||
15381 | if (null == registryVersion) | ||
15382 | { | ||
15383 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "MajorVersion", "MinorVersion", "Advertise", "no")); | ||
15384 | } | ||
15385 | |||
15386 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion], (Default) = [Description] | ||
15387 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}", id, registryVersion), null, description, componentId); | ||
15388 | |||
15389 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\[Language]\[win16|win32|win64], (Default) = [TypeLibPath]\[ResourceId] | ||
15390 | var path = String.Concat("[#", fileServer, "]"); | ||
15391 | if (CompilerConstants.LongNotSet != resourceId) | ||
15392 | { | ||
15393 | path = String.Concat(path, Path.DirectorySeparatorChar, resourceId.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
15394 | } | ||
15395 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\{2}\{3}", id, registryVersion, language, (win64Component ? "win64" : "win32")), null, path, componentId); | ||
15396 | |||
15397 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags] | ||
15398 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId); | ||
15399 | |||
15400 | if (null != helpDirectory) | ||
15401 | { | ||
15402 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory] | ||
15403 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId); | ||
15404 | } | ||
15405 | } | ||
15406 | } | ||
15407 | |||
15408 | /// <summary> | ||
15409 | /// Parses an EmbeddedChaniner element. | ||
15410 | /// </summary> | ||
15411 | /// <param name="node">Element to parse.</param> | ||
15412 | private void ParseEmbeddedChainerElement(XElement node) | ||
15413 | { | ||
15414 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15415 | Identifier id = null; | ||
15416 | string commandLine = null; | ||
15417 | string condition = null; | ||
15418 | string source = null; | ||
15419 | var type = 0; | ||
15420 | |||
15421 | foreach (var attrib in node.Attributes()) | ||
15422 | { | ||
15423 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15424 | { | ||
15425 | switch (attrib.Name.LocalName) | ||
15426 | { | ||
15427 | case "Id": | ||
15428 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15429 | break; | ||
15430 | case "BinarySource": | ||
15431 | if (null != source) | ||
15432 | { | ||
15433 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "FileSource", "PropertySource")); | ||
15434 | } | ||
15435 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15436 | type = MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeBinaryData; | ||
15437 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", source); // add a reference to the appropriate Binary | ||
15438 | break; | ||
15439 | case "CommandLine": | ||
15440 | commandLine = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15441 | break; | ||
15442 | case "FileSource": | ||
15443 | if (null != source) | ||
15444 | { | ||
15445 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinarySource", "PropertySource")); | ||
15446 | } | ||
15447 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15448 | type = MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeSourceFile; | ||
15449 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", source); // add a reference to the appropriate File | ||
15450 | break; | ||
15451 | case "PropertySource": | ||
15452 | if (null != source) | ||
15453 | { | ||
15454 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinarySource", "FileSource")); | ||
15455 | } | ||
15456 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15457 | type = MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeProperty; | ||
15458 | // cannot add a reference to a Property because it may be created at runtime. | ||
15459 | break; | ||
15460 | default: | ||
15461 | this.Core.UnexpectedAttribute(node, attrib); | ||
15462 | break; | ||
15463 | } | ||
15464 | } | ||
15465 | else | ||
15466 | { | ||
15467 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15468 | } | ||
15469 | } | ||
15470 | |||
15471 | // Get the condition from the inner text of the element. | ||
15472 | condition = this.Core.GetConditionInnerText(node); | ||
15473 | |||
15474 | if (null == id) | ||
15475 | { | ||
15476 | id = this.Core.CreateIdentifier("mec", source, type.ToString()); | ||
15477 | } | ||
15478 | |||
15479 | if (null == source) | ||
15480 | { | ||
15481 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "BinarySource", "FileSource", "PropertySource")); | ||
15482 | } | ||
15483 | |||
15484 | if (!this.Core.EncounteredError) | ||
15485 | { | ||
15486 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiEmbeddedChainer, id); | ||
15487 | row.Set(1, condition); | ||
15488 | row.Set(2, commandLine); | ||
15489 | row.Set(3, source); | ||
15490 | row.Set(4, type); | ||
15491 | } | ||
15492 | } | ||
15493 | |||
15494 | /// <summary> | ||
15495 | /// Parses UI elements. | ||
15496 | /// </summary> | ||
15497 | /// <param name="node">Element to parse.</param> | ||
15498 | private void ParseUIElement(XElement node) | ||
15499 | { | ||
15500 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15501 | Identifier id = null; | ||
15502 | var embeddedUICount = 0; | ||
15503 | |||
15504 | foreach (var attrib in node.Attributes()) | ||
15505 | { | ||
15506 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15507 | { | ||
15508 | switch (attrib.Name.LocalName) | ||
15509 | { | ||
15510 | case "Id": | ||
15511 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15512 | break; | ||
15513 | default: | ||
15514 | this.Core.UnexpectedAttribute(node, attrib); | ||
15515 | break; | ||
15516 | } | ||
15517 | } | ||
15518 | else | ||
15519 | { | ||
15520 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15521 | } | ||
15522 | } | ||
15523 | |||
15524 | foreach (var child in node.Elements()) | ||
15525 | { | ||
15526 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15527 | { | ||
15528 | switch (child.Name.LocalName) | ||
15529 | { | ||
15530 | case "BillboardAction": | ||
15531 | this.ParseBillboardActionElement(child); | ||
15532 | break; | ||
15533 | case "ComboBox": | ||
15534 | this.ParseControlGroupElement(child, TupleDefinitionType.ComboBox, "ListItem"); | ||
15535 | break; | ||
15536 | case "Dialog": | ||
15537 | this.ParseDialogElement(child); | ||
15538 | break; | ||
15539 | case "DialogRef": | ||
15540 | this.ParseSimpleRefElement(child, "Dialog"); | ||
15541 | break; | ||
15542 | case "EmbeddedUI": | ||
15543 | if (0 < embeddedUICount) // there can be only one embedded UI | ||
15544 | { | ||
15545 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
15546 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
15547 | } | ||
15548 | this.ParseEmbeddedUIElement(child); | ||
15549 | ++embeddedUICount; | ||
15550 | break; | ||
15551 | case "Error": | ||
15552 | this.ParseErrorElement(child); | ||
15553 | break; | ||
15554 | case "ListBox": | ||
15555 | this.ParseControlGroupElement(child, TupleDefinitionType.ListBox, "ListItem"); | ||
15556 | break; | ||
15557 | case "ListView": | ||
15558 | this.ParseControlGroupElement(child, TupleDefinitionType.ListView, "ListItem"); | ||
15559 | break; | ||
15560 | case "ProgressText": | ||
15561 | this.ParseActionTextElement(child); | ||
15562 | break; | ||
15563 | case "Publish": | ||
15564 | var order = 0; | ||
15565 | this.ParsePublishElement(child, null, null, ref order); | ||
15566 | break; | ||
15567 | case "RadioButtonGroup": | ||
15568 | var radioButtonType = this.ParseRadioButtonGroupElement(child, null, RadioButtonType.NotSet); | ||
15569 | if (RadioButtonType.Bitmap == radioButtonType || RadioButtonType.Icon == radioButtonType) | ||
15570 | { | ||
15571 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
15572 | this.Core.Write(ErrorMessages.RadioButtonBitmapAndIconDisallowed(childSourceLineNumbers)); | ||
15573 | } | ||
15574 | break; | ||
15575 | case "TextStyle": | ||
15576 | this.ParseTextStyleElement(child); | ||
15577 | break; | ||
15578 | case "UIText": | ||
15579 | this.ParseUITextElement(child); | ||
15580 | break; | ||
15581 | |||
15582 | // the following are available indentically under the UI and Product elements for document organization use only | ||
15583 | case "AdminUISequence": | ||
15584 | case "InstallUISequence": | ||
15585 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
15586 | break; | ||
15587 | case "Binary": | ||
15588 | this.ParseBinaryElement(child); | ||
15589 | break; | ||
15590 | case "Property": | ||
15591 | this.ParsePropertyElement(child); | ||
15592 | break; | ||
15593 | case "PropertyRef": | ||
15594 | this.ParseSimpleRefElement(child, "Property"); | ||
15595 | break; | ||
15596 | case "UIRef": | ||
15597 | this.ParseSimpleRefElement(child, "WixUI"); | ||
15598 | break; | ||
15599 | |||
15600 | default: | ||
15601 | this.Core.UnexpectedElement(node, child); | ||
15602 | break; | ||
15603 | } | ||
15604 | } | ||
15605 | else | ||
15606 | { | ||
15607 | this.Core.ParseExtensionElement(node, child); | ||
15608 | } | ||
15609 | } | ||
15610 | |||
15611 | if (null != id && !this.Core.EncounteredError) | ||
15612 | { | ||
15613 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixUI, id); | ||
15614 | } | ||
15615 | } | ||
15616 | |||
15617 | /// <summary> | ||
15618 | /// Parses a list item element. | ||
15619 | /// </summary> | ||
15620 | /// <param name="node">Element to parse.</param> | ||
15621 | /// <param name="table">Table to add row to.</param> | ||
15622 | /// <param name="property">Identifier of property referred to by list item.</param> | ||
15623 | /// <param name="order">Relative order of list items.</param> | ||
15624 | private void ParseListItemElement(XElement node, TupleDefinitionType tableName, string property, ref int order) | ||
15625 | { | ||
15626 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15627 | string icon = null; | ||
15628 | string text = null; | ||
15629 | string value = null; | ||
15630 | |||
15631 | foreach (var attrib in node.Attributes()) | ||
15632 | { | ||
15633 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15634 | { | ||
15635 | switch (attrib.Name.LocalName) | ||
15636 | { | ||
15637 | case "Icon": | ||
15638 | if (TupleDefinitionType.ListView == tableName) | ||
15639 | { | ||
15640 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15641 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", icon); | ||
15642 | } | ||
15643 | else | ||
15644 | { | ||
15645 | this.Core.Write(ErrorMessages.IllegalAttributeExceptOnElement(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ListView")); | ||
15646 | } | ||
15647 | break; | ||
15648 | case "Text": | ||
15649 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15650 | break; | ||
15651 | case "Value": | ||
15652 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15653 | break; | ||
15654 | default: | ||
15655 | this.Core.UnexpectedAttribute(node, attrib); | ||
15656 | break; | ||
15657 | } | ||
15658 | } | ||
15659 | else | ||
15660 | { | ||
15661 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15662 | } | ||
15663 | } | ||
15664 | |||
15665 | if (null == value) | ||
15666 | { | ||
15667 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15668 | } | ||
15669 | |||
15670 | this.Core.ParseForExtensionElements(node); | ||
15671 | |||
15672 | if (!this.Core.EncounteredError) | ||
15673 | { | ||
15674 | var row = this.Core.CreateRow(sourceLineNumbers, tableName); | ||
15675 | row.Set(0, property); | ||
15676 | row.Set(1, ++order); | ||
15677 | row.Set(2, value); | ||
15678 | row.Set(3, text); | ||
15679 | if (null != icon) | ||
15680 | { | ||
15681 | row.Set(4, icon); | ||
15682 | } | ||
15683 | } | ||
15684 | } | ||
15685 | |||
15686 | /// <summary> | ||
15687 | /// Parses a radio button element. | ||
15688 | /// </summary> | ||
15689 | /// <param name="node">Element to parse.</param> | ||
15690 | /// <param name="property">Identifier of property referred to by radio button.</param> | ||
15691 | /// <param name="order">Relative order of radio buttons.</param> | ||
15692 | /// <returns>Type of this radio button.</returns> | ||
15693 | private RadioButtonType ParseRadioButtonElement(XElement node, string property, ref int order) | ||
15694 | { | ||
15695 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15696 | var type = RadioButtonType.NotSet; | ||
15697 | string value = null; | ||
15698 | string x = null; | ||
15699 | string y = null; | ||
15700 | string width = null; | ||
15701 | string height = null; | ||
15702 | string text = null; | ||
15703 | string tooltip = null; | ||
15704 | string help = null; | ||
15705 | |||
15706 | foreach (var attrib in node.Attributes()) | ||
15707 | { | ||
15708 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15709 | { | ||
15710 | switch (attrib.Name.LocalName) | ||
15711 | { | ||
15712 | case "Bitmap": | ||
15713 | if (RadioButtonType.NotSet != type) | ||
15714 | { | ||
15715 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Icon", "Text")); | ||
15716 | } | ||
15717 | text = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15718 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
15719 | type = RadioButtonType.Bitmap; | ||
15720 | break; | ||
15721 | case "Height": | ||
15722 | height = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
15723 | break; | ||
15724 | case "Help": | ||
15725 | help = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15726 | break; | ||
15727 | case "Icon": | ||
15728 | if (RadioButtonType.NotSet != type) | ||
15729 | { | ||
15730 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Text")); | ||
15731 | } | ||
15732 | text = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15733 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
15734 | type = RadioButtonType.Icon; | ||
15735 | break; | ||
15736 | case "Text": | ||
15737 | if (RadioButtonType.NotSet != type) | ||
15738 | { | ||
15739 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Icon")); | ||
15740 | } | ||
15741 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15742 | type = RadioButtonType.Text; | ||
15743 | break; | ||
15744 | case "ToolTip": | ||
15745 | tooltip = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15746 | break; | ||
15747 | case "Value": | ||
15748 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15749 | break; | ||
15750 | case "Width": | ||
15751 | width = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
15752 | break; | ||
15753 | case "X": | ||
15754 | x = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
15755 | break; | ||
15756 | case "Y": | ||
15757 | y = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
15758 | break; | ||
15759 | default: | ||
15760 | this.Core.UnexpectedAttribute(node, attrib); | ||
15761 | break; | ||
15762 | } | ||
15763 | } | ||
15764 | else | ||
15765 | { | ||
15766 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15767 | } | ||
15768 | } | ||
15769 | |||
15770 | if (null == value) | ||
15771 | { | ||
15772 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15773 | } | ||
15774 | |||
15775 | if (null == x) | ||
15776 | { | ||
15777 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X")); | ||
15778 | } | ||
15779 | |||
15780 | if (null == y) | ||
15781 | { | ||
15782 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y")); | ||
15783 | } | ||
15784 | |||
15785 | if (null == width) | ||
15786 | { | ||
15787 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width")); | ||
15788 | } | ||
15789 | |||
15790 | if (null == height) | ||
15791 | { | ||
15792 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height")); | ||
15793 | } | ||
15794 | |||
15795 | this.Core.ParseForExtensionElements(node); | ||
15796 | |||
15797 | if (!this.Core.EncounteredError) | ||
15798 | { | ||
15799 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RadioButton); | ||
15800 | row.Set(0, property); | ||
15801 | row.Set(1, ++order); | ||
15802 | row.Set(2, value); | ||
15803 | row.Set(3, x); | ||
15804 | row.Set(4, y); | ||
15805 | row.Set(5, width); | ||
15806 | row.Set(6, height); | ||
15807 | row.Set(7, text); | ||
15808 | if (null != tooltip || null != help) | ||
15809 | { | ||
15810 | row.Set(8, String.Concat(tooltip, "|", help)); | ||
15811 | } | ||
15812 | } | ||
15813 | |||
15814 | return type; | ||
15815 | } | ||
15816 | |||
15817 | /// <summary> | ||
15818 | /// Parses a billboard element. | ||
15819 | /// </summary> | ||
15820 | /// <param name="node">Element to parse.</param> | ||
15821 | private void ParseBillboardActionElement(XElement node) | ||
15822 | { | ||
15823 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15824 | string action = null; | ||
15825 | var order = 0; | ||
15826 | |||
15827 | foreach (var attrib in node.Attributes()) | ||
15828 | { | ||
15829 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15830 | { | ||
15831 | switch (attrib.Name.LocalName) | ||
15832 | { | ||
15833 | case "Id": | ||
15834 | action = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15835 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", action); | ||
15836 | break; | ||
15837 | default: | ||
15838 | this.Core.UnexpectedAttribute(node, attrib); | ||
15839 | break; | ||
15840 | } | ||
15841 | } | ||
15842 | else | ||
15843 | { | ||
15844 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15845 | } | ||
15846 | } | ||
15847 | |||
15848 | if (null == action) | ||
15849 | { | ||
15850 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
15851 | } | ||
15852 | |||
15853 | foreach (var child in node.Elements()) | ||
15854 | { | ||
15855 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15856 | { | ||
15857 | switch (child.Name.LocalName) | ||
15858 | { | ||
15859 | case "Billboard": | ||
15860 | order = order + 1; | ||
15861 | this.ParseBillboardElement(child, action, order); | ||
15862 | break; | ||
15863 | default: | ||
15864 | this.Core.UnexpectedElement(node, child); | ||
15865 | break; | ||
15866 | } | ||
15867 | } | ||
15868 | else | ||
15869 | { | ||
15870 | this.Core.ParseExtensionElement(node, child); | ||
15871 | } | ||
15872 | } | ||
15873 | } | ||
15874 | |||
15875 | /// <summary> | ||
15876 | /// Parses a billboard element. | ||
15877 | /// </summary> | ||
15878 | /// <param name="node">Element to parse.</param> | ||
15879 | /// <param name="action">Action for the billboard.</param> | ||
15880 | /// <param name="order">Order of the billboard.</param> | ||
15881 | private void ParseBillboardElement(XElement node, string action, int order) | ||
15882 | { | ||
15883 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15884 | Identifier id = null; | ||
15885 | string feature = null; | ||
15886 | |||
15887 | foreach (var attrib in node.Attributes()) | ||
15888 | { | ||
15889 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15890 | { | ||
15891 | switch (attrib.Name.LocalName) | ||
15892 | { | ||
15893 | case "Id": | ||
15894 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15895 | break; | ||
15896 | case "Feature": | ||
15897 | feature = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15898 | this.Core.CreateSimpleReference(sourceLineNumbers, "Feature", feature); | ||
15899 | break; | ||
15900 | default: | ||
15901 | this.Core.UnexpectedAttribute(node, attrib); | ||
15902 | break; | ||
15903 | } | ||
15904 | } | ||
15905 | else | ||
15906 | { | ||
15907 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15908 | } | ||
15909 | } | ||
15910 | |||
15911 | if (null == id) | ||
15912 | { | ||
15913 | id = this.Core.CreateIdentifier("bil", action, order.ToString(), feature); | ||
15914 | } | ||
15915 | |||
15916 | foreach (var child in node.Elements()) | ||
15917 | { | ||
15918 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15919 | { | ||
15920 | switch (child.Name.LocalName) | ||
15921 | { | ||
15922 | case "Control": | ||
15923 | // These are all thrown away. | ||
15924 | IntermediateTuple lastTabRow = null; | ||
15925 | string firstControl = null; | ||
15926 | string defaultControl = null; | ||
15927 | string cancelControl = null; | ||
15928 | |||
15929 | this.ParseControlElement(child, id.Id, TupleDefinitionType.BBControl, ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, false); | ||
15930 | break; | ||
15931 | default: | ||
15932 | this.Core.UnexpectedElement(node, child); | ||
15933 | break; | ||
15934 | } | ||
15935 | } | ||
15936 | else | ||
15937 | { | ||
15938 | this.Core.ParseExtensionElement(node, child); | ||
15939 | } | ||
15940 | } | ||
15941 | |||
15942 | |||
15943 | if (!this.Core.EncounteredError) | ||
15944 | { | ||
15945 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Billboard, id); | ||
15946 | row.Set(1, feature); | ||
15947 | row.Set(2, action); | ||
15948 | row.Set(3, order); | ||
15949 | } | ||
15950 | } | ||
15951 | |||
15952 | /// <summary> | ||
15953 | /// Parses a control group element. | ||
15954 | /// </summary> | ||
15955 | /// <param name="node">Element to parse.</param> | ||
15956 | /// <param name="table">Table referred to by control group.</param> | ||
15957 | /// <param name="childTag">Expected child elements.</param> | ||
15958 | private void ParseControlGroupElement(XElement node, TupleDefinitionType tableName, string childTag) | ||
15959 | { | ||
15960 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15961 | var order = 0; | ||
15962 | string property = null; | ||
15963 | |||
15964 | foreach (var attrib in node.Attributes()) | ||
15965 | { | ||
15966 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15967 | { | ||
15968 | switch (attrib.Name.LocalName) | ||
15969 | { | ||
15970 | case "Property": | ||
15971 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15972 | break; | ||
15973 | default: | ||
15974 | this.Core.UnexpectedAttribute(node, attrib); | ||
15975 | break; | ||
15976 | } | ||
15977 | } | ||
15978 | else | ||
15979 | { | ||
15980 | this.Core.ParseExtensionAttribute(node, attrib); | ||
15981 | } | ||
15982 | } | ||
15983 | |||
15984 | if (null == property) | ||
15985 | { | ||
15986 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
15987 | } | ||
15988 | |||
15989 | foreach (var child in node.Elements()) | ||
15990 | { | ||
15991 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15992 | { | ||
15993 | if (childTag != child.Name.LocalName) | ||
15994 | { | ||
15995 | this.Core.UnexpectedElement(node, child); | ||
15996 | } | ||
15997 | |||
15998 | switch (child.Name.LocalName) | ||
15999 | { | ||
16000 | case "ListItem": | ||
16001 | this.ParseListItemElement(child, tableName, property, ref order); | ||
16002 | break; | ||
16003 | case "Property": | ||
16004 | this.ParsePropertyElement(child); | ||
16005 | break; | ||
16006 | default: | ||
16007 | this.Core.UnexpectedElement(node, child); | ||
16008 | break; | ||
16009 | } | ||
16010 | } | ||
16011 | else | ||
16012 | { | ||
16013 | this.Core.ParseExtensionElement(node, child); | ||
16014 | } | ||
16015 | } | ||
16016 | |||
16017 | } | ||
16018 | |||
16019 | /// <summary> | ||
16020 | /// Parses a radio button control group element. | ||
16021 | /// </summary> | ||
16022 | /// <param name="node">Element to parse.</param> | ||
16023 | /// <param name="property">Property associated with this radio button group.</param> | ||
16024 | /// <param name="groupType">Specifies the current type of radio buttons in the group.</param> | ||
16025 | /// <returns>The current type of radio buttons in the group.</returns> | ||
16026 | private RadioButtonType ParseRadioButtonGroupElement(XElement node, string property, RadioButtonType groupType) | ||
16027 | { | ||
16028 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16029 | var order = 0; | ||
16030 | |||
16031 | foreach (var attrib in node.Attributes()) | ||
16032 | { | ||
16033 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16034 | { | ||
16035 | switch (attrib.Name.LocalName) | ||
16036 | { | ||
16037 | case "Property": | ||
16038 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
16039 | this.Core.CreateSimpleReference(sourceLineNumbers, "Property", property); | ||
16040 | break; | ||
16041 | default: | ||
16042 | this.Core.UnexpectedAttribute(node, attrib); | ||
16043 | break; | ||
16044 | } | ||
16045 | } | ||
16046 | else | ||
16047 | { | ||
16048 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16049 | } | ||
16050 | } | ||
16051 | |||
16052 | if (null == property) | ||
16053 | { | ||
16054 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
16055 | } | ||
16056 | |||
16057 | foreach (var child in node.Elements()) | ||
16058 | { | ||
16059 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16060 | { | ||
16061 | switch (child.Name.LocalName) | ||
16062 | { | ||
16063 | case "RadioButton": | ||
16064 | var type = this.ParseRadioButtonElement(child, property, ref order); | ||
16065 | if (RadioButtonType.NotSet == groupType) | ||
16066 | { | ||
16067 | groupType = type; | ||
16068 | } | ||
16069 | else if (groupType != type) | ||
16070 | { | ||
16071 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
16072 | this.Core.Write(ErrorMessages.RadioButtonTypeInconsistent(childSourceLineNumbers)); | ||
16073 | } | ||
16074 | break; | ||
16075 | default: | ||
16076 | this.Core.UnexpectedElement(node, child); | ||
16077 | break; | ||
16078 | } | ||
16079 | } | ||
16080 | else | ||
16081 | { | ||
16082 | this.Core.ParseExtensionElement(node, child); | ||
16083 | } | ||
16084 | } | ||
16085 | |||
16086 | |||
16087 | return groupType; | ||
16088 | } | ||
16089 | |||
16090 | /// <summary> | ||
16091 | /// Parses an action text element. | ||
16092 | /// </summary> | ||
16093 | /// <param name="node">Element to parse.</param> | ||
16094 | private void ParseActionTextElement(XElement node) | ||
16095 | { | ||
16096 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16097 | string action = null; | ||
16098 | string template = null; | ||
16099 | |||
16100 | foreach (var attrib in node.Attributes()) | ||
16101 | { | ||
16102 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16103 | { | ||
16104 | switch (attrib.Name.LocalName) | ||
16105 | { | ||
16106 | case "Action": | ||
16107 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16108 | break; | ||
16109 | case "Template": | ||
16110 | template = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16111 | break; | ||
16112 | default: | ||
16113 | this.Core.UnexpectedAttribute(node, attrib); | ||
16114 | break; | ||
16115 | } | ||
16116 | } | ||
16117 | else | ||
16118 | { | ||
16119 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16120 | } | ||
16121 | } | ||
16122 | |||
16123 | if (null == action) | ||
16124 | { | ||
16125 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
16126 | } | ||
16127 | |||
16128 | this.Core.ParseForExtensionElements(node); | ||
16129 | |||
16130 | if (!this.Core.EncounteredError) | ||
16131 | { | ||
16132 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ActionText); | ||
16133 | row.Set(0, action); | ||
16134 | row.Set(1, Common.GetInnerText(node)); | ||
16135 | row.Set(2, template); | ||
16136 | } | ||
16137 | } | ||
16138 | |||
16139 | /// <summary> | ||
16140 | /// Parses an ui text element. | ||
16141 | /// </summary> | ||
16142 | /// <param name="node">Element to parse.</param> | ||
16143 | private void ParseUITextElement(XElement node) | ||
16144 | { | ||
16145 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16146 | Identifier id = null; | ||
16147 | string text = null; | ||
16148 | |||
16149 | foreach (var attrib in node.Attributes()) | ||
16150 | { | ||
16151 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16152 | { | ||
16153 | switch (attrib.Name.LocalName) | ||
16154 | { | ||
16155 | case "Id": | ||
16156 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16157 | break; | ||
16158 | default: | ||
16159 | this.Core.UnexpectedAttribute(node, attrib); | ||
16160 | break; | ||
16161 | } | ||
16162 | } | ||
16163 | else | ||
16164 | { | ||
16165 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16166 | } | ||
16167 | } | ||
16168 | |||
16169 | text = Common.GetInnerText(node); | ||
16170 | |||
16171 | if (null == id) | ||
16172 | { | ||
16173 | id = this.Core.CreateIdentifier("txt", text); | ||
16174 | } | ||
16175 | |||
16176 | this.Core.ParseForExtensionElements(node); | ||
16177 | |||
16178 | if (!this.Core.EncounteredError) | ||
16179 | { | ||
16180 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.UIText, id); | ||
16181 | row.Set(1, text); | ||
16182 | } | ||
16183 | } | ||
16184 | |||
16185 | /// <summary> | ||
16186 | /// Parses a text style element. | ||
16187 | /// </summary> | ||
16188 | /// <param name="node">Element to parse.</param> | ||
16189 | private void ParseTextStyleElement(XElement node) | ||
16190 | { | ||
16191 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16192 | Identifier id = null; | ||
16193 | var bits = 0; | ||
16194 | var color = CompilerConstants.IntegerNotSet; | ||
16195 | string faceName = null; | ||
16196 | var size = "0"; | ||
16197 | |||
16198 | foreach (var attrib in node.Attributes()) | ||
16199 | { | ||
16200 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16201 | { | ||
16202 | switch (attrib.Name.LocalName) | ||
16203 | { | ||
16204 | case "Id": | ||
16205 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16206 | break; | ||
16207 | |||
16208 | // RGB Values | ||
16209 | case "Red": | ||
16210 | var redColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
16211 | if (CompilerConstants.IllegalInteger != redColor) | ||
16212 | { | ||
16213 | if (CompilerConstants.IntegerNotSet == color) | ||
16214 | { | ||
16215 | color = redColor; | ||
16216 | } | ||
16217 | else | ||
16218 | { | ||
16219 | color += redColor; | ||
16220 | } | ||
16221 | } | ||
16222 | break; | ||
16223 | case "Green": | ||
16224 | var greenColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
16225 | if (CompilerConstants.IllegalInteger != greenColor) | ||
16226 | { | ||
16227 | if (CompilerConstants.IntegerNotSet == color) | ||
16228 | { | ||
16229 | color = greenColor * 256; | ||
16230 | } | ||
16231 | else | ||
16232 | { | ||
16233 | color += greenColor * 256; | ||
16234 | } | ||
16235 | } | ||
16236 | break; | ||
16237 | case "Blue": | ||
16238 | var blueColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
16239 | if (CompilerConstants.IllegalInteger != blueColor) | ||
16240 | { | ||
16241 | if (CompilerConstants.IntegerNotSet == color) | ||
16242 | { | ||
16243 | color = blueColor * 65536; | ||
16244 | } | ||
16245 | else | ||
16246 | { | ||
16247 | color += blueColor * 65536; | ||
16248 | } | ||
16249 | } | ||
16250 | break; | ||
16251 | |||
16252 | // Style values | ||
16253 | case "Bold": | ||
16254 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16255 | { | ||
16256 | bits |= MsiInterop.MsidbTextStyleStyleBitsBold; | ||
16257 | } | ||
16258 | break; | ||
16259 | case "Italic": | ||
16260 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16261 | { | ||
16262 | bits |= MsiInterop.MsidbTextStyleStyleBitsItalic; | ||
16263 | } | ||
16264 | break; | ||
16265 | case "Strike": | ||
16266 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16267 | { | ||
16268 | bits |= MsiInterop.MsidbTextStyleStyleBitsStrike; | ||
16269 | } | ||
16270 | break; | ||
16271 | case "Underline": | ||
16272 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16273 | { | ||
16274 | bits |= MsiInterop.MsidbTextStyleStyleBitsUnderline; | ||
16275 | } | ||
16276 | break; | ||
16277 | |||
16278 | // Font values | ||
16279 | case "FaceName": | ||
16280 | faceName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16281 | break; | ||
16282 | case "Size": | ||
16283 | size = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16284 | break; | ||
16285 | |||
16286 | default: | ||
16287 | this.Core.UnexpectedAttribute(node, attrib); | ||
16288 | break; | ||
16289 | } | ||
16290 | } | ||
16291 | else | ||
16292 | { | ||
16293 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16294 | } | ||
16295 | } | ||
16296 | |||
16297 | if (null == id) | ||
16298 | { | ||
16299 | this.Core.CreateIdentifier("txs", faceName, size.ToString(), color.ToString(), bits.ToString()); | ||
16300 | } | ||
16301 | |||
16302 | if (null == faceName) | ||
16303 | { | ||
16304 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "FaceName")); | ||
16305 | } | ||
16306 | |||
16307 | this.Core.ParseForExtensionElements(node); | ||
16308 | |||
16309 | if (!this.Core.EncounteredError) | ||
16310 | { | ||
16311 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.TextStyle, id); | ||
16312 | row.Set(1, faceName); | ||
16313 | row.Set(2, size); | ||
16314 | if (0 <= color) | ||
16315 | { | ||
16316 | row.Set(3, color); | ||
16317 | } | ||
16318 | |||
16319 | if (0 < bits) | ||
16320 | { | ||
16321 | row.Set(4, bits); | ||
16322 | } | ||
16323 | } | ||
16324 | } | ||
16325 | |||
16326 | /// <summary> | ||
16327 | /// Parses a dialog element. | ||
16328 | /// </summary> | ||
16329 | /// <param name="node">Element to parse.</param> | ||
16330 | private void ParseDialogElement(XElement node) | ||
16331 | { | ||
16332 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16333 | Identifier id = null; | ||
16334 | var bits = MsiInterop.MsidbDialogAttributesVisible | MsiInterop.MsidbDialogAttributesModal | MsiInterop.MsidbDialogAttributesMinimize; | ||
16335 | var height = 0; | ||
16336 | string title = null; | ||
16337 | var trackDiskSpace = false; | ||
16338 | var width = 0; | ||
16339 | var x = 50; | ||
16340 | var y = 50; | ||
16341 | |||
16342 | foreach (var attrib in node.Attributes()) | ||
16343 | { | ||
16344 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16345 | { | ||
16346 | switch (attrib.Name.LocalName) | ||
16347 | { | ||
16348 | case "Id": | ||
16349 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16350 | break; | ||
16351 | case "Height": | ||
16352 | height = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
16353 | break; | ||
16354 | case "Title": | ||
16355 | title = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16356 | break; | ||
16357 | case "Width": | ||
16358 | width = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
16359 | break; | ||
16360 | case "X": | ||
16361 | x = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100); | ||
16362 | break; | ||
16363 | case "Y": | ||
16364 | y = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100); | ||
16365 | break; | ||
16366 | |||
16367 | case "CustomPalette": | ||
16368 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16369 | { | ||
16370 | bits ^= MsiInterop.MsidbDialogAttributesUseCustomPalette; | ||
16371 | } | ||
16372 | break; | ||
16373 | case "ErrorDialog": | ||
16374 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16375 | { | ||
16376 | bits ^= MsiInterop.MsidbDialogAttributesError; | ||
16377 | } | ||
16378 | break; | ||
16379 | case "Hidden": | ||
16380 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16381 | { | ||
16382 | bits ^= MsiInterop.MsidbDialogAttributesVisible; | ||
16383 | } | ||
16384 | break; | ||
16385 | case "KeepModeless": | ||
16386 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16387 | { | ||
16388 | bits ^= MsiInterop.MsidbDialogAttributesKeepModeless; | ||
16389 | } | ||
16390 | break; | ||
16391 | case "LeftScroll": | ||
16392 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16393 | { | ||
16394 | bits ^= MsiInterop.MsidbDialogAttributesLeftScroll; | ||
16395 | } | ||
16396 | break; | ||
16397 | case "Modeless": | ||
16398 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16399 | { | ||
16400 | bits ^= MsiInterop.MsidbDialogAttributesModal; | ||
16401 | } | ||
16402 | break; | ||
16403 | case "NoMinimize": | ||
16404 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16405 | { | ||
16406 | bits ^= MsiInterop.MsidbDialogAttributesMinimize; | ||
16407 | } | ||
16408 | break; | ||
16409 | case "RightAligned": | ||
16410 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16411 | { | ||
16412 | bits ^= MsiInterop.MsidbDialogAttributesRightAligned; | ||
16413 | } | ||
16414 | break; | ||
16415 | case "RightToLeft": | ||
16416 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16417 | { | ||
16418 | bits ^= MsiInterop.MsidbDialogAttributesRTLRO; | ||
16419 | } | ||
16420 | break; | ||
16421 | case "SystemModal": | ||
16422 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16423 | { | ||
16424 | bits ^= MsiInterop.MsidbDialogAttributesSysModal; | ||
16425 | } | ||
16426 | break; | ||
16427 | case "TrackDiskSpace": | ||
16428 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16429 | { | ||
16430 | bits ^= MsiInterop.MsidbDialogAttributesTrackDiskSpace; | ||
16431 | trackDiskSpace = true; | ||
16432 | } | ||
16433 | break; | ||
16434 | |||
16435 | default: | ||
16436 | this.Core.UnexpectedAttribute(node, attrib); | ||
16437 | break; | ||
16438 | } | ||
16439 | } | ||
16440 | else | ||
16441 | { | ||
16442 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16443 | } | ||
16444 | } | ||
16445 | |||
16446 | if (null == id) | ||
16447 | { | ||
16448 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
16449 | id = Identifier.Invalid; | ||
16450 | } | ||
16451 | |||
16452 | IntermediateTuple lastTabRow = null; | ||
16453 | string cancelControl = null; | ||
16454 | string defaultControl = null; | ||
16455 | string firstControl = null; | ||
16456 | |||
16457 | foreach (var child in node.Elements()) | ||
16458 | { | ||
16459 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16460 | { | ||
16461 | switch (child.Name.LocalName) | ||
16462 | { | ||
16463 | case "Control": | ||
16464 | this.ParseControlElement(child, id.Id, TupleDefinitionType.Control, ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, trackDiskSpace); | ||
16465 | break; | ||
16466 | default: | ||
16467 | this.Core.UnexpectedElement(node, child); | ||
16468 | break; | ||
16469 | } | ||
16470 | } | ||
16471 | else | ||
16472 | { | ||
16473 | this.Core.ParseExtensionElement(node, child); | ||
16474 | } | ||
16475 | } | ||
16476 | |||
16477 | |||
16478 | if (null != lastTabRow && null != lastTabRow[1]) | ||
16479 | { | ||
16480 | if (firstControl != lastTabRow[1].ToString()) | ||
16481 | { | ||
16482 | lastTabRow.Set(10, firstControl); | ||
16483 | } | ||
16484 | } | ||
16485 | |||
16486 | if (null == firstControl) | ||
16487 | { | ||
16488 | this.Core.Write(ErrorMessages.NoFirstControlSpecified(sourceLineNumbers, id.Id)); | ||
16489 | } | ||
16490 | |||
16491 | if (!this.Core.EncounteredError) | ||
16492 | { | ||
16493 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Dialog, id); | ||
16494 | row.Set(1, x); | ||
16495 | row.Set(2, y); | ||
16496 | row.Set(3, width); | ||
16497 | row.Set(4, height); | ||
16498 | row.Set(5, bits); | ||
16499 | row.Set(6, title); | ||
16500 | row.Set(7, firstControl); | ||
16501 | row.Set(8, defaultControl); | ||
16502 | row.Set(9, cancelControl); | ||
16503 | } | ||
16504 | } | ||
16505 | |||
16506 | /// <summary> | ||
16507 | /// Parses an EmbeddedUI element. | ||
16508 | /// </summary> | ||
16509 | /// <param name="node">Element to parse.</param> | ||
16510 | private void ParseEmbeddedUIElement(XElement node) | ||
16511 | { | ||
16512 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16513 | Identifier id = null; | ||
16514 | string name = null; | ||
16515 | var attributes = MsiInterop.MsidbEmbeddedUI; // by default this is the primary DLL that does not support basic UI. | ||
16516 | var messageFilter = MsiInterop.INSTALLLOGMODE_FATALEXIT | MsiInterop.INSTALLLOGMODE_ERROR | MsiInterop.INSTALLLOGMODE_WARNING | MsiInterop.INSTALLLOGMODE_USER | ||
16517 | | MsiInterop.INSTALLLOGMODE_INFO | MsiInterop.INSTALLLOGMODE_FILESINUSE | MsiInterop.INSTALLLOGMODE_RESOLVESOURCE | ||
16518 | | MsiInterop.INSTALLLOGMODE_OUTOFDISKSPACE | MsiInterop.INSTALLLOGMODE_ACTIONSTART | MsiInterop.INSTALLLOGMODE_ACTIONDATA | ||
16519 | | MsiInterop.INSTALLLOGMODE_PROGRESS | MsiInterop.INSTALLLOGMODE_COMMONDATA | MsiInterop.INSTALLLOGMODE_INITIALIZE | ||
16520 | | MsiInterop.INSTALLLOGMODE_TERMINATE | MsiInterop.INSTALLLOGMODE_SHOWDIALOG | MsiInterop.INSTALLLOGMODE_RMFILESINUSE | ||
16521 | | MsiInterop.INSTALLLOGMODE_INSTALLSTART | MsiInterop.INSTALLLOGMODE_INSTALLEND; | ||
16522 | string sourceFile = null; | ||
16523 | |||
16524 | foreach (var attrib in node.Attributes()) | ||
16525 | { | ||
16526 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16527 | { | ||
16528 | switch (attrib.Name.LocalName) | ||
16529 | { | ||
16530 | case "Id": | ||
16531 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16532 | break; | ||
16533 | case "Name": | ||
16534 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
16535 | break; | ||
16536 | case "IgnoreFatalExit": | ||
16537 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16538 | { | ||
16539 | messageFilter ^= MsiInterop.INSTALLLOGMODE_FATALEXIT; | ||
16540 | } | ||
16541 | break; | ||
16542 | case "IgnoreError": | ||
16543 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16544 | { | ||
16545 | messageFilter ^= MsiInterop.INSTALLLOGMODE_ERROR; | ||
16546 | } | ||
16547 | break; | ||
16548 | case "IgnoreWarning": | ||
16549 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16550 | { | ||
16551 | messageFilter ^= MsiInterop.INSTALLLOGMODE_WARNING; | ||
16552 | } | ||
16553 | break; | ||
16554 | case "IgnoreUser": | ||
16555 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16556 | { | ||
16557 | messageFilter ^= MsiInterop.INSTALLLOGMODE_USER; | ||
16558 | } | ||
16559 | break; | ||
16560 | case "IgnoreInfo": | ||
16561 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16562 | { | ||
16563 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INFO; | ||
16564 | } | ||
16565 | break; | ||
16566 | case "IgnoreFilesInUse": | ||
16567 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16568 | { | ||
16569 | messageFilter ^= MsiInterop.INSTALLLOGMODE_FILESINUSE; | ||
16570 | } | ||
16571 | break; | ||
16572 | case "IgnoreResolveSource": | ||
16573 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16574 | { | ||
16575 | messageFilter ^= MsiInterop.INSTALLLOGMODE_RESOLVESOURCE; | ||
16576 | } | ||
16577 | break; | ||
16578 | case "IgnoreOutOfDiskSpace": | ||
16579 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16580 | { | ||
16581 | messageFilter ^= MsiInterop.INSTALLLOGMODE_OUTOFDISKSPACE; | ||
16582 | } | ||
16583 | break; | ||
16584 | case "IgnoreActionStart": | ||
16585 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16586 | { | ||
16587 | messageFilter ^= MsiInterop.INSTALLLOGMODE_ACTIONSTART; | ||
16588 | } | ||
16589 | break; | ||
16590 | case "IgnoreActionData": | ||
16591 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16592 | { | ||
16593 | messageFilter ^= MsiInterop.INSTALLLOGMODE_ACTIONDATA; | ||
16594 | } | ||
16595 | break; | ||
16596 | case "IgnoreProgress": | ||
16597 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16598 | { | ||
16599 | messageFilter ^= MsiInterop.INSTALLLOGMODE_PROGRESS; | ||
16600 | } | ||
16601 | break; | ||
16602 | case "IgnoreCommonData": | ||
16603 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16604 | { | ||
16605 | messageFilter ^= MsiInterop.INSTALLLOGMODE_COMMONDATA; | ||
16606 | } | ||
16607 | break; | ||
16608 | case "IgnoreInitialize": | ||
16609 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16610 | { | ||
16611 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INITIALIZE; | ||
16612 | } | ||
16613 | break; | ||
16614 | case "IgnoreTerminate": | ||
16615 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16616 | { | ||
16617 | messageFilter ^= MsiInterop.INSTALLLOGMODE_TERMINATE; | ||
16618 | } | ||
16619 | break; | ||
16620 | case "IgnoreShowDialog": | ||
16621 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16622 | { | ||
16623 | messageFilter ^= MsiInterop.INSTALLLOGMODE_SHOWDIALOG; | ||
16624 | } | ||
16625 | break; | ||
16626 | case "IgnoreRMFilesInUse": | ||
16627 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16628 | { | ||
16629 | messageFilter ^= MsiInterop.INSTALLLOGMODE_RMFILESINUSE; | ||
16630 | } | ||
16631 | break; | ||
16632 | case "IgnoreInstallStart": | ||
16633 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16634 | { | ||
16635 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INSTALLSTART; | ||
16636 | } | ||
16637 | break; | ||
16638 | case "IgnoreInstallEnd": | ||
16639 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16640 | { | ||
16641 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INSTALLEND; | ||
16642 | } | ||
16643 | break; | ||
16644 | case "SourceFile": | ||
16645 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16646 | break; | ||
16647 | case "SupportBasicUI": | ||
16648 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16649 | { | ||
16650 | attributes |= MsiInterop.MsidbEmbeddedHandlesBasic; | ||
16651 | } | ||
16652 | break; | ||
16653 | default: | ||
16654 | this.Core.UnexpectedAttribute(node, attrib); | ||
16655 | break; | ||
16656 | } | ||
16657 | } | ||
16658 | else | ||
16659 | { | ||
16660 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16661 | } | ||
16662 | } | ||
16663 | |||
16664 | if (String.IsNullOrEmpty(sourceFile)) | ||
16665 | { | ||
16666 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
16667 | } | ||
16668 | else if (String.IsNullOrEmpty(name)) | ||
16669 | { | ||
16670 | name = Path.GetFileName(sourceFile); | ||
16671 | if (!this.Core.IsValidLongFilename(name, false)) | ||
16672 | { | ||
16673 | this.Core.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
16674 | } | ||
16675 | } | ||
16676 | |||
16677 | if (null == id) | ||
16678 | { | ||
16679 | if (!String.IsNullOrEmpty(name)) | ||
16680 | { | ||
16681 | id = this.Core.CreateIdentifierFromFilename(name); | ||
16682 | } | ||
16683 | |||
16684 | if (null == id) | ||
16685 | { | ||
16686 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
16687 | } | ||
16688 | else if (!Common.IsIdentifier(id.Id)) | ||
16689 | { | ||
16690 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
16691 | } | ||
16692 | } | ||
16693 | else if (String.IsNullOrEmpty(name)) | ||
16694 | { | ||
16695 | name = id.Id; | ||
16696 | } | ||
16697 | |||
16698 | if (!name.Contains(".")) | ||
16699 | { | ||
16700 | this.Core.Write(ErrorMessages.InvalidEmbeddedUIFileName(sourceLineNumbers, name)); | ||
16701 | } | ||
16702 | |||
16703 | foreach (var child in node.Elements()) | ||
16704 | { | ||
16705 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16706 | { | ||
16707 | switch (child.Name.LocalName) | ||
16708 | { | ||
16709 | case "EmbeddedUIResource": | ||
16710 | this.ParseEmbeddedUIResourceElement(child); | ||
16711 | break; | ||
16712 | default: | ||
16713 | this.Core.UnexpectedElement(node, child); | ||
16714 | break; | ||
16715 | } | ||
16716 | } | ||
16717 | else | ||
16718 | { | ||
16719 | this.Core.ParseExtensionElement(node, child); | ||
16720 | } | ||
16721 | } | ||
16722 | |||
16723 | if (!this.Core.EncounteredError) | ||
16724 | { | ||
16725 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiEmbeddedUI, id); | ||
16726 | row.Set(1, name); | ||
16727 | row.Set(2, attributes); | ||
16728 | row.Set(3, messageFilter); | ||
16729 | row.Set(4, sourceFile); | ||
16730 | } | ||
16731 | } | ||
16732 | |||
16733 | /// <summary> | ||
16734 | /// Parses a embedded UI resource element. | ||
16735 | /// </summary> | ||
16736 | /// <param name="node">Element to parse.</param> | ||
16737 | /// <param name="parentId">Identifier of parent EmbeddedUI element.</param> | ||
16738 | private void ParseEmbeddedUIResourceElement(XElement node) | ||
16739 | { | ||
16740 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16741 | Identifier id = null; | ||
16742 | string name = null; | ||
16743 | string sourceFile = null; | ||
16744 | |||
16745 | foreach (var attrib in node.Attributes()) | ||
16746 | { | ||
16747 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16748 | { | ||
16749 | switch (attrib.Name.LocalName) | ||
16750 | { | ||
16751 | case "Id": | ||
16752 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16753 | break; | ||
16754 | case "Name": | ||
16755 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
16756 | break; | ||
16757 | case "SourceFile": | ||
16758 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16759 | break; | ||
16760 | default: | ||
16761 | this.Core.UnexpectedAttribute(node, attrib); | ||
16762 | break; | ||
16763 | } | ||
16764 | } | ||
16765 | else | ||
16766 | { | ||
16767 | this.Core.ParseExtensionAttribute(node, attrib); | ||
16768 | } | ||
16769 | } | ||
16770 | |||
16771 | if (String.IsNullOrEmpty(sourceFile)) | ||
16772 | { | ||
16773 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
16774 | } | ||
16775 | else if (String.IsNullOrEmpty(name)) | ||
16776 | { | ||
16777 | name = Path.GetFileName(sourceFile); | ||
16778 | if (!this.Core.IsValidLongFilename(name, false)) | ||
16779 | { | ||
16780 | this.Core.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
16781 | } | ||
16782 | } | ||
16783 | |||
16784 | if (null == id) | ||
16785 | { | ||
16786 | if (!String.IsNullOrEmpty(name)) | ||
16787 | { | ||
16788 | id = this.Core.CreateIdentifierFromFilename(name); | ||
16789 | } | ||
16790 | |||
16791 | if (null == id) | ||
16792 | { | ||
16793 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
16794 | } | ||
16795 | else if (!Common.IsIdentifier(id.Id)) | ||
16796 | { | ||
16797 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
16798 | } | ||
16799 | } | ||
16800 | else if (String.IsNullOrEmpty(name)) | ||
16801 | { | ||
16802 | name = id.Id; | ||
16803 | } | ||
16804 | |||
16805 | this.Core.ParseForExtensionElements(node); | ||
16806 | |||
16807 | if (!this.Core.EncounteredError) | ||
16808 | { | ||
16809 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiEmbeddedUI, id); | ||
16810 | row.Set(1, name); | ||
16811 | row.Set(2, 0); // embedded UI resources always set this to 0 | ||
16812 | //row.Set(3, null); | ||
16813 | row.Set(4, sourceFile); | ||
16814 | } | ||
16815 | } | ||
16816 | |||
16817 | /// <summary> | ||
16818 | /// Parses a control element. | ||
16819 | /// </summary> | ||
16820 | /// <param name="node">Element to parse.</param> | ||
16821 | /// <param name="dialog">Identifier for parent dialog.</param> | ||
16822 | /// <param name="table">Table control belongs in.</param> | ||
16823 | /// <param name="lastTabRow">Last row in the tab order.</param> | ||
16824 | /// <param name="firstControl">Name of the first control in the tab order.</param> | ||
16825 | /// <param name="defaultControl">Name of the default control.</param> | ||
16826 | /// <param name="cancelControl">Name of the candle control.</param> | ||
16827 | /// <param name="trackDiskSpace">True if the containing dialog tracks disk space.</param> | ||
16828 | private void ParseControlElement(XElement node, string dialog, TupleDefinitionType tableName, ref IntermediateTuple lastTabRow, ref string firstControl, ref string defaultControl, ref string cancelControl, bool trackDiskSpace) | ||
16829 | { | ||
16830 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16831 | Identifier id = null; | ||
16832 | var bits = new BitArray(32); | ||
16833 | var attributes = 0; | ||
16834 | string checkBoxPropertyRef = null; | ||
16835 | string checkboxValue = null; | ||
16836 | string controlType = null; | ||
16837 | var disabled = false; | ||
16838 | string height = null; | ||
16839 | string help = null; | ||
16840 | var isCancel = false; | ||
16841 | var isDefault = false; | ||
16842 | var notTabbable = false; | ||
16843 | string property = null; | ||
16844 | var publishOrder = 0; | ||
16845 | string[] specialAttributes = null; | ||
16846 | string sourceFile = null; | ||
16847 | string text = null; | ||
16848 | string tooltip = null; | ||
16849 | var radioButtonsType = RadioButtonType.NotSet; | ||
16850 | string width = null; | ||
16851 | string x = null; | ||
16852 | string y = null; | ||
16853 | |||
16854 | // The rest of the method relies on the control's Type, so we have to get that first. | ||
16855 | var typeAttribute = node.Attribute("Type"); | ||
16856 | if (null == typeAttribute) | ||
16857 | { | ||
16858 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type")); | ||
16859 | } | ||
16860 | else | ||
16861 | { | ||
16862 | controlType = this.Core.GetAttributeValue(sourceLineNumbers, typeAttribute); | ||
16863 | } | ||
16864 | |||
16865 | switch (controlType) | ||
16866 | { | ||
16867 | case "Billboard": | ||
16868 | specialAttributes = null; | ||
16869 | notTabbable = true; | ||
16870 | disabled = true; | ||
16871 | |||
16872 | this.Core.EnsureTable(sourceLineNumbers, "Billboard"); | ||
16873 | break; | ||
16874 | case "Bitmap": | ||
16875 | specialAttributes = MsiInterop.BitmapControlAttributes; | ||
16876 | notTabbable = true; | ||
16877 | disabled = true; | ||
16878 | break; | ||
16879 | case "CheckBox": | ||
16880 | specialAttributes = MsiInterop.CheckboxControlAttributes; | ||
16881 | break; | ||
16882 | case "ComboBox": | ||
16883 | specialAttributes = MsiInterop.ComboboxControlAttributes; | ||
16884 | break; | ||
16885 | case "DirectoryCombo": | ||
16886 | specialAttributes = MsiInterop.VolumeControlAttributes; | ||
16887 | break; | ||
16888 | case "DirectoryList": | ||
16889 | specialAttributes = null; | ||
16890 | break; | ||
16891 | case "Edit": | ||
16892 | specialAttributes = MsiInterop.EditControlAttributes; | ||
16893 | break; | ||
16894 | case "GroupBox": | ||
16895 | specialAttributes = null; | ||
16896 | notTabbable = true; | ||
16897 | break; | ||
16898 | case "Hyperlink": | ||
16899 | specialAttributes = MsiInterop.HyperlinkControlAttributes; | ||
16900 | break; | ||
16901 | case "Icon": | ||
16902 | specialAttributes = MsiInterop.IconControlAttributes; | ||
16903 | notTabbable = true; | ||
16904 | disabled = true; | ||
16905 | break; | ||
16906 | case "Line": | ||
16907 | specialAttributes = null; | ||
16908 | notTabbable = true; | ||
16909 | disabled = true; | ||
16910 | break; | ||
16911 | case "ListBox": | ||
16912 | specialAttributes = MsiInterop.ListboxControlAttributes; | ||
16913 | break; | ||
16914 | case "ListView": | ||
16915 | specialAttributes = MsiInterop.ListviewControlAttributes; | ||
16916 | break; | ||
16917 | case "MaskedEdit": | ||
16918 | specialAttributes = MsiInterop.EditControlAttributes; | ||
16919 | break; | ||
16920 | case "PathEdit": | ||
16921 | specialAttributes = MsiInterop.EditControlAttributes; | ||
16922 | break; | ||
16923 | case "ProgressBar": | ||
16924 | specialAttributes = MsiInterop.ProgressControlAttributes; | ||
16925 | notTabbable = true; | ||
16926 | disabled = true; | ||
16927 | break; | ||
16928 | case "PushButton": | ||
16929 | specialAttributes = MsiInterop.ButtonControlAttributes; | ||
16930 | break; | ||
16931 | case "RadioButtonGroup": | ||
16932 | specialAttributes = MsiInterop.RadioControlAttributes; | ||
16933 | break; | ||
16934 | case "ScrollableText": | ||
16935 | specialAttributes = null; | ||
16936 | break; | ||
16937 | case "SelectionTree": | ||
16938 | specialAttributes = null; | ||
16939 | break; | ||
16940 | case "Text": | ||
16941 | specialAttributes = MsiInterop.TextControlAttributes; | ||
16942 | notTabbable = true; | ||
16943 | break; | ||
16944 | case "VolumeCostList": | ||
16945 | specialAttributes = MsiInterop.VolumeControlAttributes; | ||
16946 | notTabbable = true; | ||
16947 | break; | ||
16948 | case "VolumeSelectCombo": | ||
16949 | specialAttributes = MsiInterop.VolumeControlAttributes; | ||
16950 | break; | ||
16951 | default: | ||
16952 | specialAttributes = null; | ||
16953 | notTabbable = true; | ||
16954 | break; | ||
16955 | } | ||
16956 | |||
16957 | foreach (var attrib in node.Attributes()) | ||
16958 | { | ||
16959 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16960 | { | ||
16961 | switch (attrib.Name.LocalName) | ||
16962 | { | ||
16963 | case "Id": | ||
16964 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16965 | break; | ||
16966 | case "Type": // already processed | ||
16967 | break; | ||
16968 | case "Cancel": | ||
16969 | isCancel = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
16970 | break; | ||
16971 | case "CheckBoxPropertyRef": | ||
16972 | checkBoxPropertyRef = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16973 | break; | ||
16974 | case "CheckBoxValue": | ||
16975 | checkboxValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16976 | break; | ||
16977 | case "Default": | ||
16978 | isDefault = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
16979 | break; | ||
16980 | case "Height": | ||
16981 | height = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
16982 | break; | ||
16983 | case "Help": | ||
16984 | help = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16985 | break; | ||
16986 | case "IconSize": | ||
16987 | var iconSizeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16988 | if (null != specialAttributes) | ||
16989 | { | ||
16990 | if (0 < iconSizeValue.Length) | ||
16991 | { | ||
16992 | var iconsSizeType = Wix.Control.ParseIconSizeType(iconSizeValue); | ||
16993 | switch (iconsSizeType) | ||
16994 | { | ||
16995 | case Wix.Control.IconSizeType.Item16: | ||
16996 | this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
16997 | break; | ||
16998 | case Wix.Control.IconSizeType.Item32: | ||
16999 | this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
17000 | break; | ||
17001 | case Wix.Control.IconSizeType.Item48: | ||
17002 | this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
17003 | this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
17004 | break; | ||
17005 | default: | ||
17006 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "16", "32", "48")); | ||
17007 | break; | ||
17008 | } | ||
17009 | } | ||
17010 | } | ||
17011 | else | ||
17012 | { | ||
17013 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "Type")); | ||
17014 | } | ||
17015 | break; | ||
17016 | case "Property": | ||
17017 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17018 | break; | ||
17019 | case "TabSkip": | ||
17020 | notTabbable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17021 | break; | ||
17022 | case "Text": | ||
17023 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17024 | break; | ||
17025 | case "ToolTip": | ||
17026 | tooltip = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17027 | break; | ||
17028 | case "Width": | ||
17029 | width = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
17030 | break; | ||
17031 | case "X": | ||
17032 | x = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
17033 | break; | ||
17034 | case "Y": | ||
17035 | y = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
17036 | break; | ||
17037 | default: | ||
17038 | var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17039 | if (!this.Core.TrySetBitFromName(MsiInterop.CommonControlAttributes, attrib.Name.LocalName, attribValue, bits, 0)) | ||
17040 | { | ||
17041 | if (null == specialAttributes || !this.Core.TrySetBitFromName(specialAttributes, attrib.Name.LocalName, attribValue, bits, 16)) | ||
17042 | { | ||
17043 | this.Core.UnexpectedAttribute(node, attrib); | ||
17044 | } | ||
17045 | } | ||
17046 | break; | ||
17047 | } | ||
17048 | } | ||
17049 | else | ||
17050 | { | ||
17051 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17052 | } | ||
17053 | } | ||
17054 | |||
17055 | attributes = this.Core.CreateIntegerFromBitArray(bits); | ||
17056 | |||
17057 | if (disabled) | ||
17058 | { | ||
17059 | attributes |= MsiInterop.MsidbControlAttributesEnabled; // bit will be inverted when stored | ||
17060 | } | ||
17061 | |||
17062 | if (null == height) | ||
17063 | { | ||
17064 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height")); | ||
17065 | } | ||
17066 | |||
17067 | if (null == width) | ||
17068 | { | ||
17069 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width")); | ||
17070 | } | ||
17071 | |||
17072 | if (null == x) | ||
17073 | { | ||
17074 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X")); | ||
17075 | } | ||
17076 | |||
17077 | if (null == y) | ||
17078 | { | ||
17079 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y")); | ||
17080 | } | ||
17081 | |||
17082 | if (null == id) | ||
17083 | { | ||
17084 | id = this.Core.CreateIdentifier("ctl", dialog, x, y, height, width); | ||
17085 | } | ||
17086 | |||
17087 | if (isCancel) | ||
17088 | { | ||
17089 | cancelControl = id.Id; | ||
17090 | } | ||
17091 | |||
17092 | if (isDefault) | ||
17093 | { | ||
17094 | defaultControl = id.Id; | ||
17095 | } | ||
17096 | |||
17097 | foreach (var child in node.Elements()) | ||
17098 | { | ||
17099 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
17100 | { | ||
17101 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
17102 | switch (child.Name.LocalName) | ||
17103 | { | ||
17104 | case "Binary": | ||
17105 | this.ParseBinaryElement(child); | ||
17106 | break; | ||
17107 | case "ComboBox": | ||
17108 | this.ParseControlGroupElement(child, TupleDefinitionType.ComboBox, "ListItem"); | ||
17109 | break; | ||
17110 | case "Condition": | ||
17111 | this.ParseConditionElement(child, node.Name.LocalName, id.Id, dialog); | ||
17112 | break; | ||
17113 | case "ListBox": | ||
17114 | this.ParseControlGroupElement(child, TupleDefinitionType.ListBox, "ListItem"); | ||
17115 | break; | ||
17116 | case "ListView": | ||
17117 | this.ParseControlGroupElement(child, TupleDefinitionType.ListView, "ListItem"); | ||
17118 | break; | ||
17119 | case "Property": | ||
17120 | this.ParsePropertyElement(child); | ||
17121 | break; | ||
17122 | case "Publish": | ||
17123 | this.ParsePublishElement(child, dialog ?? String.Empty, id.Id, ref publishOrder); | ||
17124 | break; | ||
17125 | case "RadioButtonGroup": | ||
17126 | radioButtonsType = this.ParseRadioButtonGroupElement(child, property, radioButtonsType); | ||
17127 | break; | ||
17128 | case "Subscribe": | ||
17129 | this.ParseSubscribeElement(child, dialog, id.Id); | ||
17130 | break; | ||
17131 | case "Text": | ||
17132 | foreach (var attrib in child.Attributes()) | ||
17133 | { | ||
17134 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17135 | { | ||
17136 | switch (attrib.Name.LocalName) | ||
17137 | { | ||
17138 | case "SourceFile": | ||
17139 | sourceFile = this.Core.GetAttributeValue(childSourceLineNumbers, attrib); | ||
17140 | break; | ||
17141 | default: | ||
17142 | this.Core.UnexpectedAttribute(child, attrib); | ||
17143 | break; | ||
17144 | } | ||
17145 | } | ||
17146 | else | ||
17147 | { | ||
17148 | this.Core.ParseExtensionAttribute(child, attrib); | ||
17149 | } | ||
17150 | } | ||
17151 | |||
17152 | text = Common.GetInnerText(child); | ||
17153 | if (!String.IsNullOrEmpty(text) && null != sourceFile) | ||
17154 | { | ||
17155 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(childSourceLineNumbers, child.Name.LocalName, "SourceFile")); | ||
17156 | } | ||
17157 | break; | ||
17158 | default: | ||
17159 | this.Core.UnexpectedElement(node, child); | ||
17160 | break; | ||
17161 | } | ||
17162 | } | ||
17163 | else | ||
17164 | { | ||
17165 | this.Core.ParseExtensionElement(node, child); | ||
17166 | } | ||
17167 | } | ||
17168 | |||
17169 | // If the radio buttons have icons, then we need to add the icon attribute. | ||
17170 | switch (radioButtonsType) | ||
17171 | { | ||
17172 | case RadioButtonType.Bitmap: | ||
17173 | attributes |= MsiInterop.MsidbControlAttributesBitmap; | ||
17174 | break; | ||
17175 | case RadioButtonType.Icon: | ||
17176 | attributes |= MsiInterop.MsidbControlAttributesIcon; | ||
17177 | break; | ||
17178 | case RadioButtonType.Text: | ||
17179 | // Text is the default so nothing needs to be added bits | ||
17180 | break; | ||
17181 | } | ||
17182 | |||
17183 | // If we're tracking disk space, and this is a non-FormatSize Text control, and the text attribute starts with | ||
17184 | // '[' and ends with ']', add a space. It is not necessary for the whole string to be a property, just | ||
17185 | // those two characters matter. | ||
17186 | if (trackDiskSpace && "Text" == controlType && | ||
17187 | MsiInterop.MsidbControlAttributesFormatSize != (attributes & MsiInterop.MsidbControlAttributesFormatSize) && | ||
17188 | null != text && text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal)) | ||
17189 | { | ||
17190 | text = String.Concat(text, " "); | ||
17191 | } | ||
17192 | |||
17193 | // the logic for creating control rows is a little tricky because of the way tabable controls are set | ||
17194 | IntermediateTuple row = null; | ||
17195 | if (!this.Core.EncounteredError) | ||
17196 | { | ||
17197 | if ("CheckBox" == controlType) | ||
17198 | { | ||
17199 | if (String.IsNullOrEmpty(property) && String.IsNullOrEmpty(checkBoxPropertyRef)) | ||
17200 | { | ||
17201 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef", true)); | ||
17202 | } | ||
17203 | else if (!String.IsNullOrEmpty(property) && !String.IsNullOrEmpty(checkBoxPropertyRef)) | ||
17204 | { | ||
17205 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef")); | ||
17206 | } | ||
17207 | else if (!String.IsNullOrEmpty(property)) | ||
17208 | { | ||
17209 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CheckBox); | ||
17210 | row.Set(0, property); | ||
17211 | row.Set(1, checkboxValue); | ||
17212 | } | ||
17213 | else | ||
17214 | { | ||
17215 | this.Core.CreateSimpleReference(sourceLineNumbers, "CheckBox", checkBoxPropertyRef); | ||
17216 | } | ||
17217 | } | ||
17218 | |||
17219 | var dialogId = new Identifier(dialog, id.Access); | ||
17220 | |||
17221 | row = this.Core.CreateRow(sourceLineNumbers, tableName, dialogId); | ||
17222 | row.Set(1, id.Id); | ||
17223 | row.Set(2, controlType); | ||
17224 | row.Set(3, x); | ||
17225 | row.Set(4, y); | ||
17226 | row.Set(5, width); | ||
17227 | row.Set(6, height); | ||
17228 | row.Set(7, attributes ^ (MsiInterop.MsidbControlAttributesVisible | MsiInterop.MsidbControlAttributesEnabled)); | ||
17229 | if (TupleDefinitionType.BBControl == tableName) | ||
17230 | { | ||
17231 | row.Set(8, text); // BBControl.Text | ||
17232 | |||
17233 | if (null != sourceFile) | ||
17234 | { | ||
17235 | var wixBBControlRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBBControl, dialogId); | ||
17236 | wixBBControlRow.Set(1, id.Id); | ||
17237 | wixBBControlRow.Set(2, sourceFile); | ||
17238 | } | ||
17239 | } | ||
17240 | else | ||
17241 | { | ||
17242 | row.Set(8, !String.IsNullOrEmpty(property) ? property : checkBoxPropertyRef); | ||
17243 | row.Set(9, text); | ||
17244 | if (null != tooltip || null != help) | ||
17245 | { | ||
17246 | row.Set(11, String.Concat(tooltip, "|", help)); // Separator is required, even if only one is non-null. | ||
17247 | } | ||
17248 | |||
17249 | if (null != sourceFile) | ||
17250 | { | ||
17251 | var wixControlRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixControl, dialogId); | ||
17252 | wixControlRow.Set(1, id.Id); | ||
17253 | wixControlRow.Set(2, sourceFile); | ||
17254 | } | ||
17255 | } | ||
17256 | } | ||
17257 | |||
17258 | if (!notTabbable) | ||
17259 | { | ||
17260 | if (TupleDefinitionType.BBControl == tableName) | ||
17261 | { | ||
17262 | this.Core.Write(ErrorMessages.TabbableControlNotAllowedInBillboard(sourceLineNumbers, node.Name.LocalName, controlType)); | ||
17263 | } | ||
17264 | |||
17265 | if (null == firstControl) | ||
17266 | { | ||
17267 | firstControl = id.Id; | ||
17268 | } | ||
17269 | |||
17270 | if (null != lastTabRow) | ||
17271 | { | ||
17272 | lastTabRow.Set(10, id.Id); | ||
17273 | } | ||
17274 | lastTabRow = row; | ||
17275 | } | ||
17276 | |||
17277 | // bitmap and icon controls contain a foreign key into the binary table in the text column; | ||
17278 | // add a reference if the identifier of the binary entry is known during compilation | ||
17279 | if (("Bitmap" == controlType || "Icon" == controlType) && Common.IsIdentifier(text)) | ||
17280 | { | ||
17281 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
17282 | } | ||
17283 | } | ||
17284 | |||
17285 | /// <summary> | ||
17286 | /// Parses a publish control event element. | ||
17287 | /// </summary> | ||
17288 | /// <param name="node">Element to parse.</param> | ||
17289 | /// <param name="dialog">Identifier of parent dialog.</param> | ||
17290 | /// <param name="control">Identifier of parent control.</param> | ||
17291 | /// <param name="order">Relative order of controls.</param> | ||
17292 | private void ParsePublishElement(XElement node, string dialog, string control, ref int order) | ||
17293 | { | ||
17294 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17295 | string argument = null; | ||
17296 | string condition = null; | ||
17297 | string controlEvent = null; | ||
17298 | string property = null; | ||
17299 | |||
17300 | // give this control event a unique ordering | ||
17301 | order++; | ||
17302 | |||
17303 | foreach (var attrib in node.Attributes()) | ||
17304 | { | ||
17305 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17306 | { | ||
17307 | switch (attrib.Name.LocalName) | ||
17308 | { | ||
17309 | case "Control": | ||
17310 | if (null != control) | ||
17311 | { | ||
17312 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
17313 | } | ||
17314 | control = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
17315 | break; | ||
17316 | case "Dialog": | ||
17317 | if (null != dialog) | ||
17318 | { | ||
17319 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
17320 | } | ||
17321 | dialog = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
17322 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", dialog); | ||
17323 | break; | ||
17324 | case "Event": | ||
17325 | controlEvent = Compiler.UppercaseFirstChar(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); | ||
17326 | break; | ||
17327 | case "Order": | ||
17328 | order = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 2147483647); | ||
17329 | break; | ||
17330 | case "Property": | ||
17331 | property = String.Concat("[", this.Core.GetAttributeValue(sourceLineNumbers, attrib), "]"); | ||
17332 | break; | ||
17333 | case "Value": | ||
17334 | argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17335 | break; | ||
17336 | default: | ||
17337 | this.Core.UnexpectedAttribute(node, attrib); | ||
17338 | break; | ||
17339 | } | ||
17340 | } | ||
17341 | else | ||
17342 | { | ||
17343 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17344 | } | ||
17345 | } | ||
17346 | |||
17347 | condition = this.Core.GetConditionInnerText(node); | ||
17348 | |||
17349 | if (null == control) | ||
17350 | { | ||
17351 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Control")); | ||
17352 | } | ||
17353 | |||
17354 | if (null == dialog) | ||
17355 | { | ||
17356 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dialog")); | ||
17357 | } | ||
17358 | |||
17359 | if (null == controlEvent && null == property) // need to specify at least one | ||
17360 | { | ||
17361 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Event", "Property")); | ||
17362 | } | ||
17363 | else if (null != controlEvent && null != property) // cannot specify both | ||
17364 | { | ||
17365 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Event", "Property")); | ||
17366 | } | ||
17367 | |||
17368 | if (null == argument) | ||
17369 | { | ||
17370 | if (null != controlEvent) | ||
17371 | { | ||
17372 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value", "Event")); | ||
17373 | } | ||
17374 | else if (null != property) | ||
17375 | { | ||
17376 | // if this is setting a property to null, put a special value in the argument column | ||
17377 | argument = "{}"; | ||
17378 | } | ||
17379 | } | ||
17380 | |||
17381 | this.Core.ParseForExtensionElements(node); | ||
17382 | |||
17383 | if (!this.Core.EncounteredError) | ||
17384 | { | ||
17385 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ControlEvent); | ||
17386 | row.Set(0, dialog); | ||
17387 | row.Set(1, control); | ||
17388 | row.Set(2, (null != controlEvent ? controlEvent : property)); | ||
17389 | row.Set(3, argument); | ||
17390 | row.Set(4, condition); | ||
17391 | row.Set(5, order); | ||
17392 | } | ||
17393 | |||
17394 | if ("DoAction" == controlEvent && null != argument) | ||
17395 | { | ||
17396 | // if we're not looking at a standard action or a formatted string then create a reference | ||
17397 | // to the custom action. | ||
17398 | if (!WindowsInstallerStandard.IsStandardAction(argument) && !Common.ContainsProperty(argument)) | ||
17399 | { | ||
17400 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", argument); | ||
17401 | } | ||
17402 | } | ||
17403 | |||
17404 | // if we're referring to a dialog but not through a property, add it to the references | ||
17405 | if (("NewDialog" == controlEvent || "SpawnDialog" == controlEvent || "SpawnWaitDialog" == controlEvent || "SelectionBrowse" == controlEvent) && Common.IsIdentifier(argument)) | ||
17406 | { | ||
17407 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", argument); | ||
17408 | } | ||
17409 | } | ||
17410 | |||
17411 | /// <summary> | ||
17412 | /// Parses a control subscription element. | ||
17413 | /// </summary> | ||
17414 | /// <param name="node">Element to parse.</param> | ||
17415 | /// <param name="dialog">Identifier of dialog.</param> | ||
17416 | /// <param name="control">Identifier of control.</param> | ||
17417 | private void ParseSubscribeElement(XElement node, string dialog, string control) | ||
17418 | { | ||
17419 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17420 | string controlAttribute = null; | ||
17421 | string eventMapping = null; | ||
17422 | |||
17423 | foreach (var attrib in node.Attributes()) | ||
17424 | { | ||
17425 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17426 | { | ||
17427 | switch (attrib.Name.LocalName) | ||
17428 | { | ||
17429 | case "Attribute": | ||
17430 | controlAttribute = Compiler.UppercaseFirstChar(this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib)); | ||
17431 | break; | ||
17432 | case "Event": | ||
17433 | eventMapping = Compiler.UppercaseFirstChar(this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib)); | ||
17434 | break; | ||
17435 | default: | ||
17436 | this.Core.UnexpectedAttribute(node, attrib); | ||
17437 | break; | ||
17438 | } | ||
17439 | } | ||
17440 | else | ||
17441 | { | ||
17442 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17443 | } | ||
17444 | } | ||
17445 | |||
17446 | this.Core.ParseForExtensionElements(node); | ||
17447 | |||
17448 | if (!this.Core.EncounteredError) | ||
17449 | { | ||
17450 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.EventMapping); | ||
17451 | row.Set(0, dialog); | ||
17452 | row.Set(1, control); | ||
17453 | row.Set(2, eventMapping); | ||
17454 | row.Set(3, controlAttribute); | ||
17455 | } | ||
17456 | } | ||
17457 | |||
17458 | /// <summary> | ||
17459 | /// Parses an upgrade element. | ||
17460 | /// </summary> | ||
17461 | /// <param name="node">Element to parse.</param> | ||
17462 | private void ParseUpgradeElement(XElement node) | ||
17463 | { | ||
17464 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17465 | string id = null; | ||
17466 | |||
17467 | foreach (var attrib in node.Attributes()) | ||
17468 | { | ||
17469 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17470 | { | ||
17471 | switch (attrib.Name.LocalName) | ||
17472 | { | ||
17473 | case "Id": | ||
17474 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
17475 | break; | ||
17476 | default: | ||
17477 | this.Core.UnexpectedAttribute(node, attrib); | ||
17478 | break; | ||
17479 | } | ||
17480 | } | ||
17481 | else | ||
17482 | { | ||
17483 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17484 | } | ||
17485 | } | ||
17486 | |||
17487 | if (null == id) | ||
17488 | { | ||
17489 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
17490 | } | ||
17491 | |||
17492 | // process the UpgradeVersion children here | ||
17493 | foreach (var child in node.Elements()) | ||
17494 | { | ||
17495 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
17496 | { | ||
17497 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
17498 | |||
17499 | switch (child.Name.LocalName) | ||
17500 | { | ||
17501 | case "Property": | ||
17502 | this.ParsePropertyElement(child); | ||
17503 | this.Core.Write(WarningMessages.DeprecatedUpgradeProperty(childSourceLineNumbers)); | ||
17504 | break; | ||
17505 | case "UpgradeVersion": | ||
17506 | this.ParseUpgradeVersionElement(child, id); | ||
17507 | break; | ||
17508 | default: | ||
17509 | this.Core.UnexpectedElement(node, child); | ||
17510 | break; | ||
17511 | } | ||
17512 | } | ||
17513 | else | ||
17514 | { | ||
17515 | this.Core.ParseExtensionElement(node, child); | ||
17516 | } | ||
17517 | } | ||
17518 | |||
17519 | // No rows created here. All row creation is done in ParseUpgradeVersionElement. | ||
17520 | } | ||
17521 | |||
17522 | /// <summary> | ||
17523 | /// Parse upgrade version element. | ||
17524 | /// </summary> | ||
17525 | /// <param name="node">Element to parse.</param> | ||
17526 | /// <param name="upgradeId">Upgrade code.</param> | ||
17527 | private void ParseUpgradeVersionElement(XElement node, string upgradeId) | ||
17528 | { | ||
17529 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17530 | |||
17531 | string actionProperty = null; | ||
17532 | string language = null; | ||
17533 | string maximum = null; | ||
17534 | string minimum = null; | ||
17535 | var options = 256; | ||
17536 | string removeFeatures = null; | ||
17537 | |||
17538 | foreach (var attrib in node.Attributes()) | ||
17539 | { | ||
17540 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17541 | { | ||
17542 | switch (attrib.Name.LocalName) | ||
17543 | { | ||
17544 | case "ExcludeLanguages": | ||
17545 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17546 | { | ||
17547 | options |= MsiInterop.MsidbUpgradeAttributesLanguagesExclusive; | ||
17548 | } | ||
17549 | break; | ||
17550 | case "IgnoreRemoveFailure": | ||
17551 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17552 | { | ||
17553 | options |= MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure; | ||
17554 | } | ||
17555 | break; | ||
17556 | case "IncludeMaximum": | ||
17557 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17558 | { | ||
17559 | options |= MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive; | ||
17560 | } | ||
17561 | break; | ||
17562 | case "IncludeMinimum": // this is "yes" by default | ||
17563 | if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17564 | { | ||
17565 | options &= ~MsiInterop.MsidbUpgradeAttributesVersionMinInclusive; | ||
17566 | } | ||
17567 | break; | ||
17568 | case "Language": | ||
17569 | language = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17570 | break; | ||
17571 | case "Minimum": | ||
17572 | minimum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
17573 | break; | ||
17574 | case "Maximum": | ||
17575 | maximum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
17576 | break; | ||
17577 | case "MigrateFeatures": | ||
17578 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17579 | { | ||
17580 | options |= MsiInterop.MsidbUpgradeAttributesMigrateFeatures; | ||
17581 | } | ||
17582 | break; | ||
17583 | case "OnlyDetect": | ||
17584 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17585 | { | ||
17586 | options |= MsiInterop.MsidbUpgradeAttributesOnlyDetect; | ||
17587 | } | ||
17588 | break; | ||
17589 | case "Property": | ||
17590 | actionProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
17591 | break; | ||
17592 | case "RemoveFeatures": | ||
17593 | removeFeatures = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17594 | break; | ||
17595 | default: | ||
17596 | this.Core.UnexpectedAttribute(node, attrib); | ||
17597 | break; | ||
17598 | } | ||
17599 | } | ||
17600 | else | ||
17601 | { | ||
17602 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17603 | } | ||
17604 | } | ||
17605 | |||
17606 | if (null == actionProperty) | ||
17607 | { | ||
17608 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
17609 | } | ||
17610 | else if (actionProperty.ToUpper(CultureInfo.InvariantCulture) != actionProperty) | ||
17611 | { | ||
17612 | this.Core.Write(ErrorMessages.SecurePropertyNotUppercase(sourceLineNumbers, node.Name.LocalName, "Property", actionProperty)); | ||
17613 | } | ||
17614 | |||
17615 | if (null == minimum && null == maximum) | ||
17616 | { | ||
17617 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Minimum", "Maximum")); | ||
17618 | } | ||
17619 | |||
17620 | this.Core.ParseForExtensionElements(node); | ||
17621 | |||
17622 | if (!this.Core.EncounteredError) | ||
17623 | { | ||
17624 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Upgrade); | ||
17625 | row.Set(0, upgradeId); | ||
17626 | row.Set(1, minimum); | ||
17627 | row.Set(2, maximum); | ||
17628 | row.Set(3, language); | ||
17629 | row.Set(4, options); | ||
17630 | row.Set(5, removeFeatures); | ||
17631 | row.Set(6, actionProperty); | ||
17632 | |||
17633 | // Ensure the action property is secure. | ||
17634 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(actionProperty, AccessModifier.Private), false, true, false); | ||
17635 | |||
17636 | // Ensure that RemoveExistingProducts is authored in InstallExecuteSequence | ||
17637 | // if at least one row in Upgrade table lacks the OnlyDetect attribute. | ||
17638 | if (0 == (options & MsiInterop.MsidbUpgradeAttributesOnlyDetect)) | ||
17639 | { | ||
17640 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", "RemoveExistingProducts"); | ||
17641 | } | ||
17642 | } | ||
17643 | } | ||
17644 | |||
17645 | /// <summary> | ||
17646 | /// Parses a verb element. | ||
17647 | /// </summary> | ||
17648 | /// <param name="node">Element to parse.</param> | ||
17649 | /// <param name="extension">Extension verb is releated to.</param> | ||
17650 | /// <param name="progId">Optional progId for extension.</param> | ||
17651 | /// <param name="componentId">Identifier for parent component.</param> | ||
17652 | /// <param name="advertise">Flag if verb is advertised.</param> | ||
17653 | private void ParseVerbElement(XElement node, string extension, string progId, string componentId, YesNoType advertise) | ||
17654 | { | ||
17655 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17656 | string id = null; | ||
17657 | string argument = null; | ||
17658 | string command = null; | ||
17659 | var sequence = CompilerConstants.IntegerNotSet; | ||
17660 | string target = null; | ||
17661 | string targetFile = null; | ||
17662 | string targetProperty = null; | ||
17663 | |||
17664 | foreach (var attrib in node.Attributes()) | ||
17665 | { | ||
17666 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17667 | { | ||
17668 | switch (attrib.Name.LocalName) | ||
17669 | { | ||
17670 | case "Id": | ||
17671 | id = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17672 | break; | ||
17673 | case "Argument": | ||
17674 | argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17675 | break; | ||
17676 | case "Command": | ||
17677 | command = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17678 | break; | ||
17679 | case "Sequence": | ||
17680 | sequence = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); | ||
17681 | break; | ||
17682 | case "Target": | ||
17683 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17684 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "TargetFile", "TargetProperty")); | ||
17685 | break; | ||
17686 | case "TargetFile": | ||
17687 | targetFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17688 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", targetFile); | ||
17689 | break; | ||
17690 | case "TargetProperty": | ||
17691 | targetProperty = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17692 | break; | ||
17693 | default: | ||
17694 | this.Core.UnexpectedAttribute(node, attrib); | ||
17695 | break; | ||
17696 | } | ||
17697 | } | ||
17698 | else | ||
17699 | { | ||
17700 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17701 | } | ||
17702 | } | ||
17703 | |||
17704 | if (null == id) | ||
17705 | { | ||
17706 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
17707 | } | ||
17708 | |||
17709 | if (null != target && null != targetFile) | ||
17710 | { | ||
17711 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetFile")); | ||
17712 | } | ||
17713 | |||
17714 | if (null != target && null != targetProperty) | ||
17715 | { | ||
17716 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetProperty")); | ||
17717 | } | ||
17718 | |||
17719 | if (null != targetFile && null != targetProperty) | ||
17720 | { | ||
17721 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty")); | ||
17722 | } | ||
17723 | |||
17724 | this.Core.ParseForExtensionElements(node); | ||
17725 | |||
17726 | if (YesNoType.Yes == advertise) | ||
17727 | { | ||
17728 | if (null != target) | ||
17729 | { | ||
17730 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "Target")); | ||
17731 | } | ||
17732 | |||
17733 | if (null != targetFile) | ||
17734 | { | ||
17735 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetFile")); | ||
17736 | } | ||
17737 | |||
17738 | if (null != targetProperty) | ||
17739 | { | ||
17740 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetProperty")); | ||
17741 | } | ||
17742 | |||
17743 | if (!this.Core.EncounteredError) | ||
17744 | { | ||
17745 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Verb); | ||
17746 | row.Set(0, extension); | ||
17747 | row.Set(1, id); | ||
17748 | if (CompilerConstants.IntegerNotSet != sequence) | ||
17749 | { | ||
17750 | row.Set(2, sequence); | ||
17751 | } | ||
17752 | row.Set(3, command); | ||
17753 | row.Set(4, argument); | ||
17754 | } | ||
17755 | } | ||
17756 | else if (YesNoType.No == advertise) | ||
17757 | { | ||
17758 | if (CompilerConstants.IntegerNotSet != sequence) | ||
17759 | { | ||
17760 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Sequence", "Advertise", "no")); | ||
17761 | } | ||
17762 | |||
17763 | if (null == target && null == targetFile && null == targetProperty) | ||
17764 | { | ||
17765 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty", "Advertise", "no")); | ||
17766 | } | ||
17767 | |||
17768 | if (null == target) | ||
17769 | { | ||
17770 | if (null != targetFile) | ||
17771 | { | ||
17772 | target = String.Concat("\"[#", targetFile, "]\""); | ||
17773 | } | ||
17774 | |||
17775 | if (null != targetProperty) | ||
17776 | { | ||
17777 | target = String.Concat("\"[", targetProperty, "]\""); | ||
17778 | } | ||
17779 | } | ||
17780 | |||
17781 | if (null != argument) | ||
17782 | { | ||
17783 | target = String.Concat(target, " ", argument); | ||
17784 | } | ||
17785 | |||
17786 | var prefix = (null != progId ? progId : String.Concat(".", extension)); | ||
17787 | |||
17788 | if (null != command) | ||
17789 | { | ||
17790 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(prefix, "\\shell\\", id), String.Empty, command, componentId); | ||
17791 | } | ||
17792 | |||
17793 | this.Core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(prefix, "\\shell\\", id, "\\command"), String.Empty, target, componentId); | ||
17794 | } | ||
17795 | } | ||
17796 | |||
17797 | |||
17798 | /// <summary> | ||
17799 | /// Parses an ApprovedExeForElevation element. | ||
17800 | /// </summary> | ||
17801 | /// <param name="node">Element to parse</param> | ||
17802 | private void ParseApprovedExeForElevation(XElement node) | ||
17803 | { | ||
17804 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17805 | Identifier id = null; | ||
17806 | string key = null; | ||
17807 | string valueName = null; | ||
17808 | var win64 = YesNoType.NotSet; | ||
17809 | |||
17810 | foreach (var attrib in node.Attributes()) | ||
17811 | { | ||
17812 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17813 | { | ||
17814 | switch (attrib.Name.LocalName) | ||
17815 | { | ||
17816 | case "Id": | ||
17817 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
17818 | break; | ||
17819 | case "Key": | ||
17820 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17821 | break; | ||
17822 | case "Value": | ||
17823 | valueName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17824 | break; | ||
17825 | case "Win64": | ||
17826 | win64 = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17827 | break; | ||
17828 | default: | ||
17829 | this.Core.UnexpectedAttribute(node, attrib); | ||
17830 | break; | ||
17831 | } | ||
17832 | } | ||
17833 | else | ||
17834 | { | ||
17835 | this.Core.ParseExtensionAttribute(node, attrib); | ||
17836 | } | ||
17837 | } | ||
17838 | |||
17839 | if (null == id) | ||
17840 | { | ||
17841 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
17842 | } | ||
17843 | |||
17844 | if (null == key) | ||
17845 | { | ||
17846 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
17847 | } | ||
17848 | |||
17849 | var attributes = BundleApprovedExeForElevationAttributes.None; | ||
17850 | |||
17851 | if (win64 == YesNoType.Yes) | ||
17852 | { | ||
17853 | attributes |= BundleApprovedExeForElevationAttributes.Win64; | ||
17854 | } | ||
17855 | |||
17856 | this.Core.ParseForExtensionElements(node); | ||
17857 | |||
17858 | if (!this.Core.EncounteredError) | ||
17859 | { | ||
17860 | var wixApprovedExeForElevationRow = (WixApprovedExeForElevationTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixApprovedExeForElevation, id); | ||
17861 | wixApprovedExeForElevationRow.Key = key; | ||
17862 | wixApprovedExeForElevationRow.Value = valueName; | ||
17863 | wixApprovedExeForElevationRow.Attributes = (int)attributes; | ||
17864 | } | ||
17865 | } | ||
17866 | |||
17867 | /// <summary> | ||
17868 | /// Parses a Bundle element. | ||
17869 | /// </summary> | ||
17870 | /// <param name="node">Element to parse</param> | ||
17871 | private void ParseBundleElement(XElement node) | ||
17872 | { | ||
17873 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17874 | string copyright = null; | ||
17875 | string aboutUrl = null; | ||
17876 | var compressed = YesNoDefaultType.Default; | ||
17877 | var disableModify = -1; | ||
17878 | var disableRemove = YesNoType.NotSet; | ||
17879 | string helpTelephone = null; | ||
17880 | string helpUrl = null; | ||
17881 | string manufacturer = null; | ||
17882 | string name = null; | ||
17883 | string tag = null; | ||
17884 | string updateUrl = null; | ||
17885 | string upgradeCode = null; | ||
17886 | string version = null; | ||
17887 | string condition = null; | ||
17888 | string parentName = null; | ||
17889 | |||
17890 | string fileSystemSafeBundleName = null; | ||
17891 | string logVariablePrefixAndExtension = null; | ||
17892 | string iconSourceFile = null; | ||
17893 | string splashScreenSourceFile = null; | ||
17894 | |||
17895 | // Process only standard attributes until the active section is initialized. | ||
17896 | foreach (var attrib in node.Attributes()) | ||
17897 | { | ||
17898 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17899 | { | ||
17900 | switch (attrib.Name.LocalName) | ||
17901 | { | ||
17902 | case "AboutUrl": | ||
17903 | aboutUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17904 | break; | ||
17905 | case "Compressed": | ||
17906 | compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
17907 | break; | ||
17908 | case "Condition": | ||
17909 | condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17910 | break; | ||
17911 | case "Copyright": | ||
17912 | copyright = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17913 | break; | ||
17914 | case "DisableModify": | ||
17915 | var value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17916 | switch (value) | ||
17917 | { | ||
17918 | case "button": | ||
17919 | disableModify = 2; | ||
17920 | break; | ||
17921 | case "yes": | ||
17922 | disableModify = 1; | ||
17923 | break; | ||
17924 | case "no": | ||
17925 | disableModify = 0; | ||
17926 | break; | ||
17927 | default: | ||
17928 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "button", "yes", "no")); | ||
17929 | break; | ||
17930 | } | ||
17931 | break; | ||
17932 | case "DisableRemove": | ||
17933 | disableRemove = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17934 | break; | ||
17935 | case "DisableRepair": | ||
17936 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
17937 | break; | ||
17938 | case "HelpTelephone": | ||
17939 | helpTelephone = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17940 | break; | ||
17941 | case "HelpUrl": | ||
17942 | helpUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17943 | break; | ||
17944 | case "Manufacturer": | ||
17945 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17946 | break; | ||
17947 | case "IconSourceFile": | ||
17948 | iconSourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17949 | break; | ||
17950 | case "Name": | ||
17951 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17952 | break; | ||
17953 | case "ParentName": | ||
17954 | parentName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17955 | break; | ||
17956 | case "SplashScreenSourceFile": | ||
17957 | splashScreenSourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17958 | break; | ||
17959 | case "Tag": | ||
17960 | tag = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17961 | break; | ||
17962 | case "UpdateUrl": | ||
17963 | updateUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17964 | break; | ||
17965 | case "UpgradeCode": | ||
17966 | upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
17967 | break; | ||
17968 | case "Version": | ||
17969 | version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
17970 | break; | ||
17971 | default: | ||
17972 | this.Core.UnexpectedAttribute(node, attrib); | ||
17973 | break; | ||
17974 | } | ||
17975 | } | ||
17976 | } | ||
17977 | |||
17978 | if (String.IsNullOrEmpty(version)) | ||
17979 | { | ||
17980 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
17981 | } | ||
17982 | else if (!CompilerCore.IsValidModuleOrBundleVersion(version)) | ||
17983 | { | ||
17984 | this.Core.Write(WarningMessages.InvalidModuleOrBundleVersion(sourceLineNumbers, "Bundle", version)); | ||
17985 | } | ||
17986 | |||
17987 | if (String.IsNullOrEmpty(upgradeCode)) | ||
17988 | { | ||
17989 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpgradeCode")); | ||
17990 | } | ||
17991 | |||
17992 | if (String.IsNullOrEmpty(copyright)) | ||
17993 | { | ||
17994 | if (String.IsNullOrEmpty(manufacturer)) | ||
17995 | { | ||
17996 | copyright = "Copyright (c). All rights reserved."; | ||
17997 | } | ||
17998 | else | ||
17999 | { | ||
18000 | copyright = String.Format("Copyright (c) {0}. All rights reserved.", manufacturer); | ||
18001 | } | ||
18002 | } | ||
18003 | |||
18004 | if (String.IsNullOrEmpty(name)) | ||
18005 | { | ||
18006 | logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup.log"); | ||
18007 | } | ||
18008 | else | ||
18009 | { | ||
18010 | // Ensure only allowable path characters are in "name" (and change spaces to underscores). | ||
18011 | fileSystemSafeBundleName = CompilerCore.MakeValidLongFileName(name.Replace(' ', '_'), "_"); | ||
18012 | logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ".log"); | ||
18013 | } | ||
18014 | |||
18015 | this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name; | ||
18016 | this.Core.CreateActiveSection(this.activeName, SectionType.Bundle, 0, this.Context.CompilationId); | ||
18017 | |||
18018 | // Now that the active section is initialized, process only extension attributes. | ||
18019 | foreach (var attrib in node.Attributes()) | ||
18020 | { | ||
18021 | if (!String.IsNullOrEmpty(attrib.Name.NamespaceName) && CompilerCore.WixNamespace != attrib.Name.Namespace) | ||
18022 | { | ||
18023 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18024 | } | ||
18025 | } | ||
18026 | |||
18027 | var baSeen = false; | ||
18028 | var chainSeen = false; | ||
18029 | var logSeen = false; | ||
18030 | |||
18031 | foreach (var child in node.Elements()) | ||
18032 | { | ||
18033 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18034 | { | ||
18035 | switch (child.Name.LocalName) | ||
18036 | { | ||
18037 | case "ApprovedExeForElevation": | ||
18038 | this.ParseApprovedExeForElevation(child); | ||
18039 | break; | ||
18040 | case "BootstrapperApplication": | ||
18041 | if (baSeen) | ||
18042 | { | ||
18043 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18044 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "BootstrapperApplication")); | ||
18045 | } | ||
18046 | this.ParseBootstrapperApplicationElement(child); | ||
18047 | baSeen = true; | ||
18048 | break; | ||
18049 | case "BootstrapperApplicationRef": | ||
18050 | this.ParseBootstrapperApplicationRefElement(child); | ||
18051 | break; | ||
18052 | case "OptionalUpdateRegistration": | ||
18053 | this.ParseOptionalUpdateRegistrationElement(child, manufacturer, parentName, name); | ||
18054 | break; | ||
18055 | case "Catalog": | ||
18056 | this.ParseCatalogElement(child); | ||
18057 | break; | ||
18058 | case "Chain": | ||
18059 | if (chainSeen) | ||
18060 | { | ||
18061 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18062 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "Chain")); | ||
18063 | } | ||
18064 | this.ParseChainElement(child); | ||
18065 | chainSeen = true; | ||
18066 | break; | ||
18067 | case "Container": | ||
18068 | this.ParseContainerElement(child); | ||
18069 | break; | ||
18070 | case "ContainerRef": | ||
18071 | this.ParseSimpleRefElement(child, "WixBundleContainer"); | ||
18072 | break; | ||
18073 | case "Log": | ||
18074 | if (logSeen) | ||
18075 | { | ||
18076 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18077 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "Log")); | ||
18078 | } | ||
18079 | logVariablePrefixAndExtension = this.ParseLogElement(child, fileSystemSafeBundleName); | ||
18080 | logSeen = true; | ||
18081 | break; | ||
18082 | case "PayloadGroup": | ||
18083 | this.ParsePayloadGroupElement(child, ComplexReferenceParentType.Layout, "BundleLayoutOnlyPayloads"); | ||
18084 | break; | ||
18085 | case "PayloadGroupRef": | ||
18086 | this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Layout, "BundleLayoutOnlyPayloads", ComplexReferenceChildType.Unknown, null); | ||
18087 | break; | ||
18088 | case "RelatedBundle": | ||
18089 | this.ParseRelatedBundleElement(child); | ||
18090 | break; | ||
18091 | case "Update": | ||
18092 | this.ParseUpdateElement(child); | ||
18093 | break; | ||
18094 | case "Variable": | ||
18095 | this.ParseVariableElement(child); | ||
18096 | break; | ||
18097 | case "WixVariable": | ||
18098 | this.ParseWixVariableElement(child); | ||
18099 | break; | ||
18100 | default: | ||
18101 | this.Core.UnexpectedElement(node, child); | ||
18102 | break; | ||
18103 | } | ||
18104 | } | ||
18105 | else | ||
18106 | { | ||
18107 | this.Core.ParseExtensionElement(node, child); | ||
18108 | } | ||
18109 | } | ||
18110 | |||
18111 | |||
18112 | if (!chainSeen) | ||
18113 | { | ||
18114 | this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Chain")); | ||
18115 | } | ||
18116 | |||
18117 | if (!this.Core.EncounteredError) | ||
18118 | { | ||
18119 | if (null != upgradeCode) | ||
18120 | { | ||
18121 | var relatedBundleRow = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixRelatedBundle); | ||
18122 | relatedBundleRow.Set(0, upgradeCode); | ||
18123 | relatedBundleRow.Set(1, (int)Wix.RelatedBundle.ActionType.Upgrade); | ||
18124 | } | ||
18125 | |||
18126 | var containerRow = (WixBundleContainerTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleContainer); | ||
18127 | containerRow.WixBundleContainer = Compiler.BurnDefaultAttachedContainerId; | ||
18128 | containerRow.Name = "bundle-attached.cab"; | ||
18129 | containerRow.Type = ContainerType.Attached; | ||
18130 | |||
18131 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundle); | ||
18132 | row.Set(0, version); | ||
18133 | row.Set(1, copyright); | ||
18134 | row.Set(2, name); | ||
18135 | row.Set(3, aboutUrl); | ||
18136 | if (-1 != disableModify) | ||
18137 | { | ||
18138 | row.Set(4, disableModify); | ||
18139 | } | ||
18140 | if (YesNoType.NotSet != disableRemove) | ||
18141 | { | ||
18142 | row.Set(5, (YesNoType.Yes == disableRemove) ? 1 : 0); | ||
18143 | } | ||
18144 | // row.Set(6] - (deprecated) "disable repair" | ||
18145 | row.Set(7, helpTelephone); | ||
18146 | row.Set(8, helpUrl); | ||
18147 | row.Set(9, manufacturer); | ||
18148 | row.Set(10, updateUrl); | ||
18149 | if (YesNoDefaultType.Default != compressed) | ||
18150 | { | ||
18151 | row.Set(11, (YesNoDefaultType.Yes == compressed) ? 1 : 0); | ||
18152 | } | ||
18153 | |||
18154 | row.Set(12, logVariablePrefixAndExtension); | ||
18155 | row.Set(13, iconSourceFile); | ||
18156 | row.Set(14, splashScreenSourceFile); | ||
18157 | row.Set(15, condition); | ||
18158 | row.Set(16, tag); | ||
18159 | row.Set(17, this.CurrentPlatform.ToString()); | ||
18160 | row.Set(18, parentName); | ||
18161 | row.Set(19, upgradeCode); | ||
18162 | |||
18163 | // Ensure that the bundle stores the well-known persisted values. | ||
18164 | var bundleNameWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
18165 | bundleNameWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_NAME; | ||
18166 | bundleNameWellKnownVariable.Hidden = false; | ||
18167 | bundleNameWellKnownVariable.Persisted = true; | ||
18168 | |||
18169 | var bundleOriginalSourceWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
18170 | bundleOriginalSourceWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_ORIGINAL_SOURCE; | ||
18171 | bundleOriginalSourceWellKnownVariable.Hidden = false; | ||
18172 | bundleOriginalSourceWellKnownVariable.Persisted = true; | ||
18173 | |||
18174 | var bundleOriginalSourceFolderWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
18175 | bundleOriginalSourceFolderWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER; | ||
18176 | bundleOriginalSourceFolderWellKnownVariable.Hidden = false; | ||
18177 | bundleOriginalSourceFolderWellKnownVariable.Persisted = true; | ||
18178 | |||
18179 | var bundleLastUsedSourceWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
18180 | bundleLastUsedSourceWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_LAST_USED_SOURCE; | ||
18181 | bundleLastUsedSourceWellKnownVariable.Hidden = false; | ||
18182 | bundleLastUsedSourceWellKnownVariable.Persisted = true; | ||
18183 | } | ||
18184 | } | ||
18185 | |||
18186 | /// <summary> | ||
18187 | /// Parse a Container element. | ||
18188 | /// </summary> | ||
18189 | /// <param name="node">Element to parse</param> | ||
18190 | private string ParseLogElement(XElement node, string fileSystemSafeBundleName) | ||
18191 | { | ||
18192 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18193 | var disableLog = YesNoType.NotSet; | ||
18194 | var variable = "WixBundleLog"; | ||
18195 | var logPrefix = fileSystemSafeBundleName ?? "Setup"; | ||
18196 | var logExtension = ".log"; | ||
18197 | |||
18198 | foreach (var attrib in node.Attributes()) | ||
18199 | { | ||
18200 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18201 | { | ||
18202 | switch (attrib.Name.LocalName) | ||
18203 | { | ||
18204 | case "Disable": | ||
18205 | disableLog = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
18206 | break; | ||
18207 | case "PathVariable": | ||
18208 | variable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
18209 | break; | ||
18210 | case "Prefix": | ||
18211 | logPrefix = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18212 | break; | ||
18213 | case "Extension": | ||
18214 | logExtension = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18215 | break; | ||
18216 | default: | ||
18217 | this.Core.UnexpectedAttribute(node, attrib); | ||
18218 | break; | ||
18219 | } | ||
18220 | } | ||
18221 | else | ||
18222 | { | ||
18223 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18224 | } | ||
18225 | } | ||
18226 | |||
18227 | if (!logExtension.StartsWith(".", StringComparison.Ordinal)) | ||
18228 | { | ||
18229 | logExtension = String.Concat(".", logExtension); | ||
18230 | } | ||
18231 | |||
18232 | this.Core.ParseForExtensionElements(node); | ||
18233 | |||
18234 | return YesNoType.Yes == disableLog ? null : String.Concat(variable, ":", logPrefix, logExtension); | ||
18235 | } | ||
18236 | |||
18237 | /// <summary> | ||
18238 | /// Parse a Catalog element. | ||
18239 | /// </summary> | ||
18240 | /// <param name="node">Element to parse</param> | ||
18241 | private void ParseCatalogElement(XElement node) | ||
18242 | { | ||
18243 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18244 | Identifier id = null; | ||
18245 | string sourceFile = null; | ||
18246 | |||
18247 | foreach (var attrib in node.Attributes()) | ||
18248 | { | ||
18249 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18250 | { | ||
18251 | switch (attrib.Name.LocalName) | ||
18252 | { | ||
18253 | case "Id": | ||
18254 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18255 | break; | ||
18256 | case "SourceFile": | ||
18257 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18258 | break; | ||
18259 | default: | ||
18260 | this.Core.UnexpectedAttribute(node, attrib); | ||
18261 | break; | ||
18262 | } | ||
18263 | } | ||
18264 | } | ||
18265 | |||
18266 | if (null == id) | ||
18267 | { | ||
18268 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18269 | } | ||
18270 | |||
18271 | if (null == sourceFile) | ||
18272 | { | ||
18273 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
18274 | } | ||
18275 | |||
18276 | this.Core.ParseForExtensionElements(node); | ||
18277 | |||
18278 | // Create catalog row | ||
18279 | if (!this.Core.EncounteredError) | ||
18280 | { | ||
18281 | this.CreatePayloadRow(sourceLineNumbers, id, Path.GetFileName(sourceFile), sourceFile, null, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, ComplexReferenceChildType.Unknown, null, YesNoDefaultType.Yes, YesNoType.Yes, null, null, null); | ||
18282 | |||
18283 | var wixCatalogRow = (WixBundleCatalogTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleCatalog, id); | ||
18284 | wixCatalogRow.Payload_ = id.Id; | ||
18285 | } | ||
18286 | } | ||
18287 | |||
18288 | /// <summary> | ||
18289 | /// Parse a Container element. | ||
18290 | /// </summary> | ||
18291 | /// <param name="node">Element to parse</param> | ||
18292 | private void ParseContainerElement(XElement node) | ||
18293 | { | ||
18294 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18295 | Identifier id = null; | ||
18296 | string downloadUrl = null; | ||
18297 | string name = null; | ||
18298 | var type = ContainerType.Detached; | ||
18299 | |||
18300 | foreach (var attrib in node.Attributes()) | ||
18301 | { | ||
18302 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18303 | { | ||
18304 | switch (attrib.Name.LocalName) | ||
18305 | { | ||
18306 | case "Id": | ||
18307 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18308 | break; | ||
18309 | case "DownloadUrl": | ||
18310 | downloadUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18311 | break; | ||
18312 | case "Name": | ||
18313 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18314 | break; | ||
18315 | case "Type": | ||
18316 | var typeString = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18317 | if (!Enum.TryParse<ContainerType>(typeString, out type)) | ||
18318 | { | ||
18319 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Type", typeString, "attached, detached")); | ||
18320 | } | ||
18321 | break; | ||
18322 | default: | ||
18323 | this.Core.UnexpectedAttribute(node, attrib); | ||
18324 | break; | ||
18325 | } | ||
18326 | } | ||
18327 | else | ||
18328 | { | ||
18329 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18330 | } | ||
18331 | } | ||
18332 | |||
18333 | if (null == id) | ||
18334 | { | ||
18335 | if (!String.IsNullOrEmpty(name)) | ||
18336 | { | ||
18337 | id = this.Core.CreateIdentifierFromFilename(name); | ||
18338 | } | ||
18339 | |||
18340 | if (null == id) | ||
18341 | { | ||
18342 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18343 | id = Identifier.Invalid; | ||
18344 | } | ||
18345 | else if (!Common.IsIdentifier(id.Id)) | ||
18346 | { | ||
18347 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
18348 | } | ||
18349 | } | ||
18350 | else if (null == name) | ||
18351 | { | ||
18352 | name = id.Id; | ||
18353 | } | ||
18354 | |||
18355 | if (!String.IsNullOrEmpty(downloadUrl) && ContainerType.Detached != type) | ||
18356 | { | ||
18357 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "Type", "attached")); | ||
18358 | } | ||
18359 | |||
18360 | foreach (var child in node.Elements()) | ||
18361 | { | ||
18362 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18363 | { | ||
18364 | switch (child.Name.LocalName) | ||
18365 | { | ||
18366 | case "PackageGroupRef": | ||
18367 | this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.Container, id.Id); | ||
18368 | break; | ||
18369 | default: | ||
18370 | this.Core.UnexpectedElement(node, child); | ||
18371 | break; | ||
18372 | } | ||
18373 | } | ||
18374 | else | ||
18375 | { | ||
18376 | this.Core.ParseExtensionElement(node, child); | ||
18377 | } | ||
18378 | } | ||
18379 | |||
18380 | |||
18381 | if (!this.Core.EncounteredError) | ||
18382 | { | ||
18383 | var row = (WixBundleContainerTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleContainer, id); | ||
18384 | row.Name = name; | ||
18385 | row.Type = type; | ||
18386 | row.DownloadUrl = downloadUrl; | ||
18387 | } | ||
18388 | } | ||
18389 | |||
18390 | /// <summary> | ||
18391 | /// Parse the BoostrapperApplication element. | ||
18392 | /// </summary> | ||
18393 | /// <param name="node">Element to parse</param> | ||
18394 | private void ParseBootstrapperApplicationElement(XElement node) | ||
18395 | { | ||
18396 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18397 | string id = null; | ||
18398 | string previousId = null; | ||
18399 | var previousType = ComplexReferenceChildType.Unknown; | ||
18400 | |||
18401 | // The BootstrapperApplication element acts like a Payload element so delegate to the "Payload" attribute parsing code to parse and create a Payload entry. | ||
18402 | id = this.ParsePayloadElementContent(node, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId, false); | ||
18403 | if (null != id) | ||
18404 | { | ||
18405 | previousId = id; | ||
18406 | previousType = ComplexReferenceChildType.Payload; | ||
18407 | } | ||
18408 | |||
18409 | foreach (var child in node.Elements()) | ||
18410 | { | ||
18411 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18412 | { | ||
18413 | switch (child.Name.LocalName) | ||
18414 | { | ||
18415 | case "Payload": | ||
18416 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18417 | previousType = ComplexReferenceChildType.Payload; | ||
18418 | break; | ||
18419 | case "PayloadGroupRef": | ||
18420 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18421 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
18422 | break; | ||
18423 | default: | ||
18424 | this.Core.UnexpectedElement(node, child); | ||
18425 | break; | ||
18426 | } | ||
18427 | } | ||
18428 | else | ||
18429 | { | ||
18430 | this.Core.ParseExtensionElement(node, child); | ||
18431 | } | ||
18432 | } | ||
18433 | |||
18434 | if (null == previousId) | ||
18435 | { | ||
18436 | // We need *either* <Payload> or <PayloadGroupRef> or even just @SourceFile on the BA... | ||
18437 | // but we just say there's a missing <Payload>. | ||
18438 | // TODO: Is there a better message for this? | ||
18439 | this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Payload")); | ||
18440 | } | ||
18441 | |||
18442 | // Add the application as an attached container and if an Id was provided add that too. | ||
18443 | if (!this.Core.EncounteredError) | ||
18444 | { | ||
18445 | var containerRow = (WixBundleContainerTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleContainer); | ||
18446 | containerRow.WixBundleContainer = Compiler.BurnUXContainerId; | ||
18447 | containerRow.Name = "bundle-ux.cab"; | ||
18448 | containerRow.Type = ContainerType.Attached; | ||
18449 | |||
18450 | if (!String.IsNullOrEmpty(id)) | ||
18451 | { | ||
18452 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBootstrapperApplication); | ||
18453 | row.Set(0, id); | ||
18454 | } | ||
18455 | } | ||
18456 | } | ||
18457 | |||
18458 | /// <summary> | ||
18459 | /// Parse the BoostrapperApplicationRef element. | ||
18460 | /// </summary> | ||
18461 | /// <param name="node">Element to parse</param> | ||
18462 | private void ParseBootstrapperApplicationRefElement(XElement node) | ||
18463 | { | ||
18464 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18465 | string id = null; | ||
18466 | string previousId = null; | ||
18467 | var previousType = ComplexReferenceChildType.Unknown; | ||
18468 | |||
18469 | foreach (var attrib in node.Attributes()) | ||
18470 | { | ||
18471 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18472 | { | ||
18473 | switch (attrib.Name.LocalName) | ||
18474 | { | ||
18475 | case "Id": | ||
18476 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
18477 | break; | ||
18478 | default: | ||
18479 | this.Core.UnexpectedAttribute(node, attrib); | ||
18480 | break; | ||
18481 | } | ||
18482 | } | ||
18483 | else | ||
18484 | { | ||
18485 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18486 | } | ||
18487 | } | ||
18488 | |||
18489 | foreach (var child in node.Elements()) | ||
18490 | { | ||
18491 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18492 | { | ||
18493 | switch (child.Name.LocalName) | ||
18494 | { | ||
18495 | case "Payload": | ||
18496 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18497 | previousType = ComplexReferenceChildType.Payload; | ||
18498 | break; | ||
18499 | case "PayloadGroupRef": | ||
18500 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18501 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
18502 | break; | ||
18503 | default: | ||
18504 | this.Core.UnexpectedElement(node, child); | ||
18505 | break; | ||
18506 | } | ||
18507 | } | ||
18508 | else | ||
18509 | { | ||
18510 | this.Core.ParseExtensionElement(node, child); | ||
18511 | } | ||
18512 | } | ||
18513 | |||
18514 | |||
18515 | if (String.IsNullOrEmpty(id)) | ||
18516 | { | ||
18517 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18518 | } | ||
18519 | else | ||
18520 | { | ||
18521 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBootstrapperApplication", id); | ||
18522 | } | ||
18523 | } | ||
18524 | |||
18525 | /// <summary> | ||
18526 | /// Parse the OptionalUpdateRegistration element. | ||
18527 | /// </summary> | ||
18528 | /// <param name="node">The element to parse.</param> | ||
18529 | /// <param name="defaultManufacturer">The manufacturer.</param> | ||
18530 | /// <param name="defaultProductFamily">The product family.</param> | ||
18531 | /// <param name="defaultName">The bundle name.</param> | ||
18532 | private void ParseOptionalUpdateRegistrationElement(XElement node, string defaultManufacturer, string defaultProductFamily, string defaultName) | ||
18533 | { | ||
18534 | const string defaultClassification = "Update"; | ||
18535 | |||
18536 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18537 | string manufacturer = null; | ||
18538 | string department = null; | ||
18539 | string productFamily = null; | ||
18540 | string name = null; | ||
18541 | var classification = defaultClassification; | ||
18542 | |||
18543 | foreach (var attrib in node.Attributes()) | ||
18544 | { | ||
18545 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18546 | { | ||
18547 | switch (attrib.Name.LocalName) | ||
18548 | { | ||
18549 | case "Manufacturer": | ||
18550 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18551 | break; | ||
18552 | case "Department": | ||
18553 | department = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18554 | break; | ||
18555 | case "ProductFamily": | ||
18556 | productFamily = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18557 | break; | ||
18558 | case "Name": | ||
18559 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18560 | break; | ||
18561 | case "Classification": | ||
18562 | classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18563 | break; | ||
18564 | default: | ||
18565 | this.Core.UnexpectedAttribute(node, attrib); | ||
18566 | break; | ||
18567 | } | ||
18568 | } | ||
18569 | else | ||
18570 | { | ||
18571 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18572 | } | ||
18573 | } | ||
18574 | |||
18575 | if (String.IsNullOrEmpty(manufacturer)) | ||
18576 | { | ||
18577 | if (!String.IsNullOrEmpty(defaultManufacturer)) | ||
18578 | { | ||
18579 | manufacturer = defaultManufacturer; | ||
18580 | } | ||
18581 | else | ||
18582 | { | ||
18583 | this.Core.Write(ErrorMessages.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "Manufacturer", node.Parent.Name.LocalName)); | ||
18584 | } | ||
18585 | } | ||
18586 | |||
18587 | if (String.IsNullOrEmpty(productFamily)) | ||
18588 | { | ||
18589 | if (!String.IsNullOrEmpty(defaultProductFamily)) | ||
18590 | { | ||
18591 | productFamily = defaultProductFamily; | ||
18592 | } | ||
18593 | } | ||
18594 | |||
18595 | if (String.IsNullOrEmpty(name)) | ||
18596 | { | ||
18597 | if (!String.IsNullOrEmpty(defaultName)) | ||
18598 | { | ||
18599 | name = defaultName; | ||
18600 | } | ||
18601 | else | ||
18602 | { | ||
18603 | this.Core.Write(ErrorMessages.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "Name", node.Parent.Name.LocalName)); | ||
18604 | } | ||
18605 | } | ||
18606 | |||
18607 | if (String.IsNullOrEmpty(classification)) | ||
18608 | { | ||
18609 | this.Core.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, node.Name.LocalName, "Classification", defaultClassification)); | ||
18610 | } | ||
18611 | |||
18612 | this.Core.ParseForExtensionElements(node); | ||
18613 | |||
18614 | if (!this.Core.EncounteredError) | ||
18615 | { | ||
18616 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixUpdateRegistration); | ||
18617 | row.Set(0, manufacturer); | ||
18618 | row.Set(1, department); | ||
18619 | row.Set(2, productFamily); | ||
18620 | row.Set(3, name); | ||
18621 | row.Set(4, classification); | ||
18622 | } | ||
18623 | } | ||
18624 | |||
18625 | /// <summary> | ||
18626 | /// Parse Payload element. | ||
18627 | /// </summary> | ||
18628 | /// <param name="node">Element to parse</param> | ||
18629 | /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param> | ||
18630 | /// <param name="parentId">Identifier of parent element.</param> | ||
18631 | private string ParsePayloadElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
18632 | { | ||
18633 | Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
18634 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); | ||
18635 | |||
18636 | var id = this.ParsePayloadElementContent(node, parentType, parentId, previousType, previousId, true); | ||
18637 | var context = new Dictionary<string, string> | ||
18638 | { | ||
18639 | ["Id"] = id | ||
18640 | }; | ||
18641 | |||
18642 | foreach (var child in node.Elements()) | ||
18643 | { | ||
18644 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18645 | { | ||
18646 | switch (child.Name.LocalName) | ||
18647 | { | ||
18648 | default: | ||
18649 | this.Core.UnexpectedElement(node, child); | ||
18650 | break; | ||
18651 | } | ||
18652 | } | ||
18653 | else | ||
18654 | { | ||
18655 | this.Core.ParseExtensionElement(node, child, context); | ||
18656 | } | ||
18657 | } | ||
18658 | |||
18659 | return id; | ||
18660 | } | ||
18661 | |||
18662 | /// <summary> | ||
18663 | /// Parse the attributes of the Payload element. | ||
18664 | /// </summary> | ||
18665 | /// <param name="node">Element to parse</param> | ||
18666 | /// <param name="parentType">ComplexReferenceParentType of parent element.</param> | ||
18667 | /// <param name="parentId">Identifier of parent element.</param> | ||
18668 | private string ParsePayloadElementContent(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, bool required) | ||
18669 | { | ||
18670 | Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
18671 | |||
18672 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18673 | var compressed = YesNoDefaultType.Default; | ||
18674 | var enableSignatureVerification = YesNoType.No; | ||
18675 | Identifier id = null; | ||
18676 | string name = null; | ||
18677 | string sourceFile = null; | ||
18678 | string downloadUrl = null; | ||
18679 | Wix.RemotePayload remotePayload = null; | ||
18680 | |||
18681 | // This list lets us evaluate extension attributes *after* all core attributes | ||
18682 | // have been parsed and dealt with, regardless of authoring order. | ||
18683 | var extensionAttributes = new List<XAttribute>(); | ||
18684 | |||
18685 | foreach (var attrib in node.Attributes()) | ||
18686 | { | ||
18687 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18688 | { | ||
18689 | switch (attrib.Name.LocalName) | ||
18690 | { | ||
18691 | case "Id": | ||
18692 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18693 | break; | ||
18694 | case "Compressed": | ||
18695 | compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
18696 | break; | ||
18697 | case "Name": | ||
18698 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); | ||
18699 | break; | ||
18700 | case "SourceFile": | ||
18701 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18702 | break; | ||
18703 | case "DownloadUrl": | ||
18704 | downloadUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18705 | break; | ||
18706 | case "EnableSignatureVerification": | ||
18707 | enableSignatureVerification = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
18708 | break; | ||
18709 | default: | ||
18710 | this.Core.UnexpectedAttribute(node, attrib); | ||
18711 | break; | ||
18712 | } | ||
18713 | } | ||
18714 | else | ||
18715 | { | ||
18716 | extensionAttributes.Add(attrib); | ||
18717 | } | ||
18718 | } | ||
18719 | |||
18720 | if (!required && null == sourceFile) | ||
18721 | { | ||
18722 | // Nothing left to do! | ||
18723 | return null; | ||
18724 | } | ||
18725 | |||
18726 | if (null == id) | ||
18727 | { | ||
18728 | id = this.Core.CreateIdentifier("pay", (null != sourceFile) ? sourceFile.ToUpperInvariant() : String.Empty); | ||
18729 | } | ||
18730 | |||
18731 | // Now that the PayloadId is known, we can parse the extension attributes. | ||
18732 | var context = new Dictionary<string, string> | ||
18733 | { | ||
18734 | ["Id"] = id.Id | ||
18735 | }; | ||
18736 | |||
18737 | foreach (var extensionAttribute in extensionAttributes) | ||
18738 | { | ||
18739 | this.Core.ParseExtensionAttribute(node, extensionAttribute, context); | ||
18740 | } | ||
18741 | |||
18742 | // We only handle the elements we care about. Let caller handle other children. | ||
18743 | foreach (var child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) | ||
18744 | { | ||
18745 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18746 | |||
18747 | if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage") | ||
18748 | { | ||
18749 | this.Core.Write(ErrorMessages.RemotePayloadUnsupported(childSourceLineNumbers)); | ||
18750 | continue; | ||
18751 | } | ||
18752 | |||
18753 | if (null != remotePayload) | ||
18754 | { | ||
18755 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
18756 | } | ||
18757 | |||
18758 | remotePayload = this.ParseRemotePayloadElement(child); | ||
18759 | } | ||
18760 | |||
18761 | if (null != sourceFile && null != remotePayload) | ||
18762 | { | ||
18763 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "RemotePayload", "SourceFile")); | ||
18764 | } | ||
18765 | else if (null == sourceFile && null == remotePayload) | ||
18766 | { | ||
18767 | this.Core.Write(ErrorMessages.ExpectedAttributeOrElement(sourceLineNumbers, node.Name.LocalName, "SourceFile", "RemotePayload")); | ||
18768 | } | ||
18769 | else if (null == sourceFile) | ||
18770 | { | ||
18771 | sourceFile = String.Empty; | ||
18772 | } | ||
18773 | |||
18774 | if (null == downloadUrl && null != remotePayload) | ||
18775 | { | ||
18776 | this.Core.Write(ErrorMessages.ExpectedAttributeWithElement(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "RemotePayload")); | ||
18777 | } | ||
18778 | |||
18779 | if (Compiler.BurnUXContainerId == parentId) | ||
18780 | { | ||
18781 | if (compressed == YesNoDefaultType.No) | ||
18782 | { | ||
18783 | this.Core.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(sourceLineNumbers, sourceFile)); | ||
18784 | } | ||
18785 | |||
18786 | compressed = YesNoDefaultType.Yes; | ||
18787 | } | ||
18788 | |||
18789 | this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, parentType, parentId, previousType, previousId, compressed, enableSignatureVerification, null, null, remotePayload); | ||
18790 | |||
18791 | return id.Id; | ||
18792 | } | ||
18793 | |||
18794 | private Wix.RemotePayload ParseRemotePayloadElement(XElement node) | ||
18795 | { | ||
18796 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18797 | var remotePayload = new Wix.RemotePayload(); | ||
18798 | |||
18799 | foreach (var attrib in node.Attributes()) | ||
18800 | { | ||
18801 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18802 | { | ||
18803 | switch (attrib.Name.LocalName) | ||
18804 | { | ||
18805 | case "CertificatePublicKey": | ||
18806 | remotePayload.CertificatePublicKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18807 | break; | ||
18808 | case "CertificateThumbprint": | ||
18809 | remotePayload.CertificateThumbprint = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18810 | break; | ||
18811 | case "Description": | ||
18812 | remotePayload.Description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18813 | break; | ||
18814 | case "Hash": | ||
18815 | remotePayload.Hash = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18816 | break; | ||
18817 | case "ProductName": | ||
18818 | remotePayload.ProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18819 | break; | ||
18820 | case "Size": | ||
18821 | remotePayload.Size = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
18822 | break; | ||
18823 | case "Version": | ||
18824 | remotePayload.Version = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18825 | break; | ||
18826 | default: | ||
18827 | this.Core.UnexpectedAttribute(node, attrib); | ||
18828 | break; | ||
18829 | } | ||
18830 | } | ||
18831 | else | ||
18832 | { | ||
18833 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18834 | } | ||
18835 | } | ||
18836 | |||
18837 | if (String.IsNullOrEmpty(remotePayload.ProductName)) | ||
18838 | { | ||
18839 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProductName")); | ||
18840 | } | ||
18841 | |||
18842 | if (String.IsNullOrEmpty(remotePayload.Description)) | ||
18843 | { | ||
18844 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
18845 | } | ||
18846 | |||
18847 | if (String.IsNullOrEmpty(remotePayload.Hash)) | ||
18848 | { | ||
18849 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Hash")); | ||
18850 | } | ||
18851 | |||
18852 | if (0 == remotePayload.Size) | ||
18853 | { | ||
18854 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Size")); | ||
18855 | } | ||
18856 | |||
18857 | if (String.IsNullOrEmpty(remotePayload.Version)) | ||
18858 | { | ||
18859 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
18860 | } | ||
18861 | |||
18862 | return remotePayload; | ||
18863 | } | ||
18864 | |||
18865 | /// <summary> | ||
18866 | /// Creates the row for a Payload. | ||
18867 | /// </summary> | ||
18868 | /// <param name="node">Element to parse</param> | ||
18869 | /// <param name="parentType">ComplexReferenceParentType of parent element</param> | ||
18870 | /// <param name="parentId">Identifier of parent element.</param> | ||
18871 | private WixBundlePayloadTuple CreatePayloadRow(SourceLineNumber sourceLineNumbers, Identifier id, string name, string sourceFile, string downloadUrl, ComplexReferenceParentType parentType, | ||
18872 | string parentId, ComplexReferenceChildType previousType, string previousId, YesNoDefaultType compressed, YesNoType enableSignatureVerification, string displayName, string description, | ||
18873 | Wix.RemotePayload remotePayload) | ||
18874 | { | ||
18875 | WixBundlePayloadTuple row = null; | ||
18876 | |||
18877 | if (!this.Core.EncounteredError) | ||
18878 | { | ||
18879 | row = (WixBundlePayloadTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePayload, id); | ||
18880 | row.Name = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name; | ||
18881 | row.SourceFile = sourceFile; | ||
18882 | row.DownloadUrl = downloadUrl; | ||
18883 | row.Compressed = compressed; | ||
18884 | row.UnresolvedSourceFile = sourceFile; // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. | ||
18885 | row.DisplayName = displayName; | ||
18886 | row.Description = description; | ||
18887 | row.EnableSignatureValidation = (YesNoType.Yes == enableSignatureVerification); | ||
18888 | |||
18889 | if (null != remotePayload) | ||
18890 | { | ||
18891 | row.Description = remotePayload.Description; | ||
18892 | row.DisplayName = remotePayload.ProductName; | ||
18893 | row.Hash = remotePayload.Hash; | ||
18894 | row.PublicKey = remotePayload.CertificatePublicKey; | ||
18895 | row.Thumbprint = remotePayload.CertificateThumbprint; | ||
18896 | row.FileSize = remotePayload.Size; | ||
18897 | row.Version = remotePayload.Version; | ||
18898 | } | ||
18899 | |||
18900 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, id.Id, previousType, previousId); | ||
18901 | } | ||
18902 | |||
18903 | return row; | ||
18904 | } | ||
18905 | |||
18906 | /// <summary> | ||
18907 | /// Parse PayloadGroup element. | ||
18908 | /// </summary> | ||
18909 | /// <param name="node">Element to parse</param> | ||
18910 | /// <param name="parentType">Optional ComplexReferenceParentType of parent element. (typically another PayloadGroup)</param> | ||
18911 | /// <param name="parentId">Identifier of parent element.</param> | ||
18912 | private void ParsePayloadGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
18913 | { | ||
18914 | Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType); | ||
18915 | |||
18916 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18917 | Identifier id = null; | ||
18918 | |||
18919 | foreach (var attrib in node.Attributes()) | ||
18920 | { | ||
18921 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18922 | { | ||
18923 | switch (attrib.Name.LocalName) | ||
18924 | { | ||
18925 | case "Id": | ||
18926 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18927 | break; | ||
18928 | default: | ||
18929 | this.Core.UnexpectedAttribute(node, attrib); | ||
18930 | break; | ||
18931 | } | ||
18932 | } | ||
18933 | else | ||
18934 | { | ||
18935 | this.Core.ParseExtensionAttribute(node, attrib); | ||
18936 | } | ||
18937 | } | ||
18938 | |||
18939 | if (null == id) | ||
18940 | { | ||
18941 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18942 | id = Identifier.Invalid; | ||
18943 | } | ||
18944 | |||
18945 | var previousType = ComplexReferenceChildType.Unknown; | ||
18946 | string previousId = null; | ||
18947 | foreach (var child in node.Elements()) | ||
18948 | { | ||
18949 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18950 | { | ||
18951 | switch (child.Name.LocalName) | ||
18952 | { | ||
18953 | case "Payload": | ||
18954 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id.Id, previousType, previousId); | ||
18955 | previousType = ComplexReferenceChildType.Payload; | ||
18956 | break; | ||
18957 | case "PayloadGroupRef": | ||
18958 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id.Id, previousType, previousId); | ||
18959 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
18960 | break; | ||
18961 | default: | ||
18962 | this.Core.UnexpectedElement(node, child); | ||
18963 | break; | ||
18964 | } | ||
18965 | } | ||
18966 | else | ||
18967 | { | ||
18968 | this.Core.ParseExtensionElement(node, child); | ||
18969 | } | ||
18970 | } | ||
18971 | |||
18972 | |||
18973 | if (!this.Core.EncounteredError) | ||
18974 | { | ||
18975 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePayloadGroup, id); | ||
18976 | |||
18977 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id.Id, ComplexReferenceChildType.Unknown, null); | ||
18978 | } | ||
18979 | } | ||
18980 | |||
18981 | /// <summary> | ||
18982 | /// Parses a payload group reference element. | ||
18983 | /// </summary> | ||
18984 | /// <param name="node">Element to parse.</param> | ||
18985 | /// <param name="parentType">ComplexReferenceParentType of parent element (BA or PayloadGroup).</param> | ||
18986 | /// <param name="parentId">Identifier of parent element.</param> | ||
18987 | private string ParsePayloadGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
18988 | { | ||
18989 | Debug.Assert(ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
18990 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); | ||
18991 | |||
18992 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18993 | string id = null; | ||
18994 | |||
18995 | foreach (var attrib in node.Attributes()) | ||
18996 | { | ||
18997 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18998 | { | ||
18999 | switch (attrib.Name.LocalName) | ||
19000 | { | ||
19001 | case "Id": | ||
19002 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
19003 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBundlePayloadGroup", id); | ||
19004 | break; | ||
19005 | default: | ||
19006 | this.Core.UnexpectedAttribute(node, attrib); | ||
19007 | break; | ||
19008 | } | ||
19009 | } | ||
19010 | else | ||
19011 | { | ||
19012 | this.Core.ParseExtensionAttribute(node, attrib); | ||
19013 | } | ||
19014 | } | ||
19015 | |||
19016 | if (null == id) | ||
19017 | { | ||
19018 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19019 | } | ||
19020 | |||
19021 | this.Core.ParseForExtensionElements(node); | ||
19022 | |||
19023 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id, previousType, previousId); | ||
19024 | |||
19025 | return id; | ||
19026 | } | ||
19027 | |||
19028 | /// <summary> | ||
19029 | /// Creates group and ordering information. | ||
19030 | /// </summary> | ||
19031 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
19032 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19033 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19034 | /// <param name="type">Type of this item.</param> | ||
19035 | /// <param name="id">Identifier for this item.</param> | ||
19036 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19037 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19038 | private void CreateGroupAndOrderingRows(SourceLineNumber sourceLineNumbers, | ||
19039 | ComplexReferenceParentType parentType, string parentId, | ||
19040 | ComplexReferenceChildType type, string id, | ||
19041 | ComplexReferenceChildType previousType, string previousId) | ||
19042 | { | ||
19043 | if (ComplexReferenceParentType.Unknown != parentType && null != parentId) | ||
19044 | { | ||
19045 | this.Core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, type, id); | ||
19046 | } | ||
19047 | |||
19048 | if (ComplexReferenceChildType.Unknown != previousType && null != previousId) | ||
19049 | { | ||
19050 | this.CreateWixOrderingRow(sourceLineNumbers, type, id, previousType, previousId); | ||
19051 | } | ||
19052 | } | ||
19053 | |||
19054 | /// <summary> | ||
19055 | /// Parse ExitCode element. | ||
19056 | /// </summary> | ||
19057 | /// <param name="node">Element to parse</param> | ||
19058 | /// <param name="packageId">Id of parent element</param> | ||
19059 | private void ParseExitCodeElement(XElement node, string packageId) | ||
19060 | { | ||
19061 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19062 | var value = CompilerConstants.IntegerNotSet; | ||
19063 | var behavior = ExitCodeBehaviorType.NotSet; | ||
19064 | |||
19065 | foreach (var attrib in node.Attributes()) | ||
19066 | { | ||
19067 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19068 | { | ||
19069 | switch (attrib.Name.LocalName) | ||
19070 | { | ||
19071 | case "Value": | ||
19072 | value = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int32.MinValue + 2, Int32.MaxValue); | ||
19073 | break; | ||
19074 | case "Behavior": | ||
19075 | var behaviorString = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19076 | if (!Enum.TryParse<ExitCodeBehaviorType>(behaviorString, true, out behavior)) | ||
19077 | { | ||
19078 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Behavior", behaviorString, "success, error, scheduleReboot, forceReboot")); | ||
19079 | } | ||
19080 | break; | ||
19081 | default: | ||
19082 | this.Core.UnexpectedAttribute(node, attrib); | ||
19083 | break; | ||
19084 | } | ||
19085 | } | ||
19086 | else | ||
19087 | { | ||
19088 | this.Core.ParseExtensionAttribute(node, attrib); | ||
19089 | } | ||
19090 | } | ||
19091 | |||
19092 | if (ExitCodeBehaviorType.NotSet == behavior) | ||
19093 | { | ||
19094 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Behavior")); | ||
19095 | } | ||
19096 | |||
19097 | this.Core.ParseForExtensionElements(node); | ||
19098 | |||
19099 | if (!this.Core.EncounteredError) | ||
19100 | { | ||
19101 | var row = (WixBundlePackageExitCodeTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackageExitCode); | ||
19102 | row.ChainPackageId = packageId; | ||
19103 | row.Code = value; | ||
19104 | row.Behavior = behavior; | ||
19105 | } | ||
19106 | } | ||
19107 | |||
19108 | /// <summary> | ||
19109 | /// Parse Chain element. | ||
19110 | /// </summary> | ||
19111 | /// <param name="node">Element to parse</param> | ||
19112 | private void ParseChainElement(XElement node) | ||
19113 | { | ||
19114 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19115 | var attributes = WixChainAttributes.None; | ||
19116 | |||
19117 | foreach (var attrib in node.Attributes()) | ||
19118 | { | ||
19119 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19120 | { | ||
19121 | switch (attrib.Name.LocalName) | ||
19122 | { | ||
19123 | case "DisableRollback": | ||
19124 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
19125 | { | ||
19126 | attributes |= WixChainAttributes.DisableRollback; | ||
19127 | } | ||
19128 | break; | ||
19129 | case "DisableSystemRestore": | ||
19130 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
19131 | { | ||
19132 | attributes |= WixChainAttributes.DisableSystemRestore; | ||
19133 | } | ||
19134 | break; | ||
19135 | case "ParallelCache": | ||
19136 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
19137 | { | ||
19138 | attributes |= WixChainAttributes.ParallelCache; | ||
19139 | } | ||
19140 | break; | ||
19141 | default: | ||
19142 | this.Core.UnexpectedAttribute(node, attrib); | ||
19143 | break; | ||
19144 | } | ||
19145 | } | ||
19146 | else | ||
19147 | { | ||
19148 | this.Core.ParseExtensionAttribute(node, attrib); | ||
19149 | } | ||
19150 | } | ||
19151 | |||
19152 | // Ensure there is always a rollback boundary at the beginning of the chain. | ||
19153 | this.CreateRollbackBoundary(sourceLineNumbers, new Identifier("WixDefaultBoundary", AccessModifier.Public), YesNoType.Yes, YesNoType.No, ComplexReferenceParentType.PackageGroup, "WixChain", ComplexReferenceChildType.Unknown, null); | ||
19154 | |||
19155 | var previousId = "WixDefaultBoundary"; | ||
19156 | var previousType = ComplexReferenceChildType.Package; | ||
19157 | |||
19158 | foreach (var child in node.Elements()) | ||
19159 | { | ||
19160 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
19161 | { | ||
19162 | switch (child.Name.LocalName) | ||
19163 | { | ||
19164 | case "MsiPackage": | ||
19165 | previousId = this.ParseMsiPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19166 | previousType = ComplexReferenceChildType.Package; | ||
19167 | break; | ||
19168 | case "MspPackage": | ||
19169 | previousId = this.ParseMspPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19170 | previousType = ComplexReferenceChildType.Package; | ||
19171 | break; | ||
19172 | case "MsuPackage": | ||
19173 | previousId = this.ParseMsuPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19174 | previousType = ComplexReferenceChildType.Package; | ||
19175 | break; | ||
19176 | case "ExePackage": | ||
19177 | previousId = this.ParseExePackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19178 | previousType = ComplexReferenceChildType.Package; | ||
19179 | break; | ||
19180 | case "RollbackBoundary": | ||
19181 | previousId = this.ParseRollbackBoundaryElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19182 | previousType = ComplexReferenceChildType.Package; | ||
19183 | break; | ||
19184 | case "PackageGroupRef": | ||
19185 | previousId = this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19186 | previousType = ComplexReferenceChildType.PackageGroup; | ||
19187 | break; | ||
19188 | default: | ||
19189 | this.Core.UnexpectedElement(node, child); | ||
19190 | break; | ||
19191 | } | ||
19192 | } | ||
19193 | else | ||
19194 | { | ||
19195 | this.Core.ParseExtensionElement(node, child); | ||
19196 | } | ||
19197 | } | ||
19198 | |||
19199 | |||
19200 | if (null == previousId) | ||
19201 | { | ||
19202 | this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "MsiPackage", "ExePackage", "PackageGroupRef")); | ||
19203 | } | ||
19204 | |||
19205 | if (!this.Core.EncounteredError) | ||
19206 | { | ||
19207 | var row = (WixChainTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixChain); | ||
19208 | row.Attributes = attributes; | ||
19209 | } | ||
19210 | } | ||
19211 | |||
19212 | /// <summary> | ||
19213 | /// Parse MsiPackage element | ||
19214 | /// </summary> | ||
19215 | /// <param name="node">Element to parse</param> | ||
19216 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19217 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19218 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19219 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19220 | /// <returns>Identifier for package element.</returns> | ||
19221 | private string ParseMsiPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19222 | { | ||
19223 | return this.ParseChainPackage(node, WixBundlePackageType.Msi, parentType, parentId, previousType, previousId); | ||
19224 | } | ||
19225 | |||
19226 | /// <summary> | ||
19227 | /// Parse MspPackage element | ||
19228 | /// </summary> | ||
19229 | /// <param name="node">Element to parse</param> | ||
19230 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19231 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19232 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19233 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19234 | /// <returns>Identifier for package element.</returns> | ||
19235 | private string ParseMspPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19236 | { | ||
19237 | return this.ParseChainPackage(node, WixBundlePackageType.Msp, parentType, parentId, previousType, previousId); | ||
19238 | } | ||
19239 | |||
19240 | /// <summary> | ||
19241 | /// Parse MsuPackage element | ||
19242 | /// </summary> | ||
19243 | /// <param name="node">Element to parse</param> | ||
19244 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19245 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19246 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19247 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19248 | /// <returns>Identifier for package element.</returns> | ||
19249 | private string ParseMsuPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19250 | { | ||
19251 | return this.ParseChainPackage(node, WixBundlePackageType.Msu, parentType, parentId, previousType, previousId); | ||
19252 | } | ||
19253 | |||
19254 | /// <summary> | ||
19255 | /// Parse ExePackage element | ||
19256 | /// </summary> | ||
19257 | /// <param name="node">Element to parse</param> | ||
19258 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19259 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19260 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19261 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19262 | /// <returns>Identifier for package element.</returns> | ||
19263 | private string ParseExePackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19264 | { | ||
19265 | return this.ParseChainPackage(node, WixBundlePackageType.Exe, parentType, parentId, previousType, previousId); | ||
19266 | } | ||
19267 | |||
19268 | /// <summary> | ||
19269 | /// Parse RollbackBoundary element | ||
19270 | /// </summary> | ||
19271 | /// <param name="node">Element to parse</param> | ||
19272 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19273 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19274 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19275 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19276 | /// <returns>Identifier for package element.</returns> | ||
19277 | private string ParseRollbackBoundaryElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19278 | { | ||
19279 | Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); | ||
19280 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
19281 | |||
19282 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19283 | Identifier id = null; | ||
19284 | var vital = YesNoType.Yes; | ||
19285 | var transaction = YesNoType.No; | ||
19286 | |||
19287 | // This list lets us evaluate extension attributes *after* all core attributes | ||
19288 | // have been parsed and dealt with, regardless of authoring order. | ||
19289 | var extensionAttributes = new List<XAttribute>(); | ||
19290 | |||
19291 | foreach (var attrib in node.Attributes()) | ||
19292 | { | ||
19293 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19294 | { | ||
19295 | var allowed = true; | ||
19296 | switch (attrib.Name.LocalName) | ||
19297 | { | ||
19298 | case "Id": | ||
19299 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
19300 | break; | ||
19301 | case "Vital": | ||
19302 | vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19303 | break; | ||
19304 | case "Transaction": | ||
19305 | transaction = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19306 | break; | ||
19307 | default: | ||
19308 | allowed = false; | ||
19309 | break; | ||
19310 | } | ||
19311 | |||
19312 | if (!allowed) | ||
19313 | { | ||
19314 | this.Core.UnexpectedAttribute(node, attrib); | ||
19315 | } | ||
19316 | } | ||
19317 | else | ||
19318 | { | ||
19319 | // Save the extension attributes for later... | ||
19320 | extensionAttributes.Add(attrib); | ||
19321 | } | ||
19322 | } | ||
19323 | |||
19324 | if (null == id) | ||
19325 | { | ||
19326 | if (!String.IsNullOrEmpty(previousId)) | ||
19327 | { | ||
19328 | id = this.Core.CreateIdentifier("rba", previousId); | ||
19329 | } | ||
19330 | |||
19331 | if (null == id) | ||
19332 | { | ||
19333 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19334 | id = Identifier.Invalid; | ||
19335 | } | ||
19336 | else if (!Common.IsIdentifier(id.Id)) | ||
19337 | { | ||
19338 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
19339 | } | ||
19340 | } | ||
19341 | |||
19342 | // Now that the rollback identifier is known, we can parse the extension attributes... | ||
19343 | var contextValues = new Dictionary<string, string> | ||
19344 | { | ||
19345 | ["RollbackBoundaryId"] = id.Id | ||
19346 | }; | ||
19347 | foreach (var attribute in extensionAttributes) | ||
19348 | { | ||
19349 | this.Core.ParseExtensionAttribute(node, attribute, contextValues); | ||
19350 | } | ||
19351 | |||
19352 | this.Core.ParseForExtensionElements(node); | ||
19353 | |||
19354 | if (!this.Core.EncounteredError) | ||
19355 | { | ||
19356 | this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, parentType, parentId, previousType, previousId); | ||
19357 | } | ||
19358 | |||
19359 | return id.Id; | ||
19360 | } | ||
19361 | |||
19362 | /// <summary> | ||
19363 | /// Parses one of the ChainPackage elements | ||
19364 | /// </summary> | ||
19365 | /// <param name="node">Element to parse</param> | ||
19366 | /// <param name="packageType">Type of package to parse</param> | ||
19367 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19368 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19369 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19370 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19371 | /// <returns>Identifier for package element.</returns> | ||
19372 | /// <remarks>This method contains the shared logic for parsing all of the ChainPackage | ||
19373 | /// types, as there is more in common between them than different.</remarks> | ||
19374 | private string ParseChainPackage(XElement node, WixBundlePackageType packageType, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19375 | { | ||
19376 | Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); | ||
19377 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
19378 | |||
19379 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19380 | Identifier id = null; | ||
19381 | string name = null; | ||
19382 | string sourceFile = null; | ||
19383 | string downloadUrl = null; | ||
19384 | string after = null; | ||
19385 | string installCondition = null; | ||
19386 | var cache = YesNoAlwaysType.Yes; // the default is to cache everything in tradeoff for stability over disk space. | ||
19387 | string cacheId = null; | ||
19388 | string description = null; | ||
19389 | string displayName = null; | ||
19390 | var logPathVariable = (packageType == WixBundlePackageType.Msu) ? String.Empty : null; | ||
19391 | var rollbackPathVariable = (packageType == WixBundlePackageType.Msu) ? String.Empty : null; | ||
19392 | var permanent = YesNoType.NotSet; | ||
19393 | var visible = YesNoType.NotSet; | ||
19394 | var vital = YesNoType.Yes; | ||
19395 | string installCommand = null; | ||
19396 | string repairCommand = null; | ||
19397 | var repairable = YesNoType.NotSet; | ||
19398 | string uninstallCommand = null; | ||
19399 | var perMachine = YesNoDefaultType.NotSet; | ||
19400 | string detectCondition = null; | ||
19401 | string protocol = null; | ||
19402 | var installSize = CompilerConstants.IntegerNotSet; | ||
19403 | string msuKB = null; | ||
19404 | var suppressLooseFilePayloadGeneration = YesNoType.NotSet; | ||
19405 | var enableSignatureVerification = YesNoType.No; | ||
19406 | var compressed = YesNoDefaultType.Default; | ||
19407 | var displayInternalUI = YesNoType.NotSet; | ||
19408 | var enableFeatureSelection = YesNoType.NotSet; | ||
19409 | var forcePerMachine = YesNoType.NotSet; | ||
19410 | Wix.RemotePayload remotePayload = null; | ||
19411 | var slipstream = YesNoType.NotSet; | ||
19412 | |||
19413 | var expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" }; | ||
19414 | |||
19415 | // This list lets us evaluate extension attributes *after* all core attributes | ||
19416 | // have been parsed and dealt with, regardless of authoring order. | ||
19417 | var extensionAttributes = new List<XAttribute>(); | ||
19418 | |||
19419 | foreach (var attrib in node.Attributes()) | ||
19420 | { | ||
19421 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19422 | { | ||
19423 | var allowed = true; | ||
19424 | switch (attrib.Name.LocalName) | ||
19425 | { | ||
19426 | case "Id": | ||
19427 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
19428 | break; | ||
19429 | case "Name": | ||
19430 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); | ||
19431 | if (!this.Core.IsValidLongFilename(name, false, true)) | ||
19432 | { | ||
19433 | this.Core.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
19434 | } | ||
19435 | break; | ||
19436 | case "SourceFile": | ||
19437 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19438 | break; | ||
19439 | case "DownloadUrl": | ||
19440 | downloadUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19441 | break; | ||
19442 | case "After": | ||
19443 | after = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19444 | break; | ||
19445 | case "InstallCondition": | ||
19446 | installCondition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19447 | break; | ||
19448 | case "Cache": | ||
19449 | cache = this.Core.GetAttributeYesNoAlwaysValue(sourceLineNumbers, attrib); | ||
19450 | break; | ||
19451 | case "CacheId": | ||
19452 | cacheId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19453 | break; | ||
19454 | case "Description": | ||
19455 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19456 | break; | ||
19457 | case "DisplayName": | ||
19458 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19459 | break; | ||
19460 | case "DisplayInternalUI": | ||
19461 | displayInternalUI = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19462 | allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp); | ||
19463 | break; | ||
19464 | case "EnableFeatureSelection": | ||
19465 | enableFeatureSelection = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19466 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19467 | break; | ||
19468 | case "ForcePerMachine": | ||
19469 | forcePerMachine = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19470 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19471 | break; | ||
19472 | case "LogPathVariable": | ||
19473 | logPathVariable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
19474 | break; | ||
19475 | case "RollbackLogPathVariable": | ||
19476 | rollbackPathVariable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
19477 | break; | ||
19478 | case "Permanent": | ||
19479 | permanent = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19480 | break; | ||
19481 | case "Visible": | ||
19482 | visible = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19483 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19484 | break; | ||
19485 | case "Vital": | ||
19486 | vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19487 | break; | ||
19488 | case "InstallCommand": | ||
19489 | installCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19490 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19491 | break; | ||
19492 | case "RepairCommand": | ||
19493 | repairCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
19494 | repairable = YesNoType.Yes; | ||
19495 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19496 | break; | ||
19497 | case "UninstallCommand": | ||
19498 | uninstallCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19499 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19500 | break; | ||
19501 | case "PerMachine": | ||
19502 | perMachine = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
19503 | allowed = (packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msp); | ||
19504 | break; | ||
19505 | case "DetectCondition": | ||
19506 | detectCondition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19507 | allowed = (packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu); | ||
19508 | break; | ||
19509 | case "Protocol": | ||
19510 | protocol = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19511 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19512 | break; | ||
19513 | case "InstallSize": | ||
19514 | installSize = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
19515 | break; | ||
19516 | case "KB": | ||
19517 | msuKB = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19518 | allowed = (packageType == WixBundlePackageType.Msu); | ||
19519 | break; | ||
19520 | case "Compressed": | ||
19521 | compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
19522 | break; | ||
19523 | case "SuppressLooseFilePayloadGeneration": | ||
19524 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
19525 | suppressLooseFilePayloadGeneration = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19526 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19527 | break; | ||
19528 | case "EnableSignatureVerification": | ||
19529 | enableSignatureVerification = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19530 | break; | ||
19531 | case "Slipstream": | ||
19532 | slipstream = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19533 | allowed = (packageType == WixBundlePackageType.Msp); | ||
19534 | break; | ||
19535 | default: | ||
19536 | allowed = false; | ||
19537 | break; | ||
19538 | } | ||
19539 | |||
19540 | if (!allowed) | ||
19541 | { | ||
19542 | this.Core.UnexpectedAttribute(node, attrib); | ||
19543 | } | ||
19544 | } | ||
19545 | else | ||
19546 | { | ||
19547 | // Save the extension attributes for later... | ||
19548 | extensionAttributes.Add(attrib); | ||
19549 | } | ||
19550 | } | ||
19551 | |||
19552 | // We need to handle RemotePayload up front because it effects value of sourceFile which is used in Id generation. Id is needed by other child elements. | ||
19553 | foreach (var child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) | ||
19554 | { | ||
19555 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
19556 | |||
19557 | if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage" && node.Name.LocalName != "MsuPackage") | ||
19558 | { | ||
19559 | this.Core.Write(ErrorMessages.RemotePayloadUnsupported(childSourceLineNumbers)); | ||
19560 | continue; | ||
19561 | } | ||
19562 | |||
19563 | if (null != remotePayload) | ||
19564 | { | ||
19565 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
19566 | } | ||
19567 | |||
19568 | remotePayload = this.ParseRemotePayloadElement(child); | ||
19569 | } | ||
19570 | |||
19571 | if (String.IsNullOrEmpty(sourceFile)) | ||
19572 | { | ||
19573 | if (String.IsNullOrEmpty(name)) | ||
19574 | { | ||
19575 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", "SourceFile")); | ||
19576 | } | ||
19577 | else if (null == remotePayload) | ||
19578 | { | ||
19579 | sourceFile = Path.Combine("SourceDir", name); | ||
19580 | } | ||
19581 | } | ||
19582 | else if (null != remotePayload) | ||
19583 | { | ||
19584 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "RemotePayload", "SourceFile")); | ||
19585 | } | ||
19586 | else if (sourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | ||
19587 | { | ||
19588 | if (String.IsNullOrEmpty(name)) | ||
19589 | { | ||
19590 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name", "SourceFile", sourceFile)); | ||
19591 | } | ||
19592 | else | ||
19593 | { | ||
19594 | sourceFile = Path.Combine(sourceFile, Path.GetFileName(name)); | ||
19595 | } | ||
19596 | } | ||
19597 | |||
19598 | if (null == downloadUrl && null != remotePayload) | ||
19599 | { | ||
19600 | this.Core.Write(ErrorMessages.ExpectedAttributeWithElement(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "RemotePayload")); | ||
19601 | } | ||
19602 | |||
19603 | if (YesNoDefaultType.No != compressed && null != remotePayload) | ||
19604 | { | ||
19605 | compressed = YesNoDefaultType.No; | ||
19606 | this.Core.Write(WarningMessages.RemotePayloadsMustNotAlsoBeCompressed(sourceLineNumbers, node.Name.LocalName)); | ||
19607 | } | ||
19608 | |||
19609 | if (null == id) | ||
19610 | { | ||
19611 | if (!String.IsNullOrEmpty(name)) | ||
19612 | { | ||
19613 | id = this.Core.CreateIdentifierFromFilename(Path.GetFileName(name)); | ||
19614 | } | ||
19615 | else if (!String.IsNullOrEmpty(sourceFile)) | ||
19616 | { | ||
19617 | id = this.Core.CreateIdentifierFromFilename(Path.GetFileName(sourceFile)); | ||
19618 | } | ||
19619 | |||
19620 | if (null == id) | ||
19621 | { | ||
19622 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19623 | id = Identifier.Invalid; | ||
19624 | } | ||
19625 | else if (!Common.IsIdentifier(id.Id)) | ||
19626 | { | ||
19627 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
19628 | } | ||
19629 | } | ||
19630 | |||
19631 | if (null == logPathVariable) | ||
19632 | { | ||
19633 | logPathVariable = String.Concat("WixBundleLog_", id.Id); | ||
19634 | } | ||
19635 | |||
19636 | if (null == rollbackPathVariable) | ||
19637 | { | ||
19638 | rollbackPathVariable = String.Concat("WixBundleRollbackLog_", id.Id); | ||
19639 | } | ||
19640 | |||
19641 | if (!String.IsNullOrEmpty(protocol) && !protocol.Equals("burn", StringComparison.Ordinal) && !protocol.Equals("netfx4", StringComparison.Ordinal) && !protocol.Equals("none", StringComparison.Ordinal)) | ||
19642 | { | ||
19643 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Protocol", protocol, "none, burn, netfx4")); | ||
19644 | } | ||
19645 | |||
19646 | if (!String.IsNullOrEmpty(protocol) && protocol.Equals("netfx4", StringComparison.Ordinal)) | ||
19647 | { | ||
19648 | foreach (var expectedArgument in expectedNetFx4Args) | ||
19649 | { | ||
19650 | if (null == installCommand || -1 == installCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
19651 | { | ||
19652 | this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "InstallCommand", installCommand, expectedArgument, "Protocol", "netfx4")); | ||
19653 | } | ||
19654 | |||
19655 | if (null == repairCommand || -1 == repairCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
19656 | { | ||
19657 | this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "RepairCommand", repairCommand, expectedArgument, "Protocol", "netfx4")); | ||
19658 | } | ||
19659 | |||
19660 | if (null == uninstallCommand || -1 == uninstallCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
19661 | { | ||
19662 | this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "UninstallCommand", uninstallCommand, expectedArgument, "Protocol", "netfx4")); | ||
19663 | } | ||
19664 | } | ||
19665 | } | ||
19666 | |||
19667 | // Only set default scope for EXEs and MSPs if not already set. | ||
19668 | if ((WixBundlePackageType.Exe == packageType || WixBundlePackageType.Msp == packageType) && YesNoDefaultType.NotSet == perMachine) | ||
19669 | { | ||
19670 | perMachine = YesNoDefaultType.Default; | ||
19671 | } | ||
19672 | |||
19673 | // Now that the package ID is known, we can parse the extension attributes... | ||
19674 | var contextValues = new Dictionary<string, string>() { { "PackageId", id.Id } }; | ||
19675 | foreach (var attribute in extensionAttributes) | ||
19676 | { | ||
19677 | this.Core.ParseExtensionAttribute(node, attribute, contextValues); | ||
19678 | } | ||
19679 | |||
19680 | foreach (var child in node.Elements()) | ||
19681 | { | ||
19682 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
19683 | { | ||
19684 | var allowed = true; | ||
19685 | switch (child.Name.LocalName) | ||
19686 | { | ||
19687 | case "SlipstreamMsp": | ||
19688 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19689 | if (allowed) | ||
19690 | { | ||
19691 | this.ParseSlipstreamMspElement(child, id.Id); | ||
19692 | } | ||
19693 | break; | ||
19694 | case "MsiProperty": | ||
19695 | allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp); | ||
19696 | if (allowed) | ||
19697 | { | ||
19698 | this.ParseMsiPropertyElement(child, id.Id); | ||
19699 | } | ||
19700 | break; | ||
19701 | case "Payload": | ||
19702 | this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id.Id, ComplexReferenceChildType.Unknown, null); | ||
19703 | break; | ||
19704 | case "PayloadGroupRef": | ||
19705 | this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id.Id, ComplexReferenceChildType.Unknown, null); | ||
19706 | break; | ||
19707 | case "ExitCode": | ||
19708 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19709 | if (allowed) | ||
19710 | { | ||
19711 | this.ParseExitCodeElement(child, id.Id); | ||
19712 | } | ||
19713 | break; | ||
19714 | case "CommandLine": | ||
19715 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19716 | if (allowed) | ||
19717 | { | ||
19718 | this.ParseCommandLineElement(child, id.Id); | ||
19719 | } | ||
19720 | break; | ||
19721 | case "RemotePayload": | ||
19722 | // Handled previously | ||
19723 | break; | ||
19724 | default: | ||
19725 | allowed = false; | ||
19726 | break; | ||
19727 | } | ||
19728 | |||
19729 | if (!allowed) | ||
19730 | { | ||
19731 | this.Core.UnexpectedElement(node, child); | ||
19732 | } | ||
19733 | } | ||
19734 | else | ||
19735 | { | ||
19736 | var context = new Dictionary<string, string>() { { "Id", id.Id } }; | ||
19737 | this.Core.ParseExtensionElement(node, child, context); | ||
19738 | } | ||
19739 | } | ||
19740 | |||
19741 | if (!this.Core.EncounteredError) | ||
19742 | { | ||
19743 | // We create the package contents as a payload with this package as the parent | ||
19744 | this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, ComplexReferenceParentType.Package, id.Id, | ||
19745 | ComplexReferenceChildType.Unknown, null, compressed, enableSignatureVerification, displayName, description, remotePayload); | ||
19746 | |||
19747 | var chainItemRow = (WixChainItemTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixChainItem, id); | ||
19748 | |||
19749 | WixBundlePackageAttributes attributes = 0; | ||
19750 | attributes |= (YesNoType.Yes == permanent) ? WixBundlePackageAttributes.Permanent : 0; | ||
19751 | attributes |= (YesNoType.Yes == visible) ? WixBundlePackageAttributes.Visible : 0; | ||
19752 | |||
19753 | var chainPackageRow = (WixBundlePackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackage, id); | ||
19754 | chainPackageRow.Type = packageType; | ||
19755 | chainPackageRow.Payload_ = id.Id; | ||
19756 | chainPackageRow.Attributes = attributes; | ||
19757 | |||
19758 | chainPackageRow.InstallCondition = installCondition; | ||
19759 | |||
19760 | if (YesNoAlwaysType.NotSet != cache) | ||
19761 | { | ||
19762 | chainPackageRow.Cache = cache; | ||
19763 | } | ||
19764 | |||
19765 | chainPackageRow.CacheId = cacheId; | ||
19766 | |||
19767 | if (YesNoType.NotSet != vital) | ||
19768 | { | ||
19769 | chainPackageRow.Vital = (vital == YesNoType.Yes); | ||
19770 | } | ||
19771 | |||
19772 | if (YesNoDefaultType.NotSet != perMachine) | ||
19773 | { | ||
19774 | chainPackageRow.PerMachine = perMachine; | ||
19775 | } | ||
19776 | |||
19777 | chainPackageRow.LogPathVariable = logPathVariable; | ||
19778 | chainPackageRow.RollbackLogPathVariable = rollbackPathVariable; | ||
19779 | |||
19780 | if (CompilerConstants.IntegerNotSet != installSize) | ||
19781 | { | ||
19782 | chainPackageRow.InstallSize = installSize; | ||
19783 | } | ||
19784 | |||
19785 | switch (packageType) | ||
19786 | { | ||
19787 | case WixBundlePackageType.Exe: | ||
19788 | WixBundleExePackageAttributes exeAttributes = 0; | ||
19789 | exeAttributes |= (YesNoType.Yes == repairable) ? WixBundleExePackageAttributes.Repairable : 0; | ||
19790 | |||
19791 | var exeRow = (WixBundleExePackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleExePackage, id); | ||
19792 | exeRow.Attributes = exeAttributes; | ||
19793 | exeRow.DetectCondition = detectCondition; | ||
19794 | exeRow.InstallCommand = installCommand; | ||
19795 | exeRow.RepairCommand = repairCommand; | ||
19796 | exeRow.UninstallCommand = uninstallCommand; | ||
19797 | exeRow.ExeProtocol = protocol; | ||
19798 | break; | ||
19799 | |||
19800 | case WixBundlePackageType.Msi: | ||
19801 | WixBundleMsiPackageAttributes msiAttributes = 0; | ||
19802 | msiAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMsiPackageAttributes.DisplayInternalUI : 0; | ||
19803 | msiAttributes |= (YesNoType.Yes == enableFeatureSelection) ? WixBundleMsiPackageAttributes.EnableFeatureSelection : 0; | ||
19804 | msiAttributes |= (YesNoType.Yes == forcePerMachine) ? WixBundleMsiPackageAttributes.ForcePerMachine : 0; | ||
19805 | msiAttributes |= (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? WixBundleMsiPackageAttributes.SuppressLooseFilePayloadGeneration : 0; | ||
19806 | |||
19807 | var msiRow = (WixBundleMsiPackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMsiPackage, id); | ||
19808 | msiRow.Attributes = msiAttributes; | ||
19809 | break; | ||
19810 | |||
19811 | case WixBundlePackageType.Msp: | ||
19812 | WixBundleMspPackageAttributes mspAttributes = 0; | ||
19813 | mspAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMspPackageAttributes.DisplayInternalUI : 0; | ||
19814 | mspAttributes |= (YesNoType.Yes == slipstream) ? WixBundleMspPackageAttributes.Slipstream : 0; | ||
19815 | |||
19816 | var mspRow = (WixBundleMspPackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMspPackage, id); | ||
19817 | mspRow.Attributes = mspAttributes; | ||
19818 | break; | ||
19819 | |||
19820 | case WixBundlePackageType.Msu: | ||
19821 | var msuRow = (WixBundleMsuPackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMsuPackage, id); | ||
19822 | msuRow.DetectCondition = detectCondition; | ||
19823 | msuRow.MsuKB = msuKB; | ||
19824 | break; | ||
19825 | } | ||
19826 | |||
19827 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, after); | ||
19828 | } | ||
19829 | |||
19830 | return id.Id; | ||
19831 | } | ||
19832 | |||
19833 | /// <summary> | ||
19834 | /// Parse CommandLine element. | ||
19835 | /// </summary> | ||
19836 | /// <param name="node">Element to parse</param> | ||
19837 | private void ParseCommandLineElement(XElement node, string packageId) | ||
19838 | { | ||
19839 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19840 | string installArgument = null; | ||
19841 | string uninstallArgument = null; | ||
19842 | string repairArgument = null; | ||
19843 | string condition = null; | ||
19844 | |||
19845 | foreach (var attrib in node.Attributes()) | ||
19846 | { | ||
19847 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19848 | { | ||
19849 | switch (attrib.Name.LocalName) | ||
19850 | { | ||
19851 | case "InstallArgument": | ||
19852 | installArgument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19853 | break; | ||
19854 | case "UninstallArgument": | ||
19855 | uninstallArgument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19856 | break; | ||
19857 | case "RepairArgument": | ||
19858 | repairArgument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19859 | break; | ||
19860 | case "Condition": | ||
19861 | condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19862 | break; | ||
19863 | default: | ||
19864 | this.Core.UnexpectedAttribute(node, attrib); | ||
19865 | break; | ||
19866 | } | ||
19867 | } | ||
19868 | else | ||
19869 | { | ||
19870 | this.Core.ParseExtensionAttribute(node, attrib); | ||
19871 | } | ||
19872 | } | ||
19873 | |||
19874 | if (String.IsNullOrEmpty(condition)) | ||
19875 | { | ||
19876 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Condition")); | ||
19877 | } | ||
19878 | |||
19879 | this.Core.ParseForExtensionElements(node); | ||
19880 | |||
19881 | if (!this.Core.EncounteredError) | ||
19882 | { | ||
19883 | var row = (WixBundlePackageCommandLineTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackageCommandLine); | ||
19884 | row.WixBundlePackage_ = packageId; | ||
19885 | row.InstallArgument = installArgument; | ||
19886 | row.UninstallArgument = uninstallArgument; | ||
19887 | row.RepairArgument = repairArgument; | ||
19888 | row.Condition = condition; | ||
19889 | } | ||
19890 | } | ||
19891 | |||
19892 | /// <summary> | ||
19893 | /// Parse PackageGroup element. | ||
19894 | /// </summary> | ||
19895 | /// <param name="node">Element to parse</param> | ||
19896 | private void ParsePackageGroupElement(XElement node) | ||
19897 | { | ||
19898 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19899 | Identifier id = null; | ||
19900 | |||
19901 | foreach (var attrib in node.Attributes()) | ||
19902 | { | ||
19903 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19904 | { | ||
19905 | switch (attrib.Name.LocalName) | ||
19906 | { | ||
19907 | case "Id": | ||
19908 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
19909 | break; | ||
19910 | default: | ||
19911 | this.Core.UnexpectedAttribute(node, attrib); | ||
19912 | break; | ||
19913 | } | ||
19914 | } | ||
19915 | else | ||
19916 | { | ||
19917 | this.Core.ParseExtensionAttribute(node, attrib); | ||
19918 | } | ||
19919 | } | ||
19920 | |||
19921 | if (null == id) | ||
19922 | { | ||
19923 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19924 | id = Identifier.Invalid; | ||
19925 | } | ||
19926 | |||
19927 | var previousType = ComplexReferenceChildType.Unknown; | ||
19928 | string previousId = null; | ||
19929 | foreach (var child in node.Elements()) | ||
19930 | { | ||
19931 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
19932 | { | ||
19933 | switch (child.Name.LocalName) | ||
19934 | { | ||
19935 | case "MsiPackage": | ||
19936 | previousId = this.ParseMsiPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
19937 | previousType = ComplexReferenceChildType.Package; | ||
19938 | break; | ||
19939 | case "MspPackage": | ||
19940 | previousId = this.ParseMspPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
19941 | previousType = ComplexReferenceChildType.Package; | ||
19942 | break; | ||
19943 | case "MsuPackage": | ||
19944 | previousId = this.ParseMsuPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
19945 | previousType = ComplexReferenceChildType.Package; | ||
19946 | break; | ||
19947 | case "ExePackage": | ||
19948 | previousId = this.ParseExePackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
19949 | previousType = ComplexReferenceChildType.Package; | ||
19950 | break; | ||
19951 | case "RollbackBoundary": | ||
19952 | previousId = this.ParseRollbackBoundaryElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
19953 | previousType = ComplexReferenceChildType.Package; | ||
19954 | break; | ||
19955 | case "PackageGroupRef": | ||
19956 | previousId = this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
19957 | previousType = ComplexReferenceChildType.PackageGroup; | ||
19958 | break; | ||
19959 | default: | ||
19960 | this.Core.UnexpectedElement(node, child); | ||
19961 | break; | ||
19962 | } | ||
19963 | } | ||
19964 | else | ||
19965 | { | ||
19966 | this.Core.ParseExtensionElement(node, child); | ||
19967 | } | ||
19968 | } | ||
19969 | |||
19970 | |||
19971 | if (!this.Core.EncounteredError) | ||
19972 | { | ||
19973 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackageGroup, id); | ||
19974 | } | ||
19975 | } | ||
19976 | |||
19977 | /// <summary> | ||
19978 | /// Parses a package group reference element. | ||
19979 | /// </summary> | ||
19980 | /// <param name="node">Element to parse.</param> | ||
19981 | /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> | ||
19982 | /// <param name="parentId">Identifier of parent element.</param> | ||
19983 | /// <returns>Identifier for package group element.</rereturns> | ||
19984 | private string ParsePackageGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
19985 | { | ||
19986 | return this.ParsePackageGroupRefElement(node, parentType, parentId, ComplexReferenceChildType.Unknown, null); | ||
19987 | } | ||
19988 | |||
19989 | /// <summary> | ||
19990 | /// Parses a package group reference element. | ||
19991 | /// </summary> | ||
19992 | /// <param name="node">Element to parse.</param> | ||
19993 | /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> | ||
19994 | /// <param name="parentId">Identifier of parent element.</param> | ||
19995 | /// <param name="parentType">ComplexReferenceParentType of previous element (Unknown, Package, or PackageGroup).</param> | ||
19996 | /// <param name="parentId">Identifier of parent element.</param> | ||
19997 | /// <returns>Identifier for package group element.</rereturns> | ||
19998 | private string ParsePackageGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19999 | { | ||
20000 | Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.PackageGroup == parentType || ComplexReferenceParentType.Container == parentType); | ||
20001 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
20002 | |||
20003 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20004 | string id = null; | ||
20005 | string after = null; | ||
20006 | |||
20007 | foreach (var attrib in node.Attributes()) | ||
20008 | { | ||
20009 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20010 | { | ||
20011 | switch (attrib.Name.LocalName) | ||
20012 | { | ||
20013 | case "Id": | ||
20014 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
20015 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBundlePackageGroup", id); | ||
20016 | break; | ||
20017 | case "After": | ||
20018 | after = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
20019 | break; | ||
20020 | default: | ||
20021 | this.Core.UnexpectedAttribute(node, attrib); | ||
20022 | break; | ||
20023 | } | ||
20024 | } | ||
20025 | else | ||
20026 | { | ||
20027 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20028 | |||
20029 | } | ||
20030 | } | ||
20031 | |||
20032 | if (null == id) | ||
20033 | { | ||
20034 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20035 | } | ||
20036 | |||
20037 | if (null != after && ComplexReferenceParentType.Container == parentType) | ||
20038 | { | ||
20039 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "After", parentId)); | ||
20040 | } | ||
20041 | |||
20042 | this.Core.ParseForExtensionElements(node); | ||
20043 | |||
20044 | if (ComplexReferenceParentType.Container == parentType) | ||
20045 | { | ||
20046 | this.Core.CreateWixGroupRow(sourceLineNumbers, ComplexReferenceParentType.Container, parentId, ComplexReferenceChildType.PackageGroup, id); | ||
20047 | } | ||
20048 | else | ||
20049 | { | ||
20050 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PackageGroup, id, previousType, previousId, after); | ||
20051 | } | ||
20052 | |||
20053 | return id; | ||
20054 | } | ||
20055 | |||
20056 | /// <summary> | ||
20057 | /// Creates rollback boundary. | ||
20058 | /// </summary> | ||
20059 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
20060 | /// <param name="id">Identifier for the rollback boundary.</param> | ||
20061 | /// <param name="vital">Indicates whether the rollback boundary is vital or not.</param> | ||
20062 | /// <param name="parentType">Type of parent group.</param> | ||
20063 | /// <param name="parentId">Identifier of parent group.</param> | ||
20064 | /// <param name="previousType">Type of previous item, if any.</param> | ||
20065 | /// <param name="previousId">Identifier of previous item, if any.</param> | ||
20066 | private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
20067 | { | ||
20068 | var row = (WixChainItemTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixChainItem, id); | ||
20069 | |||
20070 | var rollbackBoundary = (WixBundleRollbackBoundaryTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleRollbackBoundary, id); | ||
20071 | |||
20072 | if (YesNoType.NotSet != vital) | ||
20073 | { | ||
20074 | rollbackBoundary.Vital = (vital == YesNoType.Yes); | ||
20075 | } | ||
20076 | if (YesNoType.NotSet != transaction) | ||
20077 | { | ||
20078 | rollbackBoundary.Transaction = (transaction == YesNoType.Yes); | ||
20079 | } | ||
20080 | |||
20081 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, null); | ||
20082 | } | ||
20083 | |||
20084 | /// <summary> | ||
20085 | /// Creates group and ordering information for packages | ||
20086 | /// </summary> | ||
20087 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
20088 | /// <param name="parentType">Type of parent group, if known.</param> | ||
20089 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
20090 | /// <param name="type">Type of this item.</param> | ||
20091 | /// <param name="id">Identifier for this item.</param> | ||
20092 | /// <param name="previousType">Type of previous item, if known.</param> | ||
20093 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
20094 | /// <param name="afterId">Identifier of explicit 'After' attribute, if given.</param> | ||
20095 | private void CreateChainPackageMetaRows(SourceLineNumber sourceLineNumbers, | ||
20096 | ComplexReferenceParentType parentType, string parentId, | ||
20097 | ComplexReferenceChildType type, string id, | ||
20098 | ComplexReferenceChildType previousType, string previousId, string afterId) | ||
20099 | { | ||
20100 | // If there's an explicit 'After' attribute, it overrides the inferred previous item. | ||
20101 | if (null != afterId) | ||
20102 | { | ||
20103 | previousType = ComplexReferenceChildType.Package; | ||
20104 | previousId = afterId; | ||
20105 | } | ||
20106 | |||
20107 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, type, id, previousType, previousId); | ||
20108 | } | ||
20109 | |||
20110 | // TODO: Should we define our own enum for this, just to ensure there's no "cross-contamination"? | ||
20111 | // TODO: Also, we could potentially include an 'Attributes' field to track things like | ||
20112 | // 'before' vs. 'after', and explicit vs. inferred dependencies. | ||
20113 | private void CreateWixOrderingRow(SourceLineNumber sourceLineNumbers, | ||
20114 | ComplexReferenceChildType itemType, string itemId, | ||
20115 | ComplexReferenceChildType dependsOnType, string dependsOnId) | ||
20116 | { | ||
20117 | if (!this.Core.EncounteredError) | ||
20118 | { | ||
20119 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixOrdering); | ||
20120 | row.Set(0, itemType.ToString()); | ||
20121 | row.Set(1, itemId); | ||
20122 | row.Set(2, dependsOnType.ToString()); | ||
20123 | row.Set(3, dependsOnId); | ||
20124 | } | ||
20125 | } | ||
20126 | |||
20127 | /// <summary> | ||
20128 | /// Parse MsiProperty element | ||
20129 | /// </summary> | ||
20130 | /// <param name="node">Element to parse</param> | ||
20131 | /// <param name="packageId">Id of parent element</param> | ||
20132 | private void ParseMsiPropertyElement(XElement node, string packageId) | ||
20133 | { | ||
20134 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20135 | string name = null; | ||
20136 | string value = null; | ||
20137 | string condition = null; | ||
20138 | |||
20139 | foreach (var attrib in node.Attributes()) | ||
20140 | { | ||
20141 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20142 | { | ||
20143 | switch (attrib.Name.LocalName) | ||
20144 | { | ||
20145 | case "Name": | ||
20146 | name = this.Core.GetAttributeMsiPropertyNameValue(sourceLineNumbers, attrib); | ||
20147 | break; | ||
20148 | case "Value": | ||
20149 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20150 | break; | ||
20151 | case "Condition": | ||
20152 | condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20153 | break; | ||
20154 | default: | ||
20155 | this.Core.UnexpectedAttribute(node, attrib); | ||
20156 | break; | ||
20157 | } | ||
20158 | } | ||
20159 | else | ||
20160 | { | ||
20161 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20162 | } | ||
20163 | } | ||
20164 | |||
20165 | if (null == name) | ||
20166 | { | ||
20167 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
20168 | } | ||
20169 | |||
20170 | if (null == value) | ||
20171 | { | ||
20172 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
20173 | } | ||
20174 | |||
20175 | this.Core.ParseForExtensionElements(node); | ||
20176 | |||
20177 | if (!this.Core.EncounteredError) | ||
20178 | { | ||
20179 | var row = (WixBundleMsiPropertyTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMsiProperty); | ||
20180 | row.WixBundlePackage_ = packageId; | ||
20181 | row.Name = name; | ||
20182 | row.Value = value; | ||
20183 | |||
20184 | if (!String.IsNullOrEmpty(condition)) | ||
20185 | { | ||
20186 | row.Condition = condition; | ||
20187 | } | ||
20188 | } | ||
20189 | } | ||
20190 | |||
20191 | /// <summary> | ||
20192 | /// Parse SlipstreamMsp element | ||
20193 | /// </summary> | ||
20194 | /// <param name="node">Element to parse</param> | ||
20195 | /// <param name="packageId">Id of parent element</param> | ||
20196 | private void ParseSlipstreamMspElement(XElement node, string packageId) | ||
20197 | { | ||
20198 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20199 | string id = null; | ||
20200 | |||
20201 | foreach (var attrib in node.Attributes()) | ||
20202 | { | ||
20203 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20204 | { | ||
20205 | switch (attrib.Name.LocalName) | ||
20206 | { | ||
20207 | case "Id": | ||
20208 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
20209 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBundlePackage", id); | ||
20210 | break; | ||
20211 | default: | ||
20212 | this.Core.UnexpectedAttribute(node, attrib); | ||
20213 | break; | ||
20214 | } | ||
20215 | } | ||
20216 | else | ||
20217 | { | ||
20218 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20219 | } | ||
20220 | } | ||
20221 | |||
20222 | if (null == id) | ||
20223 | { | ||
20224 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20225 | } | ||
20226 | |||
20227 | this.Core.ParseForExtensionElements(node); | ||
20228 | |||
20229 | if (!this.Core.EncounteredError) | ||
20230 | { | ||
20231 | var row = (WixBundleSlipstreamMspTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleSlipstreamMsp); | ||
20232 | row.WixBundlePackage_ = packageId; | ||
20233 | row.WixBundlePackage_Msp = id; | ||
20234 | } | ||
20235 | } | ||
20236 | |||
20237 | /// <summary> | ||
20238 | /// Parse RelatedBundle element | ||
20239 | /// </summary> | ||
20240 | /// <param name="node">Element to parse</param> | ||
20241 | private void ParseRelatedBundleElement(XElement node) | ||
20242 | { | ||
20243 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20244 | string id = null; | ||
20245 | string action = null; | ||
20246 | var actionType = Wix.RelatedBundle.ActionType.Detect; | ||
20247 | |||
20248 | foreach (var attrib in node.Attributes()) | ||
20249 | { | ||
20250 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20251 | { | ||
20252 | switch (attrib.Name.LocalName) | ||
20253 | { | ||
20254 | case "Id": | ||
20255 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
20256 | break; | ||
20257 | case "Action": | ||
20258 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20259 | break; | ||
20260 | default: | ||
20261 | this.Core.UnexpectedAttribute(node, attrib); | ||
20262 | break; | ||
20263 | } | ||
20264 | } | ||
20265 | else | ||
20266 | { | ||
20267 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20268 | } | ||
20269 | } | ||
20270 | |||
20271 | if (null == id) | ||
20272 | { | ||
20273 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20274 | } | ||
20275 | |||
20276 | if (!String.IsNullOrEmpty(action)) | ||
20277 | { | ||
20278 | actionType = Wix.RelatedBundle.ParseActionType(action); | ||
20279 | switch (actionType) | ||
20280 | { | ||
20281 | case Wix.RelatedBundle.ActionType.Detect: | ||
20282 | break; | ||
20283 | case Wix.RelatedBundle.ActionType.Upgrade: | ||
20284 | break; | ||
20285 | case Wix.RelatedBundle.ActionType.Addon: | ||
20286 | break; | ||
20287 | case Wix.RelatedBundle.ActionType.Patch: | ||
20288 | break; | ||
20289 | default: | ||
20290 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", action, "Detect", "Upgrade", "Addon", "Patch")); | ||
20291 | break; | ||
20292 | } | ||
20293 | } | ||
20294 | |||
20295 | this.Core.ParseForExtensionElements(node); | ||
20296 | |||
20297 | if (!this.Core.EncounteredError) | ||
20298 | { | ||
20299 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixRelatedBundle); | ||
20300 | row.Set(0, id); | ||
20301 | row.Set(1, (int)actionType); | ||
20302 | } | ||
20303 | } | ||
20304 | |||
20305 | /// <summary> | ||
20306 | /// Parse Update element | ||
20307 | /// </summary> | ||
20308 | /// <param name="node">Element to parse</param> | ||
20309 | private void ParseUpdateElement(XElement node) | ||
20310 | { | ||
20311 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20312 | string location = null; | ||
20313 | |||
20314 | foreach (var attrib in node.Attributes()) | ||
20315 | { | ||
20316 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20317 | { | ||
20318 | switch (attrib.Name.LocalName) | ||
20319 | { | ||
20320 | case "Location": | ||
20321 | location = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20322 | break; | ||
20323 | default: | ||
20324 | this.Core.UnexpectedAttribute(node, attrib); | ||
20325 | break; | ||
20326 | } | ||
20327 | } | ||
20328 | else | ||
20329 | { | ||
20330 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20331 | } | ||
20332 | } | ||
20333 | |||
20334 | if (null == location) | ||
20335 | { | ||
20336 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Location")); | ||
20337 | } | ||
20338 | |||
20339 | this.Core.ParseForExtensionElements(node); | ||
20340 | |||
20341 | if (!this.Core.EncounteredError) | ||
20342 | { | ||
20343 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleUpdate); | ||
20344 | row.Set(0, location); | ||
20345 | } | ||
20346 | } | ||
20347 | |||
20348 | /// <summary> | ||
20349 | /// Parse Variable element | ||
20350 | /// </summary> | ||
20351 | /// <param name="node">Element to parse</param> | ||
20352 | private void ParseVariableElement(XElement node) | ||
20353 | { | ||
20354 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20355 | var hidden = false; | ||
20356 | string name = null; | ||
20357 | var persisted = false; | ||
20358 | string value = null; | ||
20359 | string type = null; | ||
20360 | |||
20361 | foreach (var attrib in node.Attributes()) | ||
20362 | { | ||
20363 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20364 | { | ||
20365 | switch (attrib.Name.LocalName) | ||
20366 | { | ||
20367 | case "Hidden": | ||
20368 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
20369 | { | ||
20370 | hidden = true; | ||
20371 | } | ||
20372 | break; | ||
20373 | case "Name": | ||
20374 | name = this.Core.GetAttributeBundleVariableValue(sourceLineNumbers, attrib); | ||
20375 | break; | ||
20376 | case "Persisted": | ||
20377 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
20378 | { | ||
20379 | persisted = true; | ||
20380 | } | ||
20381 | break; | ||
20382 | case "Value": | ||
20383 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
20384 | break; | ||
20385 | case "Type": | ||
20386 | type = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20387 | break; | ||
20388 | default: | ||
20389 | this.Core.UnexpectedAttribute(node, attrib); | ||
20390 | break; | ||
20391 | } | ||
20392 | } | ||
20393 | else | ||
20394 | { | ||
20395 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20396 | } | ||
20397 | } | ||
20398 | |||
20399 | if (null == name) | ||
20400 | { | ||
20401 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
20402 | } | ||
20403 | else if (name.StartsWith("Wix", StringComparison.OrdinalIgnoreCase)) | ||
20404 | { | ||
20405 | this.Core.Write(ErrorMessages.ReservedNamespaceViolation(sourceLineNumbers, node.Name.LocalName, "Name", "Wix")); | ||
20406 | } | ||
20407 | |||
20408 | if (null == type && null != value) | ||
20409 | { | ||
20410 | // Infer the type from the current value... | ||
20411 | if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) | ||
20412 | { | ||
20413 | // Version constructor does not support simple "v#" syntax so check to see if the value is | ||
20414 | // non-negative real quick. | ||
20415 | if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out var number)) | ||
20416 | { | ||
20417 | type = "version"; | ||
20418 | } | ||
20419 | else | ||
20420 | { | ||
20421 | // Sadly, Version doesn't have a TryParse() method until .NET 4, so we have to try/catch to see if it parses. | ||
20422 | try | ||
20423 | { | ||
20424 | var version = new Version(value.Substring(1)); | ||
20425 | type = "version"; | ||
20426 | } | ||
20427 | catch (Exception) | ||
20428 | { | ||
20429 | } | ||
20430 | } | ||
20431 | } | ||
20432 | |||
20433 | // Not a version, check for numeric. | ||
20434 | if (null == type) | ||
20435 | { | ||
20436 | if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out var number)) | ||
20437 | { | ||
20438 | type = "numeric"; | ||
20439 | } | ||
20440 | else | ||
20441 | { | ||
20442 | type = "string"; | ||
20443 | } | ||
20444 | } | ||
20445 | } | ||
20446 | |||
20447 | if (null == value && null != type) | ||
20448 | { | ||
20449 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, "Variable", "Value", "Type")); | ||
20450 | } | ||
20451 | |||
20452 | this.Core.ParseForExtensionElements(node); | ||
20453 | |||
20454 | if (!this.Core.EncounteredError) | ||
20455 | { | ||
20456 | var row = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
20457 | row.WixBundleVariable = name; | ||
20458 | row.Value = value; | ||
20459 | row.Type = type; | ||
20460 | row.Hidden = hidden; | ||
20461 | row.Persisted = persisted; | ||
20462 | } | ||
20463 | } | ||
20464 | |||
20465 | |||
20466 | |||
20467 | /// <summary> | ||
20468 | /// Parses a Wix element. | ||
20469 | /// </summary> | ||
20470 | /// <param name="node">Element to parse.</param> | ||
20471 | private void ParseWixElement(XElement node) | ||
20472 | { | ||
20473 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20474 | string requiredVersion = null; | ||
20475 | |||
20476 | foreach (var attrib in node.Attributes()) | ||
20477 | { | ||
20478 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20479 | { | ||
20480 | switch (attrib.Name.LocalName) | ||
20481 | { | ||
20482 | case "RequiredVersion": | ||
20483 | requiredVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
20484 | break; | ||
20485 | default: | ||
20486 | this.Core.UnexpectedAttribute(node, attrib); | ||
20487 | break; | ||
20488 | } | ||
20489 | } | ||
20490 | else | ||
20491 | { | ||
20492 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20493 | } | ||
20494 | } | ||
20495 | |||
20496 | if (null != requiredVersion) | ||
20497 | { | ||
20498 | this.Core.VerifyRequiredVersion(sourceLineNumbers, requiredVersion); | ||
20499 | } | ||
20500 | |||
20501 | foreach (var child in node.Elements()) | ||
20502 | { | ||
20503 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
20504 | { | ||
20505 | switch (child.Name.LocalName) | ||
20506 | { | ||
20507 | case "Bundle": | ||
20508 | this.ParseBundleElement(child); | ||
20509 | break; | ||
20510 | case "Fragment": | ||
20511 | this.ParseFragmentElement(child); | ||
20512 | break; | ||
20513 | case "Module": | ||
20514 | this.ParseModuleElement(child); | ||
20515 | break; | ||
20516 | case "PatchCreation": | ||
20517 | this.ParsePatchCreationElement(child); | ||
20518 | break; | ||
20519 | case "Product": | ||
20520 | this.ParseProductElement(child); | ||
20521 | break; | ||
20522 | case "Patch": | ||
20523 | this.ParsePatchElement(child); | ||
20524 | break; | ||
20525 | default: | ||
20526 | this.Core.UnexpectedElement(node, child); | ||
20527 | break; | ||
20528 | } | ||
20529 | } | ||
20530 | else | ||
20531 | { | ||
20532 | this.Core.ParseExtensionElement(node, child); | ||
20533 | } | ||
20534 | } | ||
20535 | } | ||
20536 | |||
20537 | /// <summary> | ||
20538 | /// Parses a WixVariable element. | ||
20539 | /// </summary> | ||
20540 | /// <param name="node">Element to parse.</param> | ||
20541 | private void ParseWixVariableElement(XElement node) | ||
20542 | { | ||
20543 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20544 | Identifier id = null; | ||
20545 | var overridable = false; | ||
20546 | string value = null; | ||
20547 | |||
20548 | foreach (var attrib in node.Attributes()) | ||
20549 | { | ||
20550 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20551 | { | ||
20552 | switch (attrib.Name.LocalName) | ||
20553 | { | ||
20554 | case "Id": | ||
20555 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
20556 | break; | ||
20557 | case "Overridable": | ||
20558 | overridable = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
20559 | break; | ||
20560 | case "Value": | ||
20561 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
20562 | break; | ||
20563 | default: | ||
20564 | this.Core.UnexpectedAttribute(node, attrib); | ||
20565 | break; | ||
20566 | } | ||
20567 | } | ||
20568 | else | ||
20569 | { | ||
20570 | this.Core.ParseExtensionAttribute(node, attrib); | ||
20571 | } | ||
20572 | } | ||
20573 | |||
20574 | if (null == id) | ||
20575 | { | ||
20576 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20577 | } | ||
20578 | |||
20579 | if (null == value) | ||
20580 | { | ||
20581 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
20582 | } | ||
20583 | |||
20584 | this.Core.ParseForExtensionElements(node); | ||
20585 | |||
20586 | if (!this.Core.EncounteredError) | ||
20587 | { | ||
20588 | var wixVariableRow = (WixVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixVariable, id); | ||
20589 | wixVariableRow.Value = value; | ||
20590 | wixVariableRow.Overridable = overridable; | ||
20591 | } | ||
20592 | } | ||
20593 | } | 9972 | } |
20594 | } | 9973 | } |
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs index 4df94713..d21e490f 100644 --- a/src/WixToolset.Core/CompilerCore.cs +++ b/src/WixToolset.Core/CompilerCore.cs | |||
@@ -13,6 +13,7 @@ namespace WixToolset.Core | |||
13 | using System.Text.RegularExpressions; | 13 | using System.Text.RegularExpressions; |
14 | using System.Xml.Linq; | 14 | using System.Xml.Linq; |
15 | using WixToolset.Data; | 15 | using WixToolset.Data; |
16 | using WixToolset.Data.Tuples; | ||
16 | using WixToolset.Extensibility; | 17 | using WixToolset.Extensibility; |
17 | using WixToolset.Extensibility.Data; | 18 | using WixToolset.Extensibility.Data; |
18 | using WixToolset.Extensibility.Services; | 19 | using WixToolset.Extensibility.Services; |
@@ -165,6 +166,15 @@ namespace WixToolset.Core | |||
165 | public bool ShowPedanticMessages { get; set; } | 166 | public bool ShowPedanticMessages { get; set; } |
166 | 167 | ||
167 | /// <summary> | 168 | /// <summary> |
169 | /// Add a tuple to the active section. | ||
170 | /// </summary> | ||
171 | /// <param name="tuple">Tuple to add.</param> | ||
172 | public void AddTuple(IntermediateTuple tuple) | ||
173 | { | ||
174 | this.ActiveSection.Tuples.Add(tuple); | ||
175 | } | ||
176 | |||
177 | /// <summary> | ||
168 | /// Convert a bit array into an int value. | 178 | /// Convert a bit array into an int value. |
169 | /// </summary> | 179 | /// </summary> |
170 | /// <param name="bits">The bit array to convert.</param> | 180 | /// <param name="bits">The bit array to convert.</param> |
@@ -418,7 +428,7 @@ namespace WixToolset.Core | |||
418 | /// <param name="name">The registry entry name.</param> | 428 | /// <param name="name">The registry entry name.</param> |
419 | /// <param name="value">The registry entry value.</param> | 429 | /// <param name="value">The registry entry value.</param> |
420 | /// <param name="componentId">The component which will control installation/uninstallation of the registry entry.</param> | 430 | /// <param name="componentId">The component which will control installation/uninstallation of the registry entry.</param> |
421 | public Identifier CreateRegistryRow(SourceLineNumber sourceLineNumbers, int root, string key, string name, string value, string componentId) | 431 | public Identifier CreateRegistryRow(SourceLineNumber sourceLineNumbers, RegistryRootType root, string key, string name, string value, string componentId) |
422 | { | 432 | { |
423 | return this.parseHelper.CreateRegistryRow(this.ActiveSection, sourceLineNumbers, root, key, name, value, componentId, true); | 433 | return this.parseHelper.CreateRegistryRow(this.ActiveSection, sourceLineNumbers, root, key, name, value, componentId, true); |
424 | } | 434 | } |
@@ -839,9 +849,9 @@ namespace WixToolset.Core | |||
839 | /// <param name="allowHkmu">Whether HKMU is returned as -1 (true), or treated as an error (false).</param> | 849 | /// <param name="allowHkmu">Whether HKMU is returned as -1 (true), or treated as an error (false).</param> |
840 | /// <returns>The attribute's RegisitryRootType value.</returns> | 850 | /// <returns>The attribute's RegisitryRootType value.</returns> |
841 | [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] | 851 | [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] |
842 | public int GetAttributeMsidbRegistryRootValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowHkmu) | 852 | public RegistryRootType? GetAttributeRegistryRootValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowHkmu) |
843 | { | 853 | { |
844 | return this.parseHelper.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attribute, allowHkmu); | 854 | return this.parseHelper.GetAttributeRegistryRootValue(sourceLineNumbers, attribute, allowHkmu); |
845 | } | 855 | } |
846 | 856 | ||
847 | /// <summary> | 857 | /// <summary> |
diff --git a/src/WixToolset.Core/Compiler_2.cs b/src/WixToolset.Core/Compiler_2.cs new file mode 100644 index 00000000..f42c9da1 --- /dev/null +++ b/src/WixToolset.Core/Compiler_2.cs | |||
@@ -0,0 +1,5615 @@ | |||
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 | namespace WixToolset.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Diagnostics.CodeAnalysis; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | ||
11 | using System.Xml.Linq; | ||
12 | using WixToolset.Data; | ||
13 | using WixToolset.Data.Tuples; | ||
14 | using WixToolset.Data.WindowsInstaller; | ||
15 | using WixToolset.Extensibility; | ||
16 | |||
17 | /// <summary> | ||
18 | /// Compiler of the WiX toolset. | ||
19 | /// </summary> | ||
20 | internal partial class Compiler : ICompiler | ||
21 | { | ||
22 | /// <summary> | ||
23 | /// Parses an odbc driver or translator element. | ||
24 | /// </summary> | ||
25 | /// <param name="node">Element to parse.</param> | ||
26 | /// <param name="componentId">Identifier of parent component.</param> | ||
27 | /// <param name="fileId">Default identifer for driver/translator file.</param> | ||
28 | /// <param name="table">Table we're processing for.</param> | ||
29 | private void ParseODBCDriverOrTranslator(XElement node, string componentId, string fileId, TupleDefinitionType tableName) | ||
30 | { | ||
31 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
32 | Identifier id = null; | ||
33 | var driver = fileId; | ||
34 | string name = null; | ||
35 | var setup = fileId; | ||
36 | |||
37 | foreach (var attrib in node.Attributes()) | ||
38 | { | ||
39 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
40 | { | ||
41 | switch (attrib.Name.LocalName) | ||
42 | { | ||
43 | case "Id": | ||
44 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
45 | break; | ||
46 | case "File": | ||
47 | driver = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
48 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", driver); | ||
49 | break; | ||
50 | case "Name": | ||
51 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
52 | break; | ||
53 | case "SetupFile": | ||
54 | setup = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
55 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", setup); | ||
56 | break; | ||
57 | default: | ||
58 | this.Core.UnexpectedAttribute(node, attrib); | ||
59 | break; | ||
60 | } | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | this.Core.ParseExtensionAttribute(node, attrib); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | if (null == name) | ||
69 | { | ||
70 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
71 | } | ||
72 | |||
73 | if (null == id) | ||
74 | { | ||
75 | id = this.Core.CreateIdentifier("odb", name, fileId, setup); | ||
76 | } | ||
77 | |||
78 | // drivers have a few possible children | ||
79 | if (TupleDefinitionType.ODBCDriver == tableName) | ||
80 | { | ||
81 | // process any data sources for the driver | ||
82 | foreach (var child in node.Elements()) | ||
83 | { | ||
84 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
85 | { | ||
86 | switch (child.Name.LocalName) | ||
87 | { | ||
88 | case "ODBCDataSource": | ||
89 | string ignoredKeyPath = null; | ||
90 | this.ParseODBCDataSource(child, componentId, name, out ignoredKeyPath); | ||
91 | break; | ||
92 | case "Property": | ||
93 | this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCAttribute); | ||
94 | break; | ||
95 | default: | ||
96 | this.Core.UnexpectedElement(node, child); | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | else | ||
101 | { | ||
102 | this.Core.ParseExtensionElement(node, child); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | this.Core.ParseForExtensionElements(node); | ||
109 | } | ||
110 | |||
111 | if (!this.Core.EncounteredError) | ||
112 | { | ||
113 | var row = this.Core.CreateRow(sourceLineNumbers, tableName, id); | ||
114 | row.Set(1, componentId); | ||
115 | row.Set(2, name); | ||
116 | row.Set(3, driver); | ||
117 | row.Set(4, setup); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Parses a Property element underneath an ODBC driver or translator. | ||
123 | /// </summary> | ||
124 | /// <param name="node">Element to parse.</param> | ||
125 | /// <param name="parentId">Identifier of parent driver or translator.</param> | ||
126 | /// <param name="tableName">Name of the table to create property in.</param> | ||
127 | private void ParseODBCProperty(XElement node, string parentId, TupleDefinitionType tableName) | ||
128 | { | ||
129 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
130 | string id = null; | ||
131 | string propertyValue = null; | ||
132 | |||
133 | foreach (var attrib in node.Attributes()) | ||
134 | { | ||
135 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
136 | { | ||
137 | switch (attrib.Name.LocalName) | ||
138 | { | ||
139 | case "Id": | ||
140 | id = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
141 | break; | ||
142 | case "Value": | ||
143 | propertyValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
144 | break; | ||
145 | default: | ||
146 | this.Core.UnexpectedAttribute(node, attrib); | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | this.Core.ParseExtensionAttribute(node, attrib); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | if (null == id) | ||
157 | { | ||
158 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
159 | } | ||
160 | |||
161 | this.Core.ParseForExtensionElements(node); | ||
162 | |||
163 | if (!this.Core.EncounteredError) | ||
164 | { | ||
165 | var row = this.Core.CreateRow(sourceLineNumbers, tableName); | ||
166 | row.Set(0, parentId); | ||
167 | row.Set(1, id); | ||
168 | row.Set(2, propertyValue); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /// <summary> | ||
173 | /// Parse an odbc data source element. | ||
174 | /// </summary> | ||
175 | /// <param name="node">Element to parse.</param> | ||
176 | /// <param name="componentId">Identifier of parent component.</param> | ||
177 | /// <param name="driverName">Default name of driver.</param> | ||
178 | /// <param name="possibleKeyPath">Identifier of this element in case it is a keypath.</param> | ||
179 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
180 | private YesNoType ParseODBCDataSource(XElement node, string componentId, string driverName, out string possibleKeyPath) | ||
181 | { | ||
182 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
183 | Identifier id = null; | ||
184 | var keyPath = YesNoType.NotSet; | ||
185 | string name = null; | ||
186 | var registration = CompilerConstants.IntegerNotSet; | ||
187 | |||
188 | foreach (var attrib in node.Attributes()) | ||
189 | { | ||
190 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
191 | { | ||
192 | switch (attrib.Name.LocalName) | ||
193 | { | ||
194 | case "Id": | ||
195 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
196 | break; | ||
197 | case "DriverName": | ||
198 | driverName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
199 | break; | ||
200 | case "KeyPath": | ||
201 | keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
202 | break; | ||
203 | case "Name": | ||
204 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
205 | break; | ||
206 | case "Registration": | ||
207 | var registrationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
208 | switch (registrationValue) | ||
209 | { | ||
210 | case "machine": | ||
211 | registration = 0; | ||
212 | break; | ||
213 | case "user": | ||
214 | registration = 1; | ||
215 | break; | ||
216 | case "": | ||
217 | break; | ||
218 | default: | ||
219 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Registration", registrationValue, "machine", "user")); | ||
220 | break; | ||
221 | } | ||
222 | break; | ||
223 | default: | ||
224 | this.Core.UnexpectedAttribute(node, attrib); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | this.Core.ParseExtensionAttribute(node, attrib); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | if (CompilerConstants.IntegerNotSet == registration) | ||
235 | { | ||
236 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Registration")); | ||
237 | registration = CompilerConstants.IllegalInteger; | ||
238 | } | ||
239 | |||
240 | if (null == id) | ||
241 | { | ||
242 | id = this.Core.CreateIdentifier("odc", name, driverName, registration.ToString()); | ||
243 | } | ||
244 | |||
245 | foreach (var child in node.Elements()) | ||
246 | { | ||
247 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
248 | { | ||
249 | switch (child.Name.LocalName) | ||
250 | { | ||
251 | case "Property": | ||
252 | this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCSourceAttribute); | ||
253 | break; | ||
254 | default: | ||
255 | this.Core.UnexpectedElement(node, child); | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | this.Core.ParseExtensionElement(node, child); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | if (!this.Core.EncounteredError) | ||
266 | { | ||
267 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ODBCDataSource, id); | ||
268 | row.Set(1, componentId); | ||
269 | row.Set(2, name); | ||
270 | row.Set(3, driverName); | ||
271 | row.Set(4, registration); | ||
272 | } | ||
273 | |||
274 | possibleKeyPath = id.Id; | ||
275 | return keyPath; | ||
276 | } | ||
277 | |||
278 | /// <summary> | ||
279 | /// Parses a package element. | ||
280 | /// </summary> | ||
281 | /// <param name="node">Element to parse.</param> | ||
282 | /// <param name="productAuthor">Default package author.</param> | ||
283 | /// <param name="moduleId">The module guid - this is necessary until Module/@Guid is removed.</param> | ||
284 | private void ParsePackageElement(XElement node, string productAuthor, string moduleId) | ||
285 | { | ||
286 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
287 | var codepage = "1252"; | ||
288 | var comments = String.Format(CultureInfo.InvariantCulture, "This installer database contains the logic and data required to install {0}.", this.activeName); | ||
289 | var keywords = "Installer"; | ||
290 | var msiVersion = 100; // lowest released version, really should be specified | ||
291 | var packageAuthor = productAuthor; | ||
292 | string packageCode = null; | ||
293 | var packageLanguages = this.activeLanguage; | ||
294 | var packageName = this.activeName; | ||
295 | string platform = null; | ||
296 | string platformValue = null; | ||
297 | var security = YesNoDefaultType.Default; | ||
298 | var sourceBits = (this.compilingModule ? 2 : 0); | ||
299 | IntermediateTuple row; | ||
300 | var installPrivilegeSeen = false; | ||
301 | var installScopeSeen = false; | ||
302 | |||
303 | switch (this.CurrentPlatform) | ||
304 | { | ||
305 | case Platform.X86: | ||
306 | platform = "Intel"; | ||
307 | break; | ||
308 | case Platform.X64: | ||
309 | platform = "x64"; | ||
310 | msiVersion = 200; | ||
311 | break; | ||
312 | case Platform.IA64: | ||
313 | platform = "Intel64"; | ||
314 | msiVersion = 200; | ||
315 | break; | ||
316 | case Platform.ARM: | ||
317 | platform = "Arm"; | ||
318 | msiVersion = 500; | ||
319 | break; | ||
320 | default: | ||
321 | throw new ArgumentException("Unknown platform enumeration '{0}' encountered.", this.CurrentPlatform.ToString()); | ||
322 | } | ||
323 | |||
324 | foreach (var attrib in node.Attributes()) | ||
325 | { | ||
326 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
327 | { | ||
328 | switch (attrib.Name.LocalName) | ||
329 | { | ||
330 | case "Id": | ||
331 | packageCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, this.compilingProduct); | ||
332 | break; | ||
333 | case "AdminImage": | ||
334 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
335 | { | ||
336 | sourceBits = sourceBits | 4; | ||
337 | } | ||
338 | break; | ||
339 | case "Comments": | ||
340 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
341 | break; | ||
342 | case "Compressed": | ||
343 | // merge modules must always be compressed, so this attribute is invalid | ||
344 | if (this.compilingModule) | ||
345 | { | ||
346 | this.Core.Write(WarningMessages.DeprecatedPackageCompressedAttribute(sourceLineNumbers)); | ||
347 | // this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Compressed", "Module")); | ||
348 | } | ||
349 | else if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
350 | { | ||
351 | sourceBits = sourceBits | 2; | ||
352 | } | ||
353 | break; | ||
354 | case "Description": | ||
355 | packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
356 | break; | ||
357 | case "InstallPrivileges": | ||
358 | var installPrivileges = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
359 | switch (installPrivileges) | ||
360 | { | ||
361 | case "elevated": | ||
362 | // this is the default setting | ||
363 | installPrivilegeSeen = true; | ||
364 | break; | ||
365 | case "limited": | ||
366 | sourceBits = sourceBits | 8; | ||
367 | installPrivilegeSeen = true; | ||
368 | break; | ||
369 | case "": | ||
370 | break; | ||
371 | default: | ||
372 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installPrivileges, "elevated", "limited")); | ||
373 | break; | ||
374 | } | ||
375 | break; | ||
376 | case "InstallScope": | ||
377 | var installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
378 | switch (installScope) | ||
379 | { | ||
380 | case "perMachine": | ||
381 | { | ||
382 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Property, new Identifier("ALLUSERS", AccessModifier.Public)); | ||
383 | row.Set(1, "1"); | ||
384 | installScopeSeen = true; | ||
385 | } | ||
386 | break; | ||
387 | case "perUser": | ||
388 | sourceBits = sourceBits | 8; | ||
389 | installScopeSeen = true; | ||
390 | break; | ||
391 | case "": | ||
392 | break; | ||
393 | default: | ||
394 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installScope, "perMachine", "perUser")); | ||
395 | break; | ||
396 | } | ||
397 | break; | ||
398 | case "InstallerVersion": | ||
399 | msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
400 | break; | ||
401 | case "Keywords": | ||
402 | keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
403 | break; | ||
404 | case "Languages": | ||
405 | packageLanguages = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
406 | break; | ||
407 | case "Manufacturer": | ||
408 | packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
409 | if ("PUT-COMPANY-NAME-HERE" == packageAuthor) | ||
410 | { | ||
411 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, packageAuthor)); | ||
412 | } | ||
413 | break; | ||
414 | case "Platform": | ||
415 | if (null != platformValue) | ||
416 | { | ||
417 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platforms")); | ||
418 | } | ||
419 | |||
420 | platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
421 | switch (platformValue) | ||
422 | { | ||
423 | case "intel": | ||
424 | this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "x86")); | ||
425 | goto case "x86"; | ||
426 | case "x86": | ||
427 | platform = "Intel"; | ||
428 | break; | ||
429 | case "x64": | ||
430 | platform = "x64"; | ||
431 | break; | ||
432 | case "intel64": | ||
433 | this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "ia64")); | ||
434 | goto case "ia64"; | ||
435 | case "ia64": | ||
436 | platform = "Intel64"; | ||
437 | break; | ||
438 | case "arm": | ||
439 | platform = "Arm"; | ||
440 | break; | ||
441 | case "": | ||
442 | break; | ||
443 | default: | ||
444 | this.Core.Write(ErrorMessages.InvalidPlatformValue(sourceLineNumbers, platformValue)); | ||
445 | break; | ||
446 | } | ||
447 | break; | ||
448 | case "Platforms": | ||
449 | if (null != platformValue) | ||
450 | { | ||
451 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
452 | } | ||
453 | |||
454 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
455 | platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
456 | platform = platformValue; | ||
457 | break; | ||
458 | case "ReadOnly": | ||
459 | security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
460 | break; | ||
461 | case "ShortNames": | ||
462 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
463 | { | ||
464 | sourceBits = sourceBits | 1; | ||
465 | this.useShortFileNames = true; | ||
466 | } | ||
467 | break; | ||
468 | case "SummaryCodepage": | ||
469 | codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib, true); | ||
470 | break; | ||
471 | default: | ||
472 | this.Core.UnexpectedAttribute(node, attrib); | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | else | ||
477 | { | ||
478 | this.Core.ParseExtensionAttribute(node, attrib); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (installPrivilegeSeen && installScopeSeen) | ||
483 | { | ||
484 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "InstallPrivileges", "InstallScope")); | ||
485 | } | ||
486 | |||
487 | if ((0 != String.Compare(platform, "Intel", StringComparison.OrdinalIgnoreCase)) && 200 > msiVersion) | ||
488 | { | ||
489 | msiVersion = 200; | ||
490 | this.Core.Write(WarningMessages.RequiresMsi200for64bitPackage(sourceLineNumbers)); | ||
491 | } | ||
492 | |||
493 | if ((0 == String.Compare(platform, "Arm", StringComparison.OrdinalIgnoreCase)) && 500 > msiVersion) | ||
494 | { | ||
495 | msiVersion = 500; | ||
496 | this.Core.Write(WarningMessages.RequiresMsi500forArmPackage(sourceLineNumbers)); | ||
497 | } | ||
498 | |||
499 | if (null == packageAuthor) | ||
500 | { | ||
501 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
502 | } | ||
503 | |||
504 | if (this.compilingModule) | ||
505 | { | ||
506 | if (null == packageCode) | ||
507 | { | ||
508 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
509 | } | ||
510 | |||
511 | // merge modules use the modularization guid as the package code | ||
512 | if (null != moduleId) | ||
513 | { | ||
514 | packageCode = moduleId; | ||
515 | } | ||
516 | |||
517 | // merge modules are always compressed | ||
518 | sourceBits = 2; | ||
519 | } | ||
520 | else // product | ||
521 | { | ||
522 | if (null == packageCode) | ||
523 | { | ||
524 | packageCode = "*"; | ||
525 | } | ||
526 | |||
527 | if ("*" != packageCode) | ||
528 | { | ||
529 | this.Core.Write(WarningMessages.PackageCodeSet(sourceLineNumbers)); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | this.Core.ParseForExtensionElements(node); | ||
534 | |||
535 | if (!this.Core.EncounteredError) | ||
536 | { | ||
537 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
538 | row.Set(0, 1); | ||
539 | row.Set(1, codepage); | ||
540 | |||
541 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
542 | row.Set(0, 2); | ||
543 | row.Set(1, "Installation Database"); | ||
544 | |||
545 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
546 | row.Set(0, 3); | ||
547 | row.Set(1, packageName); | ||
548 | |||
549 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
550 | row.Set(0, 4); | ||
551 | row.Set(1, packageAuthor); | ||
552 | |||
553 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
554 | row.Set(0, 5); | ||
555 | row.Set(1, keywords); | ||
556 | |||
557 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
558 | row.Set(0, 6); | ||
559 | row.Set(1, comments); | ||
560 | |||
561 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
562 | row.Set(0, 7); | ||
563 | row.Set(1, String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, packageLanguages)); | ||
564 | |||
565 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
566 | row.Set(0, 9); | ||
567 | row.Set(1, packageCode); | ||
568 | |||
569 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
570 | row.Set(0, 14); | ||
571 | row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture)); | ||
572 | |||
573 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
574 | row.Set(0, 15); | ||
575 | row.Set(1, sourceBits.ToString(CultureInfo.InvariantCulture)); | ||
576 | |||
577 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
578 | row.Set(0, 19); | ||
579 | switch (security) | ||
580 | { | ||
581 | case YesNoDefaultType.No: // no restriction | ||
582 | row.Set(1, "0"); | ||
583 | break; | ||
584 | case YesNoDefaultType.Default: // read-only recommended | ||
585 | row.Set(1, "2"); | ||
586 | break; | ||
587 | case YesNoDefaultType.Yes: // read-only enforced | ||
588 | row.Set(1, "4"); | ||
589 | break; | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /// <summary> | ||
595 | /// Parses a patch metadata element. | ||
596 | /// </summary> | ||
597 | /// <param name="node">Element to parse.</param> | ||
598 | private void ParsePatchMetadataElement(XElement node) | ||
599 | { | ||
600 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
601 | var allowRemoval = YesNoType.NotSet; | ||
602 | string classification = null; | ||
603 | string creationTimeUtc = null; | ||
604 | string description = null; | ||
605 | string displayName = null; | ||
606 | string manufacturerName = null; | ||
607 | string minorUpdateTargetRTM = null; | ||
608 | string moreInfoUrl = null; | ||
609 | var optimizeCA = CompilerConstants.IntegerNotSet; | ||
610 | var optimizedInstallMode = YesNoType.NotSet; | ||
611 | string targetProductName = null; | ||
612 | |||
613 | foreach (var attrib in node.Attributes()) | ||
614 | { | ||
615 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
616 | { | ||
617 | switch (attrib.Name.LocalName) | ||
618 | { | ||
619 | case "AllowRemoval": | ||
620 | allowRemoval = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
621 | break; | ||
622 | case "Classification": | ||
623 | classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
624 | break; | ||
625 | case "CreationTimeUTC": | ||
626 | creationTimeUtc = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
627 | break; | ||
628 | case "Description": | ||
629 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
630 | break; | ||
631 | case "DisplayName": | ||
632 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
633 | break; | ||
634 | case "ManufacturerName": | ||
635 | manufacturerName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
636 | break; | ||
637 | case "MinorUpdateTargetRTM": | ||
638 | minorUpdateTargetRTM = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
639 | break; | ||
640 | case "MoreInfoURL": | ||
641 | moreInfoUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
642 | break; | ||
643 | case "OptimizedInstallMode": | ||
644 | optimizedInstallMode = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
645 | break; | ||
646 | case "TargetProductName": | ||
647 | targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
648 | break; | ||
649 | default: | ||
650 | this.Core.UnexpectedAttribute(node, attrib); | ||
651 | break; | ||
652 | } | ||
653 | } | ||
654 | else | ||
655 | { | ||
656 | this.Core.ParseExtensionAttribute(node, attrib); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | if (YesNoType.NotSet == allowRemoval) | ||
661 | { | ||
662 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "AllowRemoval")); | ||
663 | } | ||
664 | |||
665 | if (null == classification) | ||
666 | { | ||
667 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification")); | ||
668 | } | ||
669 | |||
670 | if (null == description) | ||
671 | { | ||
672 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
673 | } | ||
674 | |||
675 | if (null == displayName) | ||
676 | { | ||
677 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName")); | ||
678 | } | ||
679 | |||
680 | if (null == manufacturerName) | ||
681 | { | ||
682 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManufacturerName")); | ||
683 | } | ||
684 | |||
685 | if (null == moreInfoUrl) | ||
686 | { | ||
687 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MoreInfoURL")); | ||
688 | } | ||
689 | |||
690 | if (null == targetProductName) | ||
691 | { | ||
692 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetProductName")); | ||
693 | } | ||
694 | |||
695 | foreach (var child in node.Elements()) | ||
696 | { | ||
697 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
698 | { | ||
699 | switch (child.Name.LocalName) | ||
700 | { | ||
701 | case "CustomProperty": | ||
702 | this.ParseCustomPropertyElement(child); | ||
703 | break; | ||
704 | case "OptimizeCustomActions": | ||
705 | optimizeCA = this.ParseOptimizeCustomActionsElement(child); | ||
706 | break; | ||
707 | default: | ||
708 | this.Core.UnexpectedElement(node, child); | ||
709 | break; | ||
710 | } | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | this.Core.ParseExtensionElement(node, child); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | if (!this.Core.EncounteredError) | ||
719 | { | ||
720 | if (YesNoType.NotSet != allowRemoval) | ||
721 | { | ||
722 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
723 | row.Set(1, "AllowRemoval"); | ||
724 | row.Set(2, YesNoType.Yes == allowRemoval ? "1" : "0"); | ||
725 | } | ||
726 | |||
727 | if (null != classification) | ||
728 | { | ||
729 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
730 | row.Set(1, "Classification"); | ||
731 | row.Set(2, classification); | ||
732 | } | ||
733 | |||
734 | if (null != creationTimeUtc) | ||
735 | { | ||
736 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
737 | row.Set(1, "CreationTimeUTC"); | ||
738 | row.Set(2, creationTimeUtc); | ||
739 | } | ||
740 | |||
741 | if (null != description) | ||
742 | { | ||
743 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
744 | row.Set(1, "Description"); | ||
745 | row.Set(2, description); | ||
746 | } | ||
747 | |||
748 | if (null != displayName) | ||
749 | { | ||
750 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
751 | row.Set(1, "DisplayName"); | ||
752 | row.Set(2, displayName); | ||
753 | } | ||
754 | |||
755 | if (null != manufacturerName) | ||
756 | { | ||
757 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
758 | row.Set(1, "ManufacturerName"); | ||
759 | row.Set(2, manufacturerName); | ||
760 | } | ||
761 | |||
762 | if (null != minorUpdateTargetRTM) | ||
763 | { | ||
764 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
765 | row.Set(1, "MinorUpdateTargetRTM"); | ||
766 | row.Set(2, minorUpdateTargetRTM); | ||
767 | } | ||
768 | |||
769 | if (null != moreInfoUrl) | ||
770 | { | ||
771 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
772 | row.Set(1, "MoreInfoURL"); | ||
773 | row.Set(2, moreInfoUrl); | ||
774 | } | ||
775 | |||
776 | if (CompilerConstants.IntegerNotSet != optimizeCA) | ||
777 | { | ||
778 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
779 | row.Set(1, "OptimizeCA"); | ||
780 | row.Set(2, optimizeCA.ToString(CultureInfo.InvariantCulture)); | ||
781 | } | ||
782 | |||
783 | if (YesNoType.NotSet != optimizedInstallMode) | ||
784 | { | ||
785 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
786 | row.Set(1, "OptimizedInstallMode"); | ||
787 | row.Set(2, YesNoType.Yes == optimizedInstallMode ? "1" : "0"); | ||
788 | } | ||
789 | |||
790 | if (null != targetProductName) | ||
791 | { | ||
792 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
793 | row.Set(1, "TargetProductName"); | ||
794 | row.Set(2, targetProductName); | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | |||
799 | /// <summary> | ||
800 | /// Parses a custom property element for the PatchMetadata table. | ||
801 | /// </summary> | ||
802 | /// <param name="node">Element to parse.</param> | ||
803 | private void ParseCustomPropertyElement(XElement node) | ||
804 | { | ||
805 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
806 | string company = null; | ||
807 | string property = null; | ||
808 | string value = null; | ||
809 | |||
810 | foreach (var attrib in node.Attributes()) | ||
811 | { | ||
812 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
813 | { | ||
814 | switch (attrib.Name.LocalName) | ||
815 | { | ||
816 | case "Company": | ||
817 | company = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
818 | break; | ||
819 | case "Property": | ||
820 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
821 | break; | ||
822 | case "Value": | ||
823 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
824 | break; | ||
825 | default: | ||
826 | this.Core.UnexpectedAttribute(node, attrib); | ||
827 | break; | ||
828 | } | ||
829 | } | ||
830 | else | ||
831 | { | ||
832 | this.Core.ParseExtensionAttribute(node, attrib); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | if (null == company) | ||
837 | { | ||
838 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Company")); | ||
839 | } | ||
840 | |||
841 | if (null == property) | ||
842 | { | ||
843 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
844 | } | ||
845 | |||
846 | if (null == value) | ||
847 | { | ||
848 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
849 | } | ||
850 | |||
851 | this.Core.ParseForExtensionElements(node); | ||
852 | |||
853 | if (!this.Core.EncounteredError) | ||
854 | { | ||
855 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
856 | row.Set(0, company); | ||
857 | row.Set(1, property); | ||
858 | row.Set(2, value); | ||
859 | } | ||
860 | } | ||
861 | |||
862 | /// <summary> | ||
863 | /// Parses the OptimizeCustomActions element. | ||
864 | /// </summary> | ||
865 | /// <param name="node">Element to parse.</param> | ||
866 | /// <returns>The combined integer value for callers to store as appropriate.</returns> | ||
867 | private int ParseOptimizeCustomActionsElement(XElement node) | ||
868 | { | ||
869 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
870 | var optimizeCA = OptimizeCA.None; | ||
871 | |||
872 | foreach (var attrib in node.Attributes()) | ||
873 | { | ||
874 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
875 | { | ||
876 | switch (attrib.Name.LocalName) | ||
877 | { | ||
878 | case "SkipAssignment": | ||
879 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
880 | { | ||
881 | optimizeCA |= OptimizeCA.SkipAssignment; | ||
882 | } | ||
883 | break; | ||
884 | case "SkipImmediate": | ||
885 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
886 | { | ||
887 | optimizeCA |= OptimizeCA.SkipImmediate; | ||
888 | } | ||
889 | break; | ||
890 | case "SkipDeferred": | ||
891 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
892 | { | ||
893 | optimizeCA |= OptimizeCA.SkipDeferred; | ||
894 | } | ||
895 | break; | ||
896 | default: | ||
897 | this.Core.UnexpectedAttribute(node, attrib); | ||
898 | break; | ||
899 | } | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | this.Core.ParseExtensionAttribute(node, attrib); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | return (int)optimizeCA; | ||
908 | } | ||
909 | |||
910 | /// <summary> | ||
911 | /// Parses a patch information element. | ||
912 | /// </summary> | ||
913 | /// <param name="node">Element to parse.</param> | ||
914 | private void ParsePatchInformationElement(XElement node) | ||
915 | { | ||
916 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
917 | var codepage = "1252"; | ||
918 | string comments = null; | ||
919 | var keywords = "Installer,Patching,PCP,Database"; | ||
920 | var msiVersion = 1; // Should always be 1 for patches | ||
921 | string packageAuthor = null; | ||
922 | var packageName = this.activeName; | ||
923 | var security = YesNoDefaultType.Default; | ||
924 | |||
925 | foreach (var attrib in node.Attributes()) | ||
926 | { | ||
927 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
928 | { | ||
929 | switch (attrib.Name.LocalName) | ||
930 | { | ||
931 | case "AdminImage": | ||
932 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
933 | break; | ||
934 | case "Comments": | ||
935 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
936 | break; | ||
937 | case "Compressed": | ||
938 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
939 | break; | ||
940 | case "Description": | ||
941 | packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
942 | break; | ||
943 | case "Keywords": | ||
944 | keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
945 | break; | ||
946 | case "Languages": | ||
947 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
948 | break; | ||
949 | case "Manufacturer": | ||
950 | packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
951 | break; | ||
952 | case "Platforms": | ||
953 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
954 | break; | ||
955 | case "ReadOnly": | ||
956 | security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
957 | break; | ||
958 | case "ShortNames": | ||
959 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
960 | break; | ||
961 | case "SummaryCodepage": | ||
962 | codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib); | ||
963 | break; | ||
964 | default: | ||
965 | this.Core.UnexpectedAttribute(node, attrib); | ||
966 | break; | ||
967 | } | ||
968 | } | ||
969 | else | ||
970 | { | ||
971 | this.Core.ParseExtensionAttribute(node, attrib); | ||
972 | } | ||
973 | } | ||
974 | |||
975 | this.Core.ParseForExtensionElements(node); | ||
976 | |||
977 | if (!this.Core.EncounteredError) | ||
978 | { | ||
979 | // PID_CODEPAGE | ||
980 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
981 | row.Set(0, 1); | ||
982 | row.Set(1, codepage); | ||
983 | |||
984 | // PID_TITLE | ||
985 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
986 | row.Set(0, 2); | ||
987 | row.Set(1, "Patch"); | ||
988 | |||
989 | // PID_SUBJECT | ||
990 | if (null != packageName) | ||
991 | { | ||
992 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
993 | row.Set(0, 3); | ||
994 | row.Set(1, packageName); | ||
995 | } | ||
996 | |||
997 | // PID_AUTHOR | ||
998 | if (null != packageAuthor) | ||
999 | { | ||
1000 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1001 | row.Set(0, 4); | ||
1002 | row.Set(1, packageAuthor); | ||
1003 | } | ||
1004 | |||
1005 | // PID_KEYWORDS | ||
1006 | if (null != keywords) | ||
1007 | { | ||
1008 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1009 | row.Set(0, 5); | ||
1010 | row.Set(1, keywords); | ||
1011 | } | ||
1012 | |||
1013 | // PID_COMMENTS | ||
1014 | if (null != comments) | ||
1015 | { | ||
1016 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1017 | row.Set(0, 6); | ||
1018 | row.Set(1, comments); | ||
1019 | } | ||
1020 | |||
1021 | // PID_PAGECOUNT | ||
1022 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1023 | row.Set(0, 14); | ||
1024 | row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture)); | ||
1025 | |||
1026 | // PID_WORDCOUNT | ||
1027 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1028 | row.Set(0, 15); | ||
1029 | row.Set(1, "0"); | ||
1030 | |||
1031 | // PID_SECURITY | ||
1032 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1033 | row.Set(0, 19); | ||
1034 | switch (security) | ||
1035 | { | ||
1036 | case YesNoDefaultType.No: // no restriction | ||
1037 | row.Set(1, "0"); | ||
1038 | break; | ||
1039 | case YesNoDefaultType.Default: // read-only recommended | ||
1040 | row.Set(1, "2"); | ||
1041 | break; | ||
1042 | case YesNoDefaultType.Yes: // read-only enforced | ||
1043 | row.Set(1, "4"); | ||
1044 | break; | ||
1045 | } | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | /// <summary> | ||
1050 | /// Parses a permission element. | ||
1051 | /// </summary> | ||
1052 | /// <param name="node">Element to parse.</param> | ||
1053 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
1054 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
1055 | private void ParsePermissionElement(XElement node, string objectId, string tableName) | ||
1056 | { | ||
1057 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1058 | var bits = new BitArray(32); | ||
1059 | string domain = null; | ||
1060 | var permission = 0; | ||
1061 | string[] specialPermissions = null; | ||
1062 | string user = null; | ||
1063 | |||
1064 | switch (tableName) | ||
1065 | { | ||
1066 | case "CreateFolder": | ||
1067 | specialPermissions = Common.FolderPermissions; | ||
1068 | break; | ||
1069 | case "File": | ||
1070 | specialPermissions = Common.FilePermissions; | ||
1071 | break; | ||
1072 | case "Registry": | ||
1073 | specialPermissions = Common.RegistryPermissions; | ||
1074 | break; | ||
1075 | default: | ||
1076 | this.Core.UnexpectedElement(node.Parent, node); | ||
1077 | return; // stop processing this element since no valid permissions are available | ||
1078 | } | ||
1079 | |||
1080 | foreach (var attrib in node.Attributes()) | ||
1081 | { | ||
1082 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1083 | { | ||
1084 | switch (attrib.Name.LocalName) | ||
1085 | { | ||
1086 | case "Domain": | ||
1087 | domain = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1088 | break; | ||
1089 | case "User": | ||
1090 | user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1091 | break; | ||
1092 | case "FileAllRights": | ||
1093 | // match the WinNT.h mask FILE_ALL_ACCESS for value 0x001F01FF (aka 1 1111 0000 0001 1111 1111 or 2032127) | ||
1094 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[16] = bits[17] = bits[18] = bits[19] = bits[20] = true; | ||
1095 | break; | ||
1096 | case "SpecificRightsAll": | ||
1097 | // match the WinNT.h mask SPECIFIC_RIGHTS_ALL for value 0x0000FFFF (aka 1111 1111 1111 1111) | ||
1098 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[9] = bits[10] = bits[11] = bits[12] = bits[13] = bits[14] = bits[15] = true; | ||
1099 | break; | ||
1100 | default: | ||
1101 | var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1102 | if (!this.Core.TrySetBitFromName(Common.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) | ||
1103 | { | ||
1104 | if (!this.Core.TrySetBitFromName(Common.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) | ||
1105 | { | ||
1106 | if (!this.Core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | ||
1107 | { | ||
1108 | this.Core.UnexpectedAttribute(node, attrib); | ||
1109 | break; | ||
1110 | } | ||
1111 | } | ||
1112 | } | ||
1113 | break; | ||
1114 | } | ||
1115 | } | ||
1116 | else | ||
1117 | { | ||
1118 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | permission = this.Core.CreateIntegerFromBitArray(bits); | ||
1123 | |||
1124 | if (null == user) | ||
1125 | { | ||
1126 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "User")); | ||
1127 | } | ||
1128 | |||
1129 | if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL | ||
1130 | { | ||
1131 | this.Core.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); | ||
1132 | } | ||
1133 | |||
1134 | this.Core.ParseForExtensionElements(node); | ||
1135 | |||
1136 | if (!this.Core.EncounteredError) | ||
1137 | { | ||
1138 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.LockPermissions); | ||
1139 | row.Set(0, objectId); | ||
1140 | row.Set(1, tableName); | ||
1141 | row.Set(2, domain); | ||
1142 | row.Set(3, user); | ||
1143 | row.Set(4, permission); | ||
1144 | } | ||
1145 | } | ||
1146 | |||
1147 | /// <summary> | ||
1148 | /// Parses an extended permission element. | ||
1149 | /// </summary> | ||
1150 | /// <param name="node">Element to parse.</param> | ||
1151 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
1152 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
1153 | private void ParsePermissionExElement(XElement node, string objectId, string tableName) | ||
1154 | { | ||
1155 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1156 | string condition = null; | ||
1157 | Identifier id = null; | ||
1158 | string sddl = null; | ||
1159 | |||
1160 | switch (tableName) | ||
1161 | { | ||
1162 | case "CreateFolder": | ||
1163 | case "File": | ||
1164 | case "Registry": | ||
1165 | case "ServiceInstall": | ||
1166 | break; | ||
1167 | default: | ||
1168 | this.Core.UnexpectedElement(node.Parent, node); | ||
1169 | return; // stop processing this element since nothing will be valid. | ||
1170 | } | ||
1171 | |||
1172 | foreach (var attrib in node.Attributes()) | ||
1173 | { | ||
1174 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1175 | { | ||
1176 | switch (attrib.Name.LocalName) | ||
1177 | { | ||
1178 | case "Id": | ||
1179 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1180 | break; | ||
1181 | case "Sddl": | ||
1182 | sddl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1183 | break; | ||
1184 | default: | ||
1185 | this.Core.UnexpectedAttribute(node, attrib); | ||
1186 | break; | ||
1187 | } | ||
1188 | } | ||
1189 | else | ||
1190 | { | ||
1191 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1192 | } | ||
1193 | } | ||
1194 | |||
1195 | if (null == sddl) | ||
1196 | { | ||
1197 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Sddl")); | ||
1198 | } | ||
1199 | |||
1200 | if (null == id) | ||
1201 | { | ||
1202 | id = this.Core.CreateIdentifier("pme", objectId, tableName, sddl); | ||
1203 | } | ||
1204 | |||
1205 | foreach (var child in node.Elements()) | ||
1206 | { | ||
1207 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1208 | { | ||
1209 | switch (child.Name.LocalName) | ||
1210 | { | ||
1211 | case "Condition": | ||
1212 | if (null != condition) | ||
1213 | { | ||
1214 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1215 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
1216 | } | ||
1217 | |||
1218 | condition = this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
1219 | break; | ||
1220 | default: | ||
1221 | this.Core.UnexpectedElement(node, child); | ||
1222 | break; | ||
1223 | } | ||
1224 | } | ||
1225 | else | ||
1226 | { | ||
1227 | this.Core.ParseExtensionElement(node, child); | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | if (!this.Core.EncounteredError) | ||
1232 | { | ||
1233 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiLockPermissionsEx, id); | ||
1234 | row.Set(1, objectId); | ||
1235 | row.Set(2, tableName); | ||
1236 | row.Set(3, sddl); | ||
1237 | row.Set(4, condition); | ||
1238 | } | ||
1239 | } | ||
1240 | |||
1241 | /// <summary> | ||
1242 | /// Parses a product element. | ||
1243 | /// </summary> | ||
1244 | /// <param name="node">Element to parse.</param> | ||
1245 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
1246 | private void ParseProductElement(XElement node) | ||
1247 | { | ||
1248 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1249 | var codepage = 65001; | ||
1250 | string productCode = null; | ||
1251 | string upgradeCode = null; | ||
1252 | string manufacturer = null; | ||
1253 | string version = null; | ||
1254 | string symbols = null; | ||
1255 | |||
1256 | this.activeName = null; | ||
1257 | this.activeLanguage = null; | ||
1258 | |||
1259 | foreach (var attrib in node.Attributes()) | ||
1260 | { | ||
1261 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1262 | { | ||
1263 | switch (attrib.Name.LocalName) | ||
1264 | { | ||
1265 | case "Id": | ||
1266 | productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
1267 | break; | ||
1268 | case "Codepage": | ||
1269 | codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
1270 | break; | ||
1271 | case "Language": | ||
1272 | this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
1273 | break; | ||
1274 | case "Manufacturer": | ||
1275 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
1276 | if ("PUT-COMPANY-NAME-HERE" == manufacturer) | ||
1277 | { | ||
1278 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, manufacturer)); | ||
1279 | } | ||
1280 | break; | ||
1281 | case "Name": | ||
1282 | this.activeName = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
1283 | if ("PUT-PRODUCT-NAME-HERE" == this.activeName) | ||
1284 | { | ||
1285 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
1286 | } | ||
1287 | break; | ||
1288 | case "UpgradeCode": | ||
1289 | upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1290 | break; | ||
1291 | case "Version": // if the attribute is valid version, use the attribute value as is (so "1.0000.01.01" would *not* get translated to "1.0.1.1"). | ||
1292 | var verifiedVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
1293 | if (!String.IsNullOrEmpty(verifiedVersion)) | ||
1294 | { | ||
1295 | version = attrib.Value; | ||
1296 | } | ||
1297 | break; | ||
1298 | default: | ||
1299 | this.Core.UnexpectedAttribute(node, attrib); | ||
1300 | break; | ||
1301 | } | ||
1302 | } | ||
1303 | else | ||
1304 | { | ||
1305 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | if (null == productCode) | ||
1310 | { | ||
1311 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1312 | } | ||
1313 | |||
1314 | if (null == this.activeLanguage) | ||
1315 | { | ||
1316 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
1317 | } | ||
1318 | |||
1319 | if (null == manufacturer) | ||
1320 | { | ||
1321 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
1322 | } | ||
1323 | |||
1324 | if (null == this.activeName) | ||
1325 | { | ||
1326 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
1327 | } | ||
1328 | |||
1329 | if (null == upgradeCode) | ||
1330 | { | ||
1331 | this.Core.Write(WarningMessages.MissingUpgradeCode(sourceLineNumbers)); | ||
1332 | } | ||
1333 | |||
1334 | if (null == version) | ||
1335 | { | ||
1336 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
1337 | } | ||
1338 | else if (!CompilerCore.IsValidProductVersion(version)) | ||
1339 | { | ||
1340 | this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version)); | ||
1341 | } | ||
1342 | |||
1343 | if (this.Core.EncounteredError) | ||
1344 | { | ||
1345 | return; | ||
1346 | } | ||
1347 | |||
1348 | try | ||
1349 | { | ||
1350 | this.compilingProduct = true; | ||
1351 | this.Core.CreateActiveSection(productCode, SectionType.Product, codepage, this.Context.CompilationId); | ||
1352 | |||
1353 | this.AddProperty(sourceLineNumbers, new Identifier("Manufacturer", AccessModifier.Public), manufacturer, false, false, false, true); | ||
1354 | this.AddProperty(sourceLineNumbers, new Identifier("ProductCode", AccessModifier.Public), productCode, false, false, false, true); | ||
1355 | this.AddProperty(sourceLineNumbers, new Identifier("ProductLanguage", AccessModifier.Public), this.activeLanguage, false, false, false, true); | ||
1356 | this.AddProperty(sourceLineNumbers, new Identifier("ProductName", AccessModifier.Public), this.activeName, false, false, false, true); | ||
1357 | this.AddProperty(sourceLineNumbers, new Identifier("ProductVersion", AccessModifier.Public), version, false, false, false, true); | ||
1358 | if (null != upgradeCode) | ||
1359 | { | ||
1360 | this.AddProperty(sourceLineNumbers, new Identifier("UpgradeCode", AccessModifier.Public), upgradeCode, false, false, false, true); | ||
1361 | } | ||
1362 | |||
1363 | var contextValues = new Dictionary<string, string> | ||
1364 | { | ||
1365 | ["ProductLanguage"] = this.activeLanguage, | ||
1366 | ["ProductVersion"] = version, | ||
1367 | ["UpgradeCode"] = upgradeCode | ||
1368 | }; | ||
1369 | |||
1370 | var featureDisplay = 0; | ||
1371 | foreach (var child in node.Elements()) | ||
1372 | { | ||
1373 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1374 | { | ||
1375 | switch (child.Name.LocalName) | ||
1376 | { | ||
1377 | case "_locDefinition": | ||
1378 | break; | ||
1379 | case "AdminExecuteSequence": | ||
1380 | case "AdminUISequence": | ||
1381 | case "AdvertiseExecuteSequence": | ||
1382 | case "InstallExecuteSequence": | ||
1383 | case "InstallUISequence": | ||
1384 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
1385 | break; | ||
1386 | case "AppId": | ||
1387 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
1388 | break; | ||
1389 | case "Binary": | ||
1390 | this.ParseBinaryElement(child); | ||
1391 | break; | ||
1392 | case "ComplianceCheck": | ||
1393 | this.ParseComplianceCheckElement(child); | ||
1394 | break; | ||
1395 | case "Component": | ||
1396 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null); | ||
1397 | break; | ||
1398 | case "ComponentGroup": | ||
1399 | this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, null); | ||
1400 | break; | ||
1401 | case "Condition": | ||
1402 | this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
1403 | break; | ||
1404 | case "CustomAction": | ||
1405 | this.ParseCustomActionElement(child); | ||
1406 | break; | ||
1407 | case "CustomActionRef": | ||
1408 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
1409 | break; | ||
1410 | case "CustomTable": | ||
1411 | this.ParseCustomTableElement(child); | ||
1412 | break; | ||
1413 | case "Directory": | ||
1414 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
1415 | break; | ||
1416 | case "DirectoryRef": | ||
1417 | this.ParseDirectoryRefElement(child); | ||
1418 | break; | ||
1419 | case "EmbeddedChainer": | ||
1420 | this.ParseEmbeddedChainerElement(child); | ||
1421 | break; | ||
1422 | case "EmbeddedChainerRef": | ||
1423 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
1424 | break; | ||
1425 | case "EnsureTable": | ||
1426 | this.ParseEnsureTableElement(child); | ||
1427 | break; | ||
1428 | case "Feature": | ||
1429 | this.ParseFeatureElement(child, ComplexReferenceParentType.Product, productCode, ref featureDisplay); | ||
1430 | break; | ||
1431 | case "FeatureRef": | ||
1432 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
1433 | break; | ||
1434 | case "FeatureGroupRef": | ||
1435 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
1436 | break; | ||
1437 | case "Icon": | ||
1438 | this.ParseIconElement(child); | ||
1439 | break; | ||
1440 | case "InstanceTransforms": | ||
1441 | this.ParseInstanceTransformsElement(child); | ||
1442 | break; | ||
1443 | case "MajorUpgrade": | ||
1444 | this.ParseMajorUpgradeElement(child, contextValues); | ||
1445 | break; | ||
1446 | case "Media": | ||
1447 | this.ParseMediaElement(child, null); | ||
1448 | break; | ||
1449 | case "MediaTemplate": | ||
1450 | this.ParseMediaTemplateElement(child, null); | ||
1451 | break; | ||
1452 | case "Package": | ||
1453 | this.ParsePackageElement(child, manufacturer, null); | ||
1454 | break; | ||
1455 | case "PackageCertificates": | ||
1456 | case "PatchCertificates": | ||
1457 | this.ParseCertificatesElement(child); | ||
1458 | break; | ||
1459 | case "Property": | ||
1460 | this.ParsePropertyElement(child); | ||
1461 | break; | ||
1462 | case "PropertyRef": | ||
1463 | this.ParseSimpleRefElement(child, "Property"); | ||
1464 | break; | ||
1465 | case "SetDirectory": | ||
1466 | this.ParseSetDirectoryElement(child); | ||
1467 | break; | ||
1468 | case "SetProperty": | ||
1469 | this.ParseSetPropertyElement(child); | ||
1470 | break; | ||
1471 | case "SFPCatalog": | ||
1472 | string parentName = null; | ||
1473 | this.ParseSFPCatalogElement(child, ref parentName); | ||
1474 | break; | ||
1475 | case "SymbolPath": | ||
1476 | if (null != symbols) | ||
1477 | { | ||
1478 | symbols += ";" + this.ParseSymbolPathElement(child); | ||
1479 | } | ||
1480 | else | ||
1481 | { | ||
1482 | symbols = this.ParseSymbolPathElement(child); | ||
1483 | } | ||
1484 | break; | ||
1485 | case "UI": | ||
1486 | this.ParseUIElement(child); | ||
1487 | break; | ||
1488 | case "UIRef": | ||
1489 | this.ParseSimpleRefElement(child, "WixUI"); | ||
1490 | break; | ||
1491 | case "Upgrade": | ||
1492 | this.ParseUpgradeElement(child); | ||
1493 | break; | ||
1494 | case "WixVariable": | ||
1495 | this.ParseWixVariableElement(child); | ||
1496 | break; | ||
1497 | default: | ||
1498 | this.Core.UnexpectedElement(node, child); | ||
1499 | break; | ||
1500 | } | ||
1501 | } | ||
1502 | else | ||
1503 | { | ||
1504 | this.Core.ParseExtensionElement(node, child); | ||
1505 | } | ||
1506 | } | ||
1507 | |||
1508 | if (!this.Core.EncounteredError) | ||
1509 | { | ||
1510 | if (null != symbols) | ||
1511 | { | ||
1512 | var symbolRow = (WixDeltaPatchSymbolPathsTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixDeltaPatchSymbolPaths); | ||
1513 | symbolRow.Id = productCode; | ||
1514 | symbolRow.Type = SymbolPathType.Product; | ||
1515 | symbolRow.SymbolPaths = symbols; | ||
1516 | } | ||
1517 | } | ||
1518 | } | ||
1519 | finally | ||
1520 | { | ||
1521 | this.compilingProduct = false; | ||
1522 | } | ||
1523 | } | ||
1524 | |||
1525 | /// <summary> | ||
1526 | /// Parses a progid element | ||
1527 | /// </summary> | ||
1528 | /// <param name="node">Element to parse.</param> | ||
1529 | /// <param name="componentId">Identifier of parent component.</param> | ||
1530 | /// <param name="advertise">Flag if progid is advertised.</param> | ||
1531 | /// <param name="classId">CLSID related to ProgId.</param> | ||
1532 | /// <param name="description">Default description of ProgId</param> | ||
1533 | /// <param name="parent">Optional parent ProgId</param> | ||
1534 | /// <param name="foundExtension">Set to true if an extension is found; used for error-checking.</param> | ||
1535 | /// <param name="firstProgIdForClass">Whether or not this ProgId is the first one found in the parent class.</param> | ||
1536 | /// <returns>This element's Id.</returns> | ||
1537 | private string ParseProgIdElement(XElement node, string componentId, YesNoType advertise, string classId, string description, string parent, ref bool foundExtension, YesNoType firstProgIdForClass) | ||
1538 | { | ||
1539 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1540 | string icon = null; | ||
1541 | var iconIndex = CompilerConstants.IntegerNotSet; | ||
1542 | string noOpen = null; | ||
1543 | string progId = null; | ||
1544 | var progIdAdvertise = YesNoType.NotSet; | ||
1545 | |||
1546 | foreach (var attrib in node.Attributes()) | ||
1547 | { | ||
1548 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1549 | { | ||
1550 | switch (attrib.Name.LocalName) | ||
1551 | { | ||
1552 | case "Id": | ||
1553 | progId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1554 | break; | ||
1555 | case "Advertise": | ||
1556 | progIdAdvertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1557 | break; | ||
1558 | case "Description": | ||
1559 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1560 | break; | ||
1561 | case "Icon": | ||
1562 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1563 | break; | ||
1564 | case "IconIndex": | ||
1565 | iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue); | ||
1566 | break; | ||
1567 | case "NoOpen": | ||
1568 | noOpen = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1569 | break; | ||
1570 | default: | ||
1571 | this.Core.UnexpectedAttribute(node, attrib); | ||
1572 | break; | ||
1573 | } | ||
1574 | } | ||
1575 | else | ||
1576 | { | ||
1577 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1581 | if ((YesNoType.No == advertise && YesNoType.Yes == progIdAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == progIdAdvertise)) | ||
1582 | { | ||
1583 | this.Core.Write(ErrorMessages.AdvertiseStateMustMatch(sourceLineNumbers, advertise.ToString(), progIdAdvertise.ToString())); | ||
1584 | } | ||
1585 | else | ||
1586 | { | ||
1587 | advertise = progIdAdvertise; | ||
1588 | } | ||
1589 | |||
1590 | if (YesNoType.NotSet == advertise) | ||
1591 | { | ||
1592 | advertise = YesNoType.No; | ||
1593 | } | ||
1594 | |||
1595 | if (null != parent && (null != icon || CompilerConstants.IntegerNotSet != iconIndex)) | ||
1596 | { | ||
1597 | this.Core.Write(ErrorMessages.VersionIndependentProgIdsCannotHaveIcons(sourceLineNumbers)); | ||
1598 | } | ||
1599 | |||
1600 | var firstProgIdForNestedClass = YesNoType.Yes; | ||
1601 | foreach (var child in node.Elements()) | ||
1602 | { | ||
1603 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1604 | { | ||
1605 | switch (child.Name.LocalName) | ||
1606 | { | ||
1607 | case "Extension": | ||
1608 | this.ParseExtensionElement(child, componentId, advertise, progId); | ||
1609 | foundExtension = true; | ||
1610 | break; | ||
1611 | case "ProgId": | ||
1612 | // Only allow one nested ProgId. If we have a child, we should not have a parent. | ||
1613 | if (null == parent) | ||
1614 | { | ||
1615 | if (YesNoType.Yes == advertise) | ||
1616 | { | ||
1617 | this.ParseProgIdElement(child, componentId, advertise, null, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
1618 | } | ||
1619 | else if (YesNoType.No == advertise) | ||
1620 | { | ||
1621 | this.ParseProgIdElement(child, componentId, advertise, classId, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
1622 | } | ||
1623 | |||
1624 | firstProgIdForNestedClass = YesNoType.No; // any ProgId after this one is definitely not the first. | ||
1625 | } | ||
1626 | else | ||
1627 | { | ||
1628 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
1629 | this.Core.Write(ErrorMessages.ProgIdNestedTooDeep(childSourceLineNumbers)); | ||
1630 | } | ||
1631 | break; | ||
1632 | default: | ||
1633 | this.Core.UnexpectedElement(node, child); | ||
1634 | break; | ||
1635 | } | ||
1636 | } | ||
1637 | else | ||
1638 | { | ||
1639 | this.Core.ParseExtensionElement(node, child); | ||
1640 | } | ||
1641 | } | ||
1642 | |||
1643 | if (YesNoType.Yes == advertise) | ||
1644 | { | ||
1645 | if (!this.Core.EncounteredError) | ||
1646 | { | ||
1647 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ProgId); | ||
1648 | row.Set(0, progId); | ||
1649 | row.Set(1, parent); | ||
1650 | row.Set(2, classId); | ||
1651 | row.Set(3, description); | ||
1652 | if (null != icon) | ||
1653 | { | ||
1654 | row.Set(4, icon); | ||
1655 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
1656 | } | ||
1657 | |||
1658 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
1659 | { | ||
1660 | row.Set(5, iconIndex); | ||
1661 | } | ||
1662 | |||
1663 | this.Core.EnsureTable(sourceLineNumbers, "Class"); | ||
1664 | } | ||
1665 | } | ||
1666 | else if (YesNoType.No == advertise) | ||
1667 | { | ||
1668 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, progId, String.Empty, description, componentId); | ||
1669 | if (null != classId) | ||
1670 | { | ||
1671 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\CLSID"), String.Empty, classId, componentId); | ||
1672 | if (null != parent) // if this is a version independent ProgId | ||
1673 | { | ||
1674 | if (YesNoType.Yes == firstProgIdForClass) | ||
1675 | { | ||
1676 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\VersionIndependentProgID"), String.Empty, progId, componentId); | ||
1677 | } | ||
1678 | |||
1679 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\CurVer"), String.Empty, parent, componentId); | ||
1680 | } | ||
1681 | else | ||
1682 | { | ||
1683 | if (YesNoType.Yes == firstProgIdForClass) | ||
1684 | { | ||
1685 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\ProgID"), String.Empty, progId, componentId); | ||
1686 | } | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | if (null != icon) // ProgId's Default Icon | ||
1691 | { | ||
1692 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", icon); | ||
1693 | |||
1694 | icon = String.Format(CultureInfo.InvariantCulture, "\"[#{0}]\"", icon); | ||
1695 | |||
1696 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
1697 | { | ||
1698 | icon = String.Concat(icon, ",", iconIndex); | ||
1699 | } | ||
1700 | |||
1701 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\DefaultIcon"), String.Empty, icon, componentId); | ||
1702 | } | ||
1703 | } | ||
1704 | |||
1705 | if (null != noOpen) | ||
1706 | { | ||
1707 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, progId, "NoOpen", noOpen, componentId); // ProgId NoOpen name | ||
1708 | } | ||
1709 | |||
1710 | // raise an error for an orphaned ProgId | ||
1711 | if (YesNoType.Yes == advertise && !foundExtension && null == parent && null == classId) | ||
1712 | { | ||
1713 | this.Core.Write(WarningMessages.OrphanedProgId(sourceLineNumbers, progId)); | ||
1714 | } | ||
1715 | |||
1716 | return progId; | ||
1717 | } | ||
1718 | |||
1719 | /// <summary> | ||
1720 | /// Parses a property element. | ||
1721 | /// </summary> | ||
1722 | /// <param name="node">Element to parse.</param> | ||
1723 | private void ParsePropertyElement(XElement node) | ||
1724 | { | ||
1725 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1726 | Identifier id = null; | ||
1727 | var admin = false; | ||
1728 | var complianceCheck = false; | ||
1729 | var hidden = false; | ||
1730 | var secure = false; | ||
1731 | var suppressModularization = YesNoType.NotSet; | ||
1732 | string value = null; | ||
1733 | |||
1734 | foreach (var attrib in node.Attributes()) | ||
1735 | { | ||
1736 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1737 | { | ||
1738 | switch (attrib.Name.LocalName) | ||
1739 | { | ||
1740 | case "Id": | ||
1741 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1742 | break; | ||
1743 | case "Admin": | ||
1744 | admin = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1745 | break; | ||
1746 | case "ComplianceCheck": | ||
1747 | complianceCheck = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1748 | break; | ||
1749 | case "Hidden": | ||
1750 | hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1751 | break; | ||
1752 | case "Secure": | ||
1753 | secure = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1754 | break; | ||
1755 | case "SuppressModularization": | ||
1756 | suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1757 | break; | ||
1758 | case "Value": | ||
1759 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1760 | break; | ||
1761 | default: | ||
1762 | this.Core.UnexpectedAttribute(node, attrib); | ||
1763 | break; | ||
1764 | } | ||
1765 | } | ||
1766 | else | ||
1767 | { | ||
1768 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1769 | } | ||
1770 | } | ||
1771 | |||
1772 | if (null == id) | ||
1773 | { | ||
1774 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1775 | id = Identifier.Invalid; | ||
1776 | } | ||
1777 | else if ("ProductID" == id.Id) | ||
1778 | { | ||
1779 | this.Core.Write(WarningMessages.ProductIdAuthored(sourceLineNumbers)); | ||
1780 | } | ||
1781 | else if ("SecureCustomProperties" == id.Id || "AdminProperties" == id.Id || "MsiHiddenProperties" == id.Id) | ||
1782 | { | ||
1783 | this.Core.Write(ErrorMessages.CannotAuthorSpecialProperties(sourceLineNumbers, id.Id)); | ||
1784 | } | ||
1785 | |||
1786 | var innerText = this.Core.GetTrimmedInnerText(node); | ||
1787 | if (null != value) | ||
1788 | { | ||
1789 | // cannot specify both the value attribute and inner text | ||
1790 | if (!String.IsNullOrEmpty(innerText)) | ||
1791 | { | ||
1792 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
1793 | } | ||
1794 | } | ||
1795 | else // value attribute not specified, use inner text if any. | ||
1796 | { | ||
1797 | value = innerText; | ||
1798 | } | ||
1799 | |||
1800 | if ("ErrorDialog" == id.Id) | ||
1801 | { | ||
1802 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", value); | ||
1803 | } | ||
1804 | |||
1805 | foreach (var child in node.Elements()) | ||
1806 | { | ||
1807 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1808 | { | ||
1809 | { | ||
1810 | switch (child.Name.LocalName) | ||
1811 | { | ||
1812 | case "ProductSearch": | ||
1813 | this.ParseProductSearchElement(child, id.Id); | ||
1814 | secure = true; | ||
1815 | break; | ||
1816 | default: | ||
1817 | // let ParseSearchSignatures handle standard AppSearch children and unknown elements | ||
1818 | break; | ||
1819 | } | ||
1820 | } | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | // see if this property is used for appSearch | ||
1825 | var signatures = this.ParseSearchSignatures(node); | ||
1826 | |||
1827 | // If we're doing CCP then there must be a signature. | ||
1828 | if (complianceCheck && 0 == signatures.Count) | ||
1829 | { | ||
1830 | this.Core.Write(ErrorMessages.SearchElementRequiredWithAttribute(sourceLineNumbers, node.Name.LocalName, "ComplianceCheck", "yes")); | ||
1831 | } | ||
1832 | |||
1833 | foreach (var sig in signatures) | ||
1834 | { | ||
1835 | if (complianceCheck && !this.Core.EncounteredError) | ||
1836 | { | ||
1837 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CCPSearch, new Identifier(sig, AccessModifier.Private)); | ||
1838 | } | ||
1839 | |||
1840 | this.AddAppSearch(sourceLineNumbers, id, sig); | ||
1841 | } | ||
1842 | |||
1843 | // If we're doing AppSearch get that setup. | ||
1844 | if (0 < signatures.Count) | ||
1845 | { | ||
1846 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
1847 | } | ||
1848 | else // just a normal old property. | ||
1849 | { | ||
1850 | // If the property value is empty and none of the flags are set, print out a warning that we're ignoring | ||
1851 | // the element. | ||
1852 | if (String.IsNullOrEmpty(value) && !admin && !secure && !hidden) | ||
1853 | { | ||
1854 | this.Core.Write(WarningMessages.PropertyUseless(sourceLineNumbers, id.Id)); | ||
1855 | } | ||
1856 | else // there is a value and/or a flag set, do that. | ||
1857 | { | ||
1858 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
1859 | } | ||
1860 | } | ||
1861 | |||
1862 | if (!this.Core.EncounteredError && YesNoType.Yes == suppressModularization) | ||
1863 | { | ||
1864 | this.Core.Write(WarningMessages.PropertyModularizationSuppressed(sourceLineNumbers)); | ||
1865 | |||
1866 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSuppressModularization, id); | ||
1867 | } | ||
1868 | } | ||
1869 | |||
1870 | /// <summary> | ||
1871 | /// Parses a RegistryKey element. | ||
1872 | /// </summary> | ||
1873 | /// <param name="node">Element to parse.</param> | ||
1874 | /// <param name="componentId">Identifier for parent component.</param> | ||
1875 | /// <param name="root">Root specified when element is nested under another Registry element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
1876 | /// <param name="parentKey">Parent key for this Registry element when nested.</param> | ||
1877 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
1878 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
1879 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
1880 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
1881 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
1882 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
1883 | private YesNoType ParseRegistryKeyElement(XElement node, string componentId, RegistryRootType? root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
1884 | { | ||
1885 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1886 | Identifier id = null; | ||
1887 | var key = parentKey; // default to parent key path | ||
1888 | var forceCreateOnInstall = false; | ||
1889 | var forceDeleteOnUninstall = false; | ||
1890 | var keyPath = YesNoType.NotSet; | ||
1891 | |||
1892 | possibleKeyPath = null; | ||
1893 | |||
1894 | foreach (var attrib in node.Attributes()) | ||
1895 | { | ||
1896 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1897 | { | ||
1898 | switch (attrib.Name.LocalName) | ||
1899 | { | ||
1900 | case "Id": | ||
1901 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1902 | break; | ||
1903 | case "Action": | ||
1904 | this.Core.Write(WarningMessages.DeprecatedRegistryKeyActionAttribute(sourceLineNumbers)); | ||
1905 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1906 | switch (actionValue) | ||
1907 | { | ||
1908 | case "create": | ||
1909 | forceCreateOnInstall = true; | ||
1910 | break; | ||
1911 | case "createAndRemoveOnUninstall": | ||
1912 | forceCreateOnInstall = true; | ||
1913 | forceDeleteOnUninstall = true; | ||
1914 | break; | ||
1915 | case "none": | ||
1916 | break; | ||
1917 | case "": | ||
1918 | break; | ||
1919 | default: | ||
1920 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "createAndRemoveOnUninstall", "none")); | ||
1921 | break; | ||
1922 | } | ||
1923 | break; | ||
1924 | case "ForceCreateOnInstall": | ||
1925 | forceCreateOnInstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1926 | break; | ||
1927 | case "ForceDeleteOnUninstall": | ||
1928 | forceDeleteOnUninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1929 | break; | ||
1930 | case "Key": | ||
1931 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1932 | if (null != parentKey) | ||
1933 | { | ||
1934 | key = Path.Combine(parentKey, key); | ||
1935 | } | ||
1936 | break; | ||
1937 | case "Root": | ||
1938 | if (root.HasValue) | ||
1939 | { | ||
1940 | this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers)); | ||
1941 | } | ||
1942 | |||
1943 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
1944 | break; | ||
1945 | default: | ||
1946 | this.Core.UnexpectedAttribute(node, attrib); | ||
1947 | break; | ||
1948 | } | ||
1949 | } | ||
1950 | else | ||
1951 | { | ||
1952 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1953 | } | ||
1954 | } | ||
1955 | |||
1956 | var name = forceCreateOnInstall ? (forceDeleteOnUninstall ? "*" : "+") : (forceDeleteOnUninstall ? "-" : null); | ||
1957 | |||
1958 | if (forceCreateOnInstall || forceDeleteOnUninstall) // generates a Registry row, so an Id must be present | ||
1959 | { | ||
1960 | // generate the identifier if it wasn't provided | ||
1961 | if (null == id) | ||
1962 | { | ||
1963 | id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
1964 | } | ||
1965 | } | ||
1966 | else // does not generate a Registry row, so no Id should be present | ||
1967 | { | ||
1968 | if (null != id) | ||
1969 | { | ||
1970 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Id", "ForceCreateOnInstall", "ForceDeleteOnUninstall", "yes", true)); | ||
1971 | } | ||
1972 | } | ||
1973 | |||
1974 | if (!root.HasValue) | ||
1975 | { | ||
1976 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
1977 | } | ||
1978 | |||
1979 | if (null == key) | ||
1980 | { | ||
1981 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
1982 | key = String.Empty; // set the key to something to prevent null reference exceptions | ||
1983 | } | ||
1984 | |||
1985 | foreach (var child in node.Elements()) | ||
1986 | { | ||
1987 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1988 | { | ||
1989 | string possibleChildKeyPath = null; | ||
1990 | |||
1991 | switch (child.Name.LocalName) | ||
1992 | { | ||
1993 | case "RegistryKey": | ||
1994 | if (YesNoType.Yes == this.ParseRegistryKeyElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
1995 | { | ||
1996 | if (YesNoType.Yes == keyPath) | ||
1997 | { | ||
1998 | this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
1999 | } | ||
2000 | |||
2001 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
2002 | keyPath = YesNoType.Yes; | ||
2003 | } | ||
2004 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
2005 | { | ||
2006 | possibleKeyPath = possibleChildKeyPath; | ||
2007 | } | ||
2008 | break; | ||
2009 | case "RegistryValue": | ||
2010 | if (YesNoType.Yes == this.ParseRegistryValueElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
2011 | { | ||
2012 | if (YesNoType.Yes == keyPath) | ||
2013 | { | ||
2014 | this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
2015 | } | ||
2016 | |||
2017 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
2018 | keyPath = YesNoType.Yes; | ||
2019 | } | ||
2020 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
2021 | { | ||
2022 | possibleKeyPath = possibleChildKeyPath; | ||
2023 | } | ||
2024 | break; | ||
2025 | case "Permission": | ||
2026 | if (!forceCreateOnInstall) | ||
2027 | { | ||
2028 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
2029 | } | ||
2030 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
2031 | break; | ||
2032 | case "PermissionEx": | ||
2033 | if (!forceCreateOnInstall) | ||
2034 | { | ||
2035 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
2036 | } | ||
2037 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
2038 | break; | ||
2039 | default: | ||
2040 | this.Core.UnexpectedElement(node, child); | ||
2041 | break; | ||
2042 | } | ||
2043 | } | ||
2044 | else | ||
2045 | { | ||
2046 | var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
2047 | this.Core.ParseExtensionElement(node, child, context); | ||
2048 | } | ||
2049 | } | ||
2050 | |||
2051 | if (!this.Core.EncounteredError && null != name) | ||
2052 | { | ||
2053 | var tuple = new RegistryTuple(sourceLineNumbers, id) | ||
2054 | { | ||
2055 | Root = root.Value, | ||
2056 | Key = key, | ||
2057 | Name = name, | ||
2058 | Component_ = componentId, | ||
2059 | }; | ||
2060 | |||
2061 | this.Core.AddTuple(tuple); | ||
2062 | } | ||
2063 | |||
2064 | return keyPath; | ||
2065 | } | ||
2066 | |||
2067 | /// <summary> | ||
2068 | /// Parses a RegistryValue element. | ||
2069 | /// </summary> | ||
2070 | /// <param name="node">Element to parse.</param> | ||
2071 | /// <param name="componentId">Identifier for parent component.</param> | ||
2072 | /// <param name="root">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
2073 | /// <param name="parentKey">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
2074 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
2075 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
2076 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
2077 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
2078 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
2079 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
2080 | private YesNoType ParseRegistryValueElement(XElement node, string componentId, RegistryRootType? root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
2081 | { | ||
2082 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2083 | Identifier id = null; | ||
2084 | var key = parentKey; // default to parent key path | ||
2085 | string name = null; | ||
2086 | string value = null; | ||
2087 | string action = null; | ||
2088 | var valueType = RegistryValueType.String; | ||
2089 | var actionType = RegistryValueActionType.Write; | ||
2090 | var keyPath = YesNoType.NotSet; | ||
2091 | |||
2092 | possibleKeyPath = null; | ||
2093 | |||
2094 | foreach (var attrib in node.Attributes()) | ||
2095 | { | ||
2096 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2097 | { | ||
2098 | switch (attrib.Name.LocalName) | ||
2099 | { | ||
2100 | case "Id": | ||
2101 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2102 | break; | ||
2103 | case "Action": | ||
2104 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2105 | switch (actionValue) | ||
2106 | { | ||
2107 | case "append": | ||
2108 | actionType = RegistryValueActionType.Append; | ||
2109 | break; | ||
2110 | case "prepend": | ||
2111 | actionType = RegistryValueActionType.Prepend; | ||
2112 | break; | ||
2113 | case "write": | ||
2114 | actionType = RegistryValueActionType.Write; | ||
2115 | break; | ||
2116 | case "": | ||
2117 | break; | ||
2118 | default: | ||
2119 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "append", "prepend", "write")); | ||
2120 | break; | ||
2121 | } | ||
2122 | break; | ||
2123 | case "Key": | ||
2124 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2125 | if (null != parentKey) | ||
2126 | { | ||
2127 | if (parentKey.EndsWith("\\", StringComparison.Ordinal)) | ||
2128 | { | ||
2129 | key = String.Concat(parentKey, key); | ||
2130 | } | ||
2131 | else | ||
2132 | { | ||
2133 | key = String.Concat(parentKey, "\\", key); | ||
2134 | } | ||
2135 | } | ||
2136 | break; | ||
2137 | case "KeyPath": | ||
2138 | keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
2139 | break; | ||
2140 | case "Name": | ||
2141 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2142 | break; | ||
2143 | case "Root": | ||
2144 | if (root.HasValue) | ||
2145 | { | ||
2146 | this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers)); | ||
2147 | } | ||
2148 | |||
2149 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
2150 | break; | ||
2151 | case "Type": | ||
2152 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2153 | switch (typeValue) | ||
2154 | { | ||
2155 | case "binary": | ||
2156 | valueType = RegistryValueType.Binary; | ||
2157 | break; | ||
2158 | case "expandable": | ||
2159 | valueType = RegistryValueType.Expandable; | ||
2160 | break; | ||
2161 | case "integer": | ||
2162 | valueType = RegistryValueType.Integer; | ||
2163 | break; | ||
2164 | case "multiString": | ||
2165 | valueType = RegistryValueType.MultiString; | ||
2166 | break; | ||
2167 | case "string": | ||
2168 | valueType = RegistryValueType.String; | ||
2169 | break; | ||
2170 | case "": | ||
2171 | break; | ||
2172 | default: | ||
2173 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "binary", "expandable", "integer", "multiString", "string")); | ||
2174 | break; | ||
2175 | } | ||
2176 | break; | ||
2177 | case "Value": | ||
2178 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
2179 | break; | ||
2180 | default: | ||
2181 | this.Core.UnexpectedAttribute(node, attrib); | ||
2182 | break; | ||
2183 | } | ||
2184 | } | ||
2185 | else | ||
2186 | { | ||
2187 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2188 | } | ||
2189 | } | ||
2190 | |||
2191 | // generate the identifier if it wasn't provided | ||
2192 | if (null == id) | ||
2193 | { | ||
2194 | id = this.Core.CreateIdentifier("reg", componentId, ((int)(root ?? RegistryRootType.Unknown)).ToString(), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
2195 | } | ||
2196 | |||
2197 | if (RegistryValueType.MultiString != valueType && (RegistryValueActionType.Append == actionType || RegistryValueActionType.Prepend == actionType)) | ||
2198 | { | ||
2199 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Action", action, "Type", "multiString")); | ||
2200 | } | ||
2201 | |||
2202 | if (null == key) | ||
2203 | { | ||
2204 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
2205 | } | ||
2206 | |||
2207 | if (!root.HasValue) | ||
2208 | { | ||
2209 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
2210 | } | ||
2211 | |||
2212 | foreach (var child in node.Elements()) | ||
2213 | { | ||
2214 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2215 | { | ||
2216 | switch (child.Name.LocalName) | ||
2217 | { | ||
2218 | case "MultiStringValue": | ||
2219 | if (RegistryValueType.MultiString != valueType && null != value) | ||
2220 | { | ||
2221 | this.Core.Write(ErrorMessages.RegistryMultipleValuesWithoutMultiString(sourceLineNumbers, node.Name.LocalName, "Value", child.Name.LocalName, "Type")); | ||
2222 | } | ||
2223 | else if (null == value) | ||
2224 | { | ||
2225 | value = Common.GetInnerText(child); | ||
2226 | } | ||
2227 | else | ||
2228 | { | ||
2229 | value = String.Concat(value, "[~]", Common.GetInnerText(child)); | ||
2230 | } | ||
2231 | break; | ||
2232 | case "Permission": | ||
2233 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
2234 | break; | ||
2235 | case "PermissionEx": | ||
2236 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
2237 | break; | ||
2238 | default: | ||
2239 | this.Core.UnexpectedElement(node, child); | ||
2240 | break; | ||
2241 | } | ||
2242 | } | ||
2243 | else | ||
2244 | { | ||
2245 | var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
2246 | this.Core.ParseExtensionElement(node, child, context); | ||
2247 | } | ||
2248 | } | ||
2249 | |||
2250 | //switch (typeType) | ||
2251 | //{ | ||
2252 | //case Wix.RegistryValue.TypeType.binary: | ||
2253 | // value = String.Concat("#x", value); | ||
2254 | // break; | ||
2255 | //case Wix.RegistryValue.TypeType.expandable: | ||
2256 | // value = String.Concat("#%", value); | ||
2257 | // break; | ||
2258 | //case Wix.RegistryValue.TypeType.integer: | ||
2259 | // value = String.Concat("#", value); | ||
2260 | // break; | ||
2261 | //case Wix.RegistryValue.TypeType.multiString: | ||
2262 | // switch (actionType) | ||
2263 | // { | ||
2264 | // case Wix.RegistryValue.ActionType.append: | ||
2265 | // value = String.Concat("[~]", value); | ||
2266 | // break; | ||
2267 | // case Wix.RegistryValue.ActionType.prepend: | ||
2268 | // value = String.Concat(value, "[~]"); | ||
2269 | // break; | ||
2270 | // case Wix.RegistryValue.ActionType.write: | ||
2271 | // default: | ||
2272 | // if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) | ||
2273 | // { | ||
2274 | // value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value); | ||
2275 | // } | ||
2276 | // break; | ||
2277 | // } | ||
2278 | // break; | ||
2279 | //case Wix.RegistryValue.TypeType.@string: | ||
2280 | // // escape the leading '#' character for string registry keys | ||
2281 | // if (null != value && value.StartsWith("#", StringComparison.Ordinal)) | ||
2282 | // { | ||
2283 | // value = String.Concat("#", value); | ||
2284 | // } | ||
2285 | // break; | ||
2286 | //} | ||
2287 | |||
2288 | // value may be set by child MultiStringValue elements, so it must be checked here | ||
2289 | if (null == value) | ||
2290 | { | ||
2291 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
2292 | } | ||
2293 | else if (0 == value.Length && ("+" == name || "-" == name || "*" == name)) // prevent accidental authoring of special name values | ||
2294 | { | ||
2295 | this.Core.Write(ErrorMessages.RegistryNameValueIncorrect(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
2296 | } | ||
2297 | |||
2298 | if (!this.Core.EncounteredError) | ||
2299 | { | ||
2300 | var tuple = new RegistryTuple(sourceLineNumbers, id) | ||
2301 | { | ||
2302 | Root = root.Value, | ||
2303 | Name = name, | ||
2304 | Value = value, | ||
2305 | ValueType = valueType, | ||
2306 | ValueAction = actionType, | ||
2307 | Component_ = componentId, | ||
2308 | }; | ||
2309 | |||
2310 | this.Core.AddTuple(tuple); | ||
2311 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Registry, id); | ||
2312 | //row.Set(1, (int)root); | ||
2313 | //row.Set(2, key); | ||
2314 | //row.Set(3, name); | ||
2315 | //row.Set(4, value); | ||
2316 | //row.Set(5, componentId); | ||
2317 | } | ||
2318 | |||
2319 | // If this was just a regular registry key (that could be the key path) | ||
2320 | // and no child registry key set the possible key path, let's make this | ||
2321 | // Registry/@Id a possible key path. | ||
2322 | if (null == possibleKeyPath) | ||
2323 | { | ||
2324 | possibleKeyPath = id.Id; | ||
2325 | } | ||
2326 | |||
2327 | return keyPath; | ||
2328 | } | ||
2329 | |||
2330 | /// <summary> | ||
2331 | /// Parses a RemoveRegistryKey element. | ||
2332 | /// </summary> | ||
2333 | /// <param name="node">The element to parse.</param> | ||
2334 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
2335 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
2336 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
2337 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
2338 | private void ParseRemoveRegistryKeyElement(XElement node, string componentId) | ||
2339 | { | ||
2340 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2341 | Identifier id = null; | ||
2342 | RemoveRegistryActionType? actionType = null; | ||
2343 | string key = null; | ||
2344 | var name = "-"; | ||
2345 | RegistryRootType? root = null; | ||
2346 | |||
2347 | foreach (var attrib in node.Attributes()) | ||
2348 | { | ||
2349 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2350 | { | ||
2351 | switch (attrib.Name.LocalName) | ||
2352 | { | ||
2353 | case "Id": | ||
2354 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2355 | break; | ||
2356 | case "Action": | ||
2357 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2358 | switch (actionValue) | ||
2359 | { | ||
2360 | case "removeOnInstall": | ||
2361 | actionType = RemoveRegistryActionType.RemoveOnInstall; | ||
2362 | break; | ||
2363 | case "removeOnUninstall": | ||
2364 | actionType = RemoveRegistryActionType.RemoveOnUninstall; | ||
2365 | break; | ||
2366 | case "": | ||
2367 | break; | ||
2368 | default: | ||
2369 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "removeOnInstall", "removeOnUninstall")); | ||
2370 | break; | ||
2371 | } | ||
2372 | //if (0 < action.Length) | ||
2373 | //{ | ||
2374 | // if (!Wix.RemoveRegistryKey.TryParseActionType(action, out actionType)) | ||
2375 | // { | ||
2376 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "removeOnInstall", "removeOnUninstall")); | ||
2377 | // } | ||
2378 | //} | ||
2379 | break; | ||
2380 | case "Key": | ||
2381 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2382 | break; | ||
2383 | case "Root": | ||
2384 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
2385 | break; | ||
2386 | default: | ||
2387 | this.Core.UnexpectedAttribute(node, attrib); | ||
2388 | break; | ||
2389 | } | ||
2390 | } | ||
2391 | else | ||
2392 | { | ||
2393 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | // generate the identifier if it wasn't provided | ||
2398 | if (null == id) | ||
2399 | { | ||
2400 | id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
2401 | } | ||
2402 | |||
2403 | if (!root.HasValue) | ||
2404 | { | ||
2405 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
2406 | } | ||
2407 | |||
2408 | if (null == key) | ||
2409 | { | ||
2410 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
2411 | } | ||
2412 | |||
2413 | if (!actionType.HasValue) | ||
2414 | { | ||
2415 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
2416 | } | ||
2417 | |||
2418 | this.Core.ParseForExtensionElements(node); | ||
2419 | |||
2420 | if (!this.Core.EncounteredError) | ||
2421 | { | ||
2422 | var tuple = new RemoveRegistryTuple(sourceLineNumbers, id) | ||
2423 | { | ||
2424 | Root = root.Value, | ||
2425 | Key = key, | ||
2426 | Name = name, | ||
2427 | Action = actionType.Value, | ||
2428 | Component_ = componentId | ||
2429 | }; | ||
2430 | |||
2431 | this.Core.AddTuple(tuple); | ||
2432 | } | ||
2433 | } | ||
2434 | |||
2435 | /// <summary> | ||
2436 | /// Parses a RemoveRegistryValue element. | ||
2437 | /// </summary> | ||
2438 | /// <param name="node">The element to parse.</param> | ||
2439 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
2440 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
2441 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
2442 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
2443 | private void ParseRemoveRegistryValueElement(XElement node, string componentId) | ||
2444 | { | ||
2445 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2446 | Identifier id = null; | ||
2447 | string key = null; | ||
2448 | string name = null; | ||
2449 | RegistryRootType? root = null; | ||
2450 | |||
2451 | foreach (var attrib in node.Attributes()) | ||
2452 | { | ||
2453 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2454 | { | ||
2455 | switch (attrib.Name.LocalName) | ||
2456 | { | ||
2457 | case "Id": | ||
2458 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2459 | break; | ||
2460 | case "Key": | ||
2461 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2462 | break; | ||
2463 | case "Name": | ||
2464 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2465 | break; | ||
2466 | case "Root": | ||
2467 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
2468 | break; | ||
2469 | default: | ||
2470 | this.Core.UnexpectedAttribute(node, attrib); | ||
2471 | break; | ||
2472 | } | ||
2473 | } | ||
2474 | else | ||
2475 | { | ||
2476 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2477 | } | ||
2478 | } | ||
2479 | |||
2480 | // generate the identifier if it wasn't provided | ||
2481 | if (null == id) | ||
2482 | { | ||
2483 | id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
2484 | } | ||
2485 | |||
2486 | if (!root.HasValue) | ||
2487 | { | ||
2488 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
2489 | } | ||
2490 | |||
2491 | if (null == key) | ||
2492 | { | ||
2493 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
2494 | } | ||
2495 | |||
2496 | this.Core.ParseForExtensionElements(node); | ||
2497 | |||
2498 | if (!this.Core.EncounteredError) | ||
2499 | { | ||
2500 | var tuple = new RemoveRegistryTuple(sourceLineNumbers, id) | ||
2501 | { | ||
2502 | Root = root.Value, | ||
2503 | Key = key, | ||
2504 | Name = name, | ||
2505 | Component_ = componentId | ||
2506 | }; | ||
2507 | |||
2508 | this.Core.AddTuple(tuple); | ||
2509 | } | ||
2510 | } | ||
2511 | |||
2512 | /// <summary> | ||
2513 | /// Parses a remove file element. | ||
2514 | /// </summary> | ||
2515 | /// <param name="node">Element to parse.</param> | ||
2516 | /// <param name="componentId">Identifier of parent component.</param> | ||
2517 | /// <param name="parentDirectory">Identifier of the parent component's directory.</param> | ||
2518 | private void ParseRemoveFileElement(XElement node, string componentId, string parentDirectory) | ||
2519 | { | ||
2520 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2521 | Identifier id = null; | ||
2522 | string directory = null; | ||
2523 | string name = null; | ||
2524 | var on = CompilerConstants.IntegerNotSet; | ||
2525 | string property = null; | ||
2526 | string shortName = null; | ||
2527 | |||
2528 | foreach (var attrib in node.Attributes()) | ||
2529 | { | ||
2530 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2531 | { | ||
2532 | switch (attrib.Name.LocalName) | ||
2533 | { | ||
2534 | case "Id": | ||
2535 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2536 | break; | ||
2537 | case "Directory": | ||
2538 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
2539 | break; | ||
2540 | case "Name": | ||
2541 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true); | ||
2542 | break; | ||
2543 | case "On": | ||
2544 | var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2545 | switch (onValue) | ||
2546 | { | ||
2547 | case "install": | ||
2548 | on = 1; | ||
2549 | break; | ||
2550 | case "uninstall": | ||
2551 | on = 2; | ||
2552 | break; | ||
2553 | case "both": | ||
2554 | on = 3; | ||
2555 | break; | ||
2556 | default: | ||
2557 | on = CompilerConstants.IllegalInteger; | ||
2558 | break; | ||
2559 | } | ||
2560 | break; | ||
2561 | case "Property": | ||
2562 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2563 | break; | ||
2564 | case "ShortName": | ||
2565 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true); | ||
2566 | break; | ||
2567 | default: | ||
2568 | this.Core.UnexpectedAttribute(node, attrib); | ||
2569 | break; | ||
2570 | } | ||
2571 | } | ||
2572 | else | ||
2573 | { | ||
2574 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2575 | } | ||
2576 | } | ||
2577 | |||
2578 | if (null == name) | ||
2579 | { | ||
2580 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
2581 | } | ||
2582 | else if (0 < name.Length) | ||
2583 | { | ||
2584 | if (this.Core.IsValidShortFilename(name, true)) | ||
2585 | { | ||
2586 | if (null == shortName) | ||
2587 | { | ||
2588 | shortName = name; | ||
2589 | name = null; | ||
2590 | } | ||
2591 | else | ||
2592 | { | ||
2593 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
2594 | } | ||
2595 | } | ||
2596 | else if (null == shortName) // generate a short file name. | ||
2597 | { | ||
2598 | shortName = this.Core.CreateShortName(name, true, true, node.Name.LocalName, componentId); | ||
2599 | } | ||
2600 | } | ||
2601 | |||
2602 | if (CompilerConstants.IntegerNotSet == on) | ||
2603 | { | ||
2604 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
2605 | on = CompilerConstants.IllegalInteger; | ||
2606 | } | ||
2607 | |||
2608 | if (null != directory && null != property) | ||
2609 | { | ||
2610 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
2611 | } | ||
2612 | |||
2613 | if (null == id) | ||
2614 | { | ||
2615 | id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); | ||
2616 | } | ||
2617 | |||
2618 | this.Core.ParseForExtensionElements(node); | ||
2619 | |||
2620 | if (!this.Core.EncounteredError) | ||
2621 | { | ||
2622 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id); | ||
2623 | row.Set(1, componentId); | ||
2624 | row.Set(2, this.GetMsiFilenameValue(shortName, name)); | ||
2625 | if (null != directory) | ||
2626 | { | ||
2627 | row.Set(3, directory); | ||
2628 | } | ||
2629 | else if (null != property) | ||
2630 | { | ||
2631 | row.Set(3, property); | ||
2632 | } | ||
2633 | else | ||
2634 | { | ||
2635 | row.Set(3, parentDirectory); | ||
2636 | } | ||
2637 | row.Set(4, on); | ||
2638 | } | ||
2639 | } | ||
2640 | |||
2641 | /// <summary> | ||
2642 | /// Parses a RemoveFolder element. | ||
2643 | /// </summary> | ||
2644 | /// <param name="node">Element to parse.</param> | ||
2645 | /// <param name="componentId">Identifier of parent component.</param> | ||
2646 | /// <param name="parentDirectory">Identifier of parent component's directory.</param> | ||
2647 | private void ParseRemoveFolderElement(XElement node, string componentId, string parentDirectory) | ||
2648 | { | ||
2649 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2650 | Identifier id = null; | ||
2651 | string directory = null; | ||
2652 | var on = CompilerConstants.IntegerNotSet; | ||
2653 | string property = null; | ||
2654 | |||
2655 | foreach (var attrib in node.Attributes()) | ||
2656 | { | ||
2657 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2658 | { | ||
2659 | switch (attrib.Name.LocalName) | ||
2660 | { | ||
2661 | case "Id": | ||
2662 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2663 | break; | ||
2664 | case "Directory": | ||
2665 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
2666 | break; | ||
2667 | case "On": | ||
2668 | var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2669 | switch (onValue) | ||
2670 | { | ||
2671 | case "install": | ||
2672 | on = 1; | ||
2673 | break; | ||
2674 | case "uninstall": | ||
2675 | on = 2; | ||
2676 | break; | ||
2677 | case "both": | ||
2678 | on = 3; | ||
2679 | break; | ||
2680 | default: | ||
2681 | on = CompilerConstants.IllegalInteger; | ||
2682 | break; | ||
2683 | } | ||
2684 | break; | ||
2685 | case "Property": | ||
2686 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2687 | break; | ||
2688 | default: | ||
2689 | this.Core.UnexpectedAttribute(node, attrib); | ||
2690 | break; | ||
2691 | } | ||
2692 | } | ||
2693 | else | ||
2694 | { | ||
2695 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2696 | } | ||
2697 | } | ||
2698 | |||
2699 | if (CompilerConstants.IntegerNotSet == on) | ||
2700 | { | ||
2701 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
2702 | on = CompilerConstants.IllegalInteger; | ||
2703 | } | ||
2704 | |||
2705 | if (null != directory && null != property) | ||
2706 | { | ||
2707 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
2708 | } | ||
2709 | |||
2710 | if (null == id) | ||
2711 | { | ||
2712 | id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString()); | ||
2713 | } | ||
2714 | |||
2715 | this.Core.ParseForExtensionElements(node); | ||
2716 | |||
2717 | if (!this.Core.EncounteredError) | ||
2718 | { | ||
2719 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id); | ||
2720 | row.Set(1, componentId); | ||
2721 | //row.Set(2, null); | ||
2722 | if (null != directory) | ||
2723 | { | ||
2724 | row.Set(3, directory); | ||
2725 | } | ||
2726 | else if (null != property) | ||
2727 | { | ||
2728 | row.Set(3, property); | ||
2729 | } | ||
2730 | else | ||
2731 | { | ||
2732 | row.Set(3, parentDirectory); | ||
2733 | } | ||
2734 | row.Set(4, on); | ||
2735 | } | ||
2736 | } | ||
2737 | |||
2738 | /// <summary> | ||
2739 | /// Parses a reserve cost element. | ||
2740 | /// </summary> | ||
2741 | /// <param name="node">Element to parse.</param> | ||
2742 | /// <param name="componentId">Identifier of parent component.</param> | ||
2743 | /// <param name="directoryId">Optional and default identifier of referenced directory.</param> | ||
2744 | private void ParseReserveCostElement(XElement node, string componentId, string directoryId) | ||
2745 | { | ||
2746 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2747 | Identifier id = null; | ||
2748 | var runFromSource = CompilerConstants.IntegerNotSet; | ||
2749 | var runLocal = CompilerConstants.IntegerNotSet; | ||
2750 | |||
2751 | foreach (var attrib in node.Attributes()) | ||
2752 | { | ||
2753 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2754 | { | ||
2755 | switch (attrib.Name.LocalName) | ||
2756 | { | ||
2757 | case "Id": | ||
2758 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2759 | break; | ||
2760 | case "Directory": | ||
2761 | directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | ||
2762 | break; | ||
2763 | case "RunFromSource": | ||
2764 | runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
2765 | break; | ||
2766 | case "RunLocal": | ||
2767 | runLocal = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
2768 | break; | ||
2769 | default: | ||
2770 | this.Core.UnexpectedAttribute(node, attrib); | ||
2771 | break; | ||
2772 | } | ||
2773 | } | ||
2774 | else | ||
2775 | { | ||
2776 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2777 | } | ||
2778 | } | ||
2779 | |||
2780 | if (null == id) | ||
2781 | { | ||
2782 | id = this.Core.CreateIdentifier("rc", componentId, directoryId); | ||
2783 | } | ||
2784 | |||
2785 | if (CompilerConstants.IntegerNotSet == runFromSource) | ||
2786 | { | ||
2787 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunFromSource")); | ||
2788 | } | ||
2789 | |||
2790 | if (CompilerConstants.IntegerNotSet == runLocal) | ||
2791 | { | ||
2792 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunLocal")); | ||
2793 | } | ||
2794 | |||
2795 | this.Core.ParseForExtensionElements(node); | ||
2796 | |||
2797 | if (!this.Core.EncounteredError) | ||
2798 | { | ||
2799 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ReserveCost, id); | ||
2800 | row.Set(1, componentId); | ||
2801 | row.Set(2, directoryId); | ||
2802 | row.Set(3, runLocal); | ||
2803 | row.Set(4, runFromSource); | ||
2804 | } | ||
2805 | } | ||
2806 | |||
2807 | /// <summary> | ||
2808 | /// Parses a sequence element. | ||
2809 | /// </summary> | ||
2810 | /// <param name="node">Element to parse.</param> | ||
2811 | /// <param name="sequenceTable">Name of sequence table.</param> | ||
2812 | private void ParseSequenceElement(XElement node, string sequenceTable) | ||
2813 | { | ||
2814 | // use the proper table name internally | ||
2815 | if ("AdvertiseExecuteSequence" == sequenceTable) | ||
2816 | { | ||
2817 | sequenceTable = "AdvtExecuteSequence"; | ||
2818 | } | ||
2819 | |||
2820 | // Parse each action in the sequence. | ||
2821 | foreach (var child in node.Elements()) | ||
2822 | { | ||
2823 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
2824 | var actionName = child.Name.LocalName; | ||
2825 | string afterAction = null; | ||
2826 | string beforeAction = null; | ||
2827 | string condition = null; | ||
2828 | var customAction = "Custom" == actionName; | ||
2829 | var overridable = false; | ||
2830 | var exitSequence = CompilerConstants.IntegerNotSet; | ||
2831 | var sequence = CompilerConstants.IntegerNotSet; | ||
2832 | var showDialog = "Show" == actionName; | ||
2833 | var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName; | ||
2834 | var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName; | ||
2835 | var suppress = false; | ||
2836 | |||
2837 | foreach (var attrib in child.Attributes()) | ||
2838 | { | ||
2839 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2840 | { | ||
2841 | switch (attrib.Name.LocalName) | ||
2842 | { | ||
2843 | case "Action": | ||
2844 | if (customAction) | ||
2845 | { | ||
2846 | actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2847 | this.Core.CreateSimpleReference(childSourceLineNumbers, "CustomAction", actionName); | ||
2848 | } | ||
2849 | else | ||
2850 | { | ||
2851 | this.Core.UnexpectedAttribute(child, attrib); | ||
2852 | } | ||
2853 | break; | ||
2854 | case "After": | ||
2855 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
2856 | { | ||
2857 | afterAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2858 | this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, afterAction); | ||
2859 | } | ||
2860 | else | ||
2861 | { | ||
2862 | this.Core.UnexpectedAttribute(child, attrib); | ||
2863 | } | ||
2864 | break; | ||
2865 | case "Before": | ||
2866 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
2867 | { | ||
2868 | beforeAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2869 | this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, beforeAction); | ||
2870 | } | ||
2871 | else | ||
2872 | { | ||
2873 | this.Core.UnexpectedAttribute(child, attrib); | ||
2874 | } | ||
2875 | break; | ||
2876 | case "Dialog": | ||
2877 | if (showDialog) | ||
2878 | { | ||
2879 | actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2880 | this.Core.CreateSimpleReference(childSourceLineNumbers, "Dialog", actionName); | ||
2881 | } | ||
2882 | else | ||
2883 | { | ||
2884 | this.Core.UnexpectedAttribute(child, attrib); | ||
2885 | } | ||
2886 | break; | ||
2887 | case "OnExit": | ||
2888 | if (customAction || showDialog || specialAction) | ||
2889 | { | ||
2890 | var exitValue = this.Core.GetAttributeValue(childSourceLineNumbers, attrib); | ||
2891 | switch (exitValue) | ||
2892 | { | ||
2893 | case "success": | ||
2894 | exitSequence = -1; | ||
2895 | break; | ||
2896 | case "cancel": | ||
2897 | exitSequence = -2; | ||
2898 | break; | ||
2899 | case "error": | ||
2900 | exitSequence = -3; | ||
2901 | break; | ||
2902 | case "suspend": | ||
2903 | exitSequence = -4; | ||
2904 | break; | ||
2905 | } | ||
2906 | } | ||
2907 | else | ||
2908 | { | ||
2909 | this.Core.UnexpectedAttribute(child, attrib); | ||
2910 | } | ||
2911 | break; | ||
2912 | case "Overridable": | ||
2913 | overridable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
2914 | break; | ||
2915 | case "Sequence": | ||
2916 | sequence = this.Core.GetAttributeIntegerValue(childSourceLineNumbers, attrib, 1, Int16.MaxValue); | ||
2917 | break; | ||
2918 | case "Suppress": | ||
2919 | suppress = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
2920 | break; | ||
2921 | default: | ||
2922 | this.Core.UnexpectedAttribute(node, attrib); | ||
2923 | break; | ||
2924 | } | ||
2925 | } | ||
2926 | else | ||
2927 | { | ||
2928 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2929 | } | ||
2930 | } | ||
2931 | |||
2932 | // Get the condition from the inner text of the element. | ||
2933 | condition = this.Core.GetConditionInnerText(child); | ||
2934 | |||
2935 | if (customAction && "Custom" == actionName) | ||
2936 | { | ||
2937 | this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action")); | ||
2938 | } | ||
2939 | else if (showDialog && "Show" == actionName) | ||
2940 | { | ||
2941 | this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Dialog")); | ||
2942 | } | ||
2943 | |||
2944 | if (CompilerConstants.IntegerNotSet != sequence) | ||
2945 | { | ||
2946 | if (CompilerConstants.IntegerNotSet != exitSequence) | ||
2947 | { | ||
2948 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "OnExit")); | ||
2949 | } | ||
2950 | else if (null != beforeAction || null != afterAction) | ||
2951 | { | ||
2952 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "Before", "After")); | ||
2953 | } | ||
2954 | } | ||
2955 | else // sequence not specified use OnExit (which may also be not set). | ||
2956 | { | ||
2957 | sequence = exitSequence; | ||
2958 | } | ||
2959 | |||
2960 | if (null != beforeAction && null != afterAction) | ||
2961 | { | ||
2962 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "After", "Before")); | ||
2963 | } | ||
2964 | else if ((customAction || showDialog || specialAction) && !suppress && CompilerConstants.IntegerNotSet == sequence && null == beforeAction && null == afterAction) | ||
2965 | { | ||
2966 | this.Core.Write(ErrorMessages.NeedSequenceBeforeOrAfter(childSourceLineNumbers, child.Name.LocalName)); | ||
2967 | } | ||
2968 | |||
2969 | // action that is scheduled to occur before/after itself | ||
2970 | if (beforeAction == actionName) | ||
2971 | { | ||
2972 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "Before", beforeAction)); | ||
2973 | } | ||
2974 | else if (afterAction == actionName) | ||
2975 | { | ||
2976 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "After", afterAction)); | ||
2977 | } | ||
2978 | |||
2979 | // normal standard actions cannot be set overridable by the user (since they are overridable by default) | ||
2980 | if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction) | ||
2981 | { | ||
2982 | this.Core.Write(ErrorMessages.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable")); | ||
2983 | } | ||
2984 | |||
2985 | // suppress cannot be specified at the same time as Before, After, or Sequence | ||
2986 | if (suppress && (null != afterAction || null != beforeAction || CompilerConstants.IntegerNotSet != sequence || overridable)) | ||
2987 | { | ||
2988 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(childSourceLineNumbers, child.Name.LocalName, "Suppress", "Before", "After", "Sequence", "Overridable")); | ||
2989 | } | ||
2990 | |||
2991 | this.Core.ParseForExtensionElements(child); | ||
2992 | |||
2993 | // add the row and any references needed | ||
2994 | if (!this.Core.EncounteredError) | ||
2995 | { | ||
2996 | if (suppress) | ||
2997 | { | ||
2998 | var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixSuppressAction, new Identifier(AccessModifier.Public, sequenceTable, actionName)); | ||
2999 | row.Set(0, sequenceTable); | ||
3000 | row.Set(1, actionName); | ||
3001 | } | ||
3002 | else | ||
3003 | { | ||
3004 | var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixAction, new Identifier(AccessModifier.Public, sequenceTable, actionName)); | ||
3005 | row.Set(0, sequenceTable); | ||
3006 | row.Set(1, actionName); | ||
3007 | row.Set(2, condition); | ||
3008 | if (CompilerConstants.IntegerNotSet != sequence) | ||
3009 | { | ||
3010 | row.Set(3, sequence); | ||
3011 | } | ||
3012 | row.Set(4, beforeAction); | ||
3013 | row.Set(5, afterAction); | ||
3014 | row.Set(6, overridable ? 1 : 0); | ||
3015 | } | ||
3016 | } | ||
3017 | } | ||
3018 | } | ||
3019 | |||
3020 | |||
3021 | /// <summary> | ||
3022 | /// Parses a service config element. | ||
3023 | /// </summary> | ||
3024 | /// <param name="node">Element to parse.</param> | ||
3025 | /// <param name="componentId">Identifier of parent component.</param> | ||
3026 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
3027 | private void ParseServiceConfigElement(XElement node, string componentId, string serviceName) | ||
3028 | { | ||
3029 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3030 | Identifier id = null; | ||
3031 | string delayedAutoStart = null; | ||
3032 | string failureActionsWhen = null; | ||
3033 | var name = serviceName; | ||
3034 | var install = false; | ||
3035 | var reinstall = false; | ||
3036 | var uninstall = false; | ||
3037 | string preShutdownDelay = null; | ||
3038 | string requiredPrivileges = null; | ||
3039 | string sid = null; | ||
3040 | |||
3041 | this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
3042 | |||
3043 | foreach (var attrib in node.Attributes()) | ||
3044 | { | ||
3045 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3046 | { | ||
3047 | switch (attrib.Name.LocalName) | ||
3048 | { | ||
3049 | case "Id": | ||
3050 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3051 | break; | ||
3052 | case "DelayedAutoStart": | ||
3053 | delayedAutoStart = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3054 | switch (delayedAutoStart) | ||
3055 | { | ||
3056 | case "no": | ||
3057 | delayedAutoStart = "0"; | ||
3058 | break; | ||
3059 | case "yes": | ||
3060 | delayedAutoStart = "1"; | ||
3061 | break; | ||
3062 | default: | ||
3063 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3064 | break; | ||
3065 | } | ||
3066 | break; | ||
3067 | case "FailureActionsWhen": | ||
3068 | failureActionsWhen = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3069 | switch (failureActionsWhen) | ||
3070 | { | ||
3071 | case "failedToStop": | ||
3072 | failureActionsWhen = "0"; | ||
3073 | break; | ||
3074 | case "failedToStopOrReturnedError": | ||
3075 | failureActionsWhen = "1"; | ||
3076 | break; | ||
3077 | default: | ||
3078 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3079 | break; | ||
3080 | } | ||
3081 | break; | ||
3082 | case "OnInstall": | ||
3083 | install = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3084 | //if (YesNoType.Yes == install) | ||
3085 | //{ | ||
3086 | // events |= MsiInterop.MsidbServiceConfigEventInstall; | ||
3087 | //} | ||
3088 | break; | ||
3089 | case "OnReinstall": | ||
3090 | reinstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3091 | //if (YesNoType.Yes == reinstall) | ||
3092 | //{ | ||
3093 | // events |= MsiInterop.MsidbServiceConfigEventReinstall; | ||
3094 | //} | ||
3095 | break; | ||
3096 | case "OnUninstall": | ||
3097 | uninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3098 | //if (YesNoType.Yes == uninstall) | ||
3099 | //{ | ||
3100 | // events |= MsiInterop.MsidbServiceConfigEventUninstall; | ||
3101 | //} | ||
3102 | break; | ||
3103 | default: | ||
3104 | this.Core.UnexpectedAttribute(node, attrib); | ||
3105 | break; | ||
3106 | case "PreShutdownDelay": | ||
3107 | preShutdownDelay = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
3108 | break; | ||
3109 | case "ServiceName": | ||
3110 | if (!String.IsNullOrEmpty(serviceName)) | ||
3111 | { | ||
3112 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
3113 | } | ||
3114 | |||
3115 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3116 | break; | ||
3117 | case "ServiceSid": | ||
3118 | sid = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3119 | switch (sid) | ||
3120 | { | ||
3121 | case "none": | ||
3122 | sid = "0"; | ||
3123 | break; | ||
3124 | case "restricted": | ||
3125 | sid = "3"; | ||
3126 | break; | ||
3127 | case "unrestricted": | ||
3128 | sid = "1"; | ||
3129 | break; | ||
3130 | default: | ||
3131 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3132 | break; | ||
3133 | } | ||
3134 | break; | ||
3135 | } | ||
3136 | } | ||
3137 | else | ||
3138 | { | ||
3139 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3140 | } | ||
3141 | } | ||
3142 | |||
3143 | // Get the ServiceConfig required privilegs. | ||
3144 | foreach (var child in node.Elements()) | ||
3145 | { | ||
3146 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3147 | { | ||
3148 | switch (child.Name.LocalName) | ||
3149 | { | ||
3150 | case "RequiredPrivilege": | ||
3151 | var privilege = this.Core.GetTrimmedInnerText(child); | ||
3152 | switch (privilege) | ||
3153 | { | ||
3154 | case "assignPrimaryToken": | ||
3155 | privilege = "SeAssignPrimaryTokenPrivilege"; | ||
3156 | break; | ||
3157 | case "audit": | ||
3158 | privilege = "SeAuditPrivilege"; | ||
3159 | break; | ||
3160 | case "backup": | ||
3161 | privilege = "SeBackupPrivilege"; | ||
3162 | break; | ||
3163 | case "changeNotify": | ||
3164 | privilege = "SeChangeNotifyPrivilege"; | ||
3165 | break; | ||
3166 | case "createGlobal": | ||
3167 | privilege = "SeCreateGlobalPrivilege"; | ||
3168 | break; | ||
3169 | case "createPagefile": | ||
3170 | privilege = "SeCreatePagefilePrivilege"; | ||
3171 | break; | ||
3172 | case "createPermanent": | ||
3173 | privilege = "SeCreatePermanentPrivilege"; | ||
3174 | break; | ||
3175 | case "createSymbolicLink": | ||
3176 | privilege = "SeCreateSymbolicLinkPrivilege"; | ||
3177 | break; | ||
3178 | case "createToken": | ||
3179 | privilege = "SeCreateTokenPrivilege"; | ||
3180 | break; | ||
3181 | case "debug": | ||
3182 | privilege = "SeDebugPrivilege"; | ||
3183 | break; | ||
3184 | case "enableDelegation": | ||
3185 | privilege = "SeEnableDelegationPrivilege"; | ||
3186 | break; | ||
3187 | case "impersonate": | ||
3188 | privilege = "SeImpersonatePrivilege"; | ||
3189 | break; | ||
3190 | case "increaseBasePriority": | ||
3191 | privilege = "SeIncreaseBasePriorityPrivilege"; | ||
3192 | break; | ||
3193 | case "increaseQuota": | ||
3194 | privilege = "SeIncreaseQuotaPrivilege"; | ||
3195 | break; | ||
3196 | case "increaseWorkingSet": | ||
3197 | privilege = "SeIncreaseWorkingSetPrivilege"; | ||
3198 | break; | ||
3199 | case "loadDriver": | ||
3200 | privilege = "SeLoadDriverPrivilege"; | ||
3201 | break; | ||
3202 | case "lockMemory": | ||
3203 | privilege = "SeLockMemoryPrivilege"; | ||
3204 | break; | ||
3205 | case "machineAccount": | ||
3206 | privilege = "SeMachineAccountPrivilege"; | ||
3207 | break; | ||
3208 | case "manageVolume": | ||
3209 | privilege = "SeManageVolumePrivilege"; | ||
3210 | break; | ||
3211 | case "profileSingleProcess": | ||
3212 | privilege = "SeProfileSingleProcessPrivilege"; | ||
3213 | break; | ||
3214 | case "relabel": | ||
3215 | privilege = "SeRelabelPrivilege"; | ||
3216 | break; | ||
3217 | case "remoteShutdown": | ||
3218 | privilege = "SeRemoteShutdownPrivilege"; | ||
3219 | break; | ||
3220 | case "restore": | ||
3221 | privilege = "SeRestorePrivilege"; | ||
3222 | break; | ||
3223 | case "security": | ||
3224 | privilege = "SeSecurityPrivilege"; | ||
3225 | break; | ||
3226 | case "shutdown": | ||
3227 | privilege = "SeShutdownPrivilege"; | ||
3228 | break; | ||
3229 | case "syncAgent": | ||
3230 | privilege = "SeSyncAgentPrivilege"; | ||
3231 | break; | ||
3232 | case "systemEnvironment": | ||
3233 | privilege = "SeSystemEnvironmentPrivilege"; | ||
3234 | break; | ||
3235 | case "systemProfile": | ||
3236 | privilege = "SeSystemProfilePrivilege"; | ||
3237 | break; | ||
3238 | case "systemTime": | ||
3239 | case "modifySystemTime": | ||
3240 | privilege = "SeSystemtimePrivilege"; | ||
3241 | break; | ||
3242 | case "takeOwnership": | ||
3243 | privilege = "SeTakeOwnershipPrivilege"; | ||
3244 | break; | ||
3245 | case "tcb": | ||
3246 | case "trustedComputerBase": | ||
3247 | privilege = "SeTcbPrivilege"; | ||
3248 | break; | ||
3249 | case "timeZone": | ||
3250 | case "modifyTimeZone": | ||
3251 | privilege = "SeTimeZonePrivilege"; | ||
3252 | break; | ||
3253 | case "trustedCredManAccess": | ||
3254 | case "trustedCredentialManagerAccess": | ||
3255 | privilege = "SeTrustedCredManAccessPrivilege"; | ||
3256 | break; | ||
3257 | case "undock": | ||
3258 | privilege = "SeUndockPrivilege"; | ||
3259 | break; | ||
3260 | case "unsolicitedInput": | ||
3261 | privilege = "SeUnsolicitedInputPrivilege"; | ||
3262 | break; | ||
3263 | default: | ||
3264 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3265 | break; | ||
3266 | } | ||
3267 | |||
3268 | if (null != requiredPrivileges) | ||
3269 | { | ||
3270 | requiredPrivileges = String.Concat(requiredPrivileges, "[~]"); | ||
3271 | } | ||
3272 | requiredPrivileges = String.Concat(requiredPrivileges, privilege); | ||
3273 | break; | ||
3274 | default: | ||
3275 | this.Core.UnexpectedElement(node, child); | ||
3276 | break; | ||
3277 | } | ||
3278 | } | ||
3279 | else | ||
3280 | { | ||
3281 | this.Core.ParseExtensionElement(node, child); | ||
3282 | } | ||
3283 | } | ||
3284 | |||
3285 | if (String.IsNullOrEmpty(name)) | ||
3286 | { | ||
3287 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
3288 | } | ||
3289 | else if (null == id) | ||
3290 | { | ||
3291 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3292 | } | ||
3293 | |||
3294 | if (!install && !reinstall && !uninstall) | ||
3295 | { | ||
3296 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
3297 | } | ||
3298 | |||
3299 | if (String.IsNullOrEmpty(delayedAutoStart) && String.IsNullOrEmpty(failureActionsWhen) && String.IsNullOrEmpty(preShutdownDelay) && String.IsNullOrEmpty(requiredPrivileges) && String.IsNullOrEmpty(sid)) | ||
3300 | { | ||
3301 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DelayedAutoStart", "FailureActionsWhen", "PreShutdownDelay", "ServiceSid", "RequiredPrivilege")); | ||
3302 | } | ||
3303 | |||
3304 | if (!this.Core.EncounteredError) | ||
3305 | { | ||
3306 | if (!String.IsNullOrEmpty(delayedAutoStart)) | ||
3307 | { | ||
3308 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".DS"), id.Access)) | ||
3309 | { | ||
3310 | Name = name, | ||
3311 | OnInstall = install, | ||
3312 | OnReinstall = reinstall, | ||
3313 | OnUninstall = uninstall, | ||
3314 | ConfigType = MsiServiceConfigType.DelayedAutoStart, | ||
3315 | Argument = delayedAutoStart, | ||
3316 | Component_ = componentId, | ||
3317 | }; | ||
3318 | |||
3319 | this.Core.AddTuple(tuple); | ||
3320 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".DS"), id.Access)); | ||
3321 | //row.Set(1, name); | ||
3322 | //row.Set(2, events); | ||
3323 | //row.Set(3, 3); | ||
3324 | //row.Set(4, delayedAutoStart); | ||
3325 | //row.Set(5, componentId); | ||
3326 | } | ||
3327 | |||
3328 | if (!String.IsNullOrEmpty(failureActionsWhen)) | ||
3329 | { | ||
3330 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".FA"), id.Access)) | ||
3331 | { | ||
3332 | Name = name, | ||
3333 | OnInstall = install, | ||
3334 | OnReinstall = reinstall, | ||
3335 | OnUninstall = uninstall, | ||
3336 | ConfigType = MsiServiceConfigType.FailureActionsFlag, | ||
3337 | Argument = failureActionsWhen, | ||
3338 | Component_ = componentId, | ||
3339 | }; | ||
3340 | |||
3341 | this.Core.AddTuple(tuple); | ||
3342 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".FA"), id.Access)); | ||
3343 | //row.Set(1, name); | ||
3344 | //row.Set(2, events); | ||
3345 | //row.Set(3, 4); | ||
3346 | //row.Set(4, failureActionsWhen); | ||
3347 | //row.Set(5, componentId); | ||
3348 | } | ||
3349 | |||
3350 | if (!String.IsNullOrEmpty(sid)) | ||
3351 | { | ||
3352 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".SS"), id.Access)) | ||
3353 | { | ||
3354 | Name = name, | ||
3355 | OnInstall = install, | ||
3356 | OnReinstall = reinstall, | ||
3357 | OnUninstall = uninstall, | ||
3358 | ConfigType = MsiServiceConfigType.ServiceSidInfo, | ||
3359 | Argument = sid, | ||
3360 | Component_ = componentId, | ||
3361 | }; | ||
3362 | |||
3363 | this.Core.AddTuple(tuple); | ||
3364 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".SS"), id.Access)); | ||
3365 | //row.Set(1, name); | ||
3366 | //row.Set(2, events); | ||
3367 | //row.Set(3, 5); | ||
3368 | //row.Set(4, sid); | ||
3369 | //row.Set(5, componentId); | ||
3370 | } | ||
3371 | |||
3372 | if (!String.IsNullOrEmpty(requiredPrivileges)) | ||
3373 | { | ||
3374 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".RP"), id.Access)) | ||
3375 | { | ||
3376 | Name = name, | ||
3377 | OnInstall = install, | ||
3378 | OnReinstall = reinstall, | ||
3379 | OnUninstall = uninstall, | ||
3380 | ConfigType = MsiServiceConfigType.RequiredPrivilegesInfo, | ||
3381 | Argument = requiredPrivileges, | ||
3382 | Component_ = componentId, | ||
3383 | }; | ||
3384 | |||
3385 | this.Core.AddTuple(tuple); | ||
3386 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".RP"), id.Access)); | ||
3387 | //row.Set(1, name); | ||
3388 | //row.Set(2, events); | ||
3389 | //row.Set(3, 6); | ||
3390 | //row.Set(4, requiredPrivileges); | ||
3391 | //row.Set(5, componentId); | ||
3392 | } | ||
3393 | |||
3394 | if (!String.IsNullOrEmpty(preShutdownDelay)) | ||
3395 | { | ||
3396 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".PD"), id.Access)) | ||
3397 | { | ||
3398 | Name = name, | ||
3399 | OnInstall = install, | ||
3400 | OnReinstall = reinstall, | ||
3401 | OnUninstall = uninstall, | ||
3402 | ConfigType = MsiServiceConfigType.PreshutdownInfo, | ||
3403 | Argument = preShutdownDelay, | ||
3404 | Component_ = componentId, | ||
3405 | }; | ||
3406 | |||
3407 | this.Core.AddTuple(tuple); | ||
3408 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".PD"), id.Access)); | ||
3409 | //row.Set(1, name); | ||
3410 | //row.Set(2, events); | ||
3411 | //row.Set(3, 7); | ||
3412 | //row.Set(4, preShutdownDelay); | ||
3413 | //row.Set(5, componentId); | ||
3414 | } | ||
3415 | } | ||
3416 | } | ||
3417 | |||
3418 | /// <summary> | ||
3419 | /// Parses a service config failure actions element. | ||
3420 | /// </summary> | ||
3421 | /// <param name="node">Element to parse.</param> | ||
3422 | /// <param name="componentId">Identifier of parent component.</param> | ||
3423 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
3424 | private void ParseServiceConfigFailureActionsElement(XElement node, string componentId, string serviceName) | ||
3425 | { | ||
3426 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3427 | Identifier id = null; | ||
3428 | var name = serviceName; | ||
3429 | var install = false; | ||
3430 | var reinstall = false; | ||
3431 | var uninstall = false; | ||
3432 | int? resetPeriod = null; | ||
3433 | string rebootMessage = null; | ||
3434 | string command = null; | ||
3435 | string actions = null; | ||
3436 | string actionsDelays = null; | ||
3437 | |||
3438 | this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
3439 | |||
3440 | foreach (var attrib in node.Attributes()) | ||
3441 | { | ||
3442 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3443 | { | ||
3444 | switch (attrib.Name.LocalName) | ||
3445 | { | ||
3446 | case "Id": | ||
3447 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3448 | break; | ||
3449 | case "Command": | ||
3450 | command = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
3451 | break; | ||
3452 | case "OnInstall": | ||
3453 | install = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3454 | break; | ||
3455 | case "OnReinstall": | ||
3456 | reinstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3457 | break; | ||
3458 | case "OnUninstall": | ||
3459 | uninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3460 | break; | ||
3461 | case "RebootMessage": | ||
3462 | rebootMessage = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
3463 | break; | ||
3464 | case "ResetPeriod": | ||
3465 | resetPeriod = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
3466 | break; | ||
3467 | case "ServiceName": | ||
3468 | if (!String.IsNullOrEmpty(serviceName)) | ||
3469 | { | ||
3470 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
3471 | } | ||
3472 | |||
3473 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3474 | break; | ||
3475 | default: | ||
3476 | this.Core.UnexpectedAttribute(node, attrib); | ||
3477 | break; | ||
3478 | } | ||
3479 | } | ||
3480 | else | ||
3481 | { | ||
3482 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3483 | } | ||
3484 | } | ||
3485 | |||
3486 | // Get the ServiceConfigFailureActions actions. | ||
3487 | foreach (var child in node.Elements()) | ||
3488 | { | ||
3489 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3490 | { | ||
3491 | switch (child.Name.LocalName) | ||
3492 | { | ||
3493 | case "Failure": | ||
3494 | string action = null; | ||
3495 | string delay = null; | ||
3496 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
3497 | |||
3498 | foreach (var childAttrib in child.Attributes()) | ||
3499 | { | ||
3500 | if (String.IsNullOrEmpty(childAttrib.Name.NamespaceName) || CompilerCore.WixNamespace == childAttrib.Name.Namespace) | ||
3501 | { | ||
3502 | switch (childAttrib.Name.LocalName) | ||
3503 | { | ||
3504 | case "Action": | ||
3505 | action = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3506 | switch (action) | ||
3507 | { | ||
3508 | case "none": | ||
3509 | action = "0"; | ||
3510 | break; | ||
3511 | case "restartComputer": | ||
3512 | action = "2"; | ||
3513 | break; | ||
3514 | case "restartService": | ||
3515 | action = "1"; | ||
3516 | break; | ||
3517 | case "runCommand": | ||
3518 | action = "3"; | ||
3519 | break; | ||
3520 | default: | ||
3521 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3522 | break; | ||
3523 | } | ||
3524 | break; | ||
3525 | case "Delay": | ||
3526 | delay = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3527 | break; | ||
3528 | default: | ||
3529 | this.Core.UnexpectedAttribute(child, childAttrib); | ||
3530 | break; | ||
3531 | } | ||
3532 | } | ||
3533 | } | ||
3534 | |||
3535 | if (String.IsNullOrEmpty(action)) | ||
3536 | { | ||
3537 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Action")); | ||
3538 | } | ||
3539 | |||
3540 | if (String.IsNullOrEmpty(delay)) | ||
3541 | { | ||
3542 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Delay")); | ||
3543 | } | ||
3544 | |||
3545 | if (!String.IsNullOrEmpty(actions)) | ||
3546 | { | ||
3547 | actions = String.Concat(actions, "[~]"); | ||
3548 | } | ||
3549 | actions = String.Concat(actions, action); | ||
3550 | |||
3551 | if (!String.IsNullOrEmpty(actionsDelays)) | ||
3552 | { | ||
3553 | actionsDelays = String.Concat(actionsDelays, "[~]"); | ||
3554 | } | ||
3555 | actionsDelays = String.Concat(actionsDelays, delay); | ||
3556 | break; | ||
3557 | default: | ||
3558 | this.Core.UnexpectedElement(node, child); | ||
3559 | break; | ||
3560 | } | ||
3561 | } | ||
3562 | else | ||
3563 | { | ||
3564 | this.Core.ParseExtensionElement(node, child); | ||
3565 | } | ||
3566 | } | ||
3567 | |||
3568 | if (String.IsNullOrEmpty(name)) | ||
3569 | { | ||
3570 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
3571 | } | ||
3572 | else if (null == id) | ||
3573 | { | ||
3574 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3575 | } | ||
3576 | |||
3577 | if (!install && !reinstall && !uninstall) | ||
3578 | { | ||
3579 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
3580 | } | ||
3581 | |||
3582 | if (!this.Core.EncounteredError) | ||
3583 | { | ||
3584 | var tuple = new MsiServiceConfigFailureActionsTuple(sourceLineNumbers, id) | ||
3585 | { | ||
3586 | Name = name, | ||
3587 | OnInstall = install, | ||
3588 | OnReinstall = reinstall, | ||
3589 | OnUninstall = uninstall, | ||
3590 | ResetPeriod = resetPeriod, | ||
3591 | RebootMessage = rebootMessage, | ||
3592 | Command = command, | ||
3593 | Actions = actions, | ||
3594 | DelayActions = actionsDelays, | ||
3595 | Component_ = componentId, | ||
3596 | }; | ||
3597 | |||
3598 | this.Core.AddTuple(tuple); | ||
3599 | } | ||
3600 | } | ||
3601 | |||
3602 | /// <summary> | ||
3603 | /// Parses a service control element. | ||
3604 | /// </summary> | ||
3605 | /// <param name="node">Element to parse.</param> | ||
3606 | /// <param name="componentId">Identifier of parent component.</param> | ||
3607 | private void ParseServiceControlElement(XElement node, string componentId) | ||
3608 | { | ||
3609 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3610 | string arguments = null; | ||
3611 | Identifier id = null; | ||
3612 | string name = null; | ||
3613 | var installRemove = false; | ||
3614 | var uninstallRemove = false; | ||
3615 | var installStart = false; | ||
3616 | var uninstallStart = false; | ||
3617 | var installStop = false; | ||
3618 | var uninstallStop = false; | ||
3619 | bool? wait = null; | ||
3620 | |||
3621 | foreach (var attrib in node.Attributes()) | ||
3622 | { | ||
3623 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3624 | { | ||
3625 | switch (attrib.Name.LocalName) | ||
3626 | { | ||
3627 | case "Id": | ||
3628 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3629 | break; | ||
3630 | case "Name": | ||
3631 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3632 | break; | ||
3633 | case "Remove": | ||
3634 | var removeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3635 | switch (removeValue) | ||
3636 | { | ||
3637 | case "install": | ||
3638 | installRemove = true; | ||
3639 | break; | ||
3640 | case "uninstall": | ||
3641 | uninstallRemove = true; | ||
3642 | break; | ||
3643 | case "both": | ||
3644 | installRemove = true; | ||
3645 | uninstallRemove = true; | ||
3646 | break; | ||
3647 | case "": | ||
3648 | break; | ||
3649 | } | ||
3650 | break; | ||
3651 | case "Start": | ||
3652 | var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3653 | switch (startValue) | ||
3654 | { | ||
3655 | case "install": | ||
3656 | installStart = true; | ||
3657 | break; | ||
3658 | case "uninstall": | ||
3659 | uninstallStart = true; | ||
3660 | break; | ||
3661 | case "both": | ||
3662 | installStart = true; | ||
3663 | uninstallStart = true; | ||
3664 | break; | ||
3665 | case "": | ||
3666 | break; | ||
3667 | } | ||
3668 | break; | ||
3669 | case "Stop": | ||
3670 | var stopValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3671 | switch (stopValue) | ||
3672 | { | ||
3673 | case "install": | ||
3674 | installStop = true; | ||
3675 | break; | ||
3676 | case "uninstall": | ||
3677 | uninstallStop = true; | ||
3678 | break; | ||
3679 | case "both": | ||
3680 | installStop = true; | ||
3681 | uninstallStop = true; | ||
3682 | break; | ||
3683 | case "": | ||
3684 | break; | ||
3685 | } | ||
3686 | break; | ||
3687 | case "Wait": | ||
3688 | wait = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3689 | break; | ||
3690 | default: | ||
3691 | this.Core.UnexpectedAttribute(node, attrib); | ||
3692 | break; | ||
3693 | } | ||
3694 | } | ||
3695 | else | ||
3696 | { | ||
3697 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3698 | } | ||
3699 | } | ||
3700 | |||
3701 | if (null == id) | ||
3702 | { | ||
3703 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3704 | } | ||
3705 | |||
3706 | if (null == name) | ||
3707 | { | ||
3708 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
3709 | } | ||
3710 | |||
3711 | // get the ServiceControl arguments | ||
3712 | foreach (var child in node.Elements()) | ||
3713 | { | ||
3714 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3715 | { | ||
3716 | switch (child.Name.LocalName) | ||
3717 | { | ||
3718 | case "ServiceArgument": | ||
3719 | if (null != arguments) | ||
3720 | { | ||
3721 | arguments = String.Concat(arguments, "[~]"); | ||
3722 | } | ||
3723 | arguments = String.Concat(arguments, this.Core.GetTrimmedInnerText(child)); | ||
3724 | break; | ||
3725 | default: | ||
3726 | this.Core.UnexpectedElement(node, child); | ||
3727 | break; | ||
3728 | } | ||
3729 | } | ||
3730 | else | ||
3731 | { | ||
3732 | this.Core.ParseExtensionElement(node, child); | ||
3733 | } | ||
3734 | } | ||
3735 | |||
3736 | if (!this.Core.EncounteredError) | ||
3737 | { | ||
3738 | var tuple = new ServiceControlTuple(sourceLineNumbers, id) | ||
3739 | { | ||
3740 | Name = name, | ||
3741 | InstallRemove = installRemove, | ||
3742 | UninstallRemove = uninstallRemove, | ||
3743 | InstallStart = installStart, | ||
3744 | UninstallStart = uninstallStart, | ||
3745 | InstallStop = installStop, | ||
3746 | UninstallStop = uninstallStop, | ||
3747 | Arguments = arguments, | ||
3748 | Wait = wait, | ||
3749 | Component_ = componentId | ||
3750 | }; | ||
3751 | |||
3752 | this.Core.AddTuple(tuple); | ||
3753 | } | ||
3754 | } | ||
3755 | |||
3756 | /// <summary> | ||
3757 | /// Parses a service dependency element. | ||
3758 | /// </summary> | ||
3759 | /// <param name="node">Element to parse.</param> | ||
3760 | /// <returns>Parsed sevice dependency name.</returns> | ||
3761 | private string ParseServiceDependencyElement(XElement node) | ||
3762 | { | ||
3763 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3764 | string dependency = null; | ||
3765 | var group = false; | ||
3766 | |||
3767 | foreach (var attrib in node.Attributes()) | ||
3768 | { | ||
3769 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3770 | { | ||
3771 | switch (attrib.Name.LocalName) | ||
3772 | { | ||
3773 | case "Id": | ||
3774 | dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3775 | break; | ||
3776 | case "Group": | ||
3777 | group = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3778 | break; | ||
3779 | default: | ||
3780 | this.Core.UnexpectedAttribute(node, attrib); | ||
3781 | break; | ||
3782 | } | ||
3783 | } | ||
3784 | else | ||
3785 | { | ||
3786 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3787 | } | ||
3788 | } | ||
3789 | |||
3790 | if (null == dependency) | ||
3791 | { | ||
3792 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3793 | } | ||
3794 | |||
3795 | this.Core.ParseForExtensionElements(node); | ||
3796 | |||
3797 | return group ? String.Concat("+", dependency) : dependency; | ||
3798 | } | ||
3799 | |||
3800 | /// <summary> | ||
3801 | /// Parses a service install element. | ||
3802 | /// </summary> | ||
3803 | /// <param name="node">Element to parse.</param> | ||
3804 | /// <param name="componentId">Identifier of parent component.</param> | ||
3805 | private void ParseServiceInstallElement(XElement node, string componentId, bool win64Component) | ||
3806 | { | ||
3807 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3808 | Identifier id = null; | ||
3809 | string account = null; | ||
3810 | string arguments = null; | ||
3811 | string dependencies = null; | ||
3812 | string description = null; | ||
3813 | string displayName = null; | ||
3814 | var eraseDescription = false; | ||
3815 | string loadOrderGroup = null; | ||
3816 | string name = null; | ||
3817 | string password = null; | ||
3818 | |||
3819 | var serviceType = ServiceType.OwnProcess; | ||
3820 | var startType = ServiceStartType.Demand; | ||
3821 | var errorControl = ServiceErrorControl.Normal; | ||
3822 | var interactive = false; | ||
3823 | var vital = false; | ||
3824 | |||
3825 | foreach (var attrib in node.Attributes()) | ||
3826 | { | ||
3827 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3828 | { | ||
3829 | switch (attrib.Name.LocalName) | ||
3830 | { | ||
3831 | case "Id": | ||
3832 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3833 | break; | ||
3834 | case "Account": | ||
3835 | account = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3836 | break; | ||
3837 | case "Arguments": | ||
3838 | arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3839 | break; | ||
3840 | case "Description": | ||
3841 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3842 | break; | ||
3843 | case "DisplayName": | ||
3844 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3845 | break; | ||
3846 | case "EraseDescription": | ||
3847 | eraseDescription = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3848 | break; | ||
3849 | case "ErrorControl": | ||
3850 | var errorControlValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3851 | switch (errorControlValue) | ||
3852 | { | ||
3853 | case "ignore": | ||
3854 | errorControl = ServiceErrorControl.Ignore; | ||
3855 | break; | ||
3856 | case "normal": | ||
3857 | errorControl = ServiceErrorControl.Normal; | ||
3858 | break; | ||
3859 | case "critical": | ||
3860 | errorControl = ServiceErrorControl.Critical; | ||
3861 | break; | ||
3862 | case "": // error case handled by GetAttributeValue() | ||
3863 | break; | ||
3864 | default: | ||
3865 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, errorControlValue, "ignore", "normal", "critical")); | ||
3866 | break; | ||
3867 | } | ||
3868 | break; | ||
3869 | case "Interactive": | ||
3870 | interactive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3871 | break; | ||
3872 | case "LoadOrderGroup": | ||
3873 | loadOrderGroup = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3874 | break; | ||
3875 | case "Name": | ||
3876 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3877 | break; | ||
3878 | case "Password": | ||
3879 | password = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3880 | break; | ||
3881 | case "Start": | ||
3882 | var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3883 | switch (startValue) | ||
3884 | { | ||
3885 | case "auto": | ||
3886 | startType = ServiceStartType.Auto; | ||
3887 | break; | ||
3888 | case "demand": | ||
3889 | startType = ServiceStartType.Demand; | ||
3890 | break; | ||
3891 | case "disabled": | ||
3892 | startType = ServiceStartType.Disabled; | ||
3893 | break; | ||
3894 | case "boot": | ||
3895 | case "system": | ||
3896 | this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue)); | ||
3897 | break; | ||
3898 | case "": | ||
3899 | break; | ||
3900 | default: | ||
3901 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue, "auto", "demand", "disabled")); | ||
3902 | break; | ||
3903 | } | ||
3904 | break; | ||
3905 | case "Type": | ||
3906 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3907 | switch (typeValue) | ||
3908 | { | ||
3909 | case "ownProcess": | ||
3910 | serviceType = ServiceType.OwnProcess; | ||
3911 | break; | ||
3912 | case "shareProcess": | ||
3913 | serviceType = ServiceType.ShareProcess; | ||
3914 | break; | ||
3915 | case "kernelDriver": | ||
3916 | case "systemDriver": | ||
3917 | this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue)); | ||
3918 | break; | ||
3919 | case "": | ||
3920 | break; | ||
3921 | default: | ||
3922 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, node.Name.LocalName, typeValue, "ownProcess", "shareProcess")); | ||
3923 | break; | ||
3924 | } | ||
3925 | break; | ||
3926 | case "Vital": | ||
3927 | vital = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3928 | break; | ||
3929 | default: | ||
3930 | this.Core.UnexpectedAttribute(node, attrib); | ||
3931 | break; | ||
3932 | } | ||
3933 | } | ||
3934 | else | ||
3935 | { | ||
3936 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3937 | } | ||
3938 | } | ||
3939 | |||
3940 | if (String.IsNullOrEmpty(name)) | ||
3941 | { | ||
3942 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
3943 | } | ||
3944 | else if (null == id) | ||
3945 | { | ||
3946 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3947 | } | ||
3948 | |||
3949 | if (0 == startType) | ||
3950 | { | ||
3951 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Start")); | ||
3952 | } | ||
3953 | |||
3954 | if (eraseDescription) | ||
3955 | { | ||
3956 | description = "[~]"; | ||
3957 | } | ||
3958 | |||
3959 | // get the ServiceInstall dependencies and config | ||
3960 | foreach (var child in node.Elements()) | ||
3961 | { | ||
3962 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3963 | { | ||
3964 | switch (child.Name.LocalName) | ||
3965 | { | ||
3966 | case "PermissionEx": | ||
3967 | this.ParsePermissionExElement(child, id.Id, "ServiceInstall"); | ||
3968 | break; | ||
3969 | case "ServiceConfig": | ||
3970 | this.ParseServiceConfigElement(child, componentId, name); | ||
3971 | break; | ||
3972 | case "ServiceConfigFailureActions": | ||
3973 | this.ParseServiceConfigFailureActionsElement(child, componentId, name); | ||
3974 | break; | ||
3975 | case "ServiceDependency": | ||
3976 | dependencies = String.Concat(dependencies, this.ParseServiceDependencyElement(child), "[~]"); | ||
3977 | break; | ||
3978 | default: | ||
3979 | this.Core.UnexpectedElement(node, child); | ||
3980 | break; | ||
3981 | } | ||
3982 | } | ||
3983 | else | ||
3984 | { | ||
3985 | var context = new Dictionary<string, string>() { { "ServiceInstallId", id.Id }, { "ServiceInstallName", name }, { "ServiceInstallComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
3986 | this.Core.ParseExtensionElement(node, child, context); | ||
3987 | } | ||
3988 | } | ||
3989 | |||
3990 | if (null != dependencies) | ||
3991 | { | ||
3992 | dependencies = String.Concat(dependencies, "[~]"); | ||
3993 | } | ||
3994 | |||
3995 | if (!this.Core.EncounteredError) | ||
3996 | { | ||
3997 | var tuple = new ServiceInstallTuple(sourceLineNumbers, id) | ||
3998 | { | ||
3999 | Name = name, | ||
4000 | DisplayName = displayName, | ||
4001 | ServiceType = serviceType, | ||
4002 | StartType = startType, | ||
4003 | ErrorControl = errorControl, | ||
4004 | LoadOrderGroup = loadOrderGroup, | ||
4005 | Dependencies = dependencies, | ||
4006 | StartName = account, | ||
4007 | Password = password, | ||
4008 | Arguments = arguments, | ||
4009 | Component_ = componentId, | ||
4010 | Description = description, | ||
4011 | Interactive = interactive, | ||
4012 | Vital = vital | ||
4013 | }; | ||
4014 | |||
4015 | this.Core.AddTuple(tuple); | ||
4016 | |||
4017 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ServiceInstall, id); | ||
4018 | //row.Set(1, name); | ||
4019 | //row.Set(2, displayName); | ||
4020 | //row.Set(3, typebits); | ||
4021 | //row.Set(4, startType); | ||
4022 | //row.Set(5, errorbits); | ||
4023 | //row.Set(6, loadOrderGroup); | ||
4024 | //row.Set(7, dependencies); | ||
4025 | //row.Set(8, account); | ||
4026 | //row.Set(9, password); | ||
4027 | //row.Set(10, arguments); | ||
4028 | //row.Set(11, componentId); | ||
4029 | //row.Set(12, description); | ||
4030 | } | ||
4031 | } | ||
4032 | |||
4033 | /// <summary> | ||
4034 | /// Parses a SetDirectory element. | ||
4035 | /// </summary> | ||
4036 | /// <param name="node">Element to parse.</param> | ||
4037 | private void ParseSetDirectoryElement(XElement node) | ||
4038 | { | ||
4039 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4040 | string actionName = null; | ||
4041 | string id = null; | ||
4042 | string condition = null; | ||
4043 | var executionType = CustomActionExecutionType.Immediate; | ||
4044 | var sequences = new[] { SequenceTable.InstallUISequence, SequenceTable.InstallExecuteSequence }; // default to "both" | ||
4045 | string value = null; | ||
4046 | |||
4047 | foreach (var attrib in node.Attributes()) | ||
4048 | { | ||
4049 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4050 | { | ||
4051 | switch (attrib.Name.LocalName) | ||
4052 | { | ||
4053 | case "Action": | ||
4054 | actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4055 | break; | ||
4056 | case "Id": | ||
4057 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4058 | this.Core.CreateSimpleReference(sourceLineNumbers, "Directory", id); | ||
4059 | break; | ||
4060 | case "Sequence": | ||
4061 | var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4062 | switch (sequenceValue) | ||
4063 | { | ||
4064 | case "execute": | ||
4065 | sequences = new[] { SequenceTable.InstallExecuteSequence }; | ||
4066 | break; | ||
4067 | case "first": | ||
4068 | executionType = CustomActionExecutionType.FirstSequence; | ||
4069 | break; | ||
4070 | case "ui": | ||
4071 | sequences = new[] { SequenceTable.InstallUISequence }; | ||
4072 | break; | ||
4073 | case "both": | ||
4074 | break; | ||
4075 | case "": | ||
4076 | break; | ||
4077 | default: | ||
4078 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
4079 | break; | ||
4080 | } | ||
4081 | break; | ||
4082 | case "Value": | ||
4083 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4084 | break; | ||
4085 | default: | ||
4086 | this.Core.UnexpectedAttribute(node, attrib); | ||
4087 | break; | ||
4088 | } | ||
4089 | } | ||
4090 | else | ||
4091 | { | ||
4092 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4093 | } | ||
4094 | } | ||
4095 | |||
4096 | condition = this.Core.GetConditionInnerText(node); | ||
4097 | |||
4098 | if (null == id) | ||
4099 | { | ||
4100 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4101 | } | ||
4102 | else if (String.IsNullOrEmpty(actionName)) | ||
4103 | { | ||
4104 | actionName = String.Concat("Set", id); | ||
4105 | } | ||
4106 | |||
4107 | if (null == value) | ||
4108 | { | ||
4109 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4110 | } | ||
4111 | |||
4112 | this.Core.ParseForExtensionElements(node); | ||
4113 | |||
4114 | if (!this.Core.EncounteredError) | ||
4115 | { | ||
4116 | var tuple = new CustomActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, actionName)) | ||
4117 | { | ||
4118 | ExecutionType = executionType, | ||
4119 | SourceType = CustomActionSourceType.Directory, | ||
4120 | TargetType = CustomActionTargetType.TextData, | ||
4121 | Source = id, | ||
4122 | Target = value | ||
4123 | }; | ||
4124 | |||
4125 | this.Core.AddTuple(tuple); | ||
4126 | |||
4127 | foreach (var sequence in sequences) | ||
4128 | { | ||
4129 | var sequenceId = new Identifier(AccessModifier.Public, sequence.ToString(), actionName); | ||
4130 | |||
4131 | var sequenceTuple = new WixActionTuple(sourceLineNumbers, sequenceId) | ||
4132 | { | ||
4133 | SequenceTable = sequence, | ||
4134 | Action = actionName, | ||
4135 | Condition = condition, | ||
4136 | After = "CostInialize", | ||
4137 | Overridable = false | ||
4138 | }; | ||
4139 | |||
4140 | this.Core.AddTuple(tuple); | ||
4141 | } | ||
4142 | } | ||
4143 | } | ||
4144 | |||
4145 | /// <summary> | ||
4146 | /// Parses a SetProperty element. | ||
4147 | /// </summary> | ||
4148 | /// <param name="node">Element to parse.</param> | ||
4149 | private void ParseSetPropertyElement(XElement node) | ||
4150 | { | ||
4151 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4152 | string actionName = null; | ||
4153 | string id = null; | ||
4154 | string afterAction = null; | ||
4155 | string beforeAction = null; | ||
4156 | var executionType = CustomActionExecutionType.Immediate; | ||
4157 | var sequences = new[] { SequenceTable.InstallUISequence, SequenceTable.InstallExecuteSequence }; // default to "both" | ||
4158 | string value = null; | ||
4159 | |||
4160 | foreach (var attrib in node.Attributes()) | ||
4161 | { | ||
4162 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4163 | { | ||
4164 | switch (attrib.Name.LocalName) | ||
4165 | { | ||
4166 | case "Action": | ||
4167 | actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4168 | break; | ||
4169 | case "Id": | ||
4170 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4171 | break; | ||
4172 | case "After": | ||
4173 | afterAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4174 | break; | ||
4175 | case "Before": | ||
4176 | beforeAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4177 | break; | ||
4178 | case "Sequence": | ||
4179 | var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4180 | switch (sequenceValue) | ||
4181 | { | ||
4182 | case "execute": | ||
4183 | sequences = new[] { SequenceTable.InstallExecuteSequence }; | ||
4184 | break; | ||
4185 | case "first": | ||
4186 | executionType = CustomActionExecutionType.FirstSequence; | ||
4187 | break; | ||
4188 | case "ui": | ||
4189 | sequences = new[] { SequenceTable.InstallUISequence }; | ||
4190 | break; | ||
4191 | case "both": | ||
4192 | break; | ||
4193 | case "": | ||
4194 | break; | ||
4195 | default: | ||
4196 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
4197 | break; | ||
4198 | } | ||
4199 | //if (0 < sequenceValue.Length) | ||
4200 | //{ | ||
4201 | // var sequenceType = Wix.Enums.ParseSequenceType(sequenceValue); | ||
4202 | // switch (sequenceType) | ||
4203 | // { | ||
4204 | // case Wix.SequenceType.execute: | ||
4205 | // sequences = new string[] { "InstallExecuteSequence" }; | ||
4206 | // break; | ||
4207 | // case Wix.SequenceType.ui: | ||
4208 | // sequences = new string[] { "InstallUISequence" }; | ||
4209 | // break; | ||
4210 | // case Wix.SequenceType.first: | ||
4211 | // firstSequence = true; | ||
4212 | // // default puts it in both sequence which is what we want | ||
4213 | // break; | ||
4214 | // case Wix.SequenceType.both: | ||
4215 | // // default so no work necessary. | ||
4216 | // break; | ||
4217 | // default: | ||
4218 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
4219 | // break; | ||
4220 | // } | ||
4221 | //} | ||
4222 | break; | ||
4223 | case "Value": | ||
4224 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
4225 | break; | ||
4226 | default: | ||
4227 | this.Core.UnexpectedAttribute(node, attrib); | ||
4228 | break; | ||
4229 | } | ||
4230 | } | ||
4231 | else | ||
4232 | { | ||
4233 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4234 | } | ||
4235 | } | ||
4236 | |||
4237 | var condition = this.Core.GetConditionInnerText(node); | ||
4238 | |||
4239 | if (null == id) | ||
4240 | { | ||
4241 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4242 | } | ||
4243 | else if (String.IsNullOrEmpty(actionName)) | ||
4244 | { | ||
4245 | actionName = String.Concat("Set", id); | ||
4246 | } | ||
4247 | |||
4248 | if (null == value) | ||
4249 | { | ||
4250 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4251 | } | ||
4252 | |||
4253 | if (null != beforeAction && null != afterAction) | ||
4254 | { | ||
4255 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before")); | ||
4256 | } | ||
4257 | else if (null == beforeAction && null == afterAction) | ||
4258 | { | ||
4259 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before", "Id")); | ||
4260 | } | ||
4261 | |||
4262 | this.Core.ParseForExtensionElements(node); | ||
4263 | |||
4264 | // add the row and any references needed | ||
4265 | if (!this.Core.EncounteredError) | ||
4266 | { | ||
4267 | // action that is scheduled to occur before/after itself | ||
4268 | if (beforeAction == actionName) | ||
4269 | { | ||
4270 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "Before", beforeAction)); | ||
4271 | } | ||
4272 | else if (afterAction == actionName) | ||
4273 | { | ||
4274 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "After", afterAction)); | ||
4275 | } | ||
4276 | |||
4277 | var tuple = new CustomActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, actionName)) | ||
4278 | { | ||
4279 | ExecutionType = executionType, | ||
4280 | SourceType = CustomActionSourceType.Property, | ||
4281 | TargetType = CustomActionTargetType.TextData, | ||
4282 | Source = id, | ||
4283 | Target = value | ||
4284 | }; | ||
4285 | |||
4286 | this.Core.AddTuple(tuple); | ||
4287 | |||
4288 | foreach (var sequence in sequences) | ||
4289 | { | ||
4290 | var sequenceId = new Identifier(AccessModifier.Public, sequence.ToString(), actionName); | ||
4291 | |||
4292 | var sequenceTuple = new WixActionTuple(sourceLineNumbers, sequenceId) | ||
4293 | { | ||
4294 | SequenceTable = sequence, | ||
4295 | Action = actionName, | ||
4296 | Condition = condition, | ||
4297 | Before = beforeAction, | ||
4298 | After = afterAction, | ||
4299 | Overridable = false | ||
4300 | }; | ||
4301 | |||
4302 | this.Core.AddTuple(tuple); | ||
4303 | |||
4304 | if (null != beforeAction) | ||
4305 | { | ||
4306 | if (WindowsInstallerStandard.IsStandardAction(beforeAction)) | ||
4307 | { | ||
4308 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence.ToString(), beforeAction); | ||
4309 | } | ||
4310 | else | ||
4311 | { | ||
4312 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction); | ||
4313 | } | ||
4314 | } | ||
4315 | |||
4316 | if (null != afterAction) | ||
4317 | { | ||
4318 | if (WindowsInstallerStandard.IsStandardAction(afterAction)) | ||
4319 | { | ||
4320 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence.ToString(), afterAction); | ||
4321 | } | ||
4322 | else | ||
4323 | { | ||
4324 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction); | ||
4325 | } | ||
4326 | } | ||
4327 | } | ||
4328 | } | ||
4329 | } | ||
4330 | |||
4331 | /// <summary> | ||
4332 | /// Parses a SFP catalog element. | ||
4333 | /// </summary> | ||
4334 | /// <param name="node">Element to parse.</param> | ||
4335 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
4336 | private void ParseSFPFileElement(XElement node, string parentSFPCatalog) | ||
4337 | { | ||
4338 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4339 | string id = null; | ||
4340 | |||
4341 | foreach (var attrib in node.Attributes()) | ||
4342 | { | ||
4343 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4344 | { | ||
4345 | switch (attrib.Name.LocalName) | ||
4346 | { | ||
4347 | case "Id": | ||
4348 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4349 | break; | ||
4350 | default: | ||
4351 | this.Core.UnexpectedAttribute(node, attrib); | ||
4352 | break; | ||
4353 | } | ||
4354 | } | ||
4355 | else | ||
4356 | { | ||
4357 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4358 | } | ||
4359 | } | ||
4360 | |||
4361 | if (null == id) | ||
4362 | { | ||
4363 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4364 | } | ||
4365 | |||
4366 | this.Core.ParseForExtensionElements(node); | ||
4367 | |||
4368 | if (!this.Core.EncounteredError) | ||
4369 | { | ||
4370 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.FileSFPCatalog); | ||
4371 | row.Set(0, id); | ||
4372 | row.Set(1, parentSFPCatalog); | ||
4373 | } | ||
4374 | } | ||
4375 | |||
4376 | /// <summary> | ||
4377 | /// Parses a SFP catalog element. | ||
4378 | /// </summary> | ||
4379 | /// <param name="node">Element to parse.</param> | ||
4380 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
4381 | private void ParseSFPCatalogElement(XElement node, ref string parentSFPCatalog) | ||
4382 | { | ||
4383 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4384 | string parentName = null; | ||
4385 | string dependency = null; | ||
4386 | string name = null; | ||
4387 | string sourceFile = null; | ||
4388 | |||
4389 | foreach (var attrib in node.Attributes()) | ||
4390 | { | ||
4391 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4392 | { | ||
4393 | switch (attrib.Name.LocalName) | ||
4394 | { | ||
4395 | case "Dependency": | ||
4396 | dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4397 | break; | ||
4398 | case "Name": | ||
4399 | name = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
4400 | parentSFPCatalog = name; | ||
4401 | break; | ||
4402 | case "SourceFile": | ||
4403 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4404 | break; | ||
4405 | default: | ||
4406 | this.Core.UnexpectedAttribute(node, attrib); | ||
4407 | break; | ||
4408 | } | ||
4409 | } | ||
4410 | else | ||
4411 | { | ||
4412 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4413 | } | ||
4414 | } | ||
4415 | |||
4416 | if (null == name) | ||
4417 | { | ||
4418 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
4419 | } | ||
4420 | |||
4421 | if (null == sourceFile) | ||
4422 | { | ||
4423 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
4424 | } | ||
4425 | |||
4426 | foreach (var child in node.Elements()) | ||
4427 | { | ||
4428 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4429 | { | ||
4430 | switch (child.Name.LocalName) | ||
4431 | { | ||
4432 | case "SFPCatalog": | ||
4433 | this.ParseSFPCatalogElement(child, ref parentName); | ||
4434 | if (null != dependency && parentName == dependency) | ||
4435 | { | ||
4436 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
4437 | } | ||
4438 | dependency = parentName; | ||
4439 | break; | ||
4440 | case "SFPFile": | ||
4441 | this.ParseSFPFileElement(child, name); | ||
4442 | break; | ||
4443 | default: | ||
4444 | this.Core.UnexpectedElement(node, child); | ||
4445 | break; | ||
4446 | } | ||
4447 | } | ||
4448 | else | ||
4449 | { | ||
4450 | this.Core.ParseExtensionElement(node, child); | ||
4451 | } | ||
4452 | } | ||
4453 | |||
4454 | if (null == dependency) | ||
4455 | { | ||
4456 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
4457 | } | ||
4458 | |||
4459 | if (!this.Core.EncounteredError) | ||
4460 | { | ||
4461 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.SFPCatalog); | ||
4462 | row.Set(0, name); | ||
4463 | row.Set(1, sourceFile); | ||
4464 | row.Set(2, dependency); | ||
4465 | } | ||
4466 | } | ||
4467 | |||
4468 | /// <summary> | ||
4469 | /// Parses a shortcut element. | ||
4470 | /// </summary> | ||
4471 | /// <param name="node">Element to parse.</param> | ||
4472 | /// <param name="componentId">Identifer for parent component.</param> | ||
4473 | /// <param name="parentElementLocalName">Local name of parent element.</param> | ||
4474 | /// <param name="defaultTarget">Default identifier of parent (which is usually the target).</param> | ||
4475 | /// <param name="parentKeyPath">Flag to indicate whether the parent element is the keypath of a component or not (will only be true for file parent elements).</param> | ||
4476 | private void ParseShortcutElement(XElement node, string componentId, string parentElementLocalName, string defaultTarget, YesNoType parentKeyPath) | ||
4477 | { | ||
4478 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4479 | Identifier id = null; | ||
4480 | var advertise = false; | ||
4481 | string arguments = null; | ||
4482 | string description = null; | ||
4483 | string descriptionResourceDll = null; | ||
4484 | int? descriptionResourceId = null; | ||
4485 | string directory = null; | ||
4486 | string displayResourceDll = null; | ||
4487 | int? displayResourceId = null; | ||
4488 | int? hotkey = null; | ||
4489 | string icon = null; | ||
4490 | int? iconIndex = null; | ||
4491 | string name = null; | ||
4492 | string shortName = null; | ||
4493 | ShortcutShowType? show = null; | ||
4494 | string target = null; | ||
4495 | string workingDirectory = null; | ||
4496 | |||
4497 | foreach (var attrib in node.Attributes()) | ||
4498 | { | ||
4499 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4500 | { | ||
4501 | switch (attrib.Name.LocalName) | ||
4502 | { | ||
4503 | case "Id": | ||
4504 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4505 | break; | ||
4506 | case "Advertise": | ||
4507 | advertise = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
4508 | break; | ||
4509 | case "Arguments": | ||
4510 | arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4511 | break; | ||
4512 | case "Description": | ||
4513 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4514 | break; | ||
4515 | case "DescriptionResourceDll": | ||
4516 | descriptionResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4517 | break; | ||
4518 | case "DescriptionResourceId": | ||
4519 | descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4520 | break; | ||
4521 | case "Directory": | ||
4522 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
4523 | break; | ||
4524 | case "DisplayResourceDll": | ||
4525 | displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4526 | break; | ||
4527 | case "DisplayResourceId": | ||
4528 | displayResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4529 | break; | ||
4530 | case "Hotkey": | ||
4531 | hotkey = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4532 | break; | ||
4533 | case "Icon": | ||
4534 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4535 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
4536 | break; | ||
4537 | case "IconIndex": | ||
4538 | iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue); | ||
4539 | break; | ||
4540 | case "Name": | ||
4541 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
4542 | break; | ||
4543 | case "ShortName": | ||
4544 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
4545 | break; | ||
4546 | case "Show": | ||
4547 | var showValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4548 | switch (showValue) | ||
4549 | { | ||
4550 | case "normal": | ||
4551 | show = ShortcutShowType.Normal; | ||
4552 | break; | ||
4553 | case "maximized": | ||
4554 | show = ShortcutShowType.Maximized; | ||
4555 | break; | ||
4556 | case "minimized": | ||
4557 | show = ShortcutShowType.Minimized; | ||
4558 | break; | ||
4559 | case "": | ||
4560 | break; | ||
4561 | default: | ||
4562 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized")); | ||
4563 | break; | ||
4564 | } | ||
4565 | //if (showValue.Length == 0) | ||
4566 | //{ | ||
4567 | // show = CompilerConstants.IllegalInteger; | ||
4568 | //} | ||
4569 | //else | ||
4570 | //{ | ||
4571 | // var showType = Wix.Shortcut.ParseShowType(showValue); | ||
4572 | // switch (showType) | ||
4573 | // { | ||
4574 | // case Wix.Shortcut.ShowType.normal: | ||
4575 | // show = 1; | ||
4576 | // break; | ||
4577 | // case Wix.Shortcut.ShowType.maximized: | ||
4578 | // show = 3; | ||
4579 | // break; | ||
4580 | // case Wix.Shortcut.ShowType.minimized: | ||
4581 | // show = 7; | ||
4582 | // break; | ||
4583 | // default: | ||
4584 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized")); | ||
4585 | // show = CompilerConstants.IllegalInteger; | ||
4586 | // break; | ||
4587 | // } | ||
4588 | //} | ||
4589 | break; | ||
4590 | case "Target": | ||
4591 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4592 | break; | ||
4593 | case "WorkingDirectory": | ||
4594 | workingDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4595 | break; | ||
4596 | default: | ||
4597 | this.Core.UnexpectedAttribute(node, attrib); | ||
4598 | break; | ||
4599 | } | ||
4600 | } | ||
4601 | else | ||
4602 | { | ||
4603 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4604 | } | ||
4605 | } | ||
4606 | |||
4607 | if (advertise && null != target) | ||
4608 | { | ||
4609 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes")); | ||
4610 | } | ||
4611 | |||
4612 | if (null == directory) | ||
4613 | { | ||
4614 | if ("Component" == parentElementLocalName) | ||
4615 | { | ||
4616 | directory = defaultTarget; | ||
4617 | } | ||
4618 | else | ||
4619 | { | ||
4620 | this.Core.Write(ErrorMessages.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Directory", "Component")); | ||
4621 | } | ||
4622 | } | ||
4623 | |||
4624 | if (null != descriptionResourceDll) | ||
4625 | { | ||
4626 | if (!descriptionResourceId.HasValue) | ||
4627 | { | ||
4628 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceDll", "DescriptionResourceId")); | ||
4629 | } | ||
4630 | } | ||
4631 | else | ||
4632 | { | ||
4633 | if (descriptionResourceId.HasValue) | ||
4634 | { | ||
4635 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceId", "DescriptionResourceDll")); | ||
4636 | } | ||
4637 | } | ||
4638 | |||
4639 | if (null != displayResourceDll) | ||
4640 | { | ||
4641 | if (!displayResourceId.HasValue) | ||
4642 | { | ||
4643 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceDll", "DisplayResourceId")); | ||
4644 | } | ||
4645 | } | ||
4646 | else | ||
4647 | { | ||
4648 | if (displayResourceId.HasValue) | ||
4649 | { | ||
4650 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceId", "DisplayResourceDll")); | ||
4651 | } | ||
4652 | } | ||
4653 | |||
4654 | if (null == name) | ||
4655 | { | ||
4656 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
4657 | } | ||
4658 | else if (0 < name.Length) | ||
4659 | { | ||
4660 | if (this.Core.IsValidShortFilename(name, false)) | ||
4661 | { | ||
4662 | if (null == shortName) | ||
4663 | { | ||
4664 | shortName = name; | ||
4665 | name = null; | ||
4666 | } | ||
4667 | else | ||
4668 | { | ||
4669 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
4670 | } | ||
4671 | } | ||
4672 | else if (null == shortName) // generate a short file name. | ||
4673 | { | ||
4674 | shortName = this.Core.CreateShortName(name, true, false, node.Name.LocalName, componentId, directory); | ||
4675 | } | ||
4676 | } | ||
4677 | |||
4678 | if ("Component" != parentElementLocalName && null != target) | ||
4679 | { | ||
4680 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName)); | ||
4681 | } | ||
4682 | |||
4683 | if (null == id) | ||
4684 | { | ||
4685 | id = this.Core.CreateIdentifier("sct", directory, LowercaseOrNull(name) ?? LowercaseOrNull(shortName)); | ||
4686 | } | ||
4687 | |||
4688 | foreach (var child in node.Elements()) | ||
4689 | { | ||
4690 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4691 | { | ||
4692 | switch (child.Name.LocalName) | ||
4693 | { | ||
4694 | case "Icon": | ||
4695 | icon = this.ParseIconElement(child); | ||
4696 | break; | ||
4697 | case "ShortcutProperty": | ||
4698 | this.ParseShortcutPropertyElement(child, id.Id); | ||
4699 | break; | ||
4700 | default: | ||
4701 | this.Core.UnexpectedElement(node, child); | ||
4702 | break; | ||
4703 | } | ||
4704 | } | ||
4705 | else | ||
4706 | { | ||
4707 | this.Core.ParseExtensionElement(node, child); | ||
4708 | } | ||
4709 | } | ||
4710 | |||
4711 | if (!this.Core.EncounteredError) | ||
4712 | { | ||
4713 | if (advertise) | ||
4714 | { | ||
4715 | if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName) | ||
4716 | { | ||
4717 | this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget)); | ||
4718 | } | ||
4719 | |||
4720 | target = Guid.Empty.ToString("B"); | ||
4721 | } | ||
4722 | else if (null != target) | ||
4723 | { | ||
4724 | } | ||
4725 | else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName) | ||
4726 | { | ||
4727 | target = String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget); | ||
4728 | } | ||
4729 | else if ("File" == parentElementLocalName) | ||
4730 | { | ||
4731 | target = String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget); | ||
4732 | } | ||
4733 | |||
4734 | var tuple = new ShortcutTuple(sourceLineNumbers, id) | ||
4735 | { | ||
4736 | Directory_ = directory, | ||
4737 | Name = this.GetMsiFilenameValue(shortName, name), | ||
4738 | Component_ = componentId, | ||
4739 | Target = target, | ||
4740 | Arguments = arguments, | ||
4741 | Description = description, | ||
4742 | Hotkey = hotkey, | ||
4743 | Icon_ = icon, | ||
4744 | IconIndex = iconIndex, | ||
4745 | Show = show, | ||
4746 | WorkingDirectory = workingDirectory, | ||
4747 | DisplayResourceDll = displayResourceDll, | ||
4748 | DisplayResourceId = displayResourceId, | ||
4749 | DescriptionResourceDll = descriptionResourceDll, | ||
4750 | DescriptionResourceId = descriptionResourceId, | ||
4751 | }; | ||
4752 | |||
4753 | this.Core.AddTuple(tuple); | ||
4754 | |||
4755 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Shortcut, id); | ||
4756 | //row.Set(1, directory); | ||
4757 | //row.Set(2, this.GetMsiFilenameValue(shortName, name)); | ||
4758 | //row.Set(3, componentId); | ||
4759 | //if (advertise) | ||
4760 | //{ | ||
4761 | // if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName) | ||
4762 | // { | ||
4763 | // this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget)); | ||
4764 | // } | ||
4765 | // row.Set(4, Guid.Empty.ToString("B")); | ||
4766 | //} | ||
4767 | //else if (null != target) | ||
4768 | //{ | ||
4769 | // row.Set(4, target); | ||
4770 | //} | ||
4771 | //else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName) | ||
4772 | //{ | ||
4773 | // row.Set(4, String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget)); | ||
4774 | //} | ||
4775 | //else if ("File" == parentElementLocalName) | ||
4776 | //{ | ||
4777 | // row.Set(4, String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget)); | ||
4778 | //} | ||
4779 | //row.Set(5, arguments); | ||
4780 | //row.Set(6, description); | ||
4781 | //if (CompilerConstants.IntegerNotSet != hotkey) | ||
4782 | //{ | ||
4783 | // row.Set(7, hotkey); | ||
4784 | //} | ||
4785 | //row.Set(8, icon); | ||
4786 | //if (CompilerConstants.IntegerNotSet != iconIndex) | ||
4787 | //{ | ||
4788 | // row.Set(9, iconIndex); | ||
4789 | //} | ||
4790 | |||
4791 | //if (show.HasValue) | ||
4792 | //{ | ||
4793 | // row.Set(10, show.Value); | ||
4794 | //} | ||
4795 | //row.Set(11, workingDirectory); | ||
4796 | //row.Set(12, displayResourceDll); | ||
4797 | //if (CompilerConstants.IntegerNotSet != displayResourceId) | ||
4798 | //{ | ||
4799 | // row.Set(13, displayResourceId); | ||
4800 | //} | ||
4801 | //row.Set(14, descriptionResourceDll); | ||
4802 | //if (CompilerConstants.IntegerNotSet != descriptionResourceId) | ||
4803 | //{ | ||
4804 | // row.Set(15, descriptionResourceId); | ||
4805 | //} | ||
4806 | } | ||
4807 | } | ||
4808 | |||
4809 | /// <summary> | ||
4810 | /// Parses a shortcut property element. | ||
4811 | /// </summary> | ||
4812 | /// <param name="node">Element to parse.</param> | ||
4813 | private void ParseShortcutPropertyElement(XElement node, string shortcutId) | ||
4814 | { | ||
4815 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4816 | Identifier id = null; | ||
4817 | string key = null; | ||
4818 | string value = null; | ||
4819 | |||
4820 | foreach (var attrib in node.Attributes()) | ||
4821 | { | ||
4822 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4823 | { | ||
4824 | switch (attrib.Name.LocalName) | ||
4825 | { | ||
4826 | case "Id": | ||
4827 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4828 | break; | ||
4829 | case "Key": | ||
4830 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4831 | break; | ||
4832 | case "Value": | ||
4833 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4834 | break; | ||
4835 | default: | ||
4836 | this.Core.UnexpectedAttribute(node, attrib); | ||
4837 | break; | ||
4838 | } | ||
4839 | } | ||
4840 | else | ||
4841 | { | ||
4842 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4843 | } | ||
4844 | } | ||
4845 | |||
4846 | if (String.IsNullOrEmpty(key)) | ||
4847 | { | ||
4848 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
4849 | } | ||
4850 | else if (null == id) | ||
4851 | { | ||
4852 | id = this.Core.CreateIdentifier("scp", shortcutId, key.ToUpperInvariant()); | ||
4853 | } | ||
4854 | |||
4855 | var innerText = this.Core.GetTrimmedInnerText(node); | ||
4856 | if (!String.IsNullOrEmpty(innerText)) | ||
4857 | { | ||
4858 | if (String.IsNullOrEmpty(value)) | ||
4859 | { | ||
4860 | value = innerText; | ||
4861 | } | ||
4862 | else // cannot specify both the value attribute and inner text | ||
4863 | { | ||
4864 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4865 | } | ||
4866 | } | ||
4867 | |||
4868 | if (String.IsNullOrEmpty(value)) | ||
4869 | { | ||
4870 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4871 | } | ||
4872 | |||
4873 | this.Core.ParseForExtensionElements(node); | ||
4874 | |||
4875 | if (!this.Core.EncounteredError) | ||
4876 | { | ||
4877 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiShortcutProperty, id); | ||
4878 | row.Set(1, shortcutId); | ||
4879 | row.Set(2, key); | ||
4880 | row.Set(3, value); | ||
4881 | } | ||
4882 | } | ||
4883 | |||
4884 | /// <summary> | ||
4885 | /// Parses a typelib element. | ||
4886 | /// </summary> | ||
4887 | /// <param name="node">Element to parse.</param> | ||
4888 | /// <param name="componentId">Identifier of parent component.</param> | ||
4889 | /// <param name="fileServer">Identifier of file that acts as typelib server.</param> | ||
4890 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
4891 | private void ParseTypeLibElement(XElement node, string componentId, string fileServer, bool win64Component) | ||
4892 | { | ||
4893 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4894 | string id = null; | ||
4895 | var advertise = YesNoType.NotSet; | ||
4896 | var cost = CompilerConstants.IntegerNotSet; | ||
4897 | string description = null; | ||
4898 | var flags = 0; | ||
4899 | string helpDirectory = null; | ||
4900 | var language = CompilerConstants.IntegerNotSet; | ||
4901 | var majorVersion = CompilerConstants.IntegerNotSet; | ||
4902 | var minorVersion = CompilerConstants.IntegerNotSet; | ||
4903 | var resourceId = CompilerConstants.LongNotSet; | ||
4904 | |||
4905 | foreach (var attrib in node.Attributes()) | ||
4906 | { | ||
4907 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4908 | { | ||
4909 | switch (attrib.Name.LocalName) | ||
4910 | { | ||
4911 | case "Id": | ||
4912 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
4913 | break; | ||
4914 | case "Advertise": | ||
4915 | advertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
4916 | break; | ||
4917 | case "Control": | ||
4918 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4919 | { | ||
4920 | flags |= 2; | ||
4921 | } | ||
4922 | break; | ||
4923 | case "Cost": | ||
4924 | cost = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
4925 | break; | ||
4926 | case "Description": | ||
4927 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4928 | break; | ||
4929 | case "HasDiskImage": | ||
4930 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4931 | { | ||
4932 | flags |= 8; | ||
4933 | } | ||
4934 | break; | ||
4935 | case "HelpDirectory": | ||
4936 | helpDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
4937 | break; | ||
4938 | case "Hidden": | ||
4939 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4940 | { | ||
4941 | flags |= 4; | ||
4942 | } | ||
4943 | break; | ||
4944 | case "Language": | ||
4945 | language = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4946 | break; | ||
4947 | case "MajorVersion": | ||
4948 | majorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, UInt16.MaxValue); | ||
4949 | break; | ||
4950 | case "MinorVersion": | ||
4951 | minorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
4952 | break; | ||
4953 | case "ResourceId": | ||
4954 | resourceId = this.Core.GetAttributeLongValue(sourceLineNumbers, attrib, Int32.MinValue, Int32.MaxValue); | ||
4955 | break; | ||
4956 | case "Restricted": | ||
4957 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4958 | { | ||
4959 | flags |= 1; | ||
4960 | } | ||
4961 | break; | ||
4962 | default: | ||
4963 | this.Core.UnexpectedAttribute(node, attrib); | ||
4964 | break; | ||
4965 | } | ||
4966 | } | ||
4967 | else | ||
4968 | { | ||
4969 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4970 | } | ||
4971 | } | ||
4972 | |||
4973 | if (null == id) | ||
4974 | { | ||
4975 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4976 | } | ||
4977 | |||
4978 | if (CompilerConstants.IntegerNotSet == language) | ||
4979 | { | ||
4980 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
4981 | language = CompilerConstants.IllegalInteger; | ||
4982 | } | ||
4983 | |||
4984 | // build up the typelib version string for the registry if the major or minor version was specified | ||
4985 | string registryVersion = null; | ||
4986 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
4987 | { | ||
4988 | if (CompilerConstants.IntegerNotSet != majorVersion) | ||
4989 | { | ||
4990 | registryVersion = majorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat); | ||
4991 | } | ||
4992 | else | ||
4993 | { | ||
4994 | registryVersion = "0"; | ||
4995 | } | ||
4996 | |||
4997 | if (CompilerConstants.IntegerNotSet != minorVersion) | ||
4998 | { | ||
4999 | registryVersion = String.Concat(registryVersion, ".", minorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat)); | ||
5000 | } | ||
5001 | else | ||
5002 | { | ||
5003 | registryVersion = String.Concat(registryVersion, ".0"); | ||
5004 | } | ||
5005 | } | ||
5006 | |||
5007 | // if the advertise state has not been set, default to non-advertised | ||
5008 | if (YesNoType.NotSet == advertise) | ||
5009 | { | ||
5010 | advertise = YesNoType.No; | ||
5011 | } | ||
5012 | |||
5013 | foreach (var child in node.Elements()) | ||
5014 | { | ||
5015 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5016 | { | ||
5017 | switch (child.Name.LocalName) | ||
5018 | { | ||
5019 | case "AppId": | ||
5020 | this.ParseAppIdElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion); | ||
5021 | break; | ||
5022 | case "Class": | ||
5023 | this.ParseClassElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion, null); | ||
5024 | break; | ||
5025 | case "Interface": | ||
5026 | this.ParseInterfaceElement(child, componentId, null, null, id, registryVersion); | ||
5027 | break; | ||
5028 | default: | ||
5029 | this.Core.UnexpectedElement(node, child); | ||
5030 | break; | ||
5031 | } | ||
5032 | } | ||
5033 | else | ||
5034 | { | ||
5035 | this.Core.ParseExtensionElement(node, child); | ||
5036 | } | ||
5037 | } | ||
5038 | |||
5039 | |||
5040 | if (YesNoType.Yes == advertise) | ||
5041 | { | ||
5042 | if (CompilerConstants.LongNotSet != resourceId) | ||
5043 | { | ||
5044 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "ResourceId")); | ||
5045 | } | ||
5046 | |||
5047 | if (0 != flags) | ||
5048 | { | ||
5049 | if (0x1 == (flags & 0x1)) | ||
5050 | { | ||
5051 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Restricted", "Advertise", "yes")); | ||
5052 | } | ||
5053 | |||
5054 | if (0x2 == (flags & 0x2)) | ||
5055 | { | ||
5056 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Control", "Advertise", "yes")); | ||
5057 | } | ||
5058 | |||
5059 | if (0x4 == (flags & 0x4)) | ||
5060 | { | ||
5061 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Hidden", "Advertise", "yes")); | ||
5062 | } | ||
5063 | |||
5064 | if (0x8 == (flags & 0x8)) | ||
5065 | { | ||
5066 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "HasDiskImage", "Advertise", "yes")); | ||
5067 | } | ||
5068 | } | ||
5069 | |||
5070 | if (!this.Core.EncounteredError) | ||
5071 | { | ||
5072 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.TypeLib); | ||
5073 | row.Set(0, id); | ||
5074 | row.Set(1, language); | ||
5075 | row.Set(2, componentId); | ||
5076 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
5077 | { | ||
5078 | row.Set(3, (CompilerConstants.IntegerNotSet != majorVersion ? majorVersion * 256 : 0) + (CompilerConstants.IntegerNotSet != minorVersion ? minorVersion : 0)); | ||
5079 | } | ||
5080 | row.Set(4, description); | ||
5081 | row.Set(5, helpDirectory); | ||
5082 | row.Set(6, Guid.Empty.ToString("B")); | ||
5083 | if (CompilerConstants.IntegerNotSet != cost) | ||
5084 | { | ||
5085 | row.Set(7, cost); | ||
5086 | } | ||
5087 | } | ||
5088 | } | ||
5089 | else if (YesNoType.No == advertise) | ||
5090 | { | ||
5091 | if (CompilerConstants.IntegerNotSet != cost && CompilerConstants.IllegalInteger != cost) | ||
5092 | { | ||
5093 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Cost", "Advertise", "no")); | ||
5094 | } | ||
5095 | |||
5096 | if (null == fileServer) | ||
5097 | { | ||
5098 | this.Core.Write(ErrorMessages.MissingTypeLibFile(sourceLineNumbers, node.Name.LocalName, "File")); | ||
5099 | } | ||
5100 | |||
5101 | if (null == registryVersion) | ||
5102 | { | ||
5103 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "MajorVersion", "MinorVersion", "Advertise", "no")); | ||
5104 | } | ||
5105 | |||
5106 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion], (Default) = [Description] | ||
5107 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}", id, registryVersion), null, description, componentId); | ||
5108 | |||
5109 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\[Language]\[win16|win32|win64], (Default) = [TypeLibPath]\[ResourceId] | ||
5110 | var path = String.Concat("[#", fileServer, "]"); | ||
5111 | if (CompilerConstants.LongNotSet != resourceId) | ||
5112 | { | ||
5113 | path = String.Concat(path, Path.DirectorySeparatorChar, resourceId.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
5114 | } | ||
5115 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\{2}\{3}", id, registryVersion, language, (win64Component ? "win64" : "win32")), null, path, componentId); | ||
5116 | |||
5117 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags] | ||
5118 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId); | ||
5119 | |||
5120 | if (null != helpDirectory) | ||
5121 | { | ||
5122 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory] | ||
5123 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId); | ||
5124 | } | ||
5125 | } | ||
5126 | } | ||
5127 | |||
5128 | /// <summary> | ||
5129 | /// Parses an upgrade element. | ||
5130 | /// </summary> | ||
5131 | /// <param name="node">Element to parse.</param> | ||
5132 | private void ParseUpgradeElement(XElement node) | ||
5133 | { | ||
5134 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5135 | string id = null; | ||
5136 | |||
5137 | foreach (var attrib in node.Attributes()) | ||
5138 | { | ||
5139 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5140 | { | ||
5141 | switch (attrib.Name.LocalName) | ||
5142 | { | ||
5143 | case "Id": | ||
5144 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
5145 | break; | ||
5146 | default: | ||
5147 | this.Core.UnexpectedAttribute(node, attrib); | ||
5148 | break; | ||
5149 | } | ||
5150 | } | ||
5151 | else | ||
5152 | { | ||
5153 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5154 | } | ||
5155 | } | ||
5156 | |||
5157 | if (null == id) | ||
5158 | { | ||
5159 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5160 | } | ||
5161 | |||
5162 | // process the UpgradeVersion children here | ||
5163 | foreach (var child in node.Elements()) | ||
5164 | { | ||
5165 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5166 | { | ||
5167 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
5168 | |||
5169 | switch (child.Name.LocalName) | ||
5170 | { | ||
5171 | case "Property": | ||
5172 | this.ParsePropertyElement(child); | ||
5173 | this.Core.Write(WarningMessages.DeprecatedUpgradeProperty(childSourceLineNumbers)); | ||
5174 | break; | ||
5175 | case "UpgradeVersion": | ||
5176 | this.ParseUpgradeVersionElement(child, id); | ||
5177 | break; | ||
5178 | default: | ||
5179 | this.Core.UnexpectedElement(node, child); | ||
5180 | break; | ||
5181 | } | ||
5182 | } | ||
5183 | else | ||
5184 | { | ||
5185 | this.Core.ParseExtensionElement(node, child); | ||
5186 | } | ||
5187 | } | ||
5188 | |||
5189 | // No rows created here. All row creation is done in ParseUpgradeVersionElement. | ||
5190 | } | ||
5191 | |||
5192 | /// <summary> | ||
5193 | /// Parse upgrade version element. | ||
5194 | /// </summary> | ||
5195 | /// <param name="node">Element to parse.</param> | ||
5196 | /// <param name="upgradeId">Upgrade code.</param> | ||
5197 | private void ParseUpgradeVersionElement(XElement node, string upgradeId) | ||
5198 | { | ||
5199 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5200 | |||
5201 | string actionProperty = null; | ||
5202 | string language = null; | ||
5203 | string maximum = null; | ||
5204 | string minimum = null; | ||
5205 | var excludeLanguages = false; | ||
5206 | var ignoreFailures = false; | ||
5207 | var includeMax = false; | ||
5208 | var includeMin = true; | ||
5209 | var migrateFeatures = false; | ||
5210 | var onlyDetect = false; | ||
5211 | string removeFeatures = null; | ||
5212 | |||
5213 | foreach (var attrib in node.Attributes()) | ||
5214 | { | ||
5215 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5216 | { | ||
5217 | switch (attrib.Name.LocalName) | ||
5218 | { | ||
5219 | case "ExcludeLanguages": | ||
5220 | excludeLanguages = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5221 | break; | ||
5222 | case "IgnoreRemoveFailure": | ||
5223 | ignoreFailures = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5224 | break; | ||
5225 | case "IncludeMaximum": | ||
5226 | includeMax = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5227 | break; | ||
5228 | case "IncludeMinimum": // this is "yes" by default | ||
5229 | includeMin = YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5230 | break; | ||
5231 | case "Language": | ||
5232 | language = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5233 | break; | ||
5234 | case "Minimum": | ||
5235 | minimum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
5236 | break; | ||
5237 | case "Maximum": | ||
5238 | maximum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
5239 | break; | ||
5240 | case "MigrateFeatures": | ||
5241 | migrateFeatures = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5242 | break; | ||
5243 | case "OnlyDetect": | ||
5244 | onlyDetect = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5245 | break; | ||
5246 | case "Property": | ||
5247 | actionProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
5248 | break; | ||
5249 | case "RemoveFeatures": | ||
5250 | removeFeatures = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5251 | break; | ||
5252 | default: | ||
5253 | this.Core.UnexpectedAttribute(node, attrib); | ||
5254 | break; | ||
5255 | } | ||
5256 | } | ||
5257 | else | ||
5258 | { | ||
5259 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5260 | } | ||
5261 | } | ||
5262 | |||
5263 | if (null == actionProperty) | ||
5264 | { | ||
5265 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
5266 | } | ||
5267 | else if (actionProperty.ToUpper(CultureInfo.InvariantCulture) != actionProperty) | ||
5268 | { | ||
5269 | this.Core.Write(ErrorMessages.SecurePropertyNotUppercase(sourceLineNumbers, node.Name.LocalName, "Property", actionProperty)); | ||
5270 | } | ||
5271 | |||
5272 | if (null == minimum && null == maximum) | ||
5273 | { | ||
5274 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Minimum", "Maximum")); | ||
5275 | } | ||
5276 | |||
5277 | this.Core.ParseForExtensionElements(node); | ||
5278 | |||
5279 | if (!this.Core.EncounteredError) | ||
5280 | { | ||
5281 | var tuple = new UpgradeTuple(sourceLineNumbers) | ||
5282 | { | ||
5283 | UpgradeCode = upgradeId, | ||
5284 | VersionMin = minimum, | ||
5285 | VersionMax = maximum, | ||
5286 | Language = language, | ||
5287 | ExcludeLanguages = excludeLanguages, | ||
5288 | IgnoreRemoveFailures = ignoreFailures, | ||
5289 | VersionMaxInclusive = includeMax, | ||
5290 | VersionMinInclusive = includeMin, | ||
5291 | MigrateFeatures = migrateFeatures, | ||
5292 | OnlyDetect = onlyDetect, | ||
5293 | Remove = removeFeatures, | ||
5294 | ActionProperty = actionProperty | ||
5295 | }; | ||
5296 | |||
5297 | this.Core.AddTuple(tuple); | ||
5298 | |||
5299 | // Ensure the action property is secure. | ||
5300 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(actionProperty, AccessModifier.Private), false, true, false); | ||
5301 | |||
5302 | // Ensure that RemoveExistingProducts is authored in InstallExecuteSequence | ||
5303 | // if at least one row in Upgrade table lacks the OnlyDetect attribute. | ||
5304 | if (onlyDetect) | ||
5305 | { | ||
5306 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", "RemoveExistingProducts"); | ||
5307 | } | ||
5308 | } | ||
5309 | } | ||
5310 | |||
5311 | /// <summary> | ||
5312 | /// Parses a verb element. | ||
5313 | /// </summary> | ||
5314 | /// <param name="node">Element to parse.</param> | ||
5315 | /// <param name="extension">Extension verb is releated to.</param> | ||
5316 | /// <param name="progId">Optional progId for extension.</param> | ||
5317 | /// <param name="componentId">Identifier for parent component.</param> | ||
5318 | /// <param name="advertise">Flag if verb is advertised.</param> | ||
5319 | private void ParseVerbElement(XElement node, string extension, string progId, string componentId, YesNoType advertise) | ||
5320 | { | ||
5321 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5322 | string id = null; | ||
5323 | string argument = null; | ||
5324 | string command = null; | ||
5325 | var sequence = CompilerConstants.IntegerNotSet; | ||
5326 | string target = null; | ||
5327 | string targetFile = null; | ||
5328 | string targetProperty = null; | ||
5329 | |||
5330 | foreach (var attrib in node.Attributes()) | ||
5331 | { | ||
5332 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5333 | { | ||
5334 | switch (attrib.Name.LocalName) | ||
5335 | { | ||
5336 | case "Id": | ||
5337 | id = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5338 | break; | ||
5339 | case "Argument": | ||
5340 | argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5341 | break; | ||
5342 | case "Command": | ||
5343 | command = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5344 | break; | ||
5345 | case "Sequence": | ||
5346 | sequence = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); | ||
5347 | break; | ||
5348 | case "Target": | ||
5349 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5350 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "TargetFile", "TargetProperty")); | ||
5351 | break; | ||
5352 | case "TargetFile": | ||
5353 | targetFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5354 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", targetFile); | ||
5355 | break; | ||
5356 | case "TargetProperty": | ||
5357 | targetProperty = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5358 | break; | ||
5359 | default: | ||
5360 | this.Core.UnexpectedAttribute(node, attrib); | ||
5361 | break; | ||
5362 | } | ||
5363 | } | ||
5364 | else | ||
5365 | { | ||
5366 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5367 | } | ||
5368 | } | ||
5369 | |||
5370 | if (null == id) | ||
5371 | { | ||
5372 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5373 | } | ||
5374 | |||
5375 | if (null != target && null != targetFile) | ||
5376 | { | ||
5377 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetFile")); | ||
5378 | } | ||
5379 | |||
5380 | if (null != target && null != targetProperty) | ||
5381 | { | ||
5382 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetProperty")); | ||
5383 | } | ||
5384 | |||
5385 | if (null != targetFile && null != targetProperty) | ||
5386 | { | ||
5387 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty")); | ||
5388 | } | ||
5389 | |||
5390 | this.Core.ParseForExtensionElements(node); | ||
5391 | |||
5392 | if (YesNoType.Yes == advertise) | ||
5393 | { | ||
5394 | if (null != target) | ||
5395 | { | ||
5396 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "Target")); | ||
5397 | } | ||
5398 | |||
5399 | if (null != targetFile) | ||
5400 | { | ||
5401 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetFile")); | ||
5402 | } | ||
5403 | |||
5404 | if (null != targetProperty) | ||
5405 | { | ||
5406 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetProperty")); | ||
5407 | } | ||
5408 | |||
5409 | if (!this.Core.EncounteredError) | ||
5410 | { | ||
5411 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Verb); | ||
5412 | row.Set(0, extension); | ||
5413 | row.Set(1, id); | ||
5414 | if (CompilerConstants.IntegerNotSet != sequence) | ||
5415 | { | ||
5416 | row.Set(2, sequence); | ||
5417 | } | ||
5418 | row.Set(3, command); | ||
5419 | row.Set(4, argument); | ||
5420 | } | ||
5421 | } | ||
5422 | else if (YesNoType.No == advertise) | ||
5423 | { | ||
5424 | if (CompilerConstants.IntegerNotSet != sequence) | ||
5425 | { | ||
5426 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Sequence", "Advertise", "no")); | ||
5427 | } | ||
5428 | |||
5429 | if (null == target && null == targetFile && null == targetProperty) | ||
5430 | { | ||
5431 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty", "Advertise", "no")); | ||
5432 | } | ||
5433 | |||
5434 | if (null == target) | ||
5435 | { | ||
5436 | if (null != targetFile) | ||
5437 | { | ||
5438 | target = String.Concat("\"[#", targetFile, "]\""); | ||
5439 | } | ||
5440 | |||
5441 | if (null != targetProperty) | ||
5442 | { | ||
5443 | target = String.Concat("\"[", targetProperty, "]\""); | ||
5444 | } | ||
5445 | } | ||
5446 | |||
5447 | if (null != argument) | ||
5448 | { | ||
5449 | target = String.Concat(target, " ", argument); | ||
5450 | } | ||
5451 | |||
5452 | var prefix = (null != progId ? progId : String.Concat(".", extension)); | ||
5453 | |||
5454 | if (null != command) | ||
5455 | { | ||
5456 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(prefix, "\\shell\\", id), String.Empty, command, componentId); | ||
5457 | } | ||
5458 | |||
5459 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(prefix, "\\shell\\", id, "\\command"), String.Empty, target, componentId); | ||
5460 | } | ||
5461 | } | ||
5462 | |||
5463 | /// <summary> | ||
5464 | /// Parses a Wix element. | ||
5465 | /// </summary> | ||
5466 | /// <param name="node">Element to parse.</param> | ||
5467 | private void ParseWixElement(XElement node) | ||
5468 | { | ||
5469 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5470 | string requiredVersion = null; | ||
5471 | |||
5472 | foreach (var attrib in node.Attributes()) | ||
5473 | { | ||
5474 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5475 | { | ||
5476 | switch (attrib.Name.LocalName) | ||
5477 | { | ||
5478 | case "RequiredVersion": | ||
5479 | requiredVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
5480 | break; | ||
5481 | default: | ||
5482 | this.Core.UnexpectedAttribute(node, attrib); | ||
5483 | break; | ||
5484 | } | ||
5485 | } | ||
5486 | else | ||
5487 | { | ||
5488 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5489 | } | ||
5490 | } | ||
5491 | |||
5492 | if (null != requiredVersion) | ||
5493 | { | ||
5494 | this.Core.VerifyRequiredVersion(sourceLineNumbers, requiredVersion); | ||
5495 | } | ||
5496 | |||
5497 | foreach (var child in node.Elements()) | ||
5498 | { | ||
5499 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5500 | { | ||
5501 | switch (child.Name.LocalName) | ||
5502 | { | ||
5503 | case "Bundle": | ||
5504 | this.ParseBundleElement(child); | ||
5505 | break; | ||
5506 | case "Fragment": | ||
5507 | this.ParseFragmentElement(child); | ||
5508 | break; | ||
5509 | case "Module": | ||
5510 | this.ParseModuleElement(child); | ||
5511 | break; | ||
5512 | case "PatchCreation": | ||
5513 | this.ParsePatchCreationElement(child); | ||
5514 | break; | ||
5515 | case "Product": | ||
5516 | this.ParseProductElement(child); | ||
5517 | break; | ||
5518 | case "Patch": | ||
5519 | this.ParsePatchElement(child); | ||
5520 | break; | ||
5521 | default: | ||
5522 | this.Core.UnexpectedElement(node, child); | ||
5523 | break; | ||
5524 | } | ||
5525 | } | ||
5526 | else | ||
5527 | { | ||
5528 | this.Core.ParseExtensionElement(node, child); | ||
5529 | } | ||
5530 | } | ||
5531 | } | ||
5532 | |||
5533 | /// <summary> | ||
5534 | /// Parses a WixVariable element. | ||
5535 | /// </summary> | ||
5536 | /// <param name="node">Element to parse.</param> | ||
5537 | private void ParseWixVariableElement(XElement node) | ||
5538 | { | ||
5539 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5540 | Identifier id = null; | ||
5541 | var overridable = false; | ||
5542 | string value = null; | ||
5543 | |||
5544 | foreach (var attrib in node.Attributes()) | ||
5545 | { | ||
5546 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5547 | { | ||
5548 | switch (attrib.Name.LocalName) | ||
5549 | { | ||
5550 | case "Id": | ||
5551 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
5552 | break; | ||
5553 | case "Overridable": | ||
5554 | overridable = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
5555 | break; | ||
5556 | case "Value": | ||
5557 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
5558 | break; | ||
5559 | default: | ||
5560 | this.Core.UnexpectedAttribute(node, attrib); | ||
5561 | break; | ||
5562 | } | ||
5563 | } | ||
5564 | else | ||
5565 | { | ||
5566 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5567 | } | ||
5568 | } | ||
5569 | |||
5570 | if (null == id) | ||
5571 | { | ||
5572 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5573 | } | ||
5574 | |||
5575 | if (null == value) | ||
5576 | { | ||
5577 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
5578 | } | ||
5579 | |||
5580 | this.Core.ParseForExtensionElements(node); | ||
5581 | |||
5582 | if (!this.Core.EncounteredError) | ||
5583 | { | ||
5584 | var wixVariableRow = (WixVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixVariable, id); | ||
5585 | wixVariableRow.Value = value; | ||
5586 | wixVariableRow.Overridable = overridable; | ||
5587 | } | ||
5588 | } | ||
5589 | |||
5590 | private CompressionLevel? ParseCompressionLevel(SourceLineNumber sourceLineNumbers, XElement node, XAttribute attribute) | ||
5591 | { | ||
5592 | var compressionLevel = this.Core.GetAttributeValue(sourceLineNumbers, attribute); | ||
5593 | switch (compressionLevel) | ||
5594 | { | ||
5595 | case "high": | ||
5596 | return CompressionLevel.High; | ||
5597 | case "low": | ||
5598 | return CompressionLevel.Low; | ||
5599 | case "medium": | ||
5600 | return CompressionLevel.Medium; | ||
5601 | case "mszip": | ||
5602 | return CompressionLevel.Mszip; | ||
5603 | case "none": | ||
5604 | return CompressionLevel.None; | ||
5605 | case "": | ||
5606 | break; | ||
5607 | default: | ||
5608 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attribute.Name.LocalName, compressionLevel, "high", "low", "medium", "mszip", "none")); | ||
5609 | break; | ||
5610 | } | ||
5611 | |||
5612 | return null; | ||
5613 | } | ||
5614 | } | ||
5615 | } | ||
diff --git a/src/WixToolset.Core/Compiler_Bundle.cs b/src/WixToolset.Core/Compiler_Bundle.cs new file mode 100644 index 00000000..21028b6f --- /dev/null +++ b/src/WixToolset.Core/Compiler_Bundle.cs | |||
@@ -0,0 +1,2727 @@ | |||
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 | namespace WixToolset.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Diagnostics; | ||
8 | using System.Globalization; | ||
9 | using System.IO; | ||
10 | using System.Xml.Linq; | ||
11 | using WixToolset.Data; | ||
12 | using WixToolset.Data.Tuples; | ||
13 | using WixToolset.Extensibility; | ||
14 | |||
15 | /// <summary> | ||
16 | /// Compiler of the WiX toolset. | ||
17 | /// </summary> | ||
18 | internal partial class Compiler : ICompiler | ||
19 | { | ||
20 | public const string BurnUXContainerId = "WixUXContainer"; | ||
21 | public const string BurnDefaultAttachedContainerId = "WixAttachedContainer"; | ||
22 | |||
23 | // The following constants must stay in sync with src\burn\engine\core.h | ||
24 | private const string BURN_BUNDLE_NAME = "WixBundleName"; | ||
25 | private const string BURN_BUNDLE_ORIGINAL_SOURCE = "WixBundleOriginalSource"; | ||
26 | private const string BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER = "WixBundleOriginalSourceFolder"; | ||
27 | private const string BURN_BUNDLE_LAST_USED_SOURCE = "WixBundleLastUsedSource"; | ||
28 | |||
29 | /// <summary> | ||
30 | /// Parses an ApprovedExeForElevation element. | ||
31 | /// </summary> | ||
32 | /// <param name="node">Element to parse</param> | ||
33 | private void ParseApprovedExeForElevation(XElement node) | ||
34 | { | ||
35 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
36 | Identifier id = null; | ||
37 | string key = null; | ||
38 | string valueName = null; | ||
39 | var win64 = YesNoType.NotSet; | ||
40 | |||
41 | foreach (var attrib in node.Attributes()) | ||
42 | { | ||
43 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
44 | { | ||
45 | switch (attrib.Name.LocalName) | ||
46 | { | ||
47 | case "Id": | ||
48 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
49 | break; | ||
50 | case "Key": | ||
51 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
52 | break; | ||
53 | case "Value": | ||
54 | valueName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
55 | break; | ||
56 | case "Win64": | ||
57 | win64 = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
58 | break; | ||
59 | default: | ||
60 | this.Core.UnexpectedAttribute(node, attrib); | ||
61 | break; | ||
62 | } | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | this.Core.ParseExtensionAttribute(node, attrib); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | if (null == id) | ||
71 | { | ||
72 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
73 | } | ||
74 | |||
75 | if (null == key) | ||
76 | { | ||
77 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
78 | } | ||
79 | |||
80 | var attributes = BundleApprovedExeForElevationAttributes.None; | ||
81 | |||
82 | if (win64 == YesNoType.Yes) | ||
83 | { | ||
84 | attributes |= BundleApprovedExeForElevationAttributes.Win64; | ||
85 | } | ||
86 | |||
87 | this.Core.ParseForExtensionElements(node); | ||
88 | |||
89 | if (!this.Core.EncounteredError) | ||
90 | { | ||
91 | var wixApprovedExeForElevationRow = (WixApprovedExeForElevationTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixApprovedExeForElevation, id); | ||
92 | wixApprovedExeForElevationRow.Key = key; | ||
93 | wixApprovedExeForElevationRow.Value = valueName; | ||
94 | wixApprovedExeForElevationRow.Attributes = (int)attributes; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Parses a Bundle element. | ||
100 | /// </summary> | ||
101 | /// <param name="node">Element to parse</param> | ||
102 | private void ParseBundleElement(XElement node) | ||
103 | { | ||
104 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
105 | string copyright = null; | ||
106 | string aboutUrl = null; | ||
107 | var compressed = YesNoDefaultType.Default; | ||
108 | var disableModify = -1; | ||
109 | var disableRemove = YesNoType.NotSet; | ||
110 | string helpTelephone = null; | ||
111 | string helpUrl = null; | ||
112 | string manufacturer = null; | ||
113 | string name = null; | ||
114 | string tag = null; | ||
115 | string updateUrl = null; | ||
116 | string upgradeCode = null; | ||
117 | string version = null; | ||
118 | string condition = null; | ||
119 | string parentName = null; | ||
120 | |||
121 | string fileSystemSafeBundleName = null; | ||
122 | string logVariablePrefixAndExtension = null; | ||
123 | string iconSourceFile = null; | ||
124 | string splashScreenSourceFile = null; | ||
125 | |||
126 | // Process only standard attributes until the active section is initialized. | ||
127 | foreach (var attrib in node.Attributes()) | ||
128 | { | ||
129 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
130 | { | ||
131 | switch (attrib.Name.LocalName) | ||
132 | { | ||
133 | case "AboutUrl": | ||
134 | aboutUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
135 | break; | ||
136 | case "Compressed": | ||
137 | compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
138 | break; | ||
139 | case "Condition": | ||
140 | condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
141 | break; | ||
142 | case "Copyright": | ||
143 | copyright = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
144 | break; | ||
145 | case "DisableModify": | ||
146 | var value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
147 | switch (value) | ||
148 | { | ||
149 | case "button": | ||
150 | disableModify = 2; | ||
151 | break; | ||
152 | case "yes": | ||
153 | disableModify = 1; | ||
154 | break; | ||
155 | case "no": | ||
156 | disableModify = 0; | ||
157 | break; | ||
158 | default: | ||
159 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "button", "yes", "no")); | ||
160 | break; | ||
161 | } | ||
162 | break; | ||
163 | case "DisableRemove": | ||
164 | disableRemove = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
165 | break; | ||
166 | case "DisableRepair": | ||
167 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
168 | break; | ||
169 | case "HelpTelephone": | ||
170 | helpTelephone = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
171 | break; | ||
172 | case "HelpUrl": | ||
173 | helpUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
174 | break; | ||
175 | case "Manufacturer": | ||
176 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
177 | break; | ||
178 | case "IconSourceFile": | ||
179 | iconSourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
180 | break; | ||
181 | case "Name": | ||
182 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
183 | break; | ||
184 | case "ParentName": | ||
185 | parentName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
186 | break; | ||
187 | case "SplashScreenSourceFile": | ||
188 | splashScreenSourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
189 | break; | ||
190 | case "Tag": | ||
191 | tag = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
192 | break; | ||
193 | case "UpdateUrl": | ||
194 | updateUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
195 | break; | ||
196 | case "UpgradeCode": | ||
197 | upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
198 | break; | ||
199 | case "Version": | ||
200 | version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
201 | break; | ||
202 | default: | ||
203 | this.Core.UnexpectedAttribute(node, attrib); | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | if (String.IsNullOrEmpty(version)) | ||
210 | { | ||
211 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
212 | } | ||
213 | else if (!CompilerCore.IsValidModuleOrBundleVersion(version)) | ||
214 | { | ||
215 | this.Core.Write(WarningMessages.InvalidModuleOrBundleVersion(sourceLineNumbers, "Bundle", version)); | ||
216 | } | ||
217 | |||
218 | if (String.IsNullOrEmpty(upgradeCode)) | ||
219 | { | ||
220 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpgradeCode")); | ||
221 | } | ||
222 | |||
223 | if (String.IsNullOrEmpty(copyright)) | ||
224 | { | ||
225 | if (String.IsNullOrEmpty(manufacturer)) | ||
226 | { | ||
227 | copyright = "Copyright (c). All rights reserved."; | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | copyright = String.Format("Copyright (c) {0}. All rights reserved.", manufacturer); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (String.IsNullOrEmpty(name)) | ||
236 | { | ||
237 | logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup.log"); | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | // Ensure only allowable path characters are in "name" (and change spaces to underscores). | ||
242 | fileSystemSafeBundleName = CompilerCore.MakeValidLongFileName(name.Replace(' ', '_'), "_"); | ||
243 | logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ".log"); | ||
244 | } | ||
245 | |||
246 | this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name; | ||
247 | this.Core.CreateActiveSection(this.activeName, SectionType.Bundle, 0, this.Context.CompilationId); | ||
248 | |||
249 | // Now that the active section is initialized, process only extension attributes. | ||
250 | foreach (var attrib in node.Attributes()) | ||
251 | { | ||
252 | if (!String.IsNullOrEmpty(attrib.Name.NamespaceName) && CompilerCore.WixNamespace != attrib.Name.Namespace) | ||
253 | { | ||
254 | this.Core.ParseExtensionAttribute(node, attrib); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | var baSeen = false; | ||
259 | var chainSeen = false; | ||
260 | var logSeen = false; | ||
261 | |||
262 | foreach (var child in node.Elements()) | ||
263 | { | ||
264 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
265 | { | ||
266 | switch (child.Name.LocalName) | ||
267 | { | ||
268 | case "ApprovedExeForElevation": | ||
269 | this.ParseApprovedExeForElevation(child); | ||
270 | break; | ||
271 | case "BootstrapperApplication": | ||
272 | if (baSeen) | ||
273 | { | ||
274 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
275 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "BootstrapperApplication")); | ||
276 | } | ||
277 | this.ParseBootstrapperApplicationElement(child); | ||
278 | baSeen = true; | ||
279 | break; | ||
280 | case "BootstrapperApplicationRef": | ||
281 | this.ParseBootstrapperApplicationRefElement(child); | ||
282 | break; | ||
283 | case "OptionalUpdateRegistration": | ||
284 | this.ParseOptionalUpdateRegistrationElement(child, manufacturer, parentName, name); | ||
285 | break; | ||
286 | case "Catalog": | ||
287 | this.ParseCatalogElement(child); | ||
288 | break; | ||
289 | case "Chain": | ||
290 | if (chainSeen) | ||
291 | { | ||
292 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
293 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "Chain")); | ||
294 | } | ||
295 | this.ParseChainElement(child); | ||
296 | chainSeen = true; | ||
297 | break; | ||
298 | case "Container": | ||
299 | this.ParseContainerElement(child); | ||
300 | break; | ||
301 | case "ContainerRef": | ||
302 | this.ParseSimpleRefElement(child, "WixBundleContainer"); | ||
303 | break; | ||
304 | case "Log": | ||
305 | if (logSeen) | ||
306 | { | ||
307 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
308 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "Log")); | ||
309 | } | ||
310 | logVariablePrefixAndExtension = this.ParseLogElement(child, fileSystemSafeBundleName); | ||
311 | logSeen = true; | ||
312 | break; | ||
313 | case "PayloadGroup": | ||
314 | this.ParsePayloadGroupElement(child, ComplexReferenceParentType.Layout, "BundleLayoutOnlyPayloads"); | ||
315 | break; | ||
316 | case "PayloadGroupRef": | ||
317 | this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Layout, "BundleLayoutOnlyPayloads", ComplexReferenceChildType.Unknown, null); | ||
318 | break; | ||
319 | case "RelatedBundle": | ||
320 | this.ParseRelatedBundleElement(child); | ||
321 | break; | ||
322 | case "Update": | ||
323 | this.ParseUpdateElement(child); | ||
324 | break; | ||
325 | case "Variable": | ||
326 | this.ParseVariableElement(child); | ||
327 | break; | ||
328 | case "WixVariable": | ||
329 | this.ParseWixVariableElement(child); | ||
330 | break; | ||
331 | default: | ||
332 | this.Core.UnexpectedElement(node, child); | ||
333 | break; | ||
334 | } | ||
335 | } | ||
336 | else | ||
337 | { | ||
338 | this.Core.ParseExtensionElement(node, child); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | if (!chainSeen) | ||
343 | { | ||
344 | this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Chain")); | ||
345 | } | ||
346 | |||
347 | if (!this.Core.EncounteredError) | ||
348 | { | ||
349 | if (null != upgradeCode) | ||
350 | { | ||
351 | var tuple = new WixRelatedBundleTuple(sourceLineNumbers) | ||
352 | { | ||
353 | BundleId = upgradeCode, | ||
354 | Action = RelatedBundleActionType.Upgrade, | ||
355 | }; | ||
356 | |||
357 | this.Core.AddTuple(tuple); | ||
358 | } | ||
359 | |||
360 | var containerRow = (WixBundleContainerTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleContainer); | ||
361 | containerRow.WixBundleContainer = Compiler.BurnDefaultAttachedContainerId; | ||
362 | containerRow.Name = "bundle-attached.cab"; | ||
363 | containerRow.Type = ContainerType.Attached; | ||
364 | |||
365 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundle); | ||
366 | row.Set(0, version); | ||
367 | row.Set(1, copyright); | ||
368 | row.Set(2, name); | ||
369 | row.Set(3, aboutUrl); | ||
370 | if (-1 != disableModify) | ||
371 | { | ||
372 | row.Set(4, disableModify); | ||
373 | } | ||
374 | if (YesNoType.NotSet != disableRemove) | ||
375 | { | ||
376 | row.Set(5, (YesNoType.Yes == disableRemove) ? 1 : 0); | ||
377 | } | ||
378 | // row.Set(6] - (deprecated) "disable repair" | ||
379 | row.Set(7, helpTelephone); | ||
380 | row.Set(8, helpUrl); | ||
381 | row.Set(9, manufacturer); | ||
382 | row.Set(10, updateUrl); | ||
383 | if (YesNoDefaultType.Default != compressed) | ||
384 | { | ||
385 | row.Set(11, (YesNoDefaultType.Yes == compressed) ? 1 : 0); | ||
386 | } | ||
387 | |||
388 | row.Set(12, logVariablePrefixAndExtension); | ||
389 | row.Set(13, iconSourceFile); | ||
390 | row.Set(14, splashScreenSourceFile); | ||
391 | row.Set(15, condition); | ||
392 | row.Set(16, tag); | ||
393 | row.Set(17, this.CurrentPlatform.ToString()); | ||
394 | row.Set(18, parentName); | ||
395 | row.Set(19, upgradeCode); | ||
396 | |||
397 | // Ensure that the bundle stores the well-known persisted values. | ||
398 | var bundleNameWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
399 | bundleNameWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_NAME; | ||
400 | bundleNameWellKnownVariable.Hidden = false; | ||
401 | bundleNameWellKnownVariable.Persisted = true; | ||
402 | |||
403 | var bundleOriginalSourceWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
404 | bundleOriginalSourceWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_ORIGINAL_SOURCE; | ||
405 | bundleOriginalSourceWellKnownVariable.Hidden = false; | ||
406 | bundleOriginalSourceWellKnownVariable.Persisted = true; | ||
407 | |||
408 | var bundleOriginalSourceFolderWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
409 | bundleOriginalSourceFolderWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER; | ||
410 | bundleOriginalSourceFolderWellKnownVariable.Hidden = false; | ||
411 | bundleOriginalSourceFolderWellKnownVariable.Persisted = true; | ||
412 | |||
413 | var bundleLastUsedSourceWellKnownVariable = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
414 | bundleLastUsedSourceWellKnownVariable.WixBundleVariable = Compiler.BURN_BUNDLE_LAST_USED_SOURCE; | ||
415 | bundleLastUsedSourceWellKnownVariable.Hidden = false; | ||
416 | bundleLastUsedSourceWellKnownVariable.Persisted = true; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | /// <summary> | ||
421 | /// Parse a Container element. | ||
422 | /// </summary> | ||
423 | /// <param name="node">Element to parse</param> | ||
424 | private string ParseLogElement(XElement node, string fileSystemSafeBundleName) | ||
425 | { | ||
426 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
427 | var disableLog = YesNoType.NotSet; | ||
428 | var variable = "WixBundleLog"; | ||
429 | var logPrefix = fileSystemSafeBundleName ?? "Setup"; | ||
430 | var logExtension = ".log"; | ||
431 | |||
432 | foreach (var attrib in node.Attributes()) | ||
433 | { | ||
434 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
435 | { | ||
436 | switch (attrib.Name.LocalName) | ||
437 | { | ||
438 | case "Disable": | ||
439 | disableLog = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
440 | break; | ||
441 | case "PathVariable": | ||
442 | variable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
443 | break; | ||
444 | case "Prefix": | ||
445 | logPrefix = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
446 | break; | ||
447 | case "Extension": | ||
448 | logExtension = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
449 | break; | ||
450 | default: | ||
451 | this.Core.UnexpectedAttribute(node, attrib); | ||
452 | break; | ||
453 | } | ||
454 | } | ||
455 | else | ||
456 | { | ||
457 | this.Core.ParseExtensionAttribute(node, attrib); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | if (!logExtension.StartsWith(".", StringComparison.Ordinal)) | ||
462 | { | ||
463 | logExtension = String.Concat(".", logExtension); | ||
464 | } | ||
465 | |||
466 | this.Core.ParseForExtensionElements(node); | ||
467 | |||
468 | return YesNoType.Yes == disableLog ? null : String.Concat(variable, ":", logPrefix, logExtension); | ||
469 | } | ||
470 | |||
471 | /// <summary> | ||
472 | /// Parse a Catalog element. | ||
473 | /// </summary> | ||
474 | /// <param name="node">Element to parse</param> | ||
475 | private void ParseCatalogElement(XElement node) | ||
476 | { | ||
477 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
478 | Identifier id = null; | ||
479 | string sourceFile = null; | ||
480 | |||
481 | foreach (var attrib in node.Attributes()) | ||
482 | { | ||
483 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
484 | { | ||
485 | switch (attrib.Name.LocalName) | ||
486 | { | ||
487 | case "Id": | ||
488 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
489 | break; | ||
490 | case "SourceFile": | ||
491 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
492 | break; | ||
493 | default: | ||
494 | this.Core.UnexpectedAttribute(node, attrib); | ||
495 | break; | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | if (null == id) | ||
501 | { | ||
502 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
503 | } | ||
504 | |||
505 | if (null == sourceFile) | ||
506 | { | ||
507 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
508 | } | ||
509 | |||
510 | this.Core.ParseForExtensionElements(node); | ||
511 | |||
512 | // Create catalog row | ||
513 | if (!this.Core.EncounteredError) | ||
514 | { | ||
515 | this.CreatePayloadRow(sourceLineNumbers, id, Path.GetFileName(sourceFile), sourceFile, null, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, ComplexReferenceChildType.Unknown, null, YesNoDefaultType.Yes, YesNoType.Yes, null, null, null); | ||
516 | |||
517 | var wixCatalogRow = (WixBundleCatalogTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleCatalog, id); | ||
518 | wixCatalogRow.Payload_ = id.Id; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | /// <summary> | ||
523 | /// Parse a Container element. | ||
524 | /// </summary> | ||
525 | /// <param name="node">Element to parse</param> | ||
526 | private void ParseContainerElement(XElement node) | ||
527 | { | ||
528 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
529 | Identifier id = null; | ||
530 | string downloadUrl = null; | ||
531 | string name = null; | ||
532 | var type = ContainerType.Detached; | ||
533 | |||
534 | foreach (var attrib in node.Attributes()) | ||
535 | { | ||
536 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
537 | { | ||
538 | switch (attrib.Name.LocalName) | ||
539 | { | ||
540 | case "Id": | ||
541 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
542 | break; | ||
543 | case "DownloadUrl": | ||
544 | downloadUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
545 | break; | ||
546 | case "Name": | ||
547 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
548 | break; | ||
549 | case "Type": | ||
550 | var typeString = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
551 | if (!Enum.TryParse<ContainerType>(typeString, out type)) | ||
552 | { | ||
553 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Type", typeString, "attached, detached")); | ||
554 | } | ||
555 | break; | ||
556 | default: | ||
557 | this.Core.UnexpectedAttribute(node, attrib); | ||
558 | break; | ||
559 | } | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | this.Core.ParseExtensionAttribute(node, attrib); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | if (null == id) | ||
568 | { | ||
569 | if (!String.IsNullOrEmpty(name)) | ||
570 | { | ||
571 | id = this.Core.CreateIdentifierFromFilename(name); | ||
572 | } | ||
573 | |||
574 | if (null == id) | ||
575 | { | ||
576 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
577 | id = Identifier.Invalid; | ||
578 | } | ||
579 | else if (!Common.IsIdentifier(id.Id)) | ||
580 | { | ||
581 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
582 | } | ||
583 | } | ||
584 | else if (null == name) | ||
585 | { | ||
586 | name = id.Id; | ||
587 | } | ||
588 | |||
589 | if (!String.IsNullOrEmpty(downloadUrl) && ContainerType.Detached != type) | ||
590 | { | ||
591 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "Type", "attached")); | ||
592 | } | ||
593 | |||
594 | foreach (var child in node.Elements()) | ||
595 | { | ||
596 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
597 | { | ||
598 | switch (child.Name.LocalName) | ||
599 | { | ||
600 | case "PackageGroupRef": | ||
601 | this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.Container, id.Id); | ||
602 | break; | ||
603 | default: | ||
604 | this.Core.UnexpectedElement(node, child); | ||
605 | break; | ||
606 | } | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | this.Core.ParseExtensionElement(node, child); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | |||
615 | if (!this.Core.EncounteredError) | ||
616 | { | ||
617 | var row = (WixBundleContainerTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleContainer, id); | ||
618 | row.Name = name; | ||
619 | row.Type = type; | ||
620 | row.DownloadUrl = downloadUrl; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | /// <summary> | ||
625 | /// Parse the BoostrapperApplication element. | ||
626 | /// </summary> | ||
627 | /// <param name="node">Element to parse</param> | ||
628 | private void ParseBootstrapperApplicationElement(XElement node) | ||
629 | { | ||
630 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
631 | string id = null; | ||
632 | string previousId = null; | ||
633 | var previousType = ComplexReferenceChildType.Unknown; | ||
634 | |||
635 | // The BootstrapperApplication element acts like a Payload element so delegate to the "Payload" attribute parsing code to parse and create a Payload entry. | ||
636 | id = this.ParsePayloadElementContent(node, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId, false); | ||
637 | if (null != id) | ||
638 | { | ||
639 | previousId = id; | ||
640 | previousType = ComplexReferenceChildType.Payload; | ||
641 | } | ||
642 | |||
643 | foreach (var child in node.Elements()) | ||
644 | { | ||
645 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
646 | { | ||
647 | switch (child.Name.LocalName) | ||
648 | { | ||
649 | case "Payload": | ||
650 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
651 | previousType = ComplexReferenceChildType.Payload; | ||
652 | break; | ||
653 | case "PayloadGroupRef": | ||
654 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
655 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
656 | break; | ||
657 | default: | ||
658 | this.Core.UnexpectedElement(node, child); | ||
659 | break; | ||
660 | } | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | this.Core.ParseExtensionElement(node, child); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | if (null == previousId) | ||
669 | { | ||
670 | // We need *either* <Payload> or <PayloadGroupRef> or even just @SourceFile on the BA... | ||
671 | // but we just say there's a missing <Payload>. | ||
672 | // TODO: Is there a better message for this? | ||
673 | this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Payload")); | ||
674 | } | ||
675 | |||
676 | // Add the application as an attached container and if an Id was provided add that too. | ||
677 | if (!this.Core.EncounteredError) | ||
678 | { | ||
679 | var containerRow = (WixBundleContainerTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleContainer); | ||
680 | containerRow.WixBundleContainer = Compiler.BurnUXContainerId; | ||
681 | containerRow.Name = "bundle-ux.cab"; | ||
682 | containerRow.Type = ContainerType.Attached; | ||
683 | |||
684 | if (!String.IsNullOrEmpty(id)) | ||
685 | { | ||
686 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBootstrapperApplication); | ||
687 | row.Set(0, id); | ||
688 | } | ||
689 | } | ||
690 | } | ||
691 | |||
692 | /// <summary> | ||
693 | /// Parse the BoostrapperApplicationRef element. | ||
694 | /// </summary> | ||
695 | /// <param name="node">Element to parse</param> | ||
696 | private void ParseBootstrapperApplicationRefElement(XElement node) | ||
697 | { | ||
698 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
699 | string id = null; | ||
700 | string previousId = null; | ||
701 | var previousType = ComplexReferenceChildType.Unknown; | ||
702 | |||
703 | foreach (var attrib in node.Attributes()) | ||
704 | { | ||
705 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
706 | { | ||
707 | switch (attrib.Name.LocalName) | ||
708 | { | ||
709 | case "Id": | ||
710 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
711 | break; | ||
712 | default: | ||
713 | this.Core.UnexpectedAttribute(node, attrib); | ||
714 | break; | ||
715 | } | ||
716 | } | ||
717 | else | ||
718 | { | ||
719 | this.Core.ParseExtensionAttribute(node, attrib); | ||
720 | } | ||
721 | } | ||
722 | |||
723 | foreach (var child in node.Elements()) | ||
724 | { | ||
725 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
726 | { | ||
727 | switch (child.Name.LocalName) | ||
728 | { | ||
729 | case "Payload": | ||
730 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
731 | previousType = ComplexReferenceChildType.Payload; | ||
732 | break; | ||
733 | case "PayloadGroupRef": | ||
734 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
735 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
736 | break; | ||
737 | default: | ||
738 | this.Core.UnexpectedElement(node, child); | ||
739 | break; | ||
740 | } | ||
741 | } | ||
742 | else | ||
743 | { | ||
744 | this.Core.ParseExtensionElement(node, child); | ||
745 | } | ||
746 | } | ||
747 | |||
748 | |||
749 | if (String.IsNullOrEmpty(id)) | ||
750 | { | ||
751 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
752 | } | ||
753 | else | ||
754 | { | ||
755 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBootstrapperApplication", id); | ||
756 | } | ||
757 | } | ||
758 | |||
759 | /// <summary> | ||
760 | /// Parse the OptionalUpdateRegistration element. | ||
761 | /// </summary> | ||
762 | /// <param name="node">The element to parse.</param> | ||
763 | /// <param name="defaultManufacturer">The manufacturer.</param> | ||
764 | /// <param name="defaultProductFamily">The product family.</param> | ||
765 | /// <param name="defaultName">The bundle name.</param> | ||
766 | private void ParseOptionalUpdateRegistrationElement(XElement node, string defaultManufacturer, string defaultProductFamily, string defaultName) | ||
767 | { | ||
768 | const string defaultClassification = "Update"; | ||
769 | |||
770 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
771 | string manufacturer = null; | ||
772 | string department = null; | ||
773 | string productFamily = null; | ||
774 | string name = null; | ||
775 | var classification = defaultClassification; | ||
776 | |||
777 | foreach (var attrib in node.Attributes()) | ||
778 | { | ||
779 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
780 | { | ||
781 | switch (attrib.Name.LocalName) | ||
782 | { | ||
783 | case "Manufacturer": | ||
784 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
785 | break; | ||
786 | case "Department": | ||
787 | department = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
788 | break; | ||
789 | case "ProductFamily": | ||
790 | productFamily = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
791 | break; | ||
792 | case "Name": | ||
793 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
794 | break; | ||
795 | case "Classification": | ||
796 | classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
797 | break; | ||
798 | default: | ||
799 | this.Core.UnexpectedAttribute(node, attrib); | ||
800 | break; | ||
801 | } | ||
802 | } | ||
803 | else | ||
804 | { | ||
805 | this.Core.ParseExtensionAttribute(node, attrib); | ||
806 | } | ||
807 | } | ||
808 | |||
809 | if (String.IsNullOrEmpty(manufacturer)) | ||
810 | { | ||
811 | if (!String.IsNullOrEmpty(defaultManufacturer)) | ||
812 | { | ||
813 | manufacturer = defaultManufacturer; | ||
814 | } | ||
815 | else | ||
816 | { | ||
817 | this.Core.Write(ErrorMessages.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "Manufacturer", node.Parent.Name.LocalName)); | ||
818 | } | ||
819 | } | ||
820 | |||
821 | if (String.IsNullOrEmpty(productFamily)) | ||
822 | { | ||
823 | if (!String.IsNullOrEmpty(defaultProductFamily)) | ||
824 | { | ||
825 | productFamily = defaultProductFamily; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | if (String.IsNullOrEmpty(name)) | ||
830 | { | ||
831 | if (!String.IsNullOrEmpty(defaultName)) | ||
832 | { | ||
833 | name = defaultName; | ||
834 | } | ||
835 | else | ||
836 | { | ||
837 | this.Core.Write(ErrorMessages.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "Name", node.Parent.Name.LocalName)); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | if (String.IsNullOrEmpty(classification)) | ||
842 | { | ||
843 | this.Core.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, node.Name.LocalName, "Classification", defaultClassification)); | ||
844 | } | ||
845 | |||
846 | this.Core.ParseForExtensionElements(node); | ||
847 | |||
848 | if (!this.Core.EncounteredError) | ||
849 | { | ||
850 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixUpdateRegistration); | ||
851 | row.Set(0, manufacturer); | ||
852 | row.Set(1, department); | ||
853 | row.Set(2, productFamily); | ||
854 | row.Set(3, name); | ||
855 | row.Set(4, classification); | ||
856 | } | ||
857 | } | ||
858 | |||
859 | /// <summary> | ||
860 | /// Parse Payload element. | ||
861 | /// </summary> | ||
862 | /// <param name="node">Element to parse</param> | ||
863 | /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param> | ||
864 | /// <param name="parentId">Identifier of parent element.</param> | ||
865 | private string ParsePayloadElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
866 | { | ||
867 | Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
868 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); | ||
869 | |||
870 | var id = this.ParsePayloadElementContent(node, parentType, parentId, previousType, previousId, true); | ||
871 | var context = new Dictionary<string, string> | ||
872 | { | ||
873 | ["Id"] = id | ||
874 | }; | ||
875 | |||
876 | foreach (var child in node.Elements()) | ||
877 | { | ||
878 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
879 | { | ||
880 | switch (child.Name.LocalName) | ||
881 | { | ||
882 | default: | ||
883 | this.Core.UnexpectedElement(node, child); | ||
884 | break; | ||
885 | } | ||
886 | } | ||
887 | else | ||
888 | { | ||
889 | this.Core.ParseExtensionElement(node, child, context); | ||
890 | } | ||
891 | } | ||
892 | |||
893 | return id; | ||
894 | } | ||
895 | |||
896 | /// <summary> | ||
897 | /// Parse the attributes of the Payload element. | ||
898 | /// </summary> | ||
899 | /// <param name="node">Element to parse</param> | ||
900 | /// <param name="parentType">ComplexReferenceParentType of parent element.</param> | ||
901 | /// <param name="parentId">Identifier of parent element.</param> | ||
902 | private string ParsePayloadElementContent(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, bool required) | ||
903 | { | ||
904 | Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
905 | |||
906 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
907 | var compressed = YesNoDefaultType.Default; | ||
908 | var enableSignatureVerification = YesNoType.No; | ||
909 | Identifier id = null; | ||
910 | string name = null; | ||
911 | string sourceFile = null; | ||
912 | string downloadUrl = null; | ||
913 | RemotePayload remotePayload = null; | ||
914 | |||
915 | // This list lets us evaluate extension attributes *after* all core attributes | ||
916 | // have been parsed and dealt with, regardless of authoring order. | ||
917 | var extensionAttributes = new List<XAttribute>(); | ||
918 | |||
919 | foreach (var attrib in node.Attributes()) | ||
920 | { | ||
921 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
922 | { | ||
923 | switch (attrib.Name.LocalName) | ||
924 | { | ||
925 | case "Id": | ||
926 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
927 | break; | ||
928 | case "Compressed": | ||
929 | compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
930 | break; | ||
931 | case "Name": | ||
932 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); | ||
933 | break; | ||
934 | case "SourceFile": | ||
935 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
936 | break; | ||
937 | case "DownloadUrl": | ||
938 | downloadUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
939 | break; | ||
940 | case "EnableSignatureVerification": | ||
941 | enableSignatureVerification = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
942 | break; | ||
943 | default: | ||
944 | this.Core.UnexpectedAttribute(node, attrib); | ||
945 | break; | ||
946 | } | ||
947 | } | ||
948 | else | ||
949 | { | ||
950 | extensionAttributes.Add(attrib); | ||
951 | } | ||
952 | } | ||
953 | |||
954 | if (!required && null == sourceFile) | ||
955 | { | ||
956 | // Nothing left to do! | ||
957 | return null; | ||
958 | } | ||
959 | |||
960 | if (null == id) | ||
961 | { | ||
962 | id = this.Core.CreateIdentifier("pay", (null != sourceFile) ? sourceFile.ToUpperInvariant() : String.Empty); | ||
963 | } | ||
964 | |||
965 | // Now that the PayloadId is known, we can parse the extension attributes. | ||
966 | var context = new Dictionary<string, string> | ||
967 | { | ||
968 | ["Id"] = id.Id | ||
969 | }; | ||
970 | |||
971 | foreach (var extensionAttribute in extensionAttributes) | ||
972 | { | ||
973 | this.Core.ParseExtensionAttribute(node, extensionAttribute, context); | ||
974 | } | ||
975 | |||
976 | // We only handle the elements we care about. Let caller handle other children. | ||
977 | foreach (var child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) | ||
978 | { | ||
979 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
980 | |||
981 | if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage") | ||
982 | { | ||
983 | this.Core.Write(ErrorMessages.RemotePayloadUnsupported(childSourceLineNumbers)); | ||
984 | continue; | ||
985 | } | ||
986 | |||
987 | if (null != remotePayload) | ||
988 | { | ||
989 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
990 | } | ||
991 | |||
992 | remotePayload = this.ParseRemotePayloadElement(child); | ||
993 | } | ||
994 | |||
995 | if (null != sourceFile && null != remotePayload) | ||
996 | { | ||
997 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "RemotePayload", "SourceFile")); | ||
998 | } | ||
999 | else if (null == sourceFile && null == remotePayload) | ||
1000 | { | ||
1001 | this.Core.Write(ErrorMessages.ExpectedAttributeOrElement(sourceLineNumbers, node.Name.LocalName, "SourceFile", "RemotePayload")); | ||
1002 | } | ||
1003 | else if (null == sourceFile) | ||
1004 | { | ||
1005 | sourceFile = String.Empty; | ||
1006 | } | ||
1007 | |||
1008 | if (null == downloadUrl && null != remotePayload) | ||
1009 | { | ||
1010 | this.Core.Write(ErrorMessages.ExpectedAttributeWithElement(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "RemotePayload")); | ||
1011 | } | ||
1012 | |||
1013 | if (Compiler.BurnUXContainerId == parentId) | ||
1014 | { | ||
1015 | if (compressed == YesNoDefaultType.No) | ||
1016 | { | ||
1017 | this.Core.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(sourceLineNumbers, sourceFile)); | ||
1018 | } | ||
1019 | |||
1020 | compressed = YesNoDefaultType.Yes; | ||
1021 | } | ||
1022 | |||
1023 | this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, parentType, parentId, previousType, previousId, compressed, enableSignatureVerification, null, null, remotePayload); | ||
1024 | |||
1025 | return id.Id; | ||
1026 | } | ||
1027 | |||
1028 | private RemotePayload ParseRemotePayloadElement(XElement node) | ||
1029 | { | ||
1030 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1031 | var remotePayload = new RemotePayload(); | ||
1032 | |||
1033 | foreach (var attrib in node.Attributes()) | ||
1034 | { | ||
1035 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1036 | { | ||
1037 | switch (attrib.Name.LocalName) | ||
1038 | { | ||
1039 | case "CertificatePublicKey": | ||
1040 | remotePayload.CertificatePublicKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1041 | break; | ||
1042 | case "CertificateThumbprint": | ||
1043 | remotePayload.CertificateThumbprint = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1044 | break; | ||
1045 | case "Description": | ||
1046 | remotePayload.Description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1047 | break; | ||
1048 | case "Hash": | ||
1049 | remotePayload.Hash = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1050 | break; | ||
1051 | case "ProductName": | ||
1052 | remotePayload.ProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1053 | break; | ||
1054 | case "Size": | ||
1055 | remotePayload.Size = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
1056 | break; | ||
1057 | case "Version": | ||
1058 | remotePayload.Version = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1059 | break; | ||
1060 | default: | ||
1061 | this.Core.UnexpectedAttribute(node, attrib); | ||
1062 | break; | ||
1063 | } | ||
1064 | } | ||
1065 | else | ||
1066 | { | ||
1067 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | if (String.IsNullOrEmpty(remotePayload.ProductName)) | ||
1072 | { | ||
1073 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProductName")); | ||
1074 | } | ||
1075 | |||
1076 | if (String.IsNullOrEmpty(remotePayload.Description)) | ||
1077 | { | ||
1078 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
1079 | } | ||
1080 | |||
1081 | if (String.IsNullOrEmpty(remotePayload.Hash)) | ||
1082 | { | ||
1083 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Hash")); | ||
1084 | } | ||
1085 | |||
1086 | if (0 == remotePayload.Size) | ||
1087 | { | ||
1088 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Size")); | ||
1089 | } | ||
1090 | |||
1091 | if (String.IsNullOrEmpty(remotePayload.Version)) | ||
1092 | { | ||
1093 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
1094 | } | ||
1095 | |||
1096 | return remotePayload; | ||
1097 | } | ||
1098 | |||
1099 | /// <summary> | ||
1100 | /// Creates the row for a Payload. | ||
1101 | /// </summary> | ||
1102 | /// <param name="node">Element to parse</param> | ||
1103 | /// <param name="parentType">ComplexReferenceParentType of parent element</param> | ||
1104 | /// <param name="parentId">Identifier of parent element.</param> | ||
1105 | private WixBundlePayloadTuple CreatePayloadRow(SourceLineNumber sourceLineNumbers, Identifier id, string name, string sourceFile, string downloadUrl, ComplexReferenceParentType parentType, | ||
1106 | string parentId, ComplexReferenceChildType previousType, string previousId, YesNoDefaultType compressed, YesNoType enableSignatureVerification, string displayName, string description, | ||
1107 | RemotePayload remotePayload) | ||
1108 | { | ||
1109 | WixBundlePayloadTuple row = null; | ||
1110 | |||
1111 | if (!this.Core.EncounteredError) | ||
1112 | { | ||
1113 | row = (WixBundlePayloadTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePayload, id); | ||
1114 | row.Name = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name; | ||
1115 | row.SourceFile = sourceFile; | ||
1116 | row.DownloadUrl = downloadUrl; | ||
1117 | row.Compressed = compressed; | ||
1118 | row.UnresolvedSourceFile = sourceFile; // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. | ||
1119 | row.DisplayName = displayName; | ||
1120 | row.Description = description; | ||
1121 | row.EnableSignatureValidation = (YesNoType.Yes == enableSignatureVerification); | ||
1122 | |||
1123 | if (null != remotePayload) | ||
1124 | { | ||
1125 | row.Description = remotePayload.Description; | ||
1126 | row.DisplayName = remotePayload.ProductName; | ||
1127 | row.Hash = remotePayload.Hash; | ||
1128 | row.PublicKey = remotePayload.CertificatePublicKey; | ||
1129 | row.Thumbprint = remotePayload.CertificateThumbprint; | ||
1130 | row.FileSize = remotePayload.Size; | ||
1131 | row.Version = remotePayload.Version; | ||
1132 | } | ||
1133 | |||
1134 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, id.Id, previousType, previousId); | ||
1135 | } | ||
1136 | |||
1137 | return row; | ||
1138 | } | ||
1139 | |||
1140 | /// <summary> | ||
1141 | /// Parse PayloadGroup element. | ||
1142 | /// </summary> | ||
1143 | /// <param name="node">Element to parse</param> | ||
1144 | /// <param name="parentType">Optional ComplexReferenceParentType of parent element. (typically another PayloadGroup)</param> | ||
1145 | /// <param name="parentId">Identifier of parent element.</param> | ||
1146 | private void ParsePayloadGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
1147 | { | ||
1148 | Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType); | ||
1149 | |||
1150 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1151 | Identifier id = null; | ||
1152 | |||
1153 | foreach (var attrib in node.Attributes()) | ||
1154 | { | ||
1155 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1156 | { | ||
1157 | switch (attrib.Name.LocalName) | ||
1158 | { | ||
1159 | case "Id": | ||
1160 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1161 | break; | ||
1162 | default: | ||
1163 | this.Core.UnexpectedAttribute(node, attrib); | ||
1164 | break; | ||
1165 | } | ||
1166 | } | ||
1167 | else | ||
1168 | { | ||
1169 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1170 | } | ||
1171 | } | ||
1172 | |||
1173 | if (null == id) | ||
1174 | { | ||
1175 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1176 | id = Identifier.Invalid; | ||
1177 | } | ||
1178 | |||
1179 | var previousType = ComplexReferenceChildType.Unknown; | ||
1180 | string previousId = null; | ||
1181 | foreach (var child in node.Elements()) | ||
1182 | { | ||
1183 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1184 | { | ||
1185 | switch (child.Name.LocalName) | ||
1186 | { | ||
1187 | case "Payload": | ||
1188 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id.Id, previousType, previousId); | ||
1189 | previousType = ComplexReferenceChildType.Payload; | ||
1190 | break; | ||
1191 | case "PayloadGroupRef": | ||
1192 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id.Id, previousType, previousId); | ||
1193 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
1194 | break; | ||
1195 | default: | ||
1196 | this.Core.UnexpectedElement(node, child); | ||
1197 | break; | ||
1198 | } | ||
1199 | } | ||
1200 | else | ||
1201 | { | ||
1202 | this.Core.ParseExtensionElement(node, child); | ||
1203 | } | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | if (!this.Core.EncounteredError) | ||
1208 | { | ||
1209 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePayloadGroup, id); | ||
1210 | |||
1211 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id.Id, ComplexReferenceChildType.Unknown, null); | ||
1212 | } | ||
1213 | } | ||
1214 | |||
1215 | /// <summary> | ||
1216 | /// Parses a payload group reference element. | ||
1217 | /// </summary> | ||
1218 | /// <param name="node">Element to parse.</param> | ||
1219 | /// <param name="parentType">ComplexReferenceParentType of parent element (BA or PayloadGroup).</param> | ||
1220 | /// <param name="parentId">Identifier of parent element.</param> | ||
1221 | private string ParsePayloadGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1222 | { | ||
1223 | Debug.Assert(ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
1224 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); | ||
1225 | |||
1226 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1227 | string id = null; | ||
1228 | |||
1229 | foreach (var attrib in node.Attributes()) | ||
1230 | { | ||
1231 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1232 | { | ||
1233 | switch (attrib.Name.LocalName) | ||
1234 | { | ||
1235 | case "Id": | ||
1236 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1237 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBundlePayloadGroup", id); | ||
1238 | break; | ||
1239 | default: | ||
1240 | this.Core.UnexpectedAttribute(node, attrib); | ||
1241 | break; | ||
1242 | } | ||
1243 | } | ||
1244 | else | ||
1245 | { | ||
1246 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | if (null == id) | ||
1251 | { | ||
1252 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1253 | } | ||
1254 | |||
1255 | this.Core.ParseForExtensionElements(node); | ||
1256 | |||
1257 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id, previousType, previousId); | ||
1258 | |||
1259 | return id; | ||
1260 | } | ||
1261 | |||
1262 | /// <summary> | ||
1263 | /// Creates group and ordering information. | ||
1264 | /// </summary> | ||
1265 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
1266 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1267 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1268 | /// <param name="type">Type of this item.</param> | ||
1269 | /// <param name="id">Identifier for this item.</param> | ||
1270 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1271 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1272 | private void CreateGroupAndOrderingRows(SourceLineNumber sourceLineNumbers, | ||
1273 | ComplexReferenceParentType parentType, string parentId, | ||
1274 | ComplexReferenceChildType type, string id, | ||
1275 | ComplexReferenceChildType previousType, string previousId) | ||
1276 | { | ||
1277 | if (ComplexReferenceParentType.Unknown != parentType && null != parentId) | ||
1278 | { | ||
1279 | this.Core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, type, id); | ||
1280 | } | ||
1281 | |||
1282 | if (ComplexReferenceChildType.Unknown != previousType && null != previousId) | ||
1283 | { | ||
1284 | this.CreateWixOrderingRow(sourceLineNumbers, type, id, previousType, previousId); | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | /// <summary> | ||
1289 | /// Parse ExitCode element. | ||
1290 | /// </summary> | ||
1291 | /// <param name="node">Element to parse</param> | ||
1292 | /// <param name="packageId">Id of parent element</param> | ||
1293 | private void ParseExitCodeElement(XElement node, string packageId) | ||
1294 | { | ||
1295 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1296 | var value = CompilerConstants.IntegerNotSet; | ||
1297 | var behavior = ExitCodeBehaviorType.NotSet; | ||
1298 | |||
1299 | foreach (var attrib in node.Attributes()) | ||
1300 | { | ||
1301 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1302 | { | ||
1303 | switch (attrib.Name.LocalName) | ||
1304 | { | ||
1305 | case "Value": | ||
1306 | value = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int32.MinValue + 2, Int32.MaxValue); | ||
1307 | break; | ||
1308 | case "Behavior": | ||
1309 | var behaviorString = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1310 | if (!Enum.TryParse<ExitCodeBehaviorType>(behaviorString, true, out behavior)) | ||
1311 | { | ||
1312 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Behavior", behaviorString, "success, error, scheduleReboot, forceReboot")); | ||
1313 | } | ||
1314 | break; | ||
1315 | default: | ||
1316 | this.Core.UnexpectedAttribute(node, attrib); | ||
1317 | break; | ||
1318 | } | ||
1319 | } | ||
1320 | else | ||
1321 | { | ||
1322 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | if (ExitCodeBehaviorType.NotSet == behavior) | ||
1327 | { | ||
1328 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Behavior")); | ||
1329 | } | ||
1330 | |||
1331 | this.Core.ParseForExtensionElements(node); | ||
1332 | |||
1333 | if (!this.Core.EncounteredError) | ||
1334 | { | ||
1335 | var row = (WixBundlePackageExitCodeTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackageExitCode); | ||
1336 | row.ChainPackageId = packageId; | ||
1337 | row.Code = value; | ||
1338 | row.Behavior = behavior; | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | /// <summary> | ||
1343 | /// Parse Chain element. | ||
1344 | /// </summary> | ||
1345 | /// <param name="node">Element to parse</param> | ||
1346 | private void ParseChainElement(XElement node) | ||
1347 | { | ||
1348 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1349 | var attributes = WixChainAttributes.None; | ||
1350 | |||
1351 | foreach (var attrib in node.Attributes()) | ||
1352 | { | ||
1353 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1354 | { | ||
1355 | switch (attrib.Name.LocalName) | ||
1356 | { | ||
1357 | case "DisableRollback": | ||
1358 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
1359 | { | ||
1360 | attributes |= WixChainAttributes.DisableRollback; | ||
1361 | } | ||
1362 | break; | ||
1363 | case "DisableSystemRestore": | ||
1364 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
1365 | { | ||
1366 | attributes |= WixChainAttributes.DisableSystemRestore; | ||
1367 | } | ||
1368 | break; | ||
1369 | case "ParallelCache": | ||
1370 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
1371 | { | ||
1372 | attributes |= WixChainAttributes.ParallelCache; | ||
1373 | } | ||
1374 | break; | ||
1375 | default: | ||
1376 | this.Core.UnexpectedAttribute(node, attrib); | ||
1377 | break; | ||
1378 | } | ||
1379 | } | ||
1380 | else | ||
1381 | { | ||
1382 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | // Ensure there is always a rollback boundary at the beginning of the chain. | ||
1387 | this.CreateRollbackBoundary(sourceLineNumbers, new Identifier("WixDefaultBoundary", AccessModifier.Public), YesNoType.Yes, YesNoType.No, ComplexReferenceParentType.PackageGroup, "WixChain", ComplexReferenceChildType.Unknown, null); | ||
1388 | |||
1389 | var previousId = "WixDefaultBoundary"; | ||
1390 | var previousType = ComplexReferenceChildType.Package; | ||
1391 | |||
1392 | foreach (var child in node.Elements()) | ||
1393 | { | ||
1394 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1395 | { | ||
1396 | switch (child.Name.LocalName) | ||
1397 | { | ||
1398 | case "MsiPackage": | ||
1399 | previousId = this.ParseMsiPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
1400 | previousType = ComplexReferenceChildType.Package; | ||
1401 | break; | ||
1402 | case "MspPackage": | ||
1403 | previousId = this.ParseMspPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
1404 | previousType = ComplexReferenceChildType.Package; | ||
1405 | break; | ||
1406 | case "MsuPackage": | ||
1407 | previousId = this.ParseMsuPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
1408 | previousType = ComplexReferenceChildType.Package; | ||
1409 | break; | ||
1410 | case "ExePackage": | ||
1411 | previousId = this.ParseExePackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
1412 | previousType = ComplexReferenceChildType.Package; | ||
1413 | break; | ||
1414 | case "RollbackBoundary": | ||
1415 | previousId = this.ParseRollbackBoundaryElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
1416 | previousType = ComplexReferenceChildType.Package; | ||
1417 | break; | ||
1418 | case "PackageGroupRef": | ||
1419 | previousId = this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
1420 | previousType = ComplexReferenceChildType.PackageGroup; | ||
1421 | break; | ||
1422 | default: | ||
1423 | this.Core.UnexpectedElement(node, child); | ||
1424 | break; | ||
1425 | } | ||
1426 | } | ||
1427 | else | ||
1428 | { | ||
1429 | this.Core.ParseExtensionElement(node, child); | ||
1430 | } | ||
1431 | } | ||
1432 | |||
1433 | |||
1434 | if (null == previousId) | ||
1435 | { | ||
1436 | this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "MsiPackage", "ExePackage", "PackageGroupRef")); | ||
1437 | } | ||
1438 | |||
1439 | if (!this.Core.EncounteredError) | ||
1440 | { | ||
1441 | var row = (WixChainTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixChain); | ||
1442 | row.Attributes = attributes; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | /// <summary> | ||
1447 | /// Parse MsiPackage element | ||
1448 | /// </summary> | ||
1449 | /// <param name="node">Element to parse</param> | ||
1450 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1451 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1452 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1453 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1454 | /// <returns>Identifier for package element.</returns> | ||
1455 | private string ParseMsiPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1456 | { | ||
1457 | return this.ParseChainPackage(node, WixBundlePackageType.Msi, parentType, parentId, previousType, previousId); | ||
1458 | } | ||
1459 | |||
1460 | /// <summary> | ||
1461 | /// Parse MspPackage element | ||
1462 | /// </summary> | ||
1463 | /// <param name="node">Element to parse</param> | ||
1464 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1465 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1466 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1467 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1468 | /// <returns>Identifier for package element.</returns> | ||
1469 | private string ParseMspPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1470 | { | ||
1471 | return this.ParseChainPackage(node, WixBundlePackageType.Msp, parentType, parentId, previousType, previousId); | ||
1472 | } | ||
1473 | |||
1474 | /// <summary> | ||
1475 | /// Parse MsuPackage element | ||
1476 | /// </summary> | ||
1477 | /// <param name="node">Element to parse</param> | ||
1478 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1479 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1480 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1481 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1482 | /// <returns>Identifier for package element.</returns> | ||
1483 | private string ParseMsuPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1484 | { | ||
1485 | return this.ParseChainPackage(node, WixBundlePackageType.Msu, parentType, parentId, previousType, previousId); | ||
1486 | } | ||
1487 | |||
1488 | /// <summary> | ||
1489 | /// Parse ExePackage element | ||
1490 | /// </summary> | ||
1491 | /// <param name="node">Element to parse</param> | ||
1492 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1493 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1494 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1495 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1496 | /// <returns>Identifier for package element.</returns> | ||
1497 | private string ParseExePackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1498 | { | ||
1499 | return this.ParseChainPackage(node, WixBundlePackageType.Exe, parentType, parentId, previousType, previousId); | ||
1500 | } | ||
1501 | |||
1502 | /// <summary> | ||
1503 | /// Parse RollbackBoundary element | ||
1504 | /// </summary> | ||
1505 | /// <param name="node">Element to parse</param> | ||
1506 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1507 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1508 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1509 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1510 | /// <returns>Identifier for package element.</returns> | ||
1511 | private string ParseRollbackBoundaryElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1512 | { | ||
1513 | Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); | ||
1514 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
1515 | |||
1516 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1517 | Identifier id = null; | ||
1518 | var vital = YesNoType.Yes; | ||
1519 | var transaction = YesNoType.No; | ||
1520 | |||
1521 | // This list lets us evaluate extension attributes *after* all core attributes | ||
1522 | // have been parsed and dealt with, regardless of authoring order. | ||
1523 | var extensionAttributes = new List<XAttribute>(); | ||
1524 | |||
1525 | foreach (var attrib in node.Attributes()) | ||
1526 | { | ||
1527 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1528 | { | ||
1529 | var allowed = true; | ||
1530 | switch (attrib.Name.LocalName) | ||
1531 | { | ||
1532 | case "Id": | ||
1533 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1534 | break; | ||
1535 | case "Vital": | ||
1536 | vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1537 | break; | ||
1538 | case "Transaction": | ||
1539 | transaction = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1540 | break; | ||
1541 | default: | ||
1542 | allowed = false; | ||
1543 | break; | ||
1544 | } | ||
1545 | |||
1546 | if (!allowed) | ||
1547 | { | ||
1548 | this.Core.UnexpectedAttribute(node, attrib); | ||
1549 | } | ||
1550 | } | ||
1551 | else | ||
1552 | { | ||
1553 | // Save the extension attributes for later... | ||
1554 | extensionAttributes.Add(attrib); | ||
1555 | } | ||
1556 | } | ||
1557 | |||
1558 | if (null == id) | ||
1559 | { | ||
1560 | if (!String.IsNullOrEmpty(previousId)) | ||
1561 | { | ||
1562 | id = this.Core.CreateIdentifier("rba", previousId); | ||
1563 | } | ||
1564 | |||
1565 | if (null == id) | ||
1566 | { | ||
1567 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1568 | id = Identifier.Invalid; | ||
1569 | } | ||
1570 | else if (!Common.IsIdentifier(id.Id)) | ||
1571 | { | ||
1572 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | // Now that the rollback identifier is known, we can parse the extension attributes... | ||
1577 | var contextValues = new Dictionary<string, string> | ||
1578 | { | ||
1579 | ["RollbackBoundaryId"] = id.Id | ||
1580 | }; | ||
1581 | foreach (var attribute in extensionAttributes) | ||
1582 | { | ||
1583 | this.Core.ParseExtensionAttribute(node, attribute, contextValues); | ||
1584 | } | ||
1585 | |||
1586 | this.Core.ParseForExtensionElements(node); | ||
1587 | |||
1588 | if (!this.Core.EncounteredError) | ||
1589 | { | ||
1590 | this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, parentType, parentId, previousType, previousId); | ||
1591 | } | ||
1592 | |||
1593 | return id.Id; | ||
1594 | } | ||
1595 | |||
1596 | /// <summary> | ||
1597 | /// Parses one of the ChainPackage elements | ||
1598 | /// </summary> | ||
1599 | /// <param name="node">Element to parse</param> | ||
1600 | /// <param name="packageType">Type of package to parse</param> | ||
1601 | /// <param name="parentType">Type of parent group, if known.</param> | ||
1602 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
1603 | /// <param name="previousType">Type of previous item, if known.</param> | ||
1604 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
1605 | /// <returns>Identifier for package element.</returns> | ||
1606 | /// <remarks>This method contains the shared logic for parsing all of the ChainPackage | ||
1607 | /// types, as there is more in common between them than different.</remarks> | ||
1608 | private string ParseChainPackage(XElement node, WixBundlePackageType packageType, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
1609 | { | ||
1610 | Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); | ||
1611 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
1612 | |||
1613 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1614 | Identifier id = null; | ||
1615 | string name = null; | ||
1616 | string sourceFile = null; | ||
1617 | string downloadUrl = null; | ||
1618 | string after = null; | ||
1619 | string installCondition = null; | ||
1620 | var cache = YesNoAlwaysType.Yes; // the default is to cache everything in tradeoff for stability over disk space. | ||
1621 | string cacheId = null; | ||
1622 | string description = null; | ||
1623 | string displayName = null; | ||
1624 | var logPathVariable = (packageType == WixBundlePackageType.Msu) ? String.Empty : null; | ||
1625 | var rollbackPathVariable = (packageType == WixBundlePackageType.Msu) ? String.Empty : null; | ||
1626 | var permanent = YesNoType.NotSet; | ||
1627 | var visible = YesNoType.NotSet; | ||
1628 | var vital = YesNoType.Yes; | ||
1629 | string installCommand = null; | ||
1630 | string repairCommand = null; | ||
1631 | var repairable = YesNoType.NotSet; | ||
1632 | string uninstallCommand = null; | ||
1633 | var perMachine = YesNoDefaultType.NotSet; | ||
1634 | string detectCondition = null; | ||
1635 | string protocol = null; | ||
1636 | var installSize = CompilerConstants.IntegerNotSet; | ||
1637 | string msuKB = null; | ||
1638 | var suppressLooseFilePayloadGeneration = YesNoType.NotSet; | ||
1639 | var enableSignatureVerification = YesNoType.No; | ||
1640 | var compressed = YesNoDefaultType.Default; | ||
1641 | var displayInternalUI = YesNoType.NotSet; | ||
1642 | var enableFeatureSelection = YesNoType.NotSet; | ||
1643 | var forcePerMachine = YesNoType.NotSet; | ||
1644 | RemotePayload remotePayload = null; | ||
1645 | var slipstream = YesNoType.NotSet; | ||
1646 | |||
1647 | var expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" }; | ||
1648 | |||
1649 | // This list lets us evaluate extension attributes *after* all core attributes | ||
1650 | // have been parsed and dealt with, regardless of authoring order. | ||
1651 | var extensionAttributes = new List<XAttribute>(); | ||
1652 | |||
1653 | foreach (var attrib in node.Attributes()) | ||
1654 | { | ||
1655 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1656 | { | ||
1657 | var allowed = true; | ||
1658 | switch (attrib.Name.LocalName) | ||
1659 | { | ||
1660 | case "Id": | ||
1661 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1662 | break; | ||
1663 | case "Name": | ||
1664 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); | ||
1665 | if (!this.Core.IsValidLongFilename(name, false, true)) | ||
1666 | { | ||
1667 | this.Core.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
1668 | } | ||
1669 | break; | ||
1670 | case "SourceFile": | ||
1671 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1672 | break; | ||
1673 | case "DownloadUrl": | ||
1674 | downloadUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1675 | break; | ||
1676 | case "After": | ||
1677 | after = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1678 | break; | ||
1679 | case "InstallCondition": | ||
1680 | installCondition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1681 | break; | ||
1682 | case "Cache": | ||
1683 | cache = this.Core.GetAttributeYesNoAlwaysValue(sourceLineNumbers, attrib); | ||
1684 | break; | ||
1685 | case "CacheId": | ||
1686 | cacheId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1687 | break; | ||
1688 | case "Description": | ||
1689 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1690 | break; | ||
1691 | case "DisplayName": | ||
1692 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1693 | break; | ||
1694 | case "DisplayInternalUI": | ||
1695 | displayInternalUI = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1696 | allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp); | ||
1697 | break; | ||
1698 | case "EnableFeatureSelection": | ||
1699 | enableFeatureSelection = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1700 | allowed = (packageType == WixBundlePackageType.Msi); | ||
1701 | break; | ||
1702 | case "ForcePerMachine": | ||
1703 | forcePerMachine = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1704 | allowed = (packageType == WixBundlePackageType.Msi); | ||
1705 | break; | ||
1706 | case "LogPathVariable": | ||
1707 | logPathVariable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1708 | break; | ||
1709 | case "RollbackLogPathVariable": | ||
1710 | rollbackPathVariable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1711 | break; | ||
1712 | case "Permanent": | ||
1713 | permanent = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1714 | break; | ||
1715 | case "Visible": | ||
1716 | visible = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1717 | allowed = (packageType == WixBundlePackageType.Msi); | ||
1718 | break; | ||
1719 | case "Vital": | ||
1720 | vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1721 | break; | ||
1722 | case "InstallCommand": | ||
1723 | installCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1724 | allowed = (packageType == WixBundlePackageType.Exe); | ||
1725 | break; | ||
1726 | case "RepairCommand": | ||
1727 | repairCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1728 | repairable = YesNoType.Yes; | ||
1729 | allowed = (packageType == WixBundlePackageType.Exe); | ||
1730 | break; | ||
1731 | case "UninstallCommand": | ||
1732 | uninstallCommand = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1733 | allowed = (packageType == WixBundlePackageType.Exe); | ||
1734 | break; | ||
1735 | case "PerMachine": | ||
1736 | perMachine = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
1737 | allowed = (packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msp); | ||
1738 | break; | ||
1739 | case "DetectCondition": | ||
1740 | detectCondition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1741 | allowed = (packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu); | ||
1742 | break; | ||
1743 | case "Protocol": | ||
1744 | protocol = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1745 | allowed = (packageType == WixBundlePackageType.Exe); | ||
1746 | break; | ||
1747 | case "InstallSize": | ||
1748 | installSize = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
1749 | break; | ||
1750 | case "KB": | ||
1751 | msuKB = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1752 | allowed = (packageType == WixBundlePackageType.Msu); | ||
1753 | break; | ||
1754 | case "Compressed": | ||
1755 | compressed = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
1756 | break; | ||
1757 | case "SuppressLooseFilePayloadGeneration": | ||
1758 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
1759 | suppressLooseFilePayloadGeneration = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1760 | allowed = (packageType == WixBundlePackageType.Msi); | ||
1761 | break; | ||
1762 | case "EnableSignatureVerification": | ||
1763 | enableSignatureVerification = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1764 | break; | ||
1765 | case "Slipstream": | ||
1766 | slipstream = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1767 | allowed = (packageType == WixBundlePackageType.Msp); | ||
1768 | break; | ||
1769 | default: | ||
1770 | allowed = false; | ||
1771 | break; | ||
1772 | } | ||
1773 | |||
1774 | if (!allowed) | ||
1775 | { | ||
1776 | this.Core.UnexpectedAttribute(node, attrib); | ||
1777 | } | ||
1778 | } | ||
1779 | else | ||
1780 | { | ||
1781 | // Save the extension attributes for later... | ||
1782 | extensionAttributes.Add(attrib); | ||
1783 | } | ||
1784 | } | ||
1785 | |||
1786 | // We need to handle RemotePayload up front because it effects value of sourceFile which is used in Id generation. Id is needed by other child elements. | ||
1787 | foreach (var child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) | ||
1788 | { | ||
1789 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
1790 | |||
1791 | if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage" && node.Name.LocalName != "MsuPackage") | ||
1792 | { | ||
1793 | this.Core.Write(ErrorMessages.RemotePayloadUnsupported(childSourceLineNumbers)); | ||
1794 | continue; | ||
1795 | } | ||
1796 | |||
1797 | if (null != remotePayload) | ||
1798 | { | ||
1799 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
1800 | } | ||
1801 | |||
1802 | remotePayload = this.ParseRemotePayloadElement(child); | ||
1803 | } | ||
1804 | |||
1805 | if (String.IsNullOrEmpty(sourceFile)) | ||
1806 | { | ||
1807 | if (String.IsNullOrEmpty(name)) | ||
1808 | { | ||
1809 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", "SourceFile")); | ||
1810 | } | ||
1811 | else if (null == remotePayload) | ||
1812 | { | ||
1813 | sourceFile = Path.Combine("SourceDir", name); | ||
1814 | } | ||
1815 | } | ||
1816 | else if (null != remotePayload) | ||
1817 | { | ||
1818 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "RemotePayload", "SourceFile")); | ||
1819 | } | ||
1820 | else if (sourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | ||
1821 | { | ||
1822 | if (String.IsNullOrEmpty(name)) | ||
1823 | { | ||
1824 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name", "SourceFile", sourceFile)); | ||
1825 | } | ||
1826 | else | ||
1827 | { | ||
1828 | sourceFile = Path.Combine(sourceFile, Path.GetFileName(name)); | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1832 | if (null == downloadUrl && null != remotePayload) | ||
1833 | { | ||
1834 | this.Core.Write(ErrorMessages.ExpectedAttributeWithElement(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "RemotePayload")); | ||
1835 | } | ||
1836 | |||
1837 | if (YesNoDefaultType.No != compressed && null != remotePayload) | ||
1838 | { | ||
1839 | compressed = YesNoDefaultType.No; | ||
1840 | this.Core.Write(WarningMessages.RemotePayloadsMustNotAlsoBeCompressed(sourceLineNumbers, node.Name.LocalName)); | ||
1841 | } | ||
1842 | |||
1843 | if (null == id) | ||
1844 | { | ||
1845 | if (!String.IsNullOrEmpty(name)) | ||
1846 | { | ||
1847 | id = this.Core.CreateIdentifierFromFilename(Path.GetFileName(name)); | ||
1848 | } | ||
1849 | else if (!String.IsNullOrEmpty(sourceFile)) | ||
1850 | { | ||
1851 | id = this.Core.CreateIdentifierFromFilename(Path.GetFileName(sourceFile)); | ||
1852 | } | ||
1853 | |||
1854 | if (null == id) | ||
1855 | { | ||
1856 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1857 | id = Identifier.Invalid; | ||
1858 | } | ||
1859 | else if (!Common.IsIdentifier(id.Id)) | ||
1860 | { | ||
1861 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
1862 | } | ||
1863 | } | ||
1864 | |||
1865 | if (null == logPathVariable) | ||
1866 | { | ||
1867 | logPathVariable = String.Concat("WixBundleLog_", id.Id); | ||
1868 | } | ||
1869 | |||
1870 | if (null == rollbackPathVariable) | ||
1871 | { | ||
1872 | rollbackPathVariable = String.Concat("WixBundleRollbackLog_", id.Id); | ||
1873 | } | ||
1874 | |||
1875 | if (!String.IsNullOrEmpty(protocol) && !protocol.Equals("burn", StringComparison.Ordinal) && !protocol.Equals("netfx4", StringComparison.Ordinal) && !protocol.Equals("none", StringComparison.Ordinal)) | ||
1876 | { | ||
1877 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Protocol", protocol, "none, burn, netfx4")); | ||
1878 | } | ||
1879 | |||
1880 | if (!String.IsNullOrEmpty(protocol) && protocol.Equals("netfx4", StringComparison.Ordinal)) | ||
1881 | { | ||
1882 | foreach (var expectedArgument in expectedNetFx4Args) | ||
1883 | { | ||
1884 | if (null == installCommand || -1 == installCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
1885 | { | ||
1886 | this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "InstallCommand", installCommand, expectedArgument, "Protocol", "netfx4")); | ||
1887 | } | ||
1888 | |||
1889 | if (null == repairCommand || -1 == repairCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
1890 | { | ||
1891 | this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "RepairCommand", repairCommand, expectedArgument, "Protocol", "netfx4")); | ||
1892 | } | ||
1893 | |||
1894 | if (null == uninstallCommand || -1 == uninstallCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
1895 | { | ||
1896 | this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "UninstallCommand", uninstallCommand, expectedArgument, "Protocol", "netfx4")); | ||
1897 | } | ||
1898 | } | ||
1899 | } | ||
1900 | |||
1901 | // Only set default scope for EXEs and MSPs if not already set. | ||
1902 | if ((WixBundlePackageType.Exe == packageType || WixBundlePackageType.Msp == packageType) && YesNoDefaultType.NotSet == perMachine) | ||
1903 | { | ||
1904 | perMachine = YesNoDefaultType.Default; | ||
1905 | } | ||
1906 | |||
1907 | // Now that the package ID is known, we can parse the extension attributes... | ||
1908 | var contextValues = new Dictionary<string, string>() { { "PackageId", id.Id } }; | ||
1909 | foreach (var attribute in extensionAttributes) | ||
1910 | { | ||
1911 | this.Core.ParseExtensionAttribute(node, attribute, contextValues); | ||
1912 | } | ||
1913 | |||
1914 | foreach (var child in node.Elements()) | ||
1915 | { | ||
1916 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1917 | { | ||
1918 | var allowed = true; | ||
1919 | switch (child.Name.LocalName) | ||
1920 | { | ||
1921 | case "SlipstreamMsp": | ||
1922 | allowed = (packageType == WixBundlePackageType.Msi); | ||
1923 | if (allowed) | ||
1924 | { | ||
1925 | this.ParseSlipstreamMspElement(child, id.Id); | ||
1926 | } | ||
1927 | break; | ||
1928 | case "MsiProperty": | ||
1929 | allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp); | ||
1930 | if (allowed) | ||
1931 | { | ||
1932 | this.ParseMsiPropertyElement(child, id.Id); | ||
1933 | } | ||
1934 | break; | ||
1935 | case "Payload": | ||
1936 | this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id.Id, ComplexReferenceChildType.Unknown, null); | ||
1937 | break; | ||
1938 | case "PayloadGroupRef": | ||
1939 | this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id.Id, ComplexReferenceChildType.Unknown, null); | ||
1940 | break; | ||
1941 | case "ExitCode": | ||
1942 | allowed = (packageType == WixBundlePackageType.Exe); | ||
1943 | if (allowed) | ||
1944 | { | ||
1945 | this.ParseExitCodeElement(child, id.Id); | ||
1946 | } | ||
1947 | break; | ||
1948 | case "CommandLine": | ||
1949 | allowed = (packageType == WixBundlePackageType.Exe); | ||
1950 | if (allowed) | ||
1951 | { | ||
1952 | this.ParseCommandLineElement(child, id.Id); | ||
1953 | } | ||
1954 | break; | ||
1955 | case "RemotePayload": | ||
1956 | // Handled previously | ||
1957 | break; | ||
1958 | default: | ||
1959 | allowed = false; | ||
1960 | break; | ||
1961 | } | ||
1962 | |||
1963 | if (!allowed) | ||
1964 | { | ||
1965 | this.Core.UnexpectedElement(node, child); | ||
1966 | } | ||
1967 | } | ||
1968 | else | ||
1969 | { | ||
1970 | var context = new Dictionary<string, string>() { { "Id", id.Id } }; | ||
1971 | this.Core.ParseExtensionElement(node, child, context); | ||
1972 | } | ||
1973 | } | ||
1974 | |||
1975 | if (!this.Core.EncounteredError) | ||
1976 | { | ||
1977 | // We create the package contents as a payload with this package as the parent | ||
1978 | this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, ComplexReferenceParentType.Package, id.Id, | ||
1979 | ComplexReferenceChildType.Unknown, null, compressed, enableSignatureVerification, displayName, description, remotePayload); | ||
1980 | |||
1981 | var chainItemRow = (WixChainItemTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixChainItem, id); | ||
1982 | |||
1983 | WixBundlePackageAttributes attributes = 0; | ||
1984 | attributes |= (YesNoType.Yes == permanent) ? WixBundlePackageAttributes.Permanent : 0; | ||
1985 | attributes |= (YesNoType.Yes == visible) ? WixBundlePackageAttributes.Visible : 0; | ||
1986 | |||
1987 | var chainPackageRow = (WixBundlePackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackage, id); | ||
1988 | chainPackageRow.Type = packageType; | ||
1989 | chainPackageRow.Payload_ = id.Id; | ||
1990 | chainPackageRow.Attributes = attributes; | ||
1991 | |||
1992 | chainPackageRow.InstallCondition = installCondition; | ||
1993 | |||
1994 | if (YesNoAlwaysType.NotSet != cache) | ||
1995 | { | ||
1996 | chainPackageRow.Cache = cache; | ||
1997 | } | ||
1998 | |||
1999 | chainPackageRow.CacheId = cacheId; | ||
2000 | |||
2001 | if (YesNoType.NotSet != vital) | ||
2002 | { | ||
2003 | chainPackageRow.Vital = (vital == YesNoType.Yes); | ||
2004 | } | ||
2005 | |||
2006 | if (YesNoDefaultType.NotSet != perMachine) | ||
2007 | { | ||
2008 | chainPackageRow.PerMachine = perMachine; | ||
2009 | } | ||
2010 | |||
2011 | chainPackageRow.LogPathVariable = logPathVariable; | ||
2012 | chainPackageRow.RollbackLogPathVariable = rollbackPathVariable; | ||
2013 | |||
2014 | if (CompilerConstants.IntegerNotSet != installSize) | ||
2015 | { | ||
2016 | chainPackageRow.InstallSize = installSize; | ||
2017 | } | ||
2018 | |||
2019 | switch (packageType) | ||
2020 | { | ||
2021 | case WixBundlePackageType.Exe: | ||
2022 | WixBundleExePackageAttributes exeAttributes = 0; | ||
2023 | exeAttributes |= (YesNoType.Yes == repairable) ? WixBundleExePackageAttributes.Repairable : 0; | ||
2024 | |||
2025 | var exeRow = (WixBundleExePackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleExePackage, id); | ||
2026 | exeRow.Attributes = exeAttributes; | ||
2027 | exeRow.DetectCondition = detectCondition; | ||
2028 | exeRow.InstallCommand = installCommand; | ||
2029 | exeRow.RepairCommand = repairCommand; | ||
2030 | exeRow.UninstallCommand = uninstallCommand; | ||
2031 | exeRow.ExeProtocol = protocol; | ||
2032 | break; | ||
2033 | |||
2034 | case WixBundlePackageType.Msi: | ||
2035 | WixBundleMsiPackageAttributes msiAttributes = 0; | ||
2036 | msiAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMsiPackageAttributes.DisplayInternalUI : 0; | ||
2037 | msiAttributes |= (YesNoType.Yes == enableFeatureSelection) ? WixBundleMsiPackageAttributes.EnableFeatureSelection : 0; | ||
2038 | msiAttributes |= (YesNoType.Yes == forcePerMachine) ? WixBundleMsiPackageAttributes.ForcePerMachine : 0; | ||
2039 | msiAttributes |= (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? WixBundleMsiPackageAttributes.SuppressLooseFilePayloadGeneration : 0; | ||
2040 | |||
2041 | var msiRow = (WixBundleMsiPackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMsiPackage, id); | ||
2042 | msiRow.Attributes = msiAttributes; | ||
2043 | break; | ||
2044 | |||
2045 | case WixBundlePackageType.Msp: | ||
2046 | WixBundleMspPackageAttributes mspAttributes = 0; | ||
2047 | mspAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMspPackageAttributes.DisplayInternalUI : 0; | ||
2048 | mspAttributes |= (YesNoType.Yes == slipstream) ? WixBundleMspPackageAttributes.Slipstream : 0; | ||
2049 | |||
2050 | var mspRow = (WixBundleMspPackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMspPackage, id); | ||
2051 | mspRow.Attributes = mspAttributes; | ||
2052 | break; | ||
2053 | |||
2054 | case WixBundlePackageType.Msu: | ||
2055 | var msuRow = (WixBundleMsuPackageTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMsuPackage, id); | ||
2056 | msuRow.DetectCondition = detectCondition; | ||
2057 | msuRow.MsuKB = msuKB; | ||
2058 | break; | ||
2059 | } | ||
2060 | |||
2061 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, after); | ||
2062 | } | ||
2063 | |||
2064 | return id.Id; | ||
2065 | } | ||
2066 | |||
2067 | /// <summary> | ||
2068 | /// Parse CommandLine element. | ||
2069 | /// </summary> | ||
2070 | /// <param name="node">Element to parse</param> | ||
2071 | private void ParseCommandLineElement(XElement node, string packageId) | ||
2072 | { | ||
2073 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2074 | string installArgument = null; | ||
2075 | string uninstallArgument = null; | ||
2076 | string repairArgument = null; | ||
2077 | string condition = null; | ||
2078 | |||
2079 | foreach (var attrib in node.Attributes()) | ||
2080 | { | ||
2081 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2082 | { | ||
2083 | switch (attrib.Name.LocalName) | ||
2084 | { | ||
2085 | case "InstallArgument": | ||
2086 | installArgument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2087 | break; | ||
2088 | case "UninstallArgument": | ||
2089 | uninstallArgument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2090 | break; | ||
2091 | case "RepairArgument": | ||
2092 | repairArgument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2093 | break; | ||
2094 | case "Condition": | ||
2095 | condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2096 | break; | ||
2097 | default: | ||
2098 | this.Core.UnexpectedAttribute(node, attrib); | ||
2099 | break; | ||
2100 | } | ||
2101 | } | ||
2102 | else | ||
2103 | { | ||
2104 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2105 | } | ||
2106 | } | ||
2107 | |||
2108 | if (String.IsNullOrEmpty(condition)) | ||
2109 | { | ||
2110 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Condition")); | ||
2111 | } | ||
2112 | |||
2113 | this.Core.ParseForExtensionElements(node); | ||
2114 | |||
2115 | if (!this.Core.EncounteredError) | ||
2116 | { | ||
2117 | var row = (WixBundlePackageCommandLineTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackageCommandLine); | ||
2118 | row.WixBundlePackage_ = packageId; | ||
2119 | row.InstallArgument = installArgument; | ||
2120 | row.UninstallArgument = uninstallArgument; | ||
2121 | row.RepairArgument = repairArgument; | ||
2122 | row.Condition = condition; | ||
2123 | } | ||
2124 | } | ||
2125 | |||
2126 | /// <summary> | ||
2127 | /// Parse PackageGroup element. | ||
2128 | /// </summary> | ||
2129 | /// <param name="node">Element to parse</param> | ||
2130 | private void ParsePackageGroupElement(XElement node) | ||
2131 | { | ||
2132 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2133 | Identifier id = null; | ||
2134 | |||
2135 | foreach (var attrib in node.Attributes()) | ||
2136 | { | ||
2137 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2138 | { | ||
2139 | switch (attrib.Name.LocalName) | ||
2140 | { | ||
2141 | case "Id": | ||
2142 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2143 | break; | ||
2144 | default: | ||
2145 | this.Core.UnexpectedAttribute(node, attrib); | ||
2146 | break; | ||
2147 | } | ||
2148 | } | ||
2149 | else | ||
2150 | { | ||
2151 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2152 | } | ||
2153 | } | ||
2154 | |||
2155 | if (null == id) | ||
2156 | { | ||
2157 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2158 | id = Identifier.Invalid; | ||
2159 | } | ||
2160 | |||
2161 | var previousType = ComplexReferenceChildType.Unknown; | ||
2162 | string previousId = null; | ||
2163 | foreach (var child in node.Elements()) | ||
2164 | { | ||
2165 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2166 | { | ||
2167 | switch (child.Name.LocalName) | ||
2168 | { | ||
2169 | case "MsiPackage": | ||
2170 | previousId = this.ParseMsiPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
2171 | previousType = ComplexReferenceChildType.Package; | ||
2172 | break; | ||
2173 | case "MspPackage": | ||
2174 | previousId = this.ParseMspPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
2175 | previousType = ComplexReferenceChildType.Package; | ||
2176 | break; | ||
2177 | case "MsuPackage": | ||
2178 | previousId = this.ParseMsuPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
2179 | previousType = ComplexReferenceChildType.Package; | ||
2180 | break; | ||
2181 | case "ExePackage": | ||
2182 | previousId = this.ParseExePackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
2183 | previousType = ComplexReferenceChildType.Package; | ||
2184 | break; | ||
2185 | case "RollbackBoundary": | ||
2186 | previousId = this.ParseRollbackBoundaryElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
2187 | previousType = ComplexReferenceChildType.Package; | ||
2188 | break; | ||
2189 | case "PackageGroupRef": | ||
2190 | previousId = this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
2191 | previousType = ComplexReferenceChildType.PackageGroup; | ||
2192 | break; | ||
2193 | default: | ||
2194 | this.Core.UnexpectedElement(node, child); | ||
2195 | break; | ||
2196 | } | ||
2197 | } | ||
2198 | else | ||
2199 | { | ||
2200 | this.Core.ParseExtensionElement(node, child); | ||
2201 | } | ||
2202 | } | ||
2203 | |||
2204 | |||
2205 | if (!this.Core.EncounteredError) | ||
2206 | { | ||
2207 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundlePackageGroup, id); | ||
2208 | } | ||
2209 | } | ||
2210 | |||
2211 | /// <summary> | ||
2212 | /// Parses a package group reference element. | ||
2213 | /// </summary> | ||
2214 | /// <param name="node">Element to parse.</param> | ||
2215 | /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> | ||
2216 | /// <param name="parentId">Identifier of parent element.</param> | ||
2217 | /// <returns>Identifier for package group element.</rereturns> | ||
2218 | private string ParsePackageGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
2219 | { | ||
2220 | return this.ParsePackageGroupRefElement(node, parentType, parentId, ComplexReferenceChildType.Unknown, null); | ||
2221 | } | ||
2222 | |||
2223 | /// <summary> | ||
2224 | /// Parses a package group reference element. | ||
2225 | /// </summary> | ||
2226 | /// <param name="node">Element to parse.</param> | ||
2227 | /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> | ||
2228 | /// <param name="parentId">Identifier of parent element.</param> | ||
2229 | /// <param name="parentType">ComplexReferenceParentType of previous element (Unknown, Package, or PackageGroup).</param> | ||
2230 | /// <param name="parentId">Identifier of parent element.</param> | ||
2231 | /// <returns>Identifier for package group element.</rereturns> | ||
2232 | private string ParsePackageGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
2233 | { | ||
2234 | Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.PackageGroup == parentType || ComplexReferenceParentType.Container == parentType); | ||
2235 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
2236 | |||
2237 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2238 | string id = null; | ||
2239 | string after = null; | ||
2240 | |||
2241 | foreach (var attrib in node.Attributes()) | ||
2242 | { | ||
2243 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2244 | { | ||
2245 | switch (attrib.Name.LocalName) | ||
2246 | { | ||
2247 | case "Id": | ||
2248 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2249 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBundlePackageGroup", id); | ||
2250 | break; | ||
2251 | case "After": | ||
2252 | after = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2253 | break; | ||
2254 | default: | ||
2255 | this.Core.UnexpectedAttribute(node, attrib); | ||
2256 | break; | ||
2257 | } | ||
2258 | } | ||
2259 | else | ||
2260 | { | ||
2261 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2262 | |||
2263 | } | ||
2264 | } | ||
2265 | |||
2266 | if (null == id) | ||
2267 | { | ||
2268 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2269 | } | ||
2270 | |||
2271 | if (null != after && ComplexReferenceParentType.Container == parentType) | ||
2272 | { | ||
2273 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "After", parentId)); | ||
2274 | } | ||
2275 | |||
2276 | this.Core.ParseForExtensionElements(node); | ||
2277 | |||
2278 | if (ComplexReferenceParentType.Container == parentType) | ||
2279 | { | ||
2280 | this.Core.CreateWixGroupRow(sourceLineNumbers, ComplexReferenceParentType.Container, parentId, ComplexReferenceChildType.PackageGroup, id); | ||
2281 | } | ||
2282 | else | ||
2283 | { | ||
2284 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PackageGroup, id, previousType, previousId, after); | ||
2285 | } | ||
2286 | |||
2287 | return id; | ||
2288 | } | ||
2289 | |||
2290 | /// <summary> | ||
2291 | /// Creates rollback boundary. | ||
2292 | /// </summary> | ||
2293 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
2294 | /// <param name="id">Identifier for the rollback boundary.</param> | ||
2295 | /// <param name="vital">Indicates whether the rollback boundary is vital or not.</param> | ||
2296 | /// <param name="parentType">Type of parent group.</param> | ||
2297 | /// <param name="parentId">Identifier of parent group.</param> | ||
2298 | /// <param name="previousType">Type of previous item, if any.</param> | ||
2299 | /// <param name="previousId">Identifier of previous item, if any.</param> | ||
2300 | private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
2301 | { | ||
2302 | var row = (WixChainItemTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixChainItem, id); | ||
2303 | |||
2304 | var rollbackBoundary = (WixBundleRollbackBoundaryTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleRollbackBoundary, id); | ||
2305 | |||
2306 | if (YesNoType.NotSet != vital) | ||
2307 | { | ||
2308 | rollbackBoundary.Vital = (vital == YesNoType.Yes); | ||
2309 | } | ||
2310 | if (YesNoType.NotSet != transaction) | ||
2311 | { | ||
2312 | rollbackBoundary.Transaction = (transaction == YesNoType.Yes); | ||
2313 | } | ||
2314 | |||
2315 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, null); | ||
2316 | } | ||
2317 | |||
2318 | /// <summary> | ||
2319 | /// Creates group and ordering information for packages | ||
2320 | /// </summary> | ||
2321 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
2322 | /// <param name="parentType">Type of parent group, if known.</param> | ||
2323 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
2324 | /// <param name="type">Type of this item.</param> | ||
2325 | /// <param name="id">Identifier for this item.</param> | ||
2326 | /// <param name="previousType">Type of previous item, if known.</param> | ||
2327 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
2328 | /// <param name="afterId">Identifier of explicit 'After' attribute, if given.</param> | ||
2329 | private void CreateChainPackageMetaRows(SourceLineNumber sourceLineNumbers, | ||
2330 | ComplexReferenceParentType parentType, string parentId, | ||
2331 | ComplexReferenceChildType type, string id, | ||
2332 | ComplexReferenceChildType previousType, string previousId, string afterId) | ||
2333 | { | ||
2334 | // If there's an explicit 'After' attribute, it overrides the inferred previous item. | ||
2335 | if (null != afterId) | ||
2336 | { | ||
2337 | previousType = ComplexReferenceChildType.Package; | ||
2338 | previousId = afterId; | ||
2339 | } | ||
2340 | |||
2341 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, type, id, previousType, previousId); | ||
2342 | } | ||
2343 | |||
2344 | // TODO: Should we define our own enum for this, just to ensure there's no "cross-contamination"? | ||
2345 | // TODO: Also, we could potentially include an 'Attributes' field to track things like | ||
2346 | // 'before' vs. 'after', and explicit vs. inferred dependencies. | ||
2347 | private void CreateWixOrderingRow(SourceLineNumber sourceLineNumbers, | ||
2348 | ComplexReferenceChildType itemType, string itemId, | ||
2349 | ComplexReferenceChildType dependsOnType, string dependsOnId) | ||
2350 | { | ||
2351 | if (!this.Core.EncounteredError) | ||
2352 | { | ||
2353 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixOrdering); | ||
2354 | row.Set(0, itemType.ToString()); | ||
2355 | row.Set(1, itemId); | ||
2356 | row.Set(2, dependsOnType.ToString()); | ||
2357 | row.Set(3, dependsOnId); | ||
2358 | } | ||
2359 | } | ||
2360 | |||
2361 | /// <summary> | ||
2362 | /// Parse MsiProperty element | ||
2363 | /// </summary> | ||
2364 | /// <param name="node">Element to parse</param> | ||
2365 | /// <param name="packageId">Id of parent element</param> | ||
2366 | private void ParseMsiPropertyElement(XElement node, string packageId) | ||
2367 | { | ||
2368 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2369 | string name = null; | ||
2370 | string value = null; | ||
2371 | string condition = null; | ||
2372 | |||
2373 | foreach (var attrib in node.Attributes()) | ||
2374 | { | ||
2375 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2376 | { | ||
2377 | switch (attrib.Name.LocalName) | ||
2378 | { | ||
2379 | case "Name": | ||
2380 | name = this.Core.GetAttributeMsiPropertyNameValue(sourceLineNumbers, attrib); | ||
2381 | break; | ||
2382 | case "Value": | ||
2383 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2384 | break; | ||
2385 | case "Condition": | ||
2386 | condition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2387 | break; | ||
2388 | default: | ||
2389 | this.Core.UnexpectedAttribute(node, attrib); | ||
2390 | break; | ||
2391 | } | ||
2392 | } | ||
2393 | else | ||
2394 | { | ||
2395 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2396 | } | ||
2397 | } | ||
2398 | |||
2399 | if (null == name) | ||
2400 | { | ||
2401 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
2402 | } | ||
2403 | |||
2404 | if (null == value) | ||
2405 | { | ||
2406 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
2407 | } | ||
2408 | |||
2409 | this.Core.ParseForExtensionElements(node); | ||
2410 | |||
2411 | if (!this.Core.EncounteredError) | ||
2412 | { | ||
2413 | var row = (WixBundleMsiPropertyTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleMsiProperty); | ||
2414 | row.WixBundlePackage_ = packageId; | ||
2415 | row.Name = name; | ||
2416 | row.Value = value; | ||
2417 | |||
2418 | if (!String.IsNullOrEmpty(condition)) | ||
2419 | { | ||
2420 | row.Condition = condition; | ||
2421 | } | ||
2422 | } | ||
2423 | } | ||
2424 | |||
2425 | /// <summary> | ||
2426 | /// Parse SlipstreamMsp element | ||
2427 | /// </summary> | ||
2428 | /// <param name="node">Element to parse</param> | ||
2429 | /// <param name="packageId">Id of parent element</param> | ||
2430 | private void ParseSlipstreamMspElement(XElement node, string packageId) | ||
2431 | { | ||
2432 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2433 | string id = null; | ||
2434 | |||
2435 | foreach (var attrib in node.Attributes()) | ||
2436 | { | ||
2437 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2438 | { | ||
2439 | switch (attrib.Name.LocalName) | ||
2440 | { | ||
2441 | case "Id": | ||
2442 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2443 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixBundlePackage", id); | ||
2444 | break; | ||
2445 | default: | ||
2446 | this.Core.UnexpectedAttribute(node, attrib); | ||
2447 | break; | ||
2448 | } | ||
2449 | } | ||
2450 | else | ||
2451 | { | ||
2452 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2453 | } | ||
2454 | } | ||
2455 | |||
2456 | if (null == id) | ||
2457 | { | ||
2458 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2459 | } | ||
2460 | |||
2461 | this.Core.ParseForExtensionElements(node); | ||
2462 | |||
2463 | if (!this.Core.EncounteredError) | ||
2464 | { | ||
2465 | var row = (WixBundleSlipstreamMspTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleSlipstreamMsp); | ||
2466 | row.WixBundlePackage_ = packageId; | ||
2467 | row.WixBundlePackage_Msp = id; | ||
2468 | } | ||
2469 | } | ||
2470 | |||
2471 | /// <summary> | ||
2472 | /// Parse RelatedBundle element | ||
2473 | /// </summary> | ||
2474 | /// <param name="node">Element to parse</param> | ||
2475 | private void ParseRelatedBundleElement(XElement node) | ||
2476 | { | ||
2477 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2478 | string id = null; | ||
2479 | var actionType = RelatedBundleActionType.Detect; | ||
2480 | |||
2481 | foreach (var attrib in node.Attributes()) | ||
2482 | { | ||
2483 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2484 | { | ||
2485 | switch (attrib.Name.LocalName) | ||
2486 | { | ||
2487 | case "Id": | ||
2488 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
2489 | break; | ||
2490 | case "Action": | ||
2491 | var action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2492 | switch (action) | ||
2493 | { | ||
2494 | case "Detect": | ||
2495 | case "detect": | ||
2496 | actionType = RelatedBundleActionType.Detect; | ||
2497 | break; | ||
2498 | case "Upgrade": | ||
2499 | case "upgrade": | ||
2500 | actionType = RelatedBundleActionType.Upgrade; | ||
2501 | break; | ||
2502 | case "Addon": | ||
2503 | case "addon": | ||
2504 | actionType = RelatedBundleActionType.Addon; | ||
2505 | break; | ||
2506 | case "Patch": | ||
2507 | case "patch": | ||
2508 | actionType = RelatedBundleActionType.Patch; | ||
2509 | break; | ||
2510 | case "": | ||
2511 | break; | ||
2512 | default: | ||
2513 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", action, "Detect", "Upgrade", "Addon", "Patch")); | ||
2514 | break; | ||
2515 | } | ||
2516 | break; | ||
2517 | default: | ||
2518 | this.Core.UnexpectedAttribute(node, attrib); | ||
2519 | break; | ||
2520 | } | ||
2521 | } | ||
2522 | else | ||
2523 | { | ||
2524 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2525 | } | ||
2526 | } | ||
2527 | |||
2528 | if (null == id) | ||
2529 | { | ||
2530 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2531 | } | ||
2532 | |||
2533 | this.Core.ParseForExtensionElements(node); | ||
2534 | |||
2535 | if (!this.Core.EncounteredError) | ||
2536 | { | ||
2537 | var tuple = new WixRelatedBundleTuple(sourceLineNumbers) | ||
2538 | { | ||
2539 | BundleId = id, | ||
2540 | Action = actionType, | ||
2541 | }; | ||
2542 | |||
2543 | this.Core.AddTuple(tuple); | ||
2544 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixRelatedBundle); | ||
2545 | //row.Set(0, id); | ||
2546 | //row.Set(1, (int)actionType); | ||
2547 | } | ||
2548 | } | ||
2549 | |||
2550 | /// <summary> | ||
2551 | /// Parse Update element | ||
2552 | /// </summary> | ||
2553 | /// <param name="node">Element to parse</param> | ||
2554 | private void ParseUpdateElement(XElement node) | ||
2555 | { | ||
2556 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2557 | string location = null; | ||
2558 | |||
2559 | foreach (var attrib in node.Attributes()) | ||
2560 | { | ||
2561 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2562 | { | ||
2563 | switch (attrib.Name.LocalName) | ||
2564 | { | ||
2565 | case "Location": | ||
2566 | location = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2567 | break; | ||
2568 | default: | ||
2569 | this.Core.UnexpectedAttribute(node, attrib); | ||
2570 | break; | ||
2571 | } | ||
2572 | } | ||
2573 | else | ||
2574 | { | ||
2575 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2576 | } | ||
2577 | } | ||
2578 | |||
2579 | if (null == location) | ||
2580 | { | ||
2581 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Location")); | ||
2582 | } | ||
2583 | |||
2584 | this.Core.ParseForExtensionElements(node); | ||
2585 | |||
2586 | if (!this.Core.EncounteredError) | ||
2587 | { | ||
2588 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleUpdate); | ||
2589 | row.Set(0, location); | ||
2590 | } | ||
2591 | } | ||
2592 | |||
2593 | /// <summary> | ||
2594 | /// Parse Variable element | ||
2595 | /// </summary> | ||
2596 | /// <param name="node">Element to parse</param> | ||
2597 | private void ParseVariableElement(XElement node) | ||
2598 | { | ||
2599 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2600 | var hidden = false; | ||
2601 | string name = null; | ||
2602 | var persisted = false; | ||
2603 | string value = null; | ||
2604 | string type = null; | ||
2605 | |||
2606 | foreach (var attrib in node.Attributes()) | ||
2607 | { | ||
2608 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2609 | { | ||
2610 | switch (attrib.Name.LocalName) | ||
2611 | { | ||
2612 | case "Hidden": | ||
2613 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2614 | { | ||
2615 | hidden = true; | ||
2616 | } | ||
2617 | break; | ||
2618 | case "Name": | ||
2619 | name = this.Core.GetAttributeBundleVariableValue(sourceLineNumbers, attrib); | ||
2620 | break; | ||
2621 | case "Persisted": | ||
2622 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2623 | { | ||
2624 | persisted = true; | ||
2625 | } | ||
2626 | break; | ||
2627 | case "Value": | ||
2628 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
2629 | break; | ||
2630 | case "Type": | ||
2631 | type = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2632 | break; | ||
2633 | default: | ||
2634 | this.Core.UnexpectedAttribute(node, attrib); | ||
2635 | break; | ||
2636 | } | ||
2637 | } | ||
2638 | else | ||
2639 | { | ||
2640 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2641 | } | ||
2642 | } | ||
2643 | |||
2644 | if (null == name) | ||
2645 | { | ||
2646 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
2647 | } | ||
2648 | else if (name.StartsWith("Wix", StringComparison.OrdinalIgnoreCase)) | ||
2649 | { | ||
2650 | this.Core.Write(ErrorMessages.ReservedNamespaceViolation(sourceLineNumbers, node.Name.LocalName, "Name", "Wix")); | ||
2651 | } | ||
2652 | |||
2653 | if (null == type && null != value) | ||
2654 | { | ||
2655 | // Infer the type from the current value... | ||
2656 | if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) | ||
2657 | { | ||
2658 | // Version constructor does not support simple "v#" syntax so check to see if the value is | ||
2659 | // non-negative real quick. | ||
2660 | if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out var number)) | ||
2661 | { | ||
2662 | type = "version"; | ||
2663 | } | ||
2664 | else | ||
2665 | { | ||
2666 | // Sadly, Version doesn't have a TryParse() method until .NET 4, so we have to try/catch to see if it parses. | ||
2667 | try | ||
2668 | { | ||
2669 | var version = new Version(value.Substring(1)); | ||
2670 | type = "version"; | ||
2671 | } | ||
2672 | catch (Exception) | ||
2673 | { | ||
2674 | } | ||
2675 | } | ||
2676 | } | ||
2677 | |||
2678 | // Not a version, check for numeric. | ||
2679 | if (null == type) | ||
2680 | { | ||
2681 | if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out var number)) | ||
2682 | { | ||
2683 | type = "numeric"; | ||
2684 | } | ||
2685 | else | ||
2686 | { | ||
2687 | type = "string"; | ||
2688 | } | ||
2689 | } | ||
2690 | } | ||
2691 | |||
2692 | if (null == value && null != type) | ||
2693 | { | ||
2694 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, "Variable", "Value", "Type")); | ||
2695 | } | ||
2696 | |||
2697 | this.Core.ParseForExtensionElements(node); | ||
2698 | |||
2699 | if (!this.Core.EncounteredError) | ||
2700 | { | ||
2701 | var row = (WixBundleVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixBundleVariable); | ||
2702 | row.WixBundleVariable = name; | ||
2703 | row.Value = value; | ||
2704 | row.Type = type; | ||
2705 | row.Hidden = hidden; | ||
2706 | row.Persisted = persisted; | ||
2707 | } | ||
2708 | } | ||
2709 | |||
2710 | private class RemotePayload | ||
2711 | { | ||
2712 | public string CertificatePublicKey { get; set; } | ||
2713 | |||
2714 | public string CertificateThumbprint { get; set; } | ||
2715 | |||
2716 | public string Description { get; set; } | ||
2717 | |||
2718 | public string Hash { get; set; } | ||
2719 | |||
2720 | public string ProductName { get; set; } | ||
2721 | |||
2722 | public int Size { get; set; } | ||
2723 | |||
2724 | public string Version { get; set; } | ||
2725 | } | ||
2726 | } | ||
2727 | } | ||
diff --git a/src/WixToolset.Core/Compiler_EmbeddedUI.cs b/src/WixToolset.Core/Compiler_EmbeddedUI.cs new file mode 100644 index 00000000..3245941e --- /dev/null +++ b/src/WixToolset.Core/Compiler_EmbeddedUI.cs | |||
@@ -0,0 +1,417 @@ | |||
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 | namespace WixToolset.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.Xml.Linq; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.Tuples; | ||
10 | using WixToolset.Data.WindowsInstaller; | ||
11 | |||
12 | /// <summary> | ||
13 | /// Compiler of the WiX toolset. | ||
14 | /// </summary> | ||
15 | internal partial class Compiler : ICompiler | ||
16 | { | ||
17 | /// <summary> | ||
18 | /// Parses an EmbeddedChaniner element. | ||
19 | /// </summary> | ||
20 | /// <param name="node">Element to parse.</param> | ||
21 | private void ParseEmbeddedChainerElement(XElement node) | ||
22 | { | ||
23 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
24 | Identifier id = null; | ||
25 | string commandLine = null; | ||
26 | string source = null; | ||
27 | var type = 0; | ||
28 | |||
29 | foreach (var attrib in node.Attributes()) | ||
30 | { | ||
31 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
32 | { | ||
33 | switch (attrib.Name.LocalName) | ||
34 | { | ||
35 | case "Id": | ||
36 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
37 | break; | ||
38 | case "BinarySource": | ||
39 | if (null != source) | ||
40 | { | ||
41 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "FileSource", "PropertySource")); | ||
42 | } | ||
43 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
44 | type = 0x2; | ||
45 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", source); // add a reference to the appropriate Binary | ||
46 | break; | ||
47 | case "CommandLine": | ||
48 | commandLine = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
49 | break; | ||
50 | case "FileSource": | ||
51 | if (null != source) | ||
52 | { | ||
53 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinarySource", "PropertySource")); | ||
54 | } | ||
55 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
56 | type = 0x12; | ||
57 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", source); // add a reference to the appropriate File | ||
58 | break; | ||
59 | case "PropertySource": | ||
60 | if (null != source) | ||
61 | { | ||
62 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinarySource", "FileSource")); | ||
63 | } | ||
64 | source = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
65 | type = 0x32; | ||
66 | // cannot add a reference to a Property because it may be created at runtime. | ||
67 | break; | ||
68 | default: | ||
69 | this.Core.UnexpectedAttribute(node, attrib); | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | else | ||
74 | { | ||
75 | this.Core.ParseExtensionAttribute(node, attrib); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | // Get the condition from the inner text of the element. | ||
80 | var condition = this.Core.GetConditionInnerText(node); | ||
81 | |||
82 | if (null == id) | ||
83 | { | ||
84 | id = this.Core.CreateIdentifier("mec", source, type.ToString()); | ||
85 | } | ||
86 | |||
87 | if (null == source) | ||
88 | { | ||
89 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "BinarySource", "FileSource", "PropertySource")); | ||
90 | } | ||
91 | |||
92 | if (!this.Core.EncounteredError) | ||
93 | { | ||
94 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiEmbeddedChainer, id); | ||
95 | row.Set(1, condition); | ||
96 | row.Set(2, commandLine); | ||
97 | row.Set(3, source); | ||
98 | row.Set(4, type); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /// <summary> | ||
103 | /// Parses an EmbeddedUI element. | ||
104 | /// </summary> | ||
105 | /// <param name="node">Element to parse.</param> | ||
106 | private void ParseEmbeddedUIElement(XElement node) | ||
107 | { | ||
108 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
109 | Identifier id = null; | ||
110 | string name = null; | ||
111 | var supportsBasicUI = false; | ||
112 | var messageFilter = WindowsInstallerConstants.INSTALLLOGMODE_FATALEXIT | WindowsInstallerConstants.INSTALLLOGMODE_ERROR | WindowsInstallerConstants.INSTALLLOGMODE_WARNING | WindowsInstallerConstants.INSTALLLOGMODE_USER | ||
113 | | WindowsInstallerConstants.INSTALLLOGMODE_INFO | WindowsInstallerConstants.INSTALLLOGMODE_FILESINUSE | WindowsInstallerConstants.INSTALLLOGMODE_RESOLVESOURCE | ||
114 | | WindowsInstallerConstants.INSTALLLOGMODE_OUTOFDISKSPACE | WindowsInstallerConstants.INSTALLLOGMODE_ACTIONSTART | WindowsInstallerConstants.INSTALLLOGMODE_ACTIONDATA | ||
115 | | WindowsInstallerConstants.INSTALLLOGMODE_PROGRESS | WindowsInstallerConstants.INSTALLLOGMODE_COMMONDATA | WindowsInstallerConstants.INSTALLLOGMODE_INITIALIZE | ||
116 | | WindowsInstallerConstants.INSTALLLOGMODE_TERMINATE | WindowsInstallerConstants.INSTALLLOGMODE_SHOWDIALOG | WindowsInstallerConstants.INSTALLLOGMODE_RMFILESINUSE | ||
117 | | WindowsInstallerConstants.INSTALLLOGMODE_INSTALLSTART | WindowsInstallerConstants.INSTALLLOGMODE_INSTALLEND; | ||
118 | string sourceFile = null; | ||
119 | |||
120 | foreach (var attrib in node.Attributes()) | ||
121 | { | ||
122 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
123 | { | ||
124 | switch (attrib.Name.LocalName) | ||
125 | { | ||
126 | case "Id": | ||
127 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
128 | break; | ||
129 | case "Name": | ||
130 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
131 | break; | ||
132 | case "IgnoreFatalExit": | ||
133 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
134 | { | ||
135 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_FATALEXIT; | ||
136 | } | ||
137 | break; | ||
138 | case "IgnoreError": | ||
139 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
140 | { | ||
141 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_ERROR; | ||
142 | } | ||
143 | break; | ||
144 | case "IgnoreWarning": | ||
145 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
146 | { | ||
147 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_WARNING; | ||
148 | } | ||
149 | break; | ||
150 | case "IgnoreUser": | ||
151 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
152 | { | ||
153 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_USER; | ||
154 | } | ||
155 | break; | ||
156 | case "IgnoreInfo": | ||
157 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
158 | { | ||
159 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_INFO; | ||
160 | } | ||
161 | break; | ||
162 | case "IgnoreFilesInUse": | ||
163 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
164 | { | ||
165 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_FILESINUSE; | ||
166 | } | ||
167 | break; | ||
168 | case "IgnoreResolveSource": | ||
169 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
170 | { | ||
171 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_RESOLVESOURCE; | ||
172 | } | ||
173 | break; | ||
174 | case "IgnoreOutOfDiskSpace": | ||
175 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
176 | { | ||
177 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_OUTOFDISKSPACE; | ||
178 | } | ||
179 | break; | ||
180 | case "IgnoreActionStart": | ||
181 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
182 | { | ||
183 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_ACTIONSTART; | ||
184 | } | ||
185 | break; | ||
186 | case "IgnoreActionData": | ||
187 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
188 | { | ||
189 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_ACTIONDATA; | ||
190 | } | ||
191 | break; | ||
192 | case "IgnoreProgress": | ||
193 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
194 | { | ||
195 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_PROGRESS; | ||
196 | } | ||
197 | break; | ||
198 | case "IgnoreCommonData": | ||
199 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
200 | { | ||
201 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_COMMONDATA; | ||
202 | } | ||
203 | break; | ||
204 | case "IgnoreInitialize": | ||
205 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
206 | { | ||
207 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_INITIALIZE; | ||
208 | } | ||
209 | break; | ||
210 | case "IgnoreTerminate": | ||
211 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
212 | { | ||
213 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_TERMINATE; | ||
214 | } | ||
215 | break; | ||
216 | case "IgnoreShowDialog": | ||
217 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
218 | { | ||
219 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_SHOWDIALOG; | ||
220 | } | ||
221 | break; | ||
222 | case "IgnoreRMFilesInUse": | ||
223 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
224 | { | ||
225 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_RMFILESINUSE; | ||
226 | } | ||
227 | break; | ||
228 | case "IgnoreInstallStart": | ||
229 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
230 | { | ||
231 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_INSTALLSTART; | ||
232 | } | ||
233 | break; | ||
234 | case "IgnoreInstallEnd": | ||
235 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
236 | { | ||
237 | messageFilter ^= WindowsInstallerConstants.INSTALLLOGMODE_INSTALLEND; | ||
238 | } | ||
239 | break; | ||
240 | case "SourceFile": | ||
241 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
242 | break; | ||
243 | case "SupportBasicUI": | ||
244 | supportsBasicUI = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
245 | break; | ||
246 | default: | ||
247 | this.Core.UnexpectedAttribute(node, attrib); | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | this.Core.ParseExtensionAttribute(node, attrib); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | if (String.IsNullOrEmpty(sourceFile)) | ||
258 | { | ||
259 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
260 | } | ||
261 | else if (String.IsNullOrEmpty(name)) | ||
262 | { | ||
263 | name = Path.GetFileName(sourceFile); | ||
264 | if (!this.Core.IsValidLongFilename(name, false)) | ||
265 | { | ||
266 | this.Core.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | if (null == id) | ||
271 | { | ||
272 | if (!String.IsNullOrEmpty(name)) | ||
273 | { | ||
274 | id = this.Core.CreateIdentifierFromFilename(name); | ||
275 | } | ||
276 | |||
277 | if (null == id) | ||
278 | { | ||
279 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
280 | } | ||
281 | else if (!Common.IsIdentifier(id.Id)) | ||
282 | { | ||
283 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
284 | } | ||
285 | } | ||
286 | else if (String.IsNullOrEmpty(name)) | ||
287 | { | ||
288 | name = id.Id; | ||
289 | } | ||
290 | |||
291 | if (!name.Contains(".")) | ||
292 | { | ||
293 | this.Core.Write(ErrorMessages.InvalidEmbeddedUIFileName(sourceLineNumbers, name)); | ||
294 | } | ||
295 | |||
296 | foreach (var child in node.Elements()) | ||
297 | { | ||
298 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
299 | { | ||
300 | switch (child.Name.LocalName) | ||
301 | { | ||
302 | case "EmbeddedUIResource": | ||
303 | this.ParseEmbeddedUIResourceElement(child); | ||
304 | break; | ||
305 | default: | ||
306 | this.Core.UnexpectedElement(node, child); | ||
307 | break; | ||
308 | } | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | this.Core.ParseExtensionElement(node, child); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | if (!this.Core.EncounteredError) | ||
317 | { | ||
318 | var tuple = new MsiEmbeddedUITuple(sourceLineNumbers, id) | ||
319 | { | ||
320 | FileName = name, | ||
321 | EntryPoint = true, | ||
322 | SupportsBasicUI = supportsBasicUI, | ||
323 | MessageFilter = messageFilter, | ||
324 | Source = sourceFile | ||
325 | }; | ||
326 | |||
327 | this.Core.AddTuple(tuple); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /// <summary> | ||
332 | /// Parses a embedded UI resource element. | ||
333 | /// </summary> | ||
334 | /// <param name="node">Element to parse.</param> | ||
335 | /// <param name="parentId">Identifier of parent EmbeddedUI element.</param> | ||
336 | private void ParseEmbeddedUIResourceElement(XElement node) | ||
337 | { | ||
338 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
339 | Identifier id = null; | ||
340 | string name = null; | ||
341 | string sourceFile = null; | ||
342 | |||
343 | foreach (var attrib in node.Attributes()) | ||
344 | { | ||
345 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
346 | { | ||
347 | switch (attrib.Name.LocalName) | ||
348 | { | ||
349 | case "Id": | ||
350 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
351 | break; | ||
352 | case "Name": | ||
353 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
354 | break; | ||
355 | case "SourceFile": | ||
356 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
357 | break; | ||
358 | default: | ||
359 | this.Core.UnexpectedAttribute(node, attrib); | ||
360 | break; | ||
361 | } | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | this.Core.ParseExtensionAttribute(node, attrib); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | if (String.IsNullOrEmpty(sourceFile)) | ||
370 | { | ||
371 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
372 | } | ||
373 | else if (String.IsNullOrEmpty(name)) | ||
374 | { | ||
375 | name = Path.GetFileName(sourceFile); | ||
376 | if (!this.Core.IsValidLongFilename(name, false)) | ||
377 | { | ||
378 | this.Core.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | if (null == id) | ||
383 | { | ||
384 | if (!String.IsNullOrEmpty(name)) | ||
385 | { | ||
386 | id = this.Core.CreateIdentifierFromFilename(name); | ||
387 | } | ||
388 | |||
389 | if (null == id) | ||
390 | { | ||
391 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
392 | } | ||
393 | else if (!Common.IsIdentifier(id.Id)) | ||
394 | { | ||
395 | this.Core.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
396 | } | ||
397 | } | ||
398 | else if (String.IsNullOrEmpty(name)) | ||
399 | { | ||
400 | name = id.Id; | ||
401 | } | ||
402 | |||
403 | this.Core.ParseForExtensionElements(node); | ||
404 | |||
405 | if (!this.Core.EncounteredError) | ||
406 | { | ||
407 | var tuple = new MsiEmbeddedUITuple(sourceLineNumbers, id) | ||
408 | { | ||
409 | FileName = name, | ||
410 | Source = sourceFile | ||
411 | }; | ||
412 | |||
413 | this.Core.AddTuple(tuple); | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | } | ||
diff --git a/src/WixToolset.Core/Compiler_Module.cs b/src/WixToolset.Core/Compiler_Module.cs new file mode 100644 index 00000000..b95b5f03 --- /dev/null +++ b/src/WixToolset.Core/Compiler_Module.cs | |||
@@ -0,0 +1,650 @@ | |||
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 | namespace WixToolset.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.Globalization; | ||
7 | using System.Xml.Linq; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.Tuples; | ||
10 | using WixToolset.Extensibility; | ||
11 | |||
12 | /// <summary> | ||
13 | /// Compiler of the WiX toolset. | ||
14 | /// </summary> | ||
15 | internal partial class Compiler : ICompiler | ||
16 | { | ||
17 | /// <summary> | ||
18 | /// Parses a module element. | ||
19 | /// </summary> | ||
20 | /// <param name="node">Element to parse.</param> | ||
21 | private void ParseModuleElement(XElement node) | ||
22 | { | ||
23 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
24 | var codepage = 0; | ||
25 | string moduleId = null; | ||
26 | string version = null; | ||
27 | |||
28 | this.activeName = null; | ||
29 | this.activeLanguage = null; | ||
30 | |||
31 | foreach (var attrib in node.Attributes()) | ||
32 | { | ||
33 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
34 | { | ||
35 | switch (attrib.Name.LocalName) | ||
36 | { | ||
37 | case "Id": | ||
38 | this.activeName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
39 | if ("PUT-MODULE-NAME-HERE" == this.activeName) | ||
40 | { | ||
41 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
42 | } | ||
43 | else | ||
44 | { | ||
45 | this.activeName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
46 | } | ||
47 | break; | ||
48 | case "Codepage": | ||
49 | codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
50 | break; | ||
51 | case "Guid": | ||
52 | moduleId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
53 | this.Core.Write(WarningMessages.DeprecatedModuleGuidAttribute(sourceLineNumbers)); | ||
54 | break; | ||
55 | case "Language": | ||
56 | this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
57 | break; | ||
58 | case "Version": | ||
59 | version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
60 | break; | ||
61 | default: | ||
62 | this.Core.UnexpectedAttribute(node, attrib); | ||
63 | break; | ||
64 | } | ||
65 | } | ||
66 | else | ||
67 | { | ||
68 | this.Core.ParseExtensionAttribute(node, attrib); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | if (null == this.activeName) | ||
73 | { | ||
74 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
75 | } | ||
76 | |||
77 | if (null == this.activeLanguage) | ||
78 | { | ||
79 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
80 | } | ||
81 | |||
82 | if (null == version) | ||
83 | { | ||
84 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
85 | } | ||
86 | else if (!CompilerCore.IsValidModuleOrBundleVersion(version)) | ||
87 | { | ||
88 | this.Core.Write(WarningMessages.InvalidModuleOrBundleVersion(sourceLineNumbers, "Module", version)); | ||
89 | } | ||
90 | |||
91 | try | ||
92 | { | ||
93 | this.compilingModule = true; // notice that we are actually building a Merge Module here | ||
94 | this.Core.CreateActiveSection(this.activeName, SectionType.Module, codepage, this.Context.CompilationId); | ||
95 | |||
96 | foreach (var child in node.Elements()) | ||
97 | { | ||
98 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
99 | { | ||
100 | switch (child.Name.LocalName) | ||
101 | { | ||
102 | case "AdminExecuteSequence": | ||
103 | case "AdminUISequence": | ||
104 | case "AdvertiseExecuteSequence": | ||
105 | case "InstallExecuteSequence": | ||
106 | case "InstallUISequence": | ||
107 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
108 | break; | ||
109 | case "AppId": | ||
110 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
111 | break; | ||
112 | case "Binary": | ||
113 | this.ParseBinaryElement(child); | ||
114 | break; | ||
115 | case "Component": | ||
116 | this.ParseComponentElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage, CompilerConstants.IntegerNotSet, null, null); | ||
117 | break; | ||
118 | case "ComponentGroupRef": | ||
119 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage); | ||
120 | break; | ||
121 | case "ComponentRef": | ||
122 | this.ParseComponentRefElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage); | ||
123 | break; | ||
124 | case "Configuration": | ||
125 | this.ParseConfigurationElement(child); | ||
126 | break; | ||
127 | case "CustomAction": | ||
128 | this.ParseCustomActionElement(child); | ||
129 | break; | ||
130 | case "CustomActionRef": | ||
131 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
132 | break; | ||
133 | case "CustomTable": | ||
134 | this.ParseCustomTableElement(child); | ||
135 | break; | ||
136 | case "Dependency": | ||
137 | this.ParseDependencyElement(child); | ||
138 | break; | ||
139 | case "Directory": | ||
140 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
141 | break; | ||
142 | case "DirectoryRef": | ||
143 | this.ParseDirectoryRefElement(child); | ||
144 | break; | ||
145 | case "EmbeddedChainer": | ||
146 | this.ParseEmbeddedChainerElement(child); | ||
147 | break; | ||
148 | case "EmbeddedChainerRef": | ||
149 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
150 | break; | ||
151 | case "EnsureTable": | ||
152 | this.ParseEnsureTableElement(child); | ||
153 | break; | ||
154 | case "Exclusion": | ||
155 | this.ParseExclusionElement(child); | ||
156 | break; | ||
157 | case "Icon": | ||
158 | this.ParseIconElement(child); | ||
159 | break; | ||
160 | case "IgnoreModularization": | ||
161 | this.ParseIgnoreModularizationElement(child); | ||
162 | break; | ||
163 | case "IgnoreTable": | ||
164 | this.ParseIgnoreTableElement(child); | ||
165 | break; | ||
166 | case "Package": | ||
167 | this.ParsePackageElement(child, null, moduleId); | ||
168 | break; | ||
169 | case "Property": | ||
170 | this.ParsePropertyElement(child); | ||
171 | break; | ||
172 | case "PropertyRef": | ||
173 | this.ParseSimpleRefElement(child, "Property"); | ||
174 | break; | ||
175 | case "SetDirectory": | ||
176 | this.ParseSetDirectoryElement(child); | ||
177 | break; | ||
178 | case "SetProperty": | ||
179 | this.ParseSetPropertyElement(child); | ||
180 | break; | ||
181 | case "SFPCatalog": | ||
182 | string parentName = null; | ||
183 | this.ParseSFPCatalogElement(child, ref parentName); | ||
184 | break; | ||
185 | case "Substitution": | ||
186 | this.ParseSubstitutionElement(child); | ||
187 | break; | ||
188 | case "UI": | ||
189 | this.ParseUIElement(child); | ||
190 | break; | ||
191 | case "UIRef": | ||
192 | this.ParseSimpleRefElement(child, "WixUI"); | ||
193 | break; | ||
194 | case "WixVariable": | ||
195 | this.ParseWixVariableElement(child); | ||
196 | break; | ||
197 | default: | ||
198 | this.Core.UnexpectedElement(node, child); | ||
199 | break; | ||
200 | } | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | this.Core.ParseExtensionElement(node, child); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | |||
209 | if (!this.Core.EncounteredError) | ||
210 | { | ||
211 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleSignature); | ||
212 | row.Set(0, this.activeName); | ||
213 | row.Set(1, this.activeLanguage); | ||
214 | row.Set(2, version); | ||
215 | } | ||
216 | } | ||
217 | finally | ||
218 | { | ||
219 | this.compilingModule = false; // notice that we are no longer building a Merge Module here | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /// <summary> | ||
224 | /// Parses a dependency element. | ||
225 | /// </summary> | ||
226 | /// <param name="node">Element to parse.</param> | ||
227 | private void ParseDependencyElement(XElement node) | ||
228 | { | ||
229 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
230 | string requiredId = null; | ||
231 | var requiredLanguage = CompilerConstants.IntegerNotSet; | ||
232 | string requiredVersion = null; | ||
233 | |||
234 | foreach (var attrib in node.Attributes()) | ||
235 | { | ||
236 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
237 | { | ||
238 | switch (attrib.Name.LocalName) | ||
239 | { | ||
240 | case "RequiredId": | ||
241 | requiredId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
242 | break; | ||
243 | case "RequiredLanguage": | ||
244 | requiredLanguage = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
245 | break; | ||
246 | case "RequiredVersion": | ||
247 | requiredVersion = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
248 | break; | ||
249 | default: | ||
250 | this.Core.UnexpectedAttribute(node, attrib); | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | this.Core.ParseExtensionAttribute(node, attrib); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (null == requiredId) | ||
261 | { | ||
262 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RequiredId")); | ||
263 | requiredId = String.Empty; | ||
264 | } | ||
265 | |||
266 | if (CompilerConstants.IntegerNotSet == requiredLanguage) | ||
267 | { | ||
268 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RequiredLanguage")); | ||
269 | requiredLanguage = CompilerConstants.IllegalInteger; | ||
270 | } | ||
271 | |||
272 | this.Core.ParseForExtensionElements(node); | ||
273 | |||
274 | if (!this.Core.EncounteredError) | ||
275 | { | ||
276 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleDependency); | ||
277 | row.Set(0, this.activeName); | ||
278 | row.Set(1, this.activeLanguage); | ||
279 | row.Set(2, requiredId); | ||
280 | row.Set(3, requiredLanguage.ToString(CultureInfo.InvariantCulture)); | ||
281 | row.Set(4, requiredVersion); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | /// <summary> | ||
286 | /// Parses an exclusion element. | ||
287 | /// </summary> | ||
288 | /// <param name="node">Element to parse.</param> | ||
289 | private void ParseExclusionElement(XElement node) | ||
290 | { | ||
291 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
292 | string excludedId = null; | ||
293 | var excludeExceptLanguage = CompilerConstants.IntegerNotSet; | ||
294 | var excludeLanguage = CompilerConstants.IntegerNotSet; | ||
295 | var excludedLanguageField = "0"; | ||
296 | string excludedMaxVersion = null; | ||
297 | string excludedMinVersion = null; | ||
298 | |||
299 | foreach (var attrib in node.Attributes()) | ||
300 | { | ||
301 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
302 | { | ||
303 | switch (attrib.Name.LocalName) | ||
304 | { | ||
305 | case "ExcludedId": | ||
306 | excludedId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
307 | break; | ||
308 | case "ExcludeExceptLanguage": | ||
309 | excludeExceptLanguage = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
310 | break; | ||
311 | case "ExcludeLanguage": | ||
312 | excludeLanguage = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
313 | break; | ||
314 | case "ExcludedMaxVersion": | ||
315 | excludedMaxVersion = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
316 | break; | ||
317 | case "ExcludedMinVersion": | ||
318 | excludedMinVersion = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
319 | break; | ||
320 | default: | ||
321 | this.Core.UnexpectedAttribute(node, attrib); | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | this.Core.ParseExtensionAttribute(node, attrib); | ||
328 | } | ||
329 | } | ||
330 | |||
331 | if (null == excludedId) | ||
332 | { | ||
333 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ExcludedId")); | ||
334 | excludedId = String.Empty; | ||
335 | } | ||
336 | |||
337 | if (CompilerConstants.IntegerNotSet != excludeExceptLanguage && CompilerConstants.IntegerNotSet != excludeLanguage) | ||
338 | { | ||
339 | this.Core.Write(ErrorMessages.IllegalModuleExclusionLanguageAttributes(sourceLineNumbers)); | ||
340 | } | ||
341 | else if (CompilerConstants.IntegerNotSet != excludeExceptLanguage) | ||
342 | { | ||
343 | excludedLanguageField = Convert.ToString(-excludeExceptLanguage, CultureInfo.InvariantCulture); | ||
344 | } | ||
345 | else if (CompilerConstants.IntegerNotSet != excludeLanguage) | ||
346 | { | ||
347 | excludedLanguageField = Convert.ToString(excludeLanguage, CultureInfo.InvariantCulture); | ||
348 | } | ||
349 | |||
350 | this.Core.ParseForExtensionElements(node); | ||
351 | |||
352 | if (!this.Core.EncounteredError) | ||
353 | { | ||
354 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleExclusion); | ||
355 | row.Set(0, this.activeName); | ||
356 | row.Set(1, this.activeLanguage); | ||
357 | row.Set(2, excludedId); | ||
358 | row.Set(3, excludedLanguageField); | ||
359 | row.Set(4, excludedMinVersion); | ||
360 | row.Set(5, excludedMaxVersion); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | /// <summary> | ||
365 | /// Parses a configuration element for a configurable merge module. | ||
366 | /// </summary> | ||
367 | /// <param name="node">Element to parse.</param> | ||
368 | private void ParseConfigurationElement(XElement node) | ||
369 | { | ||
370 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
371 | string contextData = null; | ||
372 | string defaultValue = null; | ||
373 | string description = null; | ||
374 | string displayName = null; | ||
375 | var format = CompilerConstants.IntegerNotSet; | ||
376 | string helpKeyword = null; | ||
377 | string helpLocation = null; | ||
378 | bool keyNoOrphan = false; | ||
379 | bool nonNullable = false; | ||
380 | Identifier name = null; | ||
381 | string type = null; | ||
382 | |||
383 | foreach (var attrib in node.Attributes()) | ||
384 | { | ||
385 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
386 | { | ||
387 | switch (attrib.Name.LocalName) | ||
388 | { | ||
389 | case "Name": | ||
390 | name = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
391 | break; | ||
392 | case "ContextData": | ||
393 | contextData = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
394 | break; | ||
395 | case "Description": | ||
396 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
397 | break; | ||
398 | case "DefaultValue": | ||
399 | defaultValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
400 | break; | ||
401 | case "DisplayName": | ||
402 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
403 | break; | ||
404 | case "Format": | ||
405 | var formatStr = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
406 | switch (formatStr) | ||
407 | { | ||
408 | case "Text": | ||
409 | case "text": | ||
410 | format = 0; | ||
411 | break; | ||
412 | case "Key": | ||
413 | case "key": | ||
414 | format = 1; | ||
415 | break; | ||
416 | case "Integer": | ||
417 | case "integer": | ||
418 | format = 2; | ||
419 | break; | ||
420 | case "Bitfield": | ||
421 | case "bitfield": | ||
422 | format = 3; | ||
423 | break; | ||
424 | case "": | ||
425 | break; | ||
426 | default: | ||
427 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Format", formatStr, "Text", "Key", "Integer", "Bitfield")); | ||
428 | break; | ||
429 | } | ||
430 | break; | ||
431 | case "HelpKeyword": | ||
432 | helpKeyword = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
433 | break; | ||
434 | case "HelpLocation": | ||
435 | helpLocation = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
436 | break; | ||
437 | case "KeyNoOrphan": | ||
438 | keyNoOrphan = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
439 | break; | ||
440 | case "NonNullable": | ||
441 | nonNullable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
442 | break; | ||
443 | case "Type": | ||
444 | type = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
445 | break; | ||
446 | default: | ||
447 | this.Core.UnexpectedAttribute(node, attrib); | ||
448 | break; | ||
449 | } | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | this.Core.ParseExtensionAttribute(node, attrib); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | if (null == name) | ||
458 | { | ||
459 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
460 | } | ||
461 | |||
462 | if (CompilerConstants.IntegerNotSet == format) | ||
463 | { | ||
464 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Format")); | ||
465 | } | ||
466 | |||
467 | this.Core.ParseForExtensionElements(node); | ||
468 | |||
469 | if (!this.Core.EncounteredError) | ||
470 | { | ||
471 | var tuple = new ModuleConfigurationTuple(sourceLineNumbers, name) | ||
472 | { | ||
473 | Format = format, | ||
474 | Type = type, | ||
475 | ContextData = contextData, | ||
476 | DefaultValue = defaultValue, | ||
477 | KeyNoOrphan = keyNoOrphan, | ||
478 | NonNullable = nonNullable, | ||
479 | DisplayName = displayName, | ||
480 | Description = description, | ||
481 | HelpLocation = helpLocation, | ||
482 | HelpKeyword = helpKeyword | ||
483 | }; | ||
484 | |||
485 | this.Core.AddTuple(tuple); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /// <summary> | ||
490 | /// Parses a substitution element for a configurable merge module. | ||
491 | /// </summary> | ||
492 | /// <param name="node">Element to parse.</param> | ||
493 | private void ParseSubstitutionElement(XElement node) | ||
494 | { | ||
495 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
496 | string column = null; | ||
497 | string rowKeys = null; | ||
498 | string table = null; | ||
499 | string value = null; | ||
500 | |||
501 | foreach (var attrib in node.Attributes()) | ||
502 | { | ||
503 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
504 | { | ||
505 | switch (attrib.Name.LocalName) | ||
506 | { | ||
507 | case "Column": | ||
508 | column = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
509 | break; | ||
510 | case "Row": | ||
511 | rowKeys = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
512 | break; | ||
513 | case "Table": | ||
514 | table = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
515 | break; | ||
516 | case "Value": | ||
517 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
518 | break; | ||
519 | default: | ||
520 | this.Core.UnexpectedAttribute(node, attrib); | ||
521 | break; | ||
522 | } | ||
523 | } | ||
524 | else | ||
525 | { | ||
526 | this.Core.ParseExtensionAttribute(node, attrib); | ||
527 | } | ||
528 | } | ||
529 | |||
530 | if (null == column) | ||
531 | { | ||
532 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Column")); | ||
533 | column = String.Empty; | ||
534 | } | ||
535 | |||
536 | if (null == table) | ||
537 | { | ||
538 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Table")); | ||
539 | table = String.Empty; | ||
540 | } | ||
541 | |||
542 | if (null == rowKeys) | ||
543 | { | ||
544 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Row")); | ||
545 | } | ||
546 | |||
547 | this.Core.ParseForExtensionElements(node); | ||
548 | |||
549 | if (!this.Core.EncounteredError) | ||
550 | { | ||
551 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleSubstitution); | ||
552 | row.Set(0, table); | ||
553 | row.Set(1, rowKeys); | ||
554 | row.Set(2, column); | ||
555 | row.Set(3, value); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | /// <summary> | ||
560 | /// Parses an ignore modularization element. | ||
561 | /// </summary> | ||
562 | /// <param name="node">XmlNode on an IgnoreModulatization element.</param> | ||
563 | private void ParseIgnoreModularizationElement(XElement node) | ||
564 | { | ||
565 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
566 | string name = null; | ||
567 | |||
568 | this.Core.Write(WarningMessages.DeprecatedIgnoreModularizationElement(sourceLineNumbers)); | ||
569 | |||
570 | foreach (var attrib in node.Attributes()) | ||
571 | { | ||
572 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
573 | { | ||
574 | switch (attrib.Name.LocalName) | ||
575 | { | ||
576 | case "Name": | ||
577 | name = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
578 | break; | ||
579 | case "Type": | ||
580 | // this is actually not used | ||
581 | break; | ||
582 | default: | ||
583 | this.Core.UnexpectedAttribute(node, attrib); | ||
584 | break; | ||
585 | } | ||
586 | } | ||
587 | else | ||
588 | { | ||
589 | this.Core.ParseExtensionAttribute(node, attrib); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | if (null == name) | ||
594 | { | ||
595 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
596 | } | ||
597 | |||
598 | this.Core.ParseForExtensionElements(node); | ||
599 | |||
600 | if (!this.Core.EncounteredError) | ||
601 | { | ||
602 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSuppressModularization); | ||
603 | row.Set(0, name); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | /// <summary> | ||
608 | /// Parses an IgnoreTable element. | ||
609 | /// </summary> | ||
610 | /// <param name="node">Element to parse.</param> | ||
611 | private void ParseIgnoreTableElement(XElement node) | ||
612 | { | ||
613 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
614 | string id = null; | ||
615 | |||
616 | foreach (var attrib in node.Attributes()) | ||
617 | { | ||
618 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
619 | { | ||
620 | switch (attrib.Name.LocalName) | ||
621 | { | ||
622 | case "Id": | ||
623 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
624 | break; | ||
625 | default: | ||
626 | this.Core.UnexpectedAttribute(node, attrib); | ||
627 | break; | ||
628 | } | ||
629 | } | ||
630 | else | ||
631 | { | ||
632 | this.Core.ParseExtensionAttribute(node, attrib); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | if (null == id) | ||
637 | { | ||
638 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
639 | } | ||
640 | |||
641 | this.Core.ParseForExtensionElements(node); | ||
642 | |||
643 | if (!this.Core.EncounteredError) | ||
644 | { | ||
645 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ModuleIgnoreTable); | ||
646 | row.Set(0, id); | ||
647 | } | ||
648 | } | ||
649 | } | ||
650 | } | ||
diff --git a/src/WixToolset.Core/Compiler_UI.cs b/src/WixToolset.Core/Compiler_UI.cs new file mode 100644 index 00000000..fddb9061 --- /dev/null +++ b/src/WixToolset.Core/Compiler_UI.cs | |||
@@ -0,0 +1,1730 @@ | |||
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 | namespace WixToolset.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Xml.Linq; | ||
8 | using WixToolset.Data; | ||
9 | using WixToolset.Data.Tuples; | ||
10 | using WixToolset.Data.WindowsInstaller; | ||
11 | using WixToolset.Extensibility; | ||
12 | |||
13 | /// <summary> | ||
14 | /// Compiler of the WiX toolset. | ||
15 | /// </summary> | ||
16 | internal partial class Compiler : ICompiler | ||
17 | { | ||
18 | // NameToBit arrays | ||
19 | private static readonly string[] TextControlAttributes = { "Transparent", "NoPrefix", "NoWrap", "FormatSize", "UserLanguage" }; | ||
20 | private static readonly string[] HyperlinkControlAttributes = { "Transparent" }; | ||
21 | private static readonly string[] EditControlAttributes = { "Multiline", null, null, null, null, "Password" }; | ||
22 | private static readonly string[] ProgressControlAttributes = { "ProgressBlocks" }; | ||
23 | private static readonly string[] VolumeControlAttributes = { "Removable", "Fixed", "Remote", "CDROM", "RAMDisk", "Floppy", "ShowRollbackCost" }; | ||
24 | private static readonly string[] ListboxControlAttributes = { "Sorted", null, null, null, "UserLanguage" }; | ||
25 | private static readonly string[] ListviewControlAttributes = { "Sorted", null, null, null, "FixedSize", "Icon16", "Icon32" }; | ||
26 | private static readonly string[] ComboboxControlAttributes = { "Sorted", "ComboList", null, null, "UserLanguage" }; | ||
27 | private static readonly string[] RadioControlAttributes = { "Image", "PushLike", "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32", null, "HasBorder" }; | ||
28 | private static readonly string[] ButtonControlAttributes = { "Image", null, "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32", "ElevationShield" }; | ||
29 | private static readonly string[] IconControlAttributes = { "Image", null, null, null, "FixedSize", "Icon16", "Icon32" }; | ||
30 | private static readonly string[] BitmapControlAttributes = { "Image", null, null, null, "FixedSize" }; | ||
31 | private static readonly string[] CheckboxControlAttributes = { null, "PushLike", "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32" }; | ||
32 | |||
33 | /// <summary> | ||
34 | /// Parses UI elements. | ||
35 | /// </summary> | ||
36 | /// <param name="node">Element to parse.</param> | ||
37 | private void ParseUIElement(XElement node) | ||
38 | { | ||
39 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
40 | Identifier id = null; | ||
41 | var embeddedUICount = 0; | ||
42 | |||
43 | foreach (var attrib in node.Attributes()) | ||
44 | { | ||
45 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
46 | { | ||
47 | switch (attrib.Name.LocalName) | ||
48 | { | ||
49 | case "Id": | ||
50 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
51 | break; | ||
52 | default: | ||
53 | this.Core.UnexpectedAttribute(node, attrib); | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | this.Core.ParseExtensionAttribute(node, attrib); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | foreach (var child in node.Elements()) | ||
64 | { | ||
65 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
66 | { | ||
67 | switch (child.Name.LocalName) | ||
68 | { | ||
69 | case "BillboardAction": | ||
70 | this.ParseBillboardActionElement(child); | ||
71 | break; | ||
72 | case "ComboBox": | ||
73 | this.ParseControlGroupElement(child, TupleDefinitionType.ComboBox, "ListItem"); | ||
74 | break; | ||
75 | case "Dialog": | ||
76 | this.ParseDialogElement(child); | ||
77 | break; | ||
78 | case "DialogRef": | ||
79 | this.ParseSimpleRefElement(child, "Dialog"); | ||
80 | break; | ||
81 | case "EmbeddedUI": | ||
82 | if (0 < embeddedUICount) // there can be only one embedded UI | ||
83 | { | ||
84 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
85 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
86 | } | ||
87 | this.ParseEmbeddedUIElement(child); | ||
88 | ++embeddedUICount; | ||
89 | break; | ||
90 | case "Error": | ||
91 | this.ParseErrorElement(child); | ||
92 | break; | ||
93 | case "ListBox": | ||
94 | this.ParseControlGroupElement(child, TupleDefinitionType.ListBox, "ListItem"); | ||
95 | break; | ||
96 | case "ListView": | ||
97 | this.ParseControlGroupElement(child, TupleDefinitionType.ListView, "ListItem"); | ||
98 | break; | ||
99 | case "ProgressText": | ||
100 | this.ParseActionTextElement(child); | ||
101 | break; | ||
102 | case "Publish": | ||
103 | var order = 0; | ||
104 | this.ParsePublishElement(child, null, null, ref order); | ||
105 | break; | ||
106 | case "RadioButtonGroup": | ||
107 | var radioButtonType = this.ParseRadioButtonGroupElement(child, null, RadioButtonType.NotSet); | ||
108 | if (RadioButtonType.Bitmap == radioButtonType || RadioButtonType.Icon == radioButtonType) | ||
109 | { | ||
110 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
111 | this.Core.Write(ErrorMessages.RadioButtonBitmapAndIconDisallowed(childSourceLineNumbers)); | ||
112 | } | ||
113 | break; | ||
114 | case "TextStyle": | ||
115 | this.ParseTextStyleElement(child); | ||
116 | break; | ||
117 | case "UIText": | ||
118 | this.ParseUITextElement(child); | ||
119 | break; | ||
120 | |||
121 | // the following are available indentically under the UI and Product elements for document organization use only | ||
122 | case "AdminUISequence": | ||
123 | case "InstallUISequence": | ||
124 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
125 | break; | ||
126 | case "Binary": | ||
127 | this.ParseBinaryElement(child); | ||
128 | break; | ||
129 | case "Property": | ||
130 | this.ParsePropertyElement(child); | ||
131 | break; | ||
132 | case "PropertyRef": | ||
133 | this.ParseSimpleRefElement(child, "Property"); | ||
134 | break; | ||
135 | case "UIRef": | ||
136 | this.ParseSimpleRefElement(child, "WixUI"); | ||
137 | break; | ||
138 | |||
139 | default: | ||
140 | this.Core.UnexpectedElement(node, child); | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | this.Core.ParseExtensionElement(node, child); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | if (null != id && !this.Core.EncounteredError) | ||
151 | { | ||
152 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixUI, id); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /// <summary> | ||
157 | /// Parses a list item element. | ||
158 | /// </summary> | ||
159 | /// <param name="node">Element to parse.</param> | ||
160 | /// <param name="table">Table to add row to.</param> | ||
161 | /// <param name="property">Identifier of property referred to by list item.</param> | ||
162 | /// <param name="order">Relative order of list items.</param> | ||
163 | private void ParseListItemElement(XElement node, TupleDefinitionType tableName, string property, ref int order) | ||
164 | { | ||
165 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
166 | string icon = null; | ||
167 | string text = null; | ||
168 | string value = null; | ||
169 | |||
170 | foreach (var attrib in node.Attributes()) | ||
171 | { | ||
172 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
173 | { | ||
174 | switch (attrib.Name.LocalName) | ||
175 | { | ||
176 | case "Icon": | ||
177 | if (TupleDefinitionType.ListView == tableName) | ||
178 | { | ||
179 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
180 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", icon); | ||
181 | } | ||
182 | else | ||
183 | { | ||
184 | this.Core.Write(ErrorMessages.IllegalAttributeExceptOnElement(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ListView")); | ||
185 | } | ||
186 | break; | ||
187 | case "Text": | ||
188 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
189 | break; | ||
190 | case "Value": | ||
191 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
192 | break; | ||
193 | default: | ||
194 | this.Core.UnexpectedAttribute(node, attrib); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | this.Core.ParseExtensionAttribute(node, attrib); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | if (null == value) | ||
205 | { | ||
206 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
207 | } | ||
208 | |||
209 | this.Core.ParseForExtensionElements(node); | ||
210 | |||
211 | if (!this.Core.EncounteredError) | ||
212 | { | ||
213 | var row = this.Core.CreateRow(sourceLineNumbers, tableName); | ||
214 | row.Set(0, property); | ||
215 | row.Set(1, ++order); | ||
216 | row.Set(2, value); | ||
217 | row.Set(3, text); | ||
218 | if (null != icon) | ||
219 | { | ||
220 | row.Set(4, icon); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /// <summary> | ||
226 | /// Parses a radio button element. | ||
227 | /// </summary> | ||
228 | /// <param name="node">Element to parse.</param> | ||
229 | /// <param name="property">Identifier of property referred to by radio button.</param> | ||
230 | /// <param name="order">Relative order of radio buttons.</param> | ||
231 | /// <returns>Type of this radio button.</returns> | ||
232 | private RadioButtonType ParseRadioButtonElement(XElement node, string property, ref int order) | ||
233 | { | ||
234 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
235 | var type = RadioButtonType.NotSet; | ||
236 | string value = null; | ||
237 | string x = null; | ||
238 | string y = null; | ||
239 | string width = null; | ||
240 | string height = null; | ||
241 | string text = null; | ||
242 | string tooltip = null; | ||
243 | string help = null; | ||
244 | |||
245 | foreach (var attrib in node.Attributes()) | ||
246 | { | ||
247 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
248 | { | ||
249 | switch (attrib.Name.LocalName) | ||
250 | { | ||
251 | case "Bitmap": | ||
252 | if (RadioButtonType.NotSet != type) | ||
253 | { | ||
254 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Icon", "Text")); | ||
255 | } | ||
256 | text = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
257 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
258 | type = RadioButtonType.Bitmap; | ||
259 | break; | ||
260 | case "Height": | ||
261 | height = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
262 | break; | ||
263 | case "Help": | ||
264 | help = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
265 | break; | ||
266 | case "Icon": | ||
267 | if (RadioButtonType.NotSet != type) | ||
268 | { | ||
269 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Text")); | ||
270 | } | ||
271 | text = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
272 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
273 | type = RadioButtonType.Icon; | ||
274 | break; | ||
275 | case "Text": | ||
276 | if (RadioButtonType.NotSet != type) | ||
277 | { | ||
278 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Icon")); | ||
279 | } | ||
280 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
281 | type = RadioButtonType.Text; | ||
282 | break; | ||
283 | case "ToolTip": | ||
284 | tooltip = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
285 | break; | ||
286 | case "Value": | ||
287 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
288 | break; | ||
289 | case "Width": | ||
290 | width = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
291 | break; | ||
292 | case "X": | ||
293 | x = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
294 | break; | ||
295 | case "Y": | ||
296 | y = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
297 | break; | ||
298 | default: | ||
299 | this.Core.UnexpectedAttribute(node, attrib); | ||
300 | break; | ||
301 | } | ||
302 | } | ||
303 | else | ||
304 | { | ||
305 | this.Core.ParseExtensionAttribute(node, attrib); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | if (null == value) | ||
310 | { | ||
311 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
312 | } | ||
313 | |||
314 | if (null == x) | ||
315 | { | ||
316 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X")); | ||
317 | } | ||
318 | |||
319 | if (null == y) | ||
320 | { | ||
321 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y")); | ||
322 | } | ||
323 | |||
324 | if (null == width) | ||
325 | { | ||
326 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width")); | ||
327 | } | ||
328 | |||
329 | if (null == height) | ||
330 | { | ||
331 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height")); | ||
332 | } | ||
333 | |||
334 | this.Core.ParseForExtensionElements(node); | ||
335 | |||
336 | if (!this.Core.EncounteredError) | ||
337 | { | ||
338 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RadioButton); | ||
339 | row.Set(0, property); | ||
340 | row.Set(1, ++order); | ||
341 | row.Set(2, value); | ||
342 | row.Set(3, x); | ||
343 | row.Set(4, y); | ||
344 | row.Set(5, width); | ||
345 | row.Set(6, height); | ||
346 | row.Set(7, text); | ||
347 | if (null != tooltip || null != help) | ||
348 | { | ||
349 | row.Set(8, String.Concat(tooltip, "|", help)); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | return type; | ||
354 | } | ||
355 | |||
356 | /// <summary> | ||
357 | /// Parses a billboard element. | ||
358 | /// </summary> | ||
359 | /// <param name="node">Element to parse.</param> | ||
360 | private void ParseBillboardActionElement(XElement node) | ||
361 | { | ||
362 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
363 | string action = null; | ||
364 | var order = 0; | ||
365 | |||
366 | foreach (var attrib in node.Attributes()) | ||
367 | { | ||
368 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
369 | { | ||
370 | switch (attrib.Name.LocalName) | ||
371 | { | ||
372 | case "Id": | ||
373 | action = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
374 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", action); | ||
375 | break; | ||
376 | default: | ||
377 | this.Core.UnexpectedAttribute(node, attrib); | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | else | ||
382 | { | ||
383 | this.Core.ParseExtensionAttribute(node, attrib); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | if (null == action) | ||
388 | { | ||
389 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
390 | } | ||
391 | |||
392 | foreach (var child in node.Elements()) | ||
393 | { | ||
394 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
395 | { | ||
396 | switch (child.Name.LocalName) | ||
397 | { | ||
398 | case "Billboard": | ||
399 | order = order + 1; | ||
400 | this.ParseBillboardElement(child, action, order); | ||
401 | break; | ||
402 | default: | ||
403 | this.Core.UnexpectedElement(node, child); | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | this.Core.ParseExtensionElement(node, child); | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /// <summary> | ||
415 | /// Parses a billboard element. | ||
416 | /// </summary> | ||
417 | /// <param name="node">Element to parse.</param> | ||
418 | /// <param name="action">Action for the billboard.</param> | ||
419 | /// <param name="order">Order of the billboard.</param> | ||
420 | private void ParseBillboardElement(XElement node, string action, int order) | ||
421 | { | ||
422 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
423 | Identifier id = null; | ||
424 | string feature = null; | ||
425 | |||
426 | foreach (var attrib in node.Attributes()) | ||
427 | { | ||
428 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
429 | { | ||
430 | switch (attrib.Name.LocalName) | ||
431 | { | ||
432 | case "Id": | ||
433 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
434 | break; | ||
435 | case "Feature": | ||
436 | feature = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
437 | this.Core.CreateSimpleReference(sourceLineNumbers, "Feature", feature); | ||
438 | break; | ||
439 | default: | ||
440 | this.Core.UnexpectedAttribute(node, attrib); | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | this.Core.ParseExtensionAttribute(node, attrib); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | if (null == id) | ||
451 | { | ||
452 | id = this.Core.CreateIdentifier("bil", action, order.ToString(), feature); | ||
453 | } | ||
454 | |||
455 | foreach (var child in node.Elements()) | ||
456 | { | ||
457 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
458 | { | ||
459 | switch (child.Name.LocalName) | ||
460 | { | ||
461 | case "Control": | ||
462 | // These are all thrown away. | ||
463 | IntermediateTuple lastTabRow = null; | ||
464 | string firstControl = null; | ||
465 | string defaultControl = null; | ||
466 | string cancelControl = null; | ||
467 | |||
468 | this.ParseControlElement(child, id.Id, TupleDefinitionType.BBControl, ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, false); | ||
469 | break; | ||
470 | default: | ||
471 | this.Core.UnexpectedElement(node, child); | ||
472 | break; | ||
473 | } | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | this.Core.ParseExtensionElement(node, child); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | |||
482 | if (!this.Core.EncounteredError) | ||
483 | { | ||
484 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Billboard, id); | ||
485 | row.Set(1, feature); | ||
486 | row.Set(2, action); | ||
487 | row.Set(3, order); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | /// <summary> | ||
492 | /// Parses a control group element. | ||
493 | /// </summary> | ||
494 | /// <param name="node">Element to parse.</param> | ||
495 | /// <param name="table">Table referred to by control group.</param> | ||
496 | /// <param name="childTag">Expected child elements.</param> | ||
497 | private void ParseControlGroupElement(XElement node, TupleDefinitionType tableName, string childTag) | ||
498 | { | ||
499 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
500 | var order = 0; | ||
501 | string property = null; | ||
502 | |||
503 | foreach (var attrib in node.Attributes()) | ||
504 | { | ||
505 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
506 | { | ||
507 | switch (attrib.Name.LocalName) | ||
508 | { | ||
509 | case "Property": | ||
510 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
511 | break; | ||
512 | default: | ||
513 | this.Core.UnexpectedAttribute(node, attrib); | ||
514 | break; | ||
515 | } | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | this.Core.ParseExtensionAttribute(node, attrib); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | if (null == property) | ||
524 | { | ||
525 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
526 | } | ||
527 | |||
528 | foreach (var child in node.Elements()) | ||
529 | { | ||
530 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
531 | { | ||
532 | if (childTag != child.Name.LocalName) | ||
533 | { | ||
534 | this.Core.UnexpectedElement(node, child); | ||
535 | } | ||
536 | |||
537 | switch (child.Name.LocalName) | ||
538 | { | ||
539 | case "ListItem": | ||
540 | this.ParseListItemElement(child, tableName, property, ref order); | ||
541 | break; | ||
542 | case "Property": | ||
543 | this.ParsePropertyElement(child); | ||
544 | break; | ||
545 | default: | ||
546 | this.Core.UnexpectedElement(node, child); | ||
547 | break; | ||
548 | } | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | this.Core.ParseExtensionElement(node, child); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | } | ||
557 | |||
558 | /// <summary> | ||
559 | /// Parses a radio button control group element. | ||
560 | /// </summary> | ||
561 | /// <param name="node">Element to parse.</param> | ||
562 | /// <param name="property">Property associated with this radio button group.</param> | ||
563 | /// <param name="groupType">Specifies the current type of radio buttons in the group.</param> | ||
564 | /// <returns>The current type of radio buttons in the group.</returns> | ||
565 | private RadioButtonType ParseRadioButtonGroupElement(XElement node, string property, RadioButtonType groupType) | ||
566 | { | ||
567 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
568 | var order = 0; | ||
569 | |||
570 | foreach (var attrib in node.Attributes()) | ||
571 | { | ||
572 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
573 | { | ||
574 | switch (attrib.Name.LocalName) | ||
575 | { | ||
576 | case "Property": | ||
577 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
578 | this.Core.CreateSimpleReference(sourceLineNumbers, "Property", property); | ||
579 | break; | ||
580 | default: | ||
581 | this.Core.UnexpectedAttribute(node, attrib); | ||
582 | break; | ||
583 | } | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | this.Core.ParseExtensionAttribute(node, attrib); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | if (null == property) | ||
592 | { | ||
593 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
594 | } | ||
595 | |||
596 | foreach (var child in node.Elements()) | ||
597 | { | ||
598 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
599 | { | ||
600 | switch (child.Name.LocalName) | ||
601 | { | ||
602 | case "RadioButton": | ||
603 | var type = this.ParseRadioButtonElement(child, property, ref order); | ||
604 | if (RadioButtonType.NotSet == groupType) | ||
605 | { | ||
606 | groupType = type; | ||
607 | } | ||
608 | else if (groupType != type) | ||
609 | { | ||
610 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
611 | this.Core.Write(ErrorMessages.RadioButtonTypeInconsistent(childSourceLineNumbers)); | ||
612 | } | ||
613 | break; | ||
614 | default: | ||
615 | this.Core.UnexpectedElement(node, child); | ||
616 | break; | ||
617 | } | ||
618 | } | ||
619 | else | ||
620 | { | ||
621 | this.Core.ParseExtensionElement(node, child); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | |||
626 | return groupType; | ||
627 | } | ||
628 | |||
629 | /// <summary> | ||
630 | /// Parses an action text element. | ||
631 | /// </summary> | ||
632 | /// <param name="node">Element to parse.</param> | ||
633 | private void ParseActionTextElement(XElement node) | ||
634 | { | ||
635 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
636 | string action = null; | ||
637 | string template = null; | ||
638 | |||
639 | foreach (var attrib in node.Attributes()) | ||
640 | { | ||
641 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
642 | { | ||
643 | switch (attrib.Name.LocalName) | ||
644 | { | ||
645 | case "Action": | ||
646 | action = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
647 | break; | ||
648 | case "Template": | ||
649 | template = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
650 | break; | ||
651 | default: | ||
652 | this.Core.UnexpectedAttribute(node, attrib); | ||
653 | break; | ||
654 | } | ||
655 | } | ||
656 | else | ||
657 | { | ||
658 | this.Core.ParseExtensionAttribute(node, attrib); | ||
659 | } | ||
660 | } | ||
661 | |||
662 | if (null == action) | ||
663 | { | ||
664 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
665 | } | ||
666 | |||
667 | this.Core.ParseForExtensionElements(node); | ||
668 | |||
669 | if (!this.Core.EncounteredError) | ||
670 | { | ||
671 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ActionText); | ||
672 | row.Set(0, action); | ||
673 | row.Set(1, Common.GetInnerText(node)); | ||
674 | row.Set(2, template); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | /// <summary> | ||
679 | /// Parses an ui text element. | ||
680 | /// </summary> | ||
681 | /// <param name="node">Element to parse.</param> | ||
682 | private void ParseUITextElement(XElement node) | ||
683 | { | ||
684 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
685 | Identifier id = null; | ||
686 | string text = null; | ||
687 | |||
688 | foreach (var attrib in node.Attributes()) | ||
689 | { | ||
690 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
691 | { | ||
692 | switch (attrib.Name.LocalName) | ||
693 | { | ||
694 | case "Id": | ||
695 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
696 | break; | ||
697 | default: | ||
698 | this.Core.UnexpectedAttribute(node, attrib); | ||
699 | break; | ||
700 | } | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | this.Core.ParseExtensionAttribute(node, attrib); | ||
705 | } | ||
706 | } | ||
707 | |||
708 | text = Common.GetInnerText(node); | ||
709 | |||
710 | if (null == id) | ||
711 | { | ||
712 | id = this.Core.CreateIdentifier("txt", text); | ||
713 | } | ||
714 | |||
715 | this.Core.ParseForExtensionElements(node); | ||
716 | |||
717 | if (!this.Core.EncounteredError) | ||
718 | { | ||
719 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.UIText, id); | ||
720 | row.Set(1, text); | ||
721 | } | ||
722 | } | ||
723 | |||
724 | /// <summary> | ||
725 | /// Parses a text style element. | ||
726 | /// </summary> | ||
727 | /// <param name="node">Element to parse.</param> | ||
728 | private void ParseTextStyleElement(XElement node) | ||
729 | { | ||
730 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
731 | Identifier id = null; | ||
732 | var color = CompilerConstants.IntegerNotSet; | ||
733 | var bold = false; | ||
734 | var italic = false; | ||
735 | var strike = false; | ||
736 | var underline = false; | ||
737 | string faceName = null; | ||
738 | var size = "0"; | ||
739 | |||
740 | foreach (var attrib in node.Attributes()) | ||
741 | { | ||
742 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
743 | { | ||
744 | switch (attrib.Name.LocalName) | ||
745 | { | ||
746 | case "Id": | ||
747 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
748 | break; | ||
749 | |||
750 | // RGB Values | ||
751 | case "Red": | ||
752 | var redColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
753 | if (CompilerConstants.IllegalInteger != redColor) | ||
754 | { | ||
755 | if (CompilerConstants.IntegerNotSet == color) | ||
756 | { | ||
757 | color = redColor; | ||
758 | } | ||
759 | else | ||
760 | { | ||
761 | color += redColor; | ||
762 | } | ||
763 | } | ||
764 | break; | ||
765 | case "Green": | ||
766 | var greenColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
767 | if (CompilerConstants.IllegalInteger != greenColor) | ||
768 | { | ||
769 | if (CompilerConstants.IntegerNotSet == color) | ||
770 | { | ||
771 | color = greenColor * 256; | ||
772 | } | ||
773 | else | ||
774 | { | ||
775 | color += greenColor * 256; | ||
776 | } | ||
777 | } | ||
778 | break; | ||
779 | case "Blue": | ||
780 | var blueColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
781 | if (CompilerConstants.IllegalInteger != blueColor) | ||
782 | { | ||
783 | if (CompilerConstants.IntegerNotSet == color) | ||
784 | { | ||
785 | color = blueColor * 65536; | ||
786 | } | ||
787 | else | ||
788 | { | ||
789 | color += blueColor * 65536; | ||
790 | } | ||
791 | } | ||
792 | break; | ||
793 | |||
794 | // Style values | ||
795 | case "Bold": | ||
796 | bold = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
797 | break; | ||
798 | case "Italic": | ||
799 | italic = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
800 | break; | ||
801 | case "Strike": | ||
802 | strike = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
803 | break; | ||
804 | case "Underline": | ||
805 | underline = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
806 | break; | ||
807 | |||
808 | // Font values | ||
809 | case "FaceName": | ||
810 | faceName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
811 | break; | ||
812 | case "Size": | ||
813 | size = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
814 | break; | ||
815 | |||
816 | default: | ||
817 | this.Core.UnexpectedAttribute(node, attrib); | ||
818 | break; | ||
819 | } | ||
820 | } | ||
821 | else | ||
822 | { | ||
823 | this.Core.ParseExtensionAttribute(node, attrib); | ||
824 | } | ||
825 | } | ||
826 | |||
827 | if (null == id) | ||
828 | { | ||
829 | this.Core.CreateIdentifier("txs", faceName, size.ToString(), color.ToString(), bold.ToString(), italic.ToString(), strike.ToString(), underline.ToString()); | ||
830 | } | ||
831 | |||
832 | if (null == faceName) | ||
833 | { | ||
834 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "FaceName")); | ||
835 | } | ||
836 | |||
837 | this.Core.ParseForExtensionElements(node); | ||
838 | |||
839 | if (!this.Core.EncounteredError) | ||
840 | { | ||
841 | var tuple = new TextStyleTuple(sourceLineNumbers, id) | ||
842 | { | ||
843 | FaceName = faceName, | ||
844 | Color = color, | ||
845 | Bold = bold, | ||
846 | Italic = italic, | ||
847 | Strike = strike, | ||
848 | Underline = underline, | ||
849 | }; | ||
850 | |||
851 | tuple.Set((int)TextStyleTupleFields.Size, size); | ||
852 | |||
853 | this.Core.AddTuple(tuple); | ||
854 | } | ||
855 | } | ||
856 | |||
857 | /// <summary> | ||
858 | /// Parses a dialog element. | ||
859 | /// </summary> | ||
860 | /// <param name="node">Element to parse.</param> | ||
861 | private void ParseDialogElement(XElement node) | ||
862 | { | ||
863 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
864 | Identifier id = null; | ||
865 | var hidden = false; | ||
866 | var modal = true; | ||
867 | var minimize = true; | ||
868 | var customPalette = false; | ||
869 | var errorDialog = false; | ||
870 | var keepModeless = false; | ||
871 | var height = 0; | ||
872 | string title = null; | ||
873 | var leftScroll = false; | ||
874 | var rightAligned = false; | ||
875 | var rightToLeft = false; | ||
876 | var systemModal = false; | ||
877 | var trackDiskSpace = false; | ||
878 | var width = 0; | ||
879 | var x = 50; | ||
880 | var y = 50; | ||
881 | |||
882 | foreach (var attrib in node.Attributes()) | ||
883 | { | ||
884 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
885 | { | ||
886 | switch (attrib.Name.LocalName) | ||
887 | { | ||
888 | case "Id": | ||
889 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
890 | break; | ||
891 | case "Height": | ||
892 | height = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
893 | break; | ||
894 | case "Title": | ||
895 | title = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
896 | break; | ||
897 | case "Width": | ||
898 | width = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
899 | break; | ||
900 | case "X": | ||
901 | x = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100); | ||
902 | break; | ||
903 | case "Y": | ||
904 | y = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100); | ||
905 | break; | ||
906 | case "CustomPalette": | ||
907 | customPalette = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
908 | break; | ||
909 | case "ErrorDialog": | ||
910 | errorDialog = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
911 | break; | ||
912 | case "Hidden": | ||
913 | hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
914 | break; | ||
915 | case "KeepModeless": | ||
916 | keepModeless = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
917 | break; | ||
918 | case "LeftScroll": | ||
919 | leftScroll = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
920 | break; | ||
921 | case "Modeless": | ||
922 | modal = YesNoType.Yes != this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
923 | break; | ||
924 | case "NoMinimize": | ||
925 | minimize = YesNoType.Yes != this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
926 | break; | ||
927 | case "RightAligned": | ||
928 | rightAligned = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
929 | break; | ||
930 | case "RightToLeft": | ||
931 | rightToLeft = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
932 | break; | ||
933 | case "SystemModal": | ||
934 | systemModal = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
935 | break; | ||
936 | case "TrackDiskSpace": | ||
937 | trackDiskSpace = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
938 | break; | ||
939 | |||
940 | default: | ||
941 | this.Core.UnexpectedAttribute(node, attrib); | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | else | ||
946 | { | ||
947 | this.Core.ParseExtensionAttribute(node, attrib); | ||
948 | } | ||
949 | } | ||
950 | |||
951 | if (null == id) | ||
952 | { | ||
953 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
954 | id = Identifier.Invalid; | ||
955 | } | ||
956 | |||
957 | IntermediateTuple lastTabRow = null; | ||
958 | string cancelControl = null; | ||
959 | string defaultControl = null; | ||
960 | string firstControl = null; | ||
961 | |||
962 | foreach (var child in node.Elements()) | ||
963 | { | ||
964 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
965 | { | ||
966 | switch (child.Name.LocalName) | ||
967 | { | ||
968 | case "Control": | ||
969 | this.ParseControlElement(child, id.Id, TupleDefinitionType.Control, ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, trackDiskSpace); | ||
970 | break; | ||
971 | default: | ||
972 | this.Core.UnexpectedElement(node, child); | ||
973 | break; | ||
974 | } | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | this.Core.ParseExtensionElement(node, child); | ||
979 | } | ||
980 | } | ||
981 | |||
982 | if (null != lastTabRow && null != lastTabRow[1]) | ||
983 | { | ||
984 | if (firstControl != lastTabRow[1].ToString()) | ||
985 | { | ||
986 | lastTabRow.Set(10, firstControl); | ||
987 | } | ||
988 | } | ||
989 | |||
990 | if (null == firstControl) | ||
991 | { | ||
992 | this.Core.Write(ErrorMessages.NoFirstControlSpecified(sourceLineNumbers, id.Id)); | ||
993 | } | ||
994 | |||
995 | if (!this.Core.EncounteredError) | ||
996 | { | ||
997 | var tuple = new DialogTuple(sourceLineNumbers, id) | ||
998 | { | ||
999 | HCentering = x, | ||
1000 | VCentering = y, | ||
1001 | Width = width, | ||
1002 | Height = height, | ||
1003 | CustomPalette = customPalette, | ||
1004 | ErrorDialog = errorDialog, | ||
1005 | Visible = !hidden, | ||
1006 | Modal = modal, | ||
1007 | KeepModeless = keepModeless, | ||
1008 | LeftScroll = leftScroll, | ||
1009 | Minimize = minimize, | ||
1010 | RightAligned = rightAligned, | ||
1011 | RightToLeft = rightToLeft, | ||
1012 | SystemModal = systemModal, | ||
1013 | TrackDiskSpace = trackDiskSpace, | ||
1014 | Title = title, | ||
1015 | Control_First = firstControl, | ||
1016 | Control_Default = defaultControl, | ||
1017 | Control_Cancel = cancelControl, | ||
1018 | }; | ||
1019 | |||
1020 | this.Core.AddTuple(tuple); | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | /// <summary> | ||
1025 | /// Parses a control element. | ||
1026 | /// </summary> | ||
1027 | /// <param name="node">Element to parse.</param> | ||
1028 | /// <param name="dialog">Identifier for parent dialog.</param> | ||
1029 | /// <param name="table">Table control belongs in.</param> | ||
1030 | /// <param name="lastTabTuple">Last row in the tab order.</param> | ||
1031 | /// <param name="firstControl">Name of the first control in the tab order.</param> | ||
1032 | /// <param name="defaultControl">Name of the default control.</param> | ||
1033 | /// <param name="cancelControl">Name of the candle control.</param> | ||
1034 | /// <param name="trackDiskSpace">True if the containing dialog tracks disk space.</param> | ||
1035 | private void ParseControlElement(XElement node, string dialog, TupleDefinitionType tupleType, ref IntermediateTuple lastTabTuple, ref string firstControl, ref string defaultControl, ref string cancelControl, bool trackDiskSpace) | ||
1036 | { | ||
1037 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1038 | Identifier controlId = null; | ||
1039 | var bits = new BitArray(32); | ||
1040 | string checkBoxPropertyRef = null; | ||
1041 | string checkboxValue = null; | ||
1042 | string controlType = null; | ||
1043 | var disabled = false; | ||
1044 | string height = null; | ||
1045 | string help = null; | ||
1046 | var isCancel = false; | ||
1047 | var isDefault = false; | ||
1048 | var notTabbable = false; | ||
1049 | string property = null; | ||
1050 | var publishOrder = 0; | ||
1051 | string sourceFile = null; | ||
1052 | string text = null; | ||
1053 | string tooltip = null; | ||
1054 | var radioButtonsType = RadioButtonType.NotSet; | ||
1055 | string width = null; | ||
1056 | string x = null; | ||
1057 | string y = null; | ||
1058 | |||
1059 | var hidden = false; | ||
1060 | var sunken = false; | ||
1061 | var indirect = false; | ||
1062 | var integer = false; | ||
1063 | var rightToLeft = false; | ||
1064 | var rightAligned = false; | ||
1065 | var leftScroll = false; | ||
1066 | |||
1067 | // The rest of the method relies on the control's Type, so we have to get that first. | ||
1068 | var typeAttribute = node.Attribute("Type"); | ||
1069 | if (null == typeAttribute) | ||
1070 | { | ||
1071 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type")); | ||
1072 | } | ||
1073 | else | ||
1074 | { | ||
1075 | controlType = this.Core.GetAttributeValue(sourceLineNumbers, typeAttribute); | ||
1076 | } | ||
1077 | |||
1078 | string[] specialAttributes; | ||
1079 | switch (controlType) | ||
1080 | { | ||
1081 | case "Billboard": | ||
1082 | specialAttributes = null; | ||
1083 | notTabbable = true; | ||
1084 | disabled = true; | ||
1085 | |||
1086 | this.Core.EnsureTable(sourceLineNumbers, "Billboard"); | ||
1087 | break; | ||
1088 | case "Bitmap": | ||
1089 | specialAttributes = BitmapControlAttributes; | ||
1090 | notTabbable = true; | ||
1091 | disabled = true; | ||
1092 | break; | ||
1093 | case "CheckBox": | ||
1094 | specialAttributes = CheckboxControlAttributes; | ||
1095 | break; | ||
1096 | case "ComboBox": | ||
1097 | specialAttributes = ComboboxControlAttributes; | ||
1098 | break; | ||
1099 | case "DirectoryCombo": | ||
1100 | specialAttributes = VolumeControlAttributes; | ||
1101 | break; | ||
1102 | case "DirectoryList": | ||
1103 | specialAttributes = null; | ||
1104 | break; | ||
1105 | case "Edit": | ||
1106 | specialAttributes = EditControlAttributes; | ||
1107 | break; | ||
1108 | case "GroupBox": | ||
1109 | specialAttributes = null; | ||
1110 | notTabbable = true; | ||
1111 | break; | ||
1112 | case "Hyperlink": | ||
1113 | specialAttributes = HyperlinkControlAttributes; | ||
1114 | break; | ||
1115 | case "Icon": | ||
1116 | specialAttributes = IconControlAttributes; | ||
1117 | notTabbable = true; | ||
1118 | disabled = true; | ||
1119 | break; | ||
1120 | case "Line": | ||
1121 | specialAttributes = null; | ||
1122 | notTabbable = true; | ||
1123 | disabled = true; | ||
1124 | break; | ||
1125 | case "ListBox": | ||
1126 | specialAttributes = ListboxControlAttributes; | ||
1127 | break; | ||
1128 | case "ListView": | ||
1129 | specialAttributes = ListviewControlAttributes; | ||
1130 | break; | ||
1131 | case "MaskedEdit": | ||
1132 | specialAttributes = EditControlAttributes; | ||
1133 | break; | ||
1134 | case "PathEdit": | ||
1135 | specialAttributes = EditControlAttributes; | ||
1136 | break; | ||
1137 | case "ProgressBar": | ||
1138 | specialAttributes = ProgressControlAttributes; | ||
1139 | notTabbable = true; | ||
1140 | disabled = true; | ||
1141 | break; | ||
1142 | case "PushButton": | ||
1143 | specialAttributes = ButtonControlAttributes; | ||
1144 | break; | ||
1145 | case "RadioButtonGroup": | ||
1146 | specialAttributes = RadioControlAttributes; | ||
1147 | break; | ||
1148 | case "ScrollableText": | ||
1149 | specialAttributes = null; | ||
1150 | break; | ||
1151 | case "SelectionTree": | ||
1152 | specialAttributes = null; | ||
1153 | break; | ||
1154 | case "Text": | ||
1155 | specialAttributes = TextControlAttributes; | ||
1156 | notTabbable = true; | ||
1157 | break; | ||
1158 | case "VolumeCostList": | ||
1159 | specialAttributes = VolumeControlAttributes; | ||
1160 | notTabbable = true; | ||
1161 | break; | ||
1162 | case "VolumeSelectCombo": | ||
1163 | specialAttributes = VolumeControlAttributes; | ||
1164 | break; | ||
1165 | default: | ||
1166 | specialAttributes = null; | ||
1167 | notTabbable = true; | ||
1168 | break; | ||
1169 | } | ||
1170 | |||
1171 | foreach (var attrib in node.Attributes()) | ||
1172 | { | ||
1173 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1174 | { | ||
1175 | switch (attrib.Name.LocalName) | ||
1176 | { | ||
1177 | case "Id": | ||
1178 | controlId = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1179 | break; | ||
1180 | case "Type": // already processed | ||
1181 | break; | ||
1182 | case "Cancel": | ||
1183 | isCancel = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1184 | break; | ||
1185 | case "CheckBoxPropertyRef": | ||
1186 | checkBoxPropertyRef = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1187 | break; | ||
1188 | case "CheckBoxValue": | ||
1189 | checkboxValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1190 | break; | ||
1191 | case "Default": | ||
1192 | isDefault = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1193 | break; | ||
1194 | case "Height": | ||
1195 | height = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
1196 | break; | ||
1197 | case "Help": | ||
1198 | help = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1199 | break; | ||
1200 | case "IconSize": | ||
1201 | var iconSizeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1202 | if (null != specialAttributes) | ||
1203 | { | ||
1204 | switch (iconSizeValue) | ||
1205 | { | ||
1206 | case "16": | ||
1207 | this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
1208 | break; | ||
1209 | case "32": | ||
1210 | this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
1211 | break; | ||
1212 | case "48": | ||
1213 | this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
1214 | this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
1215 | break; | ||
1216 | case "": | ||
1217 | break; | ||
1218 | default: | ||
1219 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "16", "32", "48")); | ||
1220 | break; | ||
1221 | } | ||
1222 | //if (0 < iconSizeValue.Length) | ||
1223 | //{ | ||
1224 | // var iconsSizeType = Wix.Control.ParseIconSizeType(iconSizeValue); | ||
1225 | // switch (iconsSizeType) | ||
1226 | // { | ||
1227 | // case Wix.Control.IconSizeType.Item16: | ||
1228 | // this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
1229 | // break; | ||
1230 | // case Wix.Control.IconSizeType.Item32: | ||
1231 | // this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
1232 | // break; | ||
1233 | // case Wix.Control.IconSizeType.Item48: | ||
1234 | // this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
1235 | // this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
1236 | // break; | ||
1237 | // default: | ||
1238 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "16", "32", "48")); | ||
1239 | // break; | ||
1240 | // } | ||
1241 | //} | ||
1242 | } | ||
1243 | else | ||
1244 | { | ||
1245 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "Type")); | ||
1246 | } | ||
1247 | break; | ||
1248 | case "Property": | ||
1249 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1250 | break; | ||
1251 | case "TabSkip": | ||
1252 | notTabbable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1253 | break; | ||
1254 | case "Text": | ||
1255 | text = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1256 | break; | ||
1257 | case "ToolTip": | ||
1258 | tooltip = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1259 | break; | ||
1260 | case "Width": | ||
1261 | width = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
1262 | break; | ||
1263 | case "X": | ||
1264 | x = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
1265 | break; | ||
1266 | case "Y": | ||
1267 | y = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
1268 | break; | ||
1269 | case "Disabled": | ||
1270 | disabled = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1271 | break; | ||
1272 | case "Hidden": | ||
1273 | hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1274 | break; | ||
1275 | case "Sunken": | ||
1276 | sunken = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1277 | break; | ||
1278 | case "Indirect": | ||
1279 | indirect = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1280 | break; | ||
1281 | case "Integer": | ||
1282 | integer = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1283 | break; | ||
1284 | case "RightToLeft": | ||
1285 | rightToLeft = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1286 | break; | ||
1287 | case "RightAligned": | ||
1288 | rightAligned = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1289 | break; | ||
1290 | case "LeftScroll": | ||
1291 | leftScroll = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1292 | break; | ||
1293 | default: | ||
1294 | var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1295 | if (null == specialAttributes || !this.Core.TrySetBitFromName(specialAttributes, attrib.Name.LocalName, attribValue, bits, 16)) | ||
1296 | { | ||
1297 | this.Core.UnexpectedAttribute(node, attrib); | ||
1298 | } | ||
1299 | break; | ||
1300 | } | ||
1301 | } | ||
1302 | else | ||
1303 | { | ||
1304 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | var attributes = this.Core.CreateIntegerFromBitArray(bits); | ||
1309 | |||
1310 | //if (disabled) | ||
1311 | //{ | ||
1312 | // attributes |= WindowsInstallerConstants.MsidbControlAttributesEnabled; // bit will be inverted when stored | ||
1313 | //} | ||
1314 | |||
1315 | if (null == height) | ||
1316 | { | ||
1317 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height")); | ||
1318 | } | ||
1319 | |||
1320 | if (null == width) | ||
1321 | { | ||
1322 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width")); | ||
1323 | } | ||
1324 | |||
1325 | if (null == x) | ||
1326 | { | ||
1327 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X")); | ||
1328 | } | ||
1329 | |||
1330 | if (null == y) | ||
1331 | { | ||
1332 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y")); | ||
1333 | } | ||
1334 | |||
1335 | if (null == controlId) | ||
1336 | { | ||
1337 | controlId = this.Core.CreateIdentifier("ctl", dialog, x, y, height, width); | ||
1338 | } | ||
1339 | |||
1340 | if (isCancel) | ||
1341 | { | ||
1342 | cancelControl = controlId.Id; | ||
1343 | } | ||
1344 | |||
1345 | if (isDefault) | ||
1346 | { | ||
1347 | defaultControl = controlId.Id; | ||
1348 | } | ||
1349 | |||
1350 | foreach (var child in node.Elements()) | ||
1351 | { | ||
1352 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1353 | { | ||
1354 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
1355 | switch (child.Name.LocalName) | ||
1356 | { | ||
1357 | case "Binary": | ||
1358 | this.ParseBinaryElement(child); | ||
1359 | break; | ||
1360 | case "ComboBox": | ||
1361 | this.ParseControlGroupElement(child, TupleDefinitionType.ComboBox, "ListItem"); | ||
1362 | break; | ||
1363 | case "Condition": | ||
1364 | this.ParseConditionElement(child, node.Name.LocalName, controlId.Id, dialog); | ||
1365 | break; | ||
1366 | case "ListBox": | ||
1367 | this.ParseControlGroupElement(child, TupleDefinitionType.ListBox, "ListItem"); | ||
1368 | break; | ||
1369 | case "ListView": | ||
1370 | this.ParseControlGroupElement(child, TupleDefinitionType.ListView, "ListItem"); | ||
1371 | break; | ||
1372 | case "Property": | ||
1373 | this.ParsePropertyElement(child); | ||
1374 | break; | ||
1375 | case "Publish": | ||
1376 | this.ParsePublishElement(child, dialog ?? String.Empty, controlId.Id, ref publishOrder); | ||
1377 | break; | ||
1378 | case "RadioButtonGroup": | ||
1379 | radioButtonsType = this.ParseRadioButtonGroupElement(child, property, radioButtonsType); | ||
1380 | break; | ||
1381 | case "Subscribe": | ||
1382 | this.ParseSubscribeElement(child, dialog, controlId.Id); | ||
1383 | break; | ||
1384 | case "Text": | ||
1385 | foreach (var attrib in child.Attributes()) | ||
1386 | { | ||
1387 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1388 | { | ||
1389 | switch (attrib.Name.LocalName) | ||
1390 | { | ||
1391 | case "SourceFile": | ||
1392 | sourceFile = this.Core.GetAttributeValue(childSourceLineNumbers, attrib); | ||
1393 | break; | ||
1394 | default: | ||
1395 | this.Core.UnexpectedAttribute(child, attrib); | ||
1396 | break; | ||
1397 | } | ||
1398 | } | ||
1399 | else | ||
1400 | { | ||
1401 | this.Core.ParseExtensionAttribute(child, attrib); | ||
1402 | } | ||
1403 | } | ||
1404 | |||
1405 | text = Common.GetInnerText(child); | ||
1406 | if (!String.IsNullOrEmpty(text) && null != sourceFile) | ||
1407 | { | ||
1408 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(childSourceLineNumbers, child.Name.LocalName, "SourceFile")); | ||
1409 | } | ||
1410 | break; | ||
1411 | default: | ||
1412 | this.Core.UnexpectedElement(node, child); | ||
1413 | break; | ||
1414 | } | ||
1415 | } | ||
1416 | else | ||
1417 | { | ||
1418 | this.Core.ParseExtensionElement(node, child); | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | // If the radio buttons have icons, then we need to add the icon attribute. | ||
1423 | switch (radioButtonsType) | ||
1424 | { | ||
1425 | case RadioButtonType.Bitmap: | ||
1426 | attributes |= WindowsInstallerConstants.MsidbControlAttributesBitmap; | ||
1427 | break; | ||
1428 | case RadioButtonType.Icon: | ||
1429 | attributes |= WindowsInstallerConstants.MsidbControlAttributesIcon; | ||
1430 | break; | ||
1431 | case RadioButtonType.Text: | ||
1432 | // Text is the default so nothing needs to be added bits | ||
1433 | break; | ||
1434 | } | ||
1435 | |||
1436 | // the logic for creating control rows is a little tricky because of the way tabable controls are set | ||
1437 | IntermediateTuple tuple = null; | ||
1438 | if (!this.Core.EncounteredError) | ||
1439 | { | ||
1440 | if ("CheckBox" == controlType) | ||
1441 | { | ||
1442 | if (String.IsNullOrEmpty(property) && String.IsNullOrEmpty(checkBoxPropertyRef)) | ||
1443 | { | ||
1444 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef", true)); | ||
1445 | } | ||
1446 | else if (!String.IsNullOrEmpty(property) && !String.IsNullOrEmpty(checkBoxPropertyRef)) | ||
1447 | { | ||
1448 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef")); | ||
1449 | } | ||
1450 | else if (!String.IsNullOrEmpty(property)) | ||
1451 | { | ||
1452 | var checkBoxTuple = new CheckBoxTuple(sourceLineNumbers) | ||
1453 | { | ||
1454 | Property = property, | ||
1455 | Value = checkboxValue | ||
1456 | }; | ||
1457 | |||
1458 | this.Core.AddTuple(checkBoxTuple); | ||
1459 | } | ||
1460 | else | ||
1461 | { | ||
1462 | this.Core.CreateSimpleReference(sourceLineNumbers, "CheckBox", checkBoxPropertyRef); | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | var id = new Identifier(controlId.Access, dialog, controlId.Id); | ||
1467 | |||
1468 | if (TupleDefinitionType.BBControl == tupleType) | ||
1469 | { | ||
1470 | var bbTuple = new BBControlTuple(sourceLineNumbers, id) | ||
1471 | { | ||
1472 | Billboard_ = dialog, | ||
1473 | BBControl = controlId.Id, | ||
1474 | Type = controlType, | ||
1475 | Attributes = attributes, | ||
1476 | Enabled = !disabled, | ||
1477 | Indirect = indirect, | ||
1478 | Integer = integer, | ||
1479 | LeftScroll = leftScroll, | ||
1480 | RightAligned = rightAligned, | ||
1481 | RightToLeft = rightToLeft, | ||
1482 | Sunken = sunken, | ||
1483 | Visible = !hidden, | ||
1484 | Text = text, | ||
1485 | SourceFile = sourceFile | ||
1486 | }; | ||
1487 | |||
1488 | bbTuple.Set((int)BBControlTupleFields.X, x); | ||
1489 | bbTuple.Set((int)BBControlTupleFields.Y, y); | ||
1490 | bbTuple.Set((int)BBControlTupleFields.Width, width); | ||
1491 | bbTuple.Set((int)BBControlTupleFields.Height, height); | ||
1492 | |||
1493 | this.Core.AddTuple(bbTuple); | ||
1494 | |||
1495 | tuple = bbTuple; | ||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | var controlTuple = new ControlTuple(sourceLineNumbers, id) | ||
1500 | { | ||
1501 | Dialog_ = dialog, | ||
1502 | Control = controlId.Id, | ||
1503 | Type = controlType, | ||
1504 | Attributes = attributes, | ||
1505 | Enabled = !disabled, | ||
1506 | Indirect = indirect, | ||
1507 | Integer = integer, | ||
1508 | LeftScroll = leftScroll, | ||
1509 | RightAligned = rightAligned, | ||
1510 | RightToLeft = rightToLeft, | ||
1511 | Sunken = sunken, | ||
1512 | Visible = !hidden, | ||
1513 | Property = !String.IsNullOrEmpty(property) ? property : checkBoxPropertyRef, | ||
1514 | Text = text, | ||
1515 | Help = (null == tooltip && null == help) ? null : String.Concat(tooltip, "|", help), // Separator is required, even if only one is non-null.}; | ||
1516 | SourceFile = sourceFile | ||
1517 | }; | ||
1518 | |||
1519 | controlTuple.Set((int)BBControlTupleFields.X, x); | ||
1520 | controlTuple.Set((int)BBControlTupleFields.Y, y); | ||
1521 | controlTuple.Set((int)BBControlTupleFields.Width, width); | ||
1522 | controlTuple.Set((int)BBControlTupleFields.Height, height); | ||
1523 | |||
1524 | this.Core.AddTuple(controlTuple); | ||
1525 | |||
1526 | tuple = controlTuple; | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | if (!notTabbable) | ||
1531 | { | ||
1532 | if (TupleDefinitionType.BBControl == tupleType) | ||
1533 | { | ||
1534 | this.Core.Write(ErrorMessages.TabbableControlNotAllowedInBillboard(sourceLineNumbers, node.Name.LocalName, controlType)); | ||
1535 | } | ||
1536 | |||
1537 | if (null == firstControl) | ||
1538 | { | ||
1539 | firstControl = controlId.Id; | ||
1540 | } | ||
1541 | |||
1542 | if (null != lastTabTuple) | ||
1543 | { | ||
1544 | lastTabTuple.Set(10, controlId.Id); | ||
1545 | } | ||
1546 | lastTabTuple = tuple; | ||
1547 | } | ||
1548 | |||
1549 | // bitmap and icon controls contain a foreign key into the binary table in the text column; | ||
1550 | // add a reference if the identifier of the binary entry is known during compilation | ||
1551 | if (("Bitmap" == controlType || "Icon" == controlType) && Common.IsIdentifier(text)) | ||
1552 | { | ||
1553 | this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
1554 | } | ||
1555 | } | ||
1556 | |||
1557 | /// <summary> | ||
1558 | /// Parses a publish control event element. | ||
1559 | /// </summary> | ||
1560 | /// <param name="node">Element to parse.</param> | ||
1561 | /// <param name="dialog">Identifier of parent dialog.</param> | ||
1562 | /// <param name="control">Identifier of parent control.</param> | ||
1563 | /// <param name="order">Relative order of controls.</param> | ||
1564 | private void ParsePublishElement(XElement node, string dialog, string control, ref int order) | ||
1565 | { | ||
1566 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1567 | string argument = null; | ||
1568 | string condition = null; | ||
1569 | string controlEvent = null; | ||
1570 | string property = null; | ||
1571 | |||
1572 | // give this control event a unique ordering | ||
1573 | order++; | ||
1574 | |||
1575 | foreach (var attrib in node.Attributes()) | ||
1576 | { | ||
1577 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1578 | { | ||
1579 | switch (attrib.Name.LocalName) | ||
1580 | { | ||
1581 | case "Control": | ||
1582 | if (null != control) | ||
1583 | { | ||
1584 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
1585 | } | ||
1586 | control = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1587 | break; | ||
1588 | case "Dialog": | ||
1589 | if (null != dialog) | ||
1590 | { | ||
1591 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
1592 | } | ||
1593 | dialog = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1594 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", dialog); | ||
1595 | break; | ||
1596 | case "Event": | ||
1597 | controlEvent = Compiler.UppercaseFirstChar(this.Core.GetAttributeValue(sourceLineNumbers, attrib)); | ||
1598 | break; | ||
1599 | case "Order": | ||
1600 | order = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 2147483647); | ||
1601 | break; | ||
1602 | case "Property": | ||
1603 | property = String.Concat("[", this.Core.GetAttributeValue(sourceLineNumbers, attrib), "]"); | ||
1604 | break; | ||
1605 | case "Value": | ||
1606 | argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1607 | break; | ||
1608 | default: | ||
1609 | this.Core.UnexpectedAttribute(node, attrib); | ||
1610 | break; | ||
1611 | } | ||
1612 | } | ||
1613 | else | ||
1614 | { | ||
1615 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1616 | } | ||
1617 | } | ||
1618 | |||
1619 | condition = this.Core.GetConditionInnerText(node); | ||
1620 | |||
1621 | if (null == control) | ||
1622 | { | ||
1623 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Control")); | ||
1624 | } | ||
1625 | |||
1626 | if (null == dialog) | ||
1627 | { | ||
1628 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dialog")); | ||
1629 | } | ||
1630 | |||
1631 | if (null == controlEvent && null == property) // need to specify at least one | ||
1632 | { | ||
1633 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Event", "Property")); | ||
1634 | } | ||
1635 | else if (null != controlEvent && null != property) // cannot specify both | ||
1636 | { | ||
1637 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Event", "Property")); | ||
1638 | } | ||
1639 | |||
1640 | if (null == argument) | ||
1641 | { | ||
1642 | if (null != controlEvent) | ||
1643 | { | ||
1644 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value", "Event")); | ||
1645 | } | ||
1646 | else if (null != property) | ||
1647 | { | ||
1648 | // if this is setting a property to null, put a special value in the argument column | ||
1649 | argument = "{}"; | ||
1650 | } | ||
1651 | } | ||
1652 | |||
1653 | this.Core.ParseForExtensionElements(node); | ||
1654 | |||
1655 | if (!this.Core.EncounteredError) | ||
1656 | { | ||
1657 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ControlEvent); | ||
1658 | row.Set(0, dialog); | ||
1659 | row.Set(1, control); | ||
1660 | row.Set(2, (null != controlEvent ? controlEvent : property)); | ||
1661 | row.Set(3, argument); | ||
1662 | row.Set(4, condition); | ||
1663 | row.Set(5, order); | ||
1664 | } | ||
1665 | |||
1666 | if ("DoAction" == controlEvent && null != argument) | ||
1667 | { | ||
1668 | // if we're not looking at a standard action or a formatted string then create a reference | ||
1669 | // to the custom action. | ||
1670 | if (!WindowsInstallerStandard.IsStandardAction(argument) && !Common.ContainsProperty(argument)) | ||
1671 | { | ||
1672 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", argument); | ||
1673 | } | ||
1674 | } | ||
1675 | |||
1676 | // if we're referring to a dialog but not through a property, add it to the references | ||
1677 | if (("NewDialog" == controlEvent || "SpawnDialog" == controlEvent || "SpawnWaitDialog" == controlEvent || "SelectionBrowse" == controlEvent) && Common.IsIdentifier(argument)) | ||
1678 | { | ||
1679 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", argument); | ||
1680 | } | ||
1681 | } | ||
1682 | |||
1683 | /// <summary> | ||
1684 | /// Parses a control subscription element. | ||
1685 | /// </summary> | ||
1686 | /// <param name="node">Element to parse.</param> | ||
1687 | /// <param name="dialog">Identifier of dialog.</param> | ||
1688 | /// <param name="control">Identifier of control.</param> | ||
1689 | private void ParseSubscribeElement(XElement node, string dialog, string control) | ||
1690 | { | ||
1691 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1692 | string controlAttribute = null; | ||
1693 | string eventMapping = null; | ||
1694 | |||
1695 | foreach (var attrib in node.Attributes()) | ||
1696 | { | ||
1697 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1698 | { | ||
1699 | switch (attrib.Name.LocalName) | ||
1700 | { | ||
1701 | case "Attribute": | ||
1702 | controlAttribute = Compiler.UppercaseFirstChar(this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib)); | ||
1703 | break; | ||
1704 | case "Event": | ||
1705 | eventMapping = Compiler.UppercaseFirstChar(this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib)); | ||
1706 | break; | ||
1707 | default: | ||
1708 | this.Core.UnexpectedAttribute(node, attrib); | ||
1709 | break; | ||
1710 | } | ||
1711 | } | ||
1712 | else | ||
1713 | { | ||
1714 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1715 | } | ||
1716 | } | ||
1717 | |||
1718 | this.Core.ParseForExtensionElements(node); | ||
1719 | |||
1720 | if (!this.Core.EncounteredError) | ||
1721 | { | ||
1722 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.EventMapping); | ||
1723 | row.Set(0, dialog); | ||
1724 | row.Set(1, control); | ||
1725 | row.Set(2, eventMapping); | ||
1726 | row.Set(3, controlAttribute); | ||
1727 | } | ||
1728 | } | ||
1729 | } | ||
1730 | } | ||
diff --git a/src/WixToolset.Core/ComponentKeyPath.cs b/src/WixToolset.Core/ComponentKeyPath.cs index f81465fd..8e9c5776 100644 --- a/src/WixToolset.Core/ComponentKeyPath.cs +++ b/src/WixToolset.Core/ComponentKeyPath.cs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using WixToolset.Data; | ||
5 | using WixToolset.Extensibility.Data; | 6 | using WixToolset.Extensibility.Data; |
6 | 7 | ||
7 | internal class ComponentKeyPath : IComponentKeyPath | 8 | internal class ComponentKeyPath : IComponentKeyPath |
@@ -19,6 +20,6 @@ namespace WixToolset.Core | |||
19 | /// <summary> | 20 | /// <summary> |
20 | /// Type of resource to be the key path. | 21 | /// Type of resource to be the key path. |
21 | /// </summary> | 22 | /// </summary> |
22 | public ComponentKeyPathType Type { get; set; } | 23 | public PossibleKeyPathType Type { get; set; } |
23 | } | 24 | } |
24 | } | 25 | } |
diff --git a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs index dce77781..9d4a7cbd 100644 --- a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs +++ b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs | |||
@@ -16,7 +16,6 @@ namespace WixToolset.Core.ExtensibilityServices | |||
16 | using WixToolset.Extensibility; | 16 | using WixToolset.Extensibility; |
17 | using WixToolset.Extensibility.Data; | 17 | using WixToolset.Extensibility.Data; |
18 | using WixToolset.Extensibility.Services; | 18 | using WixToolset.Extensibility.Services; |
19 | using Wix = WixToolset.Data.Serialize; | ||
20 | 19 | ||
21 | internal class ParseHelper : IParseHelper | 20 | internal class ParseHelper : IParseHelper |
22 | { | 21 | { |
@@ -179,23 +178,21 @@ namespace WixToolset.Core.ExtensibilityServices | |||
179 | return new Identifier(id, AccessModifier.Private); | 178 | return new Identifier(id, AccessModifier.Private); |
180 | } | 179 | } |
181 | 180 | ||
182 | public Identifier CreateRegistryRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, int root, string key, string name, string value, string componentId, bool escapeLeadingHash) | 181 | public Identifier CreateRegistryRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, RegistryRootType root, string key, string name, string value, string componentId, bool escapeLeadingHash) |
183 | { | 182 | { |
184 | Identifier id = null; | 183 | if (RegistryRootType.Unknown == root) |
185 | |||
186 | if (-1 > root || 3 < root) | ||
187 | { | 184 | { |
188 | throw new ArgumentOutOfRangeException("root"); | 185 | throw new ArgumentOutOfRangeException(nameof(root)); |
189 | } | 186 | } |
190 | 187 | ||
191 | if (null == key) | 188 | if (null == key) |
192 | { | 189 | { |
193 | throw new ArgumentNullException("key"); | 190 | throw new ArgumentNullException(nameof(key)); |
194 | } | 191 | } |
195 | 192 | ||
196 | if (null == componentId) | 193 | if (null == componentId) |
197 | { | 194 | { |
198 | throw new ArgumentNullException("componentId"); | 195 | throw new ArgumentNullException(nameof(componentId)); |
199 | } | 196 | } |
200 | 197 | ||
201 | // Escape the leading '#' character for string registry values. | 198 | // Escape the leading '#' character for string registry values. |
@@ -204,26 +201,31 @@ namespace WixToolset.Core.ExtensibilityServices | |||
204 | value = String.Concat("#", value); | 201 | value = String.Concat("#", value); |
205 | } | 202 | } |
206 | 203 | ||
207 | id = this.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), key.ToLowerInvariant(), (null != name ? name.ToLowerInvariant() : name)); | 204 | var id = this.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), key.ToLowerInvariant(), (null != name ? name.ToLowerInvariant() : name)); |
205 | |||
206 | var tuple = new RegistryTuple(sourceLineNumbers, id) | ||
207 | { | ||
208 | Root = root, | ||
209 | Key = key, | ||
210 | Name = name, | ||
211 | Value = value, | ||
212 | Component_ = componentId, | ||
213 | }; | ||
208 | 214 | ||
209 | var row = this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.Registry, id); | 215 | section.Tuples.Add(tuple); |
210 | row.Set(1, root); | ||
211 | row.Set(2, key); | ||
212 | row.Set(3, name); | ||
213 | row.Set(4, value); | ||
214 | row.Set(5, componentId); | ||
215 | 216 | ||
216 | return id; | 217 | return id; |
217 | } | 218 | } |
218 | 219 | ||
219 | public void CreateSimpleReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, string tableName, params string[] primaryKeys) | 220 | public void CreateSimpleReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, string tableName, params string[] primaryKeys) |
220 | { | 221 | { |
221 | var joinedKeys = String.Join("/", primaryKeys); | 222 | var tuple = new WixSimpleReferenceTuple(sourceLineNumbers) |
222 | var id = String.Concat(tableName, ":", joinedKeys); | 223 | { |
224 | Table = tableName, | ||
225 | PrimaryKeys = String.Join("/", primaryKeys) | ||
226 | }; | ||
223 | 227 | ||
224 | var wixSimpleReferenceRow = (WixSimpleReferenceTuple)this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.WixSimpleReference); | 228 | section.Tuples.Add(tuple); |
225 | wixSimpleReferenceRow.Table = tableName; | ||
226 | wixSimpleReferenceRow.PrimaryKeys = joinedKeys; | ||
227 | } | 229 | } |
228 | 230 | ||
229 | public void CreateWixGroupRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) | 231 | public void CreateWixGroupRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) |
@@ -238,11 +240,15 @@ namespace WixToolset.Core.ExtensibilityServices | |||
238 | throw new ArgumentNullException("childId"); | 240 | throw new ArgumentNullException("childId"); |
239 | } | 241 | } |
240 | 242 | ||
241 | var row = (WixGroupTuple)this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.WixGroup); | 243 | var tuple = new WixGroupTuple(sourceLineNumbers) |
242 | row.ParentId = parentId; | 244 | { |
243 | row.ParentType = parentType; | 245 | ParentId = parentId, |
244 | row.ChildId = childId; | 246 | ParentType = parentType, |
245 | row.ChildType = childType; | 247 | ChildId = childId, |
248 | ChildType = childType, | ||
249 | }; | ||
250 | |||
251 | section.Tuples.Add(tuple); | ||
246 | } | 252 | } |
247 | 253 | ||
248 | public IntermediateTuple CreateRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, string tableName, Identifier identifier = null) | 254 | public IntermediateTuple CreateRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, string tableName, Identifier identifier = null) |
@@ -573,35 +579,46 @@ namespace WixToolset.Core.ExtensibilityServices | |||
573 | return Common.GetAttributeValue(this.Messaging, sourceLineNumbers, attribute, emptyRule); | 579 | return Common.GetAttributeValue(this.Messaging, sourceLineNumbers, attribute, emptyRule); |
574 | } | 580 | } |
575 | 581 | ||
576 | public int GetAttributeMsidbRegistryRootValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowHkmu) | 582 | public RegistryRootType? GetAttributeRegistryRootValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowHkmu) |
577 | { | 583 | { |
578 | Wix.RegistryRootType registryRoot = this.GetAttributeRegistryRootValue(sourceLineNumbers, attribute, allowHkmu); | 584 | string value = this.GetAttributeValue(sourceLineNumbers, attribute); |
585 | if (String.IsNullOrEmpty(value)) | ||
586 | { | ||
587 | return null; | ||
588 | } | ||
579 | 589 | ||
580 | switch (registryRoot) | 590 | switch (value) |
581 | { | 591 | { |
582 | case Wix.RegistryRootType.NotSet: | 592 | case "HKCR": |
583 | return CompilerConstants.IntegerNotSet; | 593 | return RegistryRootType.ClassesRoot; |
584 | case Wix.RegistryRootType.HKCR: | 594 | |
585 | return Core.Native.MsiInterop.MsidbRegistryRootClassesRoot; | 595 | case "HKCU": |
586 | case Wix.RegistryRootType.HKCU: | 596 | return RegistryRootType.CurrentUser; |
587 | return Core.Native.MsiInterop.MsidbRegistryRootCurrentUser; | 597 | |
588 | case Wix.RegistryRootType.HKLM: | 598 | case "HKLM": |
589 | return Core.Native.MsiInterop.MsidbRegistryRootLocalMachine; | 599 | return RegistryRootType.LocalMachine; |
590 | case Wix.RegistryRootType.HKU: | 600 | |
591 | return Core.Native.MsiInterop.MsidbRegistryRootUsers; | 601 | case "HKU": |
592 | case Wix.RegistryRootType.HKMU: | 602 | return RegistryRootType.Users; |
593 | // This is gross, but there was *one* registry root parsing instance | 603 | |
594 | // (in Compiler.ParseRegistrySearchElement()) that did not explicitly | 604 | case "HKMU": |
595 | // handle HKMU and it fell through to the default error case. The | ||
596 | // others treated it as -1, which is what we do here. | ||
597 | if (allowHkmu) | 605 | if (allowHkmu) |
598 | { | 606 | { |
599 | return -1; | 607 | return RegistryRootType.MachineUser; |
600 | } | 608 | } |
601 | break; | 609 | break; |
602 | } | 610 | } |
603 | 611 | ||
604 | return CompilerConstants.IntegerNotSet; | 612 | if (allowHkmu) |
613 | { | ||
614 | this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, "HKMU", "HKCR", "HKCU", "HKLM", "HKU")); | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, "HKCR", "HKCU", "HKLM", "HKU")); | ||
619 | } | ||
620 | |||
621 | return RegistryRootType.Unknown; | ||
605 | } | 622 | } |
606 | 623 | ||
607 | public string GetAttributeVersionValue(SourceLineNumber sourceLineNumbers, XAttribute attribute) | 624 | public string GetAttributeVersionValue(SourceLineNumber sourceLineNumbers, XAttribute attribute) |
@@ -847,34 +864,6 @@ namespace WixToolset.Core.ExtensibilityServices | |||
847 | return row; | 864 | return row; |
848 | } | 865 | } |
849 | 866 | ||
850 | private Wix.RegistryRootType GetAttributeRegistryRootValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowHkmu) | ||
851 | { | ||
852 | Wix.RegistryRootType registryRoot = Wix.RegistryRootType.NotSet; | ||
853 | string value = this.GetAttributeValue(sourceLineNumbers, attribute); | ||
854 | |||
855 | if (0 < value.Length) | ||
856 | { | ||
857 | registryRoot = Wix.Enums.ParseRegistryRootType(value); | ||
858 | |||
859 | if (Wix.RegistryRootType.IllegalValue == registryRoot || (!allowHkmu && Wix.RegistryRootType.HKMU == registryRoot)) | ||
860 | { | ||
861 | // TODO: Find a way to expose the valid values programatically! | ||
862 | if (allowHkmu) | ||
863 | { | ||
864 | this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, | ||
865 | "HKMU", "HKCR", "HKCU", "HKLM", "HKU")); | ||
866 | } | ||
867 | else | ||
868 | { | ||
869 | this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, | ||
870 | "HKCR", "HKCU", "HKLM", "HKU")); | ||
871 | } | ||
872 | } | ||
873 | } | ||
874 | |||
875 | return registryRoot; | ||
876 | } | ||
877 | |||
878 | private static bool TryFindExtension(IEnumerable<ICompilerExtension> extensions, XNamespace ns, out ICompilerExtension extension) | 867 | private static bool TryFindExtension(IEnumerable<ICompilerExtension> extensions, XNamespace ns, out ICompilerExtension extension) |
879 | { | 868 | { |
880 | extension = null; | 869 | extension = null; |
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs index 9b32ad1d..13efe6c5 100644 --- a/src/WixToolset.Core/Linker.cs +++ b/src/WixToolset.Core/Linker.cs | |||
@@ -11,6 +11,7 @@ namespace WixToolset.Core | |||
11 | using WixToolset.Core.Link; | 11 | using WixToolset.Core.Link; |
12 | using WixToolset.Data; | 12 | using WixToolset.Data; |
13 | using WixToolset.Data.Tuples; | 13 | using WixToolset.Data.Tuples; |
14 | using WixToolset.Data.WindowsInstaller; | ||
14 | using WixToolset.Extensibility.Data; | 15 | using WixToolset.Extensibility.Data; |
15 | using WixToolset.Extensibility.Services; | 16 | using WixToolset.Extensibility.Services; |
16 | 17 | ||
@@ -225,7 +226,7 @@ namespace WixToolset.Core | |||
225 | sectionCount++; | 226 | sectionCount++; |
226 | 227 | ||
227 | var sectionId = section.Id; | 228 | var sectionId = section.Id; |
228 | if (null == sectionId && sectionIdOnRows) | 229 | if (null == sectionId && this.sectionIdOnRows) |
229 | { | 230 | { |
230 | sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture); | 231 | sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture); |
231 | } | 232 | } |
@@ -611,7 +612,7 @@ namespace WixToolset.Core | |||
611 | #endif | 612 | #endif |
612 | 613 | ||
613 | //correct the section Id in FeatureComponents table | 614 | //correct the section Id in FeatureComponents table |
614 | if (sectionIdOnRows) | 615 | if (this.sectionIdOnRows) |
615 | { | 616 | { |
616 | //var componentSectionIds = new Dictionary<string, string>(); | 617 | //var componentSectionIds = new Dictionary<string, string>(); |
617 | 618 | ||
diff --git a/src/WixToolset.Core/LocalizationParser.cs b/src/WixToolset.Core/LocalizationParser.cs index f7f86a54..a3272fc8 100644 --- a/src/WixToolset.Core/LocalizationParser.cs +++ b/src/WixToolset.Core/LocalizationParser.cs | |||
@@ -5,7 +5,6 @@ namespace WixToolset.Core | |||
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Xml.Linq; | 7 | using System.Xml.Linq; |
8 | using WixToolset.Core.Native; | ||
9 | using WixToolset.Data; | 8 | using WixToolset.Data; |
10 | using WixToolset.Data.Bind; | 9 | using WixToolset.Data.Bind; |
11 | using WixToolset.Extensibility; | 10 | using WixToolset.Extensibility; |
@@ -14,7 +13,7 @@ namespace WixToolset.Core | |||
14 | internal class LocalizationParser : ILocalizationParser | 13 | internal class LocalizationParser : ILocalizationParser |
15 | { | 14 | { |
16 | public static readonly XNamespace WxlNamespace = "http://wixtoolset.org/schemas/v4/wxl"; | 15 | public static readonly XNamespace WxlNamespace = "http://wixtoolset.org/schemas/v4/wxl"; |
17 | private static string XmlElementName = "WixLocalization"; | 16 | private const string XmlElementName = "WixLocalization"; |
18 | 17 | ||
19 | internal LocalizationParser(IServiceProvider serviceProvider) | 18 | internal LocalizationParser(IServiceProvider serviceProvider) |
20 | { | 19 | { |
@@ -215,13 +214,14 @@ namespace WixToolset.Core | |||
215 | { | 214 | { |
216 | string dialog = null; | 215 | string dialog = null; |
217 | string control = null; | 216 | string control = null; |
218 | int x = CompilerConstants.IntegerNotSet; | 217 | var x = CompilerConstants.IntegerNotSet; |
219 | int y = CompilerConstants.IntegerNotSet; | 218 | var y = CompilerConstants.IntegerNotSet; |
220 | int width = CompilerConstants.IntegerNotSet; | 219 | var width = CompilerConstants.IntegerNotSet; |
221 | int height = CompilerConstants.IntegerNotSet; | 220 | var height = CompilerConstants.IntegerNotSet; |
222 | int attribs = 0; | 221 | var sourceLineNumbers = SourceLineNumber.CreateFromXObject(node); |
223 | string text = null; | 222 | var rightToLeft = false; |
224 | SourceLineNumber sourceLineNumbers = SourceLineNumber.CreateFromXObject(node); | 223 | var rightAligned = false; |
224 | var leftScroll = false; | ||
225 | 225 | ||
226 | foreach (XAttribute attrib in node.Attributes()) | 226 | foreach (XAttribute attrib in node.Attributes()) |
227 | { | 227 | { |
@@ -236,34 +236,37 @@ namespace WixToolset.Core | |||
236 | control = Common.GetAttributeIdentifierValue(messaging, sourceLineNumbers, attrib); | 236 | control = Common.GetAttributeIdentifierValue(messaging, sourceLineNumbers, attrib); |
237 | break; | 237 | break; |
238 | case "X": | 238 | case "X": |
239 | x = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, short.MaxValue); | 239 | x = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, Int16.MaxValue); |
240 | break; | 240 | break; |
241 | case "Y": | 241 | case "Y": |
242 | y = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, short.MaxValue); | 242 | y = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, Int16.MaxValue); |
243 | break; | 243 | break; |
244 | case "Width": | 244 | case "Width": |
245 | width = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, short.MaxValue); | 245 | width = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, Int16.MaxValue); |
246 | break; | 246 | break; |
247 | case "Height": | 247 | case "Height": |
248 | height = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, short.MaxValue); | 248 | height = Common.GetAttributeIntegerValue(messaging, sourceLineNumbers, attrib, 0, Int16.MaxValue); |
249 | break; | 249 | break; |
250 | case "RightToLeft": | 250 | case "RightToLeft": |
251 | if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib)) | 251 | rightToLeft = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib); |
252 | { | 252 | //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib)) |
253 | attribs |= MsiInterop.MsidbControlAttributesRTLRO; | 253 | //{ |
254 | } | 254 | // attribs |= MsiInterop.MsidbControlAttributesRTLRO; |
255 | //} | ||
255 | break; | 256 | break; |
256 | case "RightAligned": | 257 | case "RightAligned": |
257 | if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib)) | 258 | rightAligned = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib); |
258 | { | 259 | //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib)) |
259 | attribs |= MsiInterop.MsidbControlAttributesRightAligned; | 260 | //{ |
260 | } | 261 | // attribs |= MsiInterop.MsidbControlAttributesRightAligned; |
262 | //} | ||
261 | break; | 263 | break; |
262 | case "LeftScroll": | 264 | case "LeftScroll": |
263 | if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib)) | 265 | leftScroll = YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib); |
264 | { | 266 | //if (YesNoType.Yes == Common.GetAttributeYesNoValue(messaging, sourceLineNumbers, attrib)) |
265 | attribs |= MsiInterop.MsidbControlAttributesLeftScroll; | 267 | //{ |
266 | } | 268 | // attribs |= MsiInterop.MsidbControlAttributesLeftScroll; |
269 | //} | ||
267 | break; | 270 | break; |
268 | default: | 271 | default: |
269 | Common.UnexpectedAttribute(messaging, sourceLineNumbers, attrib); | 272 | Common.UnexpectedAttribute(messaging, sourceLineNumbers, attrib); |
@@ -276,19 +279,21 @@ namespace WixToolset.Core | |||
276 | } | 279 | } |
277 | } | 280 | } |
278 | 281 | ||
279 | text = Common.GetInnerText(node); | 282 | var text = Common.GetInnerText(node); |
280 | 283 | ||
281 | if (String.IsNullOrEmpty(control) && 0 < attribs) | 284 | if (String.IsNullOrEmpty(control) && (rightToLeft || rightAligned || leftScroll)) |
282 | { | 285 | { |
283 | if (MsiInterop.MsidbControlAttributesRTLRO == (attribs & MsiInterop.MsidbControlAttributesRTLRO)) | 286 | if (rightToLeft) |
284 | { | 287 | { |
285 | messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.ToString(), "RightToLeft", "Control")); | 288 | messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.ToString(), "RightToLeft", "Control")); |
286 | } | 289 | } |
287 | else if (MsiInterop.MsidbControlAttributesRightAligned == (attribs & MsiInterop.MsidbControlAttributesRightAligned)) | 290 | |
291 | if (rightAligned) | ||
288 | { | 292 | { |
289 | messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.ToString(), "RightAligned", "Control")); | 293 | messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.ToString(), "RightAligned", "Control")); |
290 | } | 294 | } |
291 | else if (MsiInterop.MsidbControlAttributesLeftScroll == (attribs & MsiInterop.MsidbControlAttributesLeftScroll)) | 295 | |
296 | if (leftScroll) | ||
292 | { | 297 | { |
293 | messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.ToString(), "LeftScroll", "Control")); | 298 | messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.ToString(), "LeftScroll", "Control")); |
294 | } | 299 | } |
@@ -301,8 +306,8 @@ namespace WixToolset.Core | |||
301 | 306 | ||
302 | if (!messaging.EncounteredError) | 307 | if (!messaging.EncounteredError) |
303 | { | 308 | { |
304 | LocalizedControl localizedControl = new LocalizedControl(dialog, control, x, y, width, height, attribs, text); | 309 | var localizedControl = new LocalizedControl(dialog, control, x, y, width, height, rightToLeft, rightAligned, leftScroll, text); |
305 | string key = localizedControl.GetKey(); | 310 | var key = localizedControl.GetKey(); |
306 | if (localizedControls.ContainsKey(key)) | 311 | if (localizedControls.ContainsKey(key)) |
307 | { | 312 | { |
308 | if (String.IsNullOrEmpty(localizedControl.Control)) | 313 | if (String.IsNullOrEmpty(localizedControl.Control)) |
diff --git a/src/WixToolset.Core/Resolver.cs b/src/WixToolset.Core/Resolver.cs index c69c4f68..4bdc5815 100644 --- a/src/WixToolset.Core/Resolver.cs +++ b/src/WixToolset.Core/Resolver.cs | |||
@@ -126,73 +126,72 @@ namespace WixToolset.Core | |||
126 | { | 126 | { |
127 | foreach (var section in context.IntermediateRepresentation.Sections) | 127 | foreach (var section in context.IntermediateRepresentation.Sections) |
128 | { | 128 | { |
129 | foreach (var row in section.Tuples.OfType<DialogTuple>()) | 129 | foreach (var tuple in section.Tuples.OfType<DialogTuple>()) |
130 | { | 130 | { |
131 | string dialog = row.Dialog; | 131 | if (context.VariableResolver.TryGetLocalizedControl(tuple.Id.Id, null, out var localizedControl)) |
132 | |||
133 | if (context.VariableResolver.TryGetLocalizedControl(dialog, null, out LocalizedControl localizedControl)) | ||
134 | { | 132 | { |
135 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | 133 | if (CompilerConstants.IntegerNotSet != localizedControl.X) |
136 | { | 134 | { |
137 | row.HCentering = localizedControl.X; | 135 | tuple.HCentering = localizedControl.X; |
138 | } | 136 | } |
139 | 137 | ||
140 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) | 138 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) |
141 | { | 139 | { |
142 | row.VCentering = localizedControl.Y; | 140 | tuple.VCentering = localizedControl.Y; |
143 | } | 141 | } |
144 | 142 | ||
145 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) | 143 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) |
146 | { | 144 | { |
147 | row.Width = localizedControl.Width; | 145 | tuple.Width = localizedControl.Width; |
148 | } | 146 | } |
149 | 147 | ||
150 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) | 148 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) |
151 | { | 149 | { |
152 | row.Height = localizedControl.Height; | 150 | tuple.Height = localizedControl.Height; |
153 | } | 151 | } |
154 | 152 | ||
155 | row.Attributes = row.Attributes | localizedControl.Attributes; | 153 | tuple.RightAligned |= localizedControl.RightAligned; |
154 | tuple.RightToLeft |= localizedControl.RightToLeft; | ||
155 | tuple.LeftScroll |= localizedControl.LeftScroll; | ||
156 | 156 | ||
157 | if (!String.IsNullOrEmpty(localizedControl.Text)) | 157 | if (!String.IsNullOrEmpty(localizedControl.Text)) |
158 | { | 158 | { |
159 | row.Title = localizedControl.Text; | 159 | tuple.Title = localizedControl.Text; |
160 | } | 160 | } |
161 | } | 161 | } |
162 | } | 162 | } |
163 | 163 | ||
164 | foreach (var row in section.Tuples.OfType<ControlTuple>()) | 164 | foreach (var tuple in section.Tuples.OfType<ControlTuple>()) |
165 | { | 165 | { |
166 | string dialog = row.Dialog_; | 166 | if (context.VariableResolver.TryGetLocalizedControl(tuple.Dialog_, tuple.Control, out var localizedControl)) |
167 | string control = row.Control; | ||
168 | |||
169 | if (context.VariableResolver.TryGetLocalizedControl(dialog, control, out LocalizedControl localizedControl)) | ||
170 | { | 167 | { |
171 | if (CompilerConstants.IntegerNotSet != localizedControl.X) | 168 | if (CompilerConstants.IntegerNotSet != localizedControl.X) |
172 | { | 169 | { |
173 | row.X = localizedControl.X; | 170 | tuple.X = localizedControl.X; |
174 | } | 171 | } |
175 | 172 | ||
176 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) | 173 | if (CompilerConstants.IntegerNotSet != localizedControl.Y) |
177 | { | 174 | { |
178 | row.Y = localizedControl.Y; | 175 | tuple.Y = localizedControl.Y; |
179 | } | 176 | } |
180 | 177 | ||
181 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) | 178 | if (CompilerConstants.IntegerNotSet != localizedControl.Width) |
182 | { | 179 | { |
183 | row.Width = localizedControl.Width; | 180 | tuple.Width = localizedControl.Width; |
184 | } | 181 | } |
185 | 182 | ||
186 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) | 183 | if (CompilerConstants.IntegerNotSet != localizedControl.Height) |
187 | { | 184 | { |
188 | row.Height = localizedControl.Height; | 185 | tuple.Height = localizedControl.Height; |
189 | } | 186 | } |
190 | 187 | ||
191 | row.Attributes = row.Attributes | localizedControl.Attributes; | 188 | tuple.RightAligned |= localizedControl.RightAligned; |
189 | tuple.RightToLeft |= localizedControl.RightToLeft; | ||
190 | tuple.LeftScroll |= localizedControl.LeftScroll; | ||
192 | 191 | ||
193 | if (!String.IsNullOrEmpty(localizedControl.Text)) | 192 | if (!String.IsNullOrEmpty(localizedControl.Text)) |
194 | { | 193 | { |
195 | row.Text = localizedControl.Text; | 194 | tuple.Text = localizedControl.Text; |
196 | } | 195 | } |
197 | } | 196 | } |
198 | } | 197 | } |
diff --git a/src/WixToolset.Core/WixToolset.Core.csproj b/src/WixToolset.Core/WixToolset.Core.csproj index 22063606..d573cbda 100644 --- a/src/WixToolset.Core/WixToolset.Core.csproj +++ b/src/WixToolset.Core/WixToolset.Core.csproj | |||
@@ -13,7 +13,6 @@ | |||
13 | <ItemGroup> | 13 | <ItemGroup> |
14 | <PackageReference Include="WixToolset.Data" Version="4.0.*" /> | 14 | <PackageReference Include="WixToolset.Data" Version="4.0.*" /> |
15 | <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" /> | 15 | <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" /> |
16 | <PackageReference Include="WixToolset.Core.Native" Version="4.0.*" /> | ||
17 | </ItemGroup> | 16 | </ItemGroup> |
18 | 17 | ||
19 | <!-- | 18 | <!-- |
@@ -26,7 +25,7 @@ | |||
26 | </ItemGroup> | 25 | </ItemGroup> |
27 | 26 | ||
28 | <ItemGroup> | 27 | <ItemGroup> |
29 | <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta-63102-01" PrivateAssets="All"/> | 28 | <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All" /> |
30 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" /> | 29 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" /> |
31 | </ItemGroup> | 30 | </ItemGroup> |
32 | </Project> | 31 | </Project> |