From 3232f84c19b86184cb7c2db137b97ccb9aec20cc Mon Sep 17 00:00:00 2001
From: comicfans <comicfans44@gmail.com>
Date: Sun, 10 Sep 2017 17:39:04 +0800
Subject: VS: Fix MANIFESTUAC link flag map to .vcxproj elements

Add special parsing of the flags given in `/MANIFESTUAC:"..."` in order
to map them correctly to `.vcxproj` elements.

Keep the old incorrect flag table entries for `uiAccess` and `level`
flags for compatibility even though they do not really exist.

Fixes: #16563
---
 Source/cmVS10LinkFlagTable.h               | 13 +++---
 Source/cmVS11LinkFlagTable.h               | 13 +++---
 Source/cmVS12LinkFlagTable.h               | 13 +++---
 Source/cmVS140LinkFlagTable.h              | 13 +++---
 Source/cmVS141LinkFlagTable.h              | 13 +++---
 Source/cmVisualStudio10TargetGenerator.cxx |  1 +
 Source/cmVisualStudioGeneratorOptions.cxx  | 68 ++++++++++++++++++++++++++++++
 Source/cmVisualStudioGeneratorOptions.h    |  2 +
 8 files changed, 111 insertions(+), 25 deletions(-)

diff --git a/Source/cmVS10LinkFlagTable.h b/Source/cmVS10LinkFlagTable.h
index c30ea9a..6a0313a 100644
--- a/Source/cmVS10LinkFlagTable.h
+++ b/Source/cmVS10LinkFlagTable.h
@@ -29,6 +29,8 @@ static cmVS7FlagTable cmVS10LinkFlagTable[] = {
   { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
     "ItaniumImage", 0 },
 
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
   { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
     "HighestAvailable", 0 },
@@ -123,8 +125,12 @@ static cmVS7FlagTable cmVS10LinkFlagTable[] = {
   { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
   { "GenerateManifest", "MANIFEST", "", "true", 0 },
   { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
   { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+
   { "GenerateDebugInformation", "DEBUG", "", "true",
     cmVS7FlagTable::CaseInsensitive },
   { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
@@ -162,11 +168,8 @@ static cmVS7FlagTable cmVS10LinkFlagTable[] = {
   { "LinkDLL", "DLL", "", "true", 0 },
 
   // Bool Properties With Argument
-  { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
-  { "EnableUAC", "MANIFESTUAC:", "", "true",
-    cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
-  { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
-    cmVS7FlagTable::UserValueRequired },
+  { "EnableUAC", "MANIFESTUAC:", "", "",
+    cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SpaceAppendable },
   { "GenerateMapFile", "MAP", "", "true",
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "MapFileName", "MAP:", "Generate Map File", "",
diff --git a/Source/cmVS11LinkFlagTable.h b/Source/cmVS11LinkFlagTable.h
index 1b3a046..24ba8fd 100644
--- a/Source/cmVS11LinkFlagTable.h
+++ b/Source/cmVS11LinkFlagTable.h
@@ -29,6 +29,8 @@ static cmVS7FlagTable cmVS11LinkFlagTable[] = {
   { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
     "ItaniumImage", 0 },
 
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
   { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
     "HighestAvailable", 0 },
@@ -135,8 +137,12 @@ static cmVS7FlagTable cmVS11LinkFlagTable[] = {
   { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
   { "GenerateManifest", "MANIFEST", "", "true", 0 },
   { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
   { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+
   { "ManifestEmbed", "manifest:embed", "", "true", 0 },
   { "GenerateDebugInformation", "DEBUG", "", "true",
     cmVS7FlagTable::CaseInsensitive },
@@ -179,11 +185,8 @@ static cmVS7FlagTable cmVS11LinkFlagTable[] = {
   { "LinkDLL", "DLL", "", "true", 0 },
 
   // Bool Properties With Argument
-  { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
-  { "EnableUAC", "MANIFESTUAC:", "", "true",
-    cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
-  { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
-    cmVS7FlagTable::UserValueRequired },
+  { "EnableUAC", "MANIFESTUAC:", "", "",
+    cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SpaceAppendable },
   { "GenerateMapFile", "MAP", "", "true",
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "MapFileName", "MAP:", "Generate Map File", "",
diff --git a/Source/cmVS12LinkFlagTable.h b/Source/cmVS12LinkFlagTable.h
index 168c34c..fc667c3 100644
--- a/Source/cmVS12LinkFlagTable.h
+++ b/Source/cmVS12LinkFlagTable.h
@@ -29,6 +29,8 @@ static cmVS7FlagTable cmVS12LinkFlagTable[] = {
   { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
     "ItaniumImage", 0 },
 
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
   { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
     "HighestAvailable", 0 },
@@ -135,8 +137,12 @@ static cmVS7FlagTable cmVS12LinkFlagTable[] = {
   { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
   { "GenerateManifest", "MANIFEST", "", "true", 0 },
   { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
   { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+
   { "ManifestEmbed", "manifest:embed", "", "true", 0 },
   { "GenerateDebugInformation", "DEBUG", "", "true",
     cmVS7FlagTable::CaseInsensitive },
@@ -179,11 +185,8 @@ static cmVS7FlagTable cmVS12LinkFlagTable[] = {
   { "LinkDLL", "DLL", "", "true", 0 },
 
   // Bool Properties With Argument
-  { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
-  { "EnableUAC", "MANIFESTUAC:", "", "true",
-    cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
-  { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
-    cmVS7FlagTable::UserValueRequired },
+  { "EnableUAC", "MANIFESTUAC:", "", "",
+    cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SpaceAppendable },
   { "GenerateMapFile", "MAP", "", "true",
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "MapFileName", "MAP:", "Generate Map File", "",
diff --git a/Source/cmVS140LinkFlagTable.h b/Source/cmVS140LinkFlagTable.h
index b9a4dc3..7c9452a 100644
--- a/Source/cmVS140LinkFlagTable.h
+++ b/Source/cmVS140LinkFlagTable.h
@@ -29,6 +29,8 @@ static cmVS7FlagTable cmVS140LinkFlagTable[] = {
   { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
     "ItaniumImage", 0 },
 
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
   { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
     "HighestAvailable", 0 },
@@ -148,8 +150,12 @@ static cmVS7FlagTable cmVS140LinkFlagTable[] = {
   { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
   { "GenerateManifest", "MANIFEST", "", "true", 0 },
   { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
   { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+
   { "ManifestEmbed", "manifest:embed", "", "true", 0 },
   { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
   { "AssemblyDebug", "ASSEMBLYDEBUG:DISABLE", "", "false", 0 },
@@ -190,11 +196,8 @@ static cmVS7FlagTable cmVS140LinkFlagTable[] = {
   { "LinkDLL", "DLL", "", "true", 0 },
 
   // Bool Properties With Argument
-  { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
-  { "EnableUAC", "MANIFESTUAC:", "", "true",
-    cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
-  { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
-    cmVS7FlagTable::UserValueRequired },
+  { "EnableUAC", "MANIFESTUAC:", "", "",
+    cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SpaceAppendable },
   { "GenerateMapFile", "MAP", "", "true",
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "MapFileName", "MAP:", "Generate Map File", "",
diff --git a/Source/cmVS141LinkFlagTable.h b/Source/cmVS141LinkFlagTable.h
index 8f0f1f4..d97c00d 100644
--- a/Source/cmVS141LinkFlagTable.h
+++ b/Source/cmVS141LinkFlagTable.h
@@ -29,6 +29,8 @@ static cmVS7FlagTable cmVS141LinkFlagTable[] = {
   { "CreateHotPatchableImage", "FUNCTIONPADMIN:16", "Itanium Image Only",
     "ItaniumImage", 0 },
 
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACExecutionLevel", "level='asInvoker'", "asInvoker", "AsInvoker", 0 },
   { "UACExecutionLevel", "level='highestAvailable'", "highestAvailable",
     "HighestAvailable", 0 },
@@ -149,8 +151,12 @@ static cmVS7FlagTable cmVS141LinkFlagTable[] = {
   { "GenerateManifest", "MANIFEST:NO", "", "false", 0 },
   { "GenerateManifest", "MANIFEST", "", "true", 0 },
   { "AllowIsolation", "ALLOWISOLATION:NO", "", "false", 0 },
+
+  // correct flags for uac should be /MANIFESTUAC, but some projects already
+  // use this bug to access uac field, so keep these for compatibility
   { "UACUIAccess", "uiAccess='false'", "", "false", 0 },
   { "UACUIAccess", "uiAccess='true'", "", "true", 0 },
+
   { "ManifestEmbed", "manifest:embed", "", "true", 0 },
   { "MapExports", "MAPINFO:EXPORTS", "", "true", 0 },
   { "AssemblyDebug", "ASSEMBLYDEBUG:DISABLE", "", "false", 0 },
@@ -191,11 +197,8 @@ static cmVS7FlagTable cmVS141LinkFlagTable[] = {
   { "LinkDLL", "DLL", "", "true", 0 },
 
   // Bool Properties With Argument
-  { "EnableUAC", "MANIFESTUAC:NO", "", "false", 0 },
-  { "EnableUAC", "MANIFESTUAC:", "", "true",
-    cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
-  { "UACUIAccess", "MANIFESTUAC:", "Enable User Account Control (UAC)", "",
-    cmVS7FlagTable::UserValueRequired },
+  { "EnableUAC", "MANIFESTUAC:", "", "",
+    cmVS7FlagTable::UserValueRequired | cmVS7FlagTable::SpaceAppendable },
   { "GenerateMapFile", "MAP", "", "true",
     cmVS7FlagTable::UserValueIgnored | cmVS7FlagTable::Continue },
   { "MapFileName", "MAP:", "Generate Map File", "",
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 7fe2f2a..b965013 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -3261,6 +3261,7 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
   }
 
   linkOptions.Parse(flags.c_str());
+  linkOptions.FixManifestUACFlags();
 
   if (this->MSTools) {
     cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 51944fa..b1686be 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -256,6 +256,74 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
   }
 }
 
+void cmVisualStudioGeneratorOptions::FixManifestUACFlags()
+{
+  static const char* ENABLE_UAC = "EnableUAC";
+  if (!HasFlag(ENABLE_UAC)) {
+    return;
+  }
+
+  const std::string uacFlag = GetFlag(ENABLE_UAC);
+  std::vector<std::string> subOptions;
+  cmsys::SystemTools::Split(uacFlag, subOptions, ' ');
+  if (subOptions.empty()) {
+    AddFlag(ENABLE_UAC, "true");
+    return;
+  }
+
+  if (subOptions.size() == 1 && subOptions[0] == "NO") {
+    AddFlag(ENABLE_UAC, "false");
+    return;
+  }
+
+  std::map<std::string, std::string> uacMap;
+  uacMap["level"] = "UACExecutionLevel";
+  uacMap["uiAccess"] = "UACUIAccess";
+
+  std::map<std::string, std::string> uacExecuteLevelMap;
+  uacExecuteLevelMap["asInvoker"] = "AsInvoker";
+  uacExecuteLevelMap["highestAvailable"] = "HighestAvailable";
+  uacExecuteLevelMap["requireAdministrator"] = "RequireAdministrator";
+
+  for (auto const& subopt : subOptions) {
+    std::vector<std::string> keyValue;
+    cmsys::SystemTools::Split(subopt, keyValue, '=');
+    if (keyValue.size() != 2 || (uacMap.find(keyValue[0]) == uacMap.end())) {
+      // ignore none key=value option or unknown flags
+      continue;
+    }
+
+    if (keyValue[1].front() == '\'' && keyValue[1].back() == '\'') {
+      keyValue[1] =
+        keyValue[1].substr(1, std::max<int>(0, keyValue[1].size() - 2));
+    }
+
+    if (keyValue[0] == "level") {
+      if (uacExecuteLevelMap.find(keyValue[1]) == uacExecuteLevelMap.end()) {
+        // unknown level value
+        continue;
+      }
+
+      AddFlag(uacMap[keyValue[0]].c_str(),
+              uacExecuteLevelMap[keyValue[1]].c_str());
+      continue;
+    }
+
+    if (keyValue[0] == "uiAccess") {
+      if (keyValue[1] != "true" && keyValue[1] != "false") {
+        // unknown uiAccess value
+        continue;
+      }
+      AddFlag(uacMap[keyValue[0]].c_str(), keyValue[1].c_str());
+      continue;
+    }
+
+    // unknwon sub option
+  }
+
+  AddFlag(ENABLE_UAC, "true");
+}
+
 void cmVisualStudioGeneratorOptions::Parse(const char* flags)
 {
   // Parse the input string as a windows command line since the string
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
index 8d7942b..7c08a2c 100644
--- a/Source/cmVisualStudioGeneratorOptions.h
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -77,6 +77,8 @@ public:
 
   void FixCudaCodeGeneration();
 
+  void FixManifestUACFlags();
+
   bool IsDebug() const;
   bool IsWinRt() const;
   bool IsManaged() const;
-- 
cgit v0.12