winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

ManifestYamlPopulator.cpp (77427B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "AppInstallerSHA256.h"
      5 #include "winget/ManifestYamlPopulator.h"
      6 
      7 namespace AppInstaller::Manifest
      8 {
      9     using ValidationErrors = std::vector<ValidationError>;
     10     using ExpectedReturnCodeInfo = AppInstaller::Manifest::ManifestInstaller::ExpectedReturnCodeInfo;
     11 
     12     namespace
     13     {
     14         template <typename Ptr>
     15         Ptr* variant_ptr(const VariantManifestPtr& v) { return std::get<Ptr*>(v); }
     16 
     17         ManifestInstaller* GetManifestInstallerPtrFromManifest(const VariantManifestPtr& v) { return &(variant_ptr<Manifest>(v)->DefaultInstallerInfo); }
     18 
     19         ManifestLocalization* GetManifestLocalizationPtrFromManifest(const VariantManifestPtr& v) { return &(variant_ptr<Manifest>(v)->DefaultLocalization); }
     20 
     21         ManifestInstaller* GetManifestInstallerPtr(const VariantManifestPtr& v)
     22         {
     23             if (auto installer = std::get_if<ManifestInstaller*>(&v))
     24             {
     25                 return *installer;
     26             }
     27 
     28             return GetManifestInstallerPtrFromManifest(v);
     29         }
     30 
     31         ManifestLocalization* GetManifestLocalizationPtr(const VariantManifestPtr& v)
     32         {
     33             if (auto localization = std::get_if<ManifestLocalization*>(&v))
     34             {
     35                 return *localization;
     36             }
     37 
     38             return GetManifestLocalizationPtrFromManifest(v);
     39         }
     40 
     41         // Only used in preview manifest
     42         std::vector<Manifest::string_t> SplitMultiValueField(const std::string& input)
     43         {
     44             if (input.empty())
     45             {
     46                 return {};
     47             }
     48 
     49             std::vector<Manifest::string_t> result;
     50             size_t currentPos = 0;
     51             while (currentPos < input.size())
     52             {
     53                 size_t splitPos = input.find(',', currentPos);
     54                 if (splitPos == std::string::npos)
     55                 {
     56                     splitPos = input.size();
     57                 }
     58 
     59                 std::string splitVal = input.substr(currentPos, splitPos - currentPos);
     60                 Utility::Trim(splitVal);
     61                 if (!splitVal.empty())
     62                 {
     63                     result.emplace_back(std::move(splitVal));
     64                 }
     65                 currentPos = splitPos + 1;
     66             }
     67 
     68             return result;
     69         }
     70 
     71         std::vector<Manifest::string_t> ProcessStringSequenceNode(const YAML::Node& node, bool trim = true)
     72         {
     73             THROW_HR_IF(E_INVALIDARG, !node.IsSequence());
     74 
     75             std::vector<Manifest::string_t> result;
     76 
     77             for (auto const& entry : node.Sequence())
     78             {
     79                 std::string value = entry.as<std::string>();
     80                 if (trim)
     81                 {
     82                     Utility::Trim(value);
     83                 }
     84 
     85                 result.emplace_back(std::move(value));
     86             }
     87 
     88             return result;
     89         }
     90 
     91         std::vector<DWORD> ProcessInstallerSuccessCodeSequenceNode(const YAML::Node& node)
     92         {
     93             THROW_HR_IF(E_INVALIDARG, !node.IsSequence());
     94 
     95             std::vector<DWORD> result;
     96 
     97             for (auto const& entry : node.Sequence())
     98             {
     99                 result.emplace_back(static_cast<DWORD>(entry.as<int>()));
    100             }
    101 
    102             return result;
    103         }
    104 
    105         std::vector<PlatformEnum> ProcessPlatformSequenceNode(const YAML::Node& node)
    106         {
    107             THROW_HR_IF(E_INVALIDARG, !node.IsSequence());
    108 
    109             std::vector<PlatformEnum> result;
    110 
    111             for (auto const& entry : node.Sequence())
    112             {
    113                 result.emplace_back(ConvertToPlatformEnum(entry.as<std::string>()));
    114             }
    115 
    116             return result;
    117         }
    118 
    119         std::vector<InstallModeEnum> ProcessInstallModeSequenceNode(const YAML::Node& node)
    120         {
    121             THROW_HR_IF(E_INVALIDARG, !node.IsSequence());
    122 
    123             std::vector<InstallModeEnum> result;
    124 
    125             for (auto const& entry : node.Sequence())
    126             {
    127                 result.emplace_back(ConvertToInstallModeEnum(entry.as<std::string>()));
    128             }
    129 
    130             return result;
    131         }
    132 
    133         std::vector<AppInstaller::Utility::Architecture> ProcessArchitectureSequenceNode(const YAML::Node& node)
    134         {
    135             THROW_HR_IF(E_INVALIDARG, !node.IsSequence());
    136 
    137             std::vector<AppInstaller::Utility::Architecture> result;
    138 
    139             for (auto const& entry : node.Sequence())
    140             {
    141                 result.emplace_back(Utility::ConvertToArchitectureEnum(entry.as<std::string>()));
    142             }
    143 
    144             return result;
    145         }
    146 
    147         std::vector<UnsupportedArgumentEnum> ProcessUnsupportedArgumentsSequenceNode(const YAML::Node& node)
    148         {
    149             THROW_HR_IF(E_INVALIDARG, !node.IsSequence());
    150 
    151             std::vector<UnsupportedArgumentEnum> result;
    152 
    153             for (auto const& entry : node.Sequence())
    154             {
    155                 result.emplace_back(ConvertToUnsupportedArgumentEnum(entry.as<std::string>()));
    156             }
    157 
    158             return result;
    159         }
    160 
    161         void ProcessDependenciesNode(DependencyType type, const YAML::Node& node, DependencyList* dependencyList)
    162         {
    163             const auto& ids = ProcessStringSequenceNode(node);
    164             for (auto id : ids)
    165             {
    166                 dependencyList->Add(Dependency(type, id));
    167             }
    168         }
    169     }
    170 
    171     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetRootFieldProcessInfo()
    172     {
    173         // Common fields across versions
    174         std::vector<FieldProcessInfo> result =
    175         {
    176             { "ManifestVersion", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { /* ManifestVersion already populated. Field listed here for duplicate and PascalCase check */ return {}; } },
    177             { "Installers", [this](const YAML::Node& value, const VariantManifestPtr&)->ValidationErrors { m_p_installersNode = &value; return {}; } },
    178             { "Localization", [this](const YAML::Node& value, const VariantManifestPtr&)->ValidationErrors { m_p_localizationsNode = &value; return {}; } },
    179             { "Channel", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Channel = Utility::Trim(value.as<std::string>()); return {}; } },
    180         };
    181 
    182         // Additional version specific fields
    183         if (m_manifestVersion.get().Major() == 0)
    184         {
    185             std::vector<FieldProcessInfo> previewRootFields
    186             {
    187                 { "Id", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Id = Utility::Trim(value.as<std::string>()); return {}; } },
    188                 { "Version", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Version = Utility::Trim(value.as<std::string>()); return {}; } },
    189                 { "AppMoniker", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Moniker = Utility::Trim(value.as<std::string>()); return {}; } },
    190             };
    191 
    192 
    193             std::move(previewRootFields.begin(), previewRootFields.end(), std::inserter(result, result.end()));
    194         }
    195         else if (m_manifestVersion.get().Major() == 1)
    196         {
    197             // Starting v1, we should be only adding new fields for each minor version increase
    198             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 })
    199             {
    200                 std::vector<FieldProcessInfo> v1RootFields
    201                 {
    202                     { "PackageIdentifier", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Id = Utility::Trim(value.as<std::string>()); return {}; } },
    203                     { "PackageVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Version = Utility::Trim(value.as<std::string>()); return {}; } },
    204                     { "Moniker", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Manifest>(v)->Moniker = Utility::Trim(value.as<std::string>()); return {}; } },
    205                     { "ManifestType", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { /* ManifestType already checked. Field listed here for duplicate and PascalCase check */ return {}; } },
    206                 };
    207 
    208                 std::move(v1RootFields.begin(), v1RootFields.end(), std::inserter(result, result.end()));
    209             }
    210         }
    211 
    212         // Root fields mapped as Installer and Localization values
    213         auto rootInstallerFields = GetInstallerFieldProcessInfo(true);
    214         std::move(rootInstallerFields.begin(), rootInstallerFields.end(), std::inserter(result, result.end()));
    215 
    216         auto rootLocalizationFields = GetLocalizationFieldProcessInfo(true);
    217         std::move(rootLocalizationFields.begin(), rootLocalizationFields.end(), std::inserter(result, result.end()));
    218 
    219         return result;
    220     }
    221 
    222     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetInstallerFieldProcessInfo(bool forRootFields)
    223     {
    224         // Common fields across versions
    225         std::vector<FieldProcessInfo> result =
    226         {
    227             { "InstallerType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->BaseInstallerType = ConvertToInstallerTypeEnum(value.as<std::string>()); return {}; } },
    228             { "PackageFamilyName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->PackageFamilyName = value.as<std::string>(); return {}; } },
    229             { "ProductCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ProductCode = value.as<std::string>(); return {}; } },
    230         };
    231 
    232         // Additional version specific fields
    233         if (m_manifestVersion.get().Major() == 0)
    234         {
    235             // Root level and Localization node level
    236             std::vector<FieldProcessInfo> previewCommonFields =
    237             {
    238                 { "UpdateBehavior", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UpdateBehavior = ConvertToUpdateBehaviorEnum(value.as<std::string>()); return {}; } },
    239                 { "Switches", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, SwitchesFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->Switches))); }},
    240             };
    241 
    242             std::move(previewCommonFields.begin(), previewCommonFields.end(), std::inserter(result, result.end()));
    243 
    244             if (!forRootFields)
    245             {
    246                 // Installer node only
    247                 std::vector<FieldProcessInfo> installerOnlyFields =
    248                 {
    249                     { "Arch", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Arch = Utility::ConvertToArchitectureEnum(value.as<std::string>()); return {}; } },
    250                     { "Url", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Url = value.as<std::string>(); return {}; } },
    251                     { "Sha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } },
    252                     { "SignatureSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->SignatureSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } },
    253                     { "Language", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Locale = value.as<std::string>(); return {}; } },
    254                     { "Scope", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Scope = ConvertToScopeEnum(value.as<std::string>()); return {}; } },
    255                 };
    256 
    257                 if (m_manifestVersion.get().HasExtension(s_MSStoreExtension))
    258                 {
    259                     installerOnlyFields.emplace_back("ProductId", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->ProductId = value.as<std::string>(); return {}; });
    260                 }
    261 
    262                 std::move(installerOnlyFields.begin(), installerOnlyFields.end(), std::inserter(result, result.end()));
    263             }
    264             else
    265             {
    266                 // Root node only
    267                 std::vector<FieldProcessInfo> rootOnlyFields =
    268                 {
    269                     { "MinOSVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->MinOSVersion = value.as<std::string>(); return {}; } },
    270                     { "Commands", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->Commands = SplitMultiValueField(value.as<std::string>()); return {}; } },
    271                     { "Protocols", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->Protocols = SplitMultiValueField(value.as<std::string>()); return {}; } },
    272                     { "FileExtensions", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtrFromManifest(v)->FileExtensions = SplitMultiValueField(value.as<std::string>()); return {}; } },
    273                 };
    274 
    275                 std::move(rootOnlyFields.begin(), rootOnlyFields.end(), std::inserter(result, result.end()));
    276             }
    277         }
    278         else if (m_manifestVersion.get().Major() == 1)
    279         {
    280             // Starting v1, we should be only adding new fields for each minor version increase
    281             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 })
    282             {
    283                 // Root level and Installer node level
    284                 std::vector<FieldProcessInfo> v1CommonFields =
    285                 {
    286                     { "InstallerLocale", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Locale = value.as<std::string>(); return {}; } },
    287                     { "Platform", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Platform = ProcessPlatformSequenceNode(value); return {}; } },
    288                     { "MinimumOSVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->MinOSVersion = value.as<std::string>(); return {}; } },
    289                     { "Scope", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Scope = ConvertToScopeEnum(value.as<std::string>()); return {}; } },
    290                     { "InstallModes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallModes = ProcessInstallModeSequenceNode(value); return {}; } },
    291                     { "InstallerSwitches", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, SwitchesFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->Switches))); }},
    292                     { "InstallerSuccessCodes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallerSuccessCodes = ProcessInstallerSuccessCodeSequenceNode(value); return {}; } },
    293                     { "UpgradeBehavior", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UpdateBehavior = ConvertToUpdateBehaviorEnum(value.as<std::string>()); return {}; } },
    294                     { "Commands", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Commands = ProcessStringSequenceNode(value); return {}; } },
    295                     { "Protocols", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Protocols = ProcessStringSequenceNode(value); return {}; } },
    296                     { "FileExtensions", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->FileExtensions = ProcessStringSequenceNode(value); return {}; } },
    297                     { "Dependencies", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, DependenciesFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->Dependencies))); }},
    298                     { "Capabilities", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->Capabilities = ProcessStringSequenceNode(value); return {}; } },
    299                     { "RestrictedCapabilities", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->RestrictedCapabilities = ProcessStringSequenceNode(value); return {}; } },
    300                 };
    301 
    302                 std::move(v1CommonFields.begin(), v1CommonFields.end(), std::inserter(result, result.end()));
    303 
    304                 if (!forRootFields)
    305                 {
    306                     // Installer level only fields
    307                     std::vector<FieldProcessInfo> v1InstallerFields =
    308                     {
    309                         { "Architecture", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Arch = Utility::ConvertToArchitectureEnum(value.as<std::string>()); return {}; } },
    310                         { "InstallerUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Url = value.as<std::string>(); return {}; } },
    311                         { "InstallerSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } },
    312                         { "SignatureSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->SignatureSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } },
    313                         // No custom validation needed at field populating time since we have semantic validation later to block msstore and productId from community repo.
    314                         { "MSStoreProductIdentifier", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestInstaller>(v)->ProductId = value.as<std::string>(); return {}; } },
    315                     };
    316 
    317                     std::move(v1InstallerFields.begin(), v1InstallerFields.end(), std::inserter(result, result.end()));
    318                 }
    319             }
    320 
    321             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 })
    322             {
    323                 std::vector<FieldProcessInfo> fields_v1_1 =
    324                 {
    325                     { "InstallerAbortsTerminal", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallerAbortsTerminal = value.as<bool>(); return {}; } },
    326                     { "InstallLocationRequired", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->InstallLocationRequired = value.as<bool>(); return {}; } },
    327                     { "RequireExplicitUpgrade", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->RequireExplicitUpgrade = value.as<bool>(); return {}; } },
    328                     { "ReleaseDate", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ReleaseDate = Utility::Trim(value.as<std::string>()); return {}; } },
    329                     { "UnsupportedOSArchitectures", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UnsupportedOSArchitectures = ProcessArchitectureSequenceNode(value); return {}; } },
    330                     { "ElevationRequirement", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ElevationRequirement = ConvertToElevationRequirementEnum(value.as<std::string>()); return {}; } },
    331                     { "Markets", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessMarketsNode(value, GetManifestInstallerPtr(v)); } },
    332                     { "AppsAndFeaturesEntries", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessAppsAndFeaturesEntriesNode(value, GetManifestInstallerPtr(v)); } },
    333                     { "ExpectedReturnCodes", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessExpectedReturnCodesNode(value, GetManifestInstallerPtr(v)); } },
    334                 };
    335 
    336                 std::move(fields_v1_1.begin(), fields_v1_1.end(), std::inserter(result, result.end()));
    337             }
    338 
    339             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 })
    340             {
    341                 std::vector<FieldProcessInfo> fields_v1_2 =
    342                 {
    343                     { "UnsupportedArguments", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->UnsupportedArguments = ProcessUnsupportedArgumentsSequenceNode(value); return {}; } },
    344                     { "DisplayInstallWarnings", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->DisplayInstallWarnings = value.as<bool>(); return {}; } },
    345                 };
    346 
    347                 std::move(fields_v1_2.begin(), fields_v1_2.end(), std::inserter(result, result.end()));
    348             }
    349 
    350             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 })
    351             {
    352                 std::vector<FieldProcessInfo> fields_v1_4 =
    353                 {
    354                     { "NestedInstallerType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->NestedInstallerType = ConvertToInstallerTypeEnum(value.as<std::string>()); return {}; } },
    355                     { "NestedInstallerFiles", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessNestedInstallerFilesNode(value, GetManifestInstallerPtr(v)); } },
    356                     { "InstallationMetadata", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ValidateAndProcessFields(value, InstallationMetadataFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->InstallationMetadata))); }},
    357                 };
    358 
    359                 std::move(fields_v1_4.begin(), fields_v1_4.end(), std::inserter(result, result.end()));
    360             }
    361 
    362             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_6 })
    363             {
    364                 std::vector<FieldProcessInfo> fields_v1_6 =
    365                 {
    366                     { "DownloadCommandProhibited", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->DownloadCommandProhibited = value.as<bool>(); return {}; }, true },
    367                 };
    368 
    369                 std::move(fields_v1_6.begin(), fields_v1_6.end(), std::inserter(result, result.end()));
    370             }
    371 
    372             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_7 })
    373             {
    374                 std::vector<FieldProcessInfo> fields_v1_7 =
    375                 {
    376                     { "RepairBehavior", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->RepairBehavior = ConvertToRepairBehaviorEnum(value.as<std::string>()); return {}; } },
    377                 };
    378 
    379                 std::move(fields_v1_7.begin(), fields_v1_7.end(), std::inserter(result, result.end()));
    380             }
    381 
    382             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_9 })
    383             {
    384                 std::vector<FieldProcessInfo> fields_v1_9 =
    385                 {
    386                     { "ArchiveBinariesDependOnPath", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->ArchiveBinariesDependOnPath = value.as<bool>(); return {}; } },
    387                 };
    388 
    389                 std::move(fields_v1_9.begin(), fields_v1_9.end(), std::inserter(result, result.end()));
    390             }
    391 
    392             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_10 })
    393             {
    394                 std::vector<FieldProcessInfo> fields_v1_10 =
    395                 {
    396                     { "Authentication", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestInstallerPtr(v)->AuthInfo = {}; auto errors = ValidateAndProcessFields(value, AuthenticationFieldInfos, VariantManifestPtr(&(GetManifestInstallerPtr(v)->AuthInfo))); GetManifestInstallerPtr(v)->AuthInfo.UpdateRequiredFieldsIfNecessary(); return errors; }, true},
    397                 };
    398 
    399                 std::move(fields_v1_10.begin(), fields_v1_10.end(), std::inserter(result, result.end()));
    400             }
    401         }
    402 
    403         return result;
    404     }
    405 
    406     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetSwitchesFieldProcessInfo()
    407     {
    408         // Common fields across versions
    409         std::vector<FieldProcessInfo> result =
    410         {
    411             { "Custom", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Custom] = value.as<std::string>(); return{}; } },
    412             { "Silent", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Silent] = value.as<std::string>(); return{}; } },
    413             { "SilentWithProgress", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::SilentWithProgress] = value.as<std::string>(); return{}; } },
    414             { "Interactive", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Interactive] = value.as<std::string>(); return{}; } },
    415             { "Log", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Log] = value.as<std::string>(); return{}; } },
    416             { "InstallLocation", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::InstallLocation] = value.as<std::string>(); return{}; } },
    417         };
    418 
    419         // Additional version specific fields
    420         if (m_manifestVersion.get().Major() == 0)
    421         {
    422             // Language only exists in preview manifests. Though we don't use it in our code yet, keep it here to be consistent with schema.
    423             result.emplace_back("Language", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Language] = value.as<std::string>(); return{}; });
    424             result.emplace_back("Update", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Update] = value.as<std::string>(); return{}; });
    425         }
    426         else if (m_manifestVersion.get().Major() == 1)
    427         {
    428             result.emplace_back("Upgrade", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Update] = value.as<std::string>(); return{}; });
    429 
    430             if (m_manifestVersion.get() >= ManifestVer{s_ManifestVersionV1_7})
    431             {
    432                 result.emplace_back("Repair", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { (*variant_ptr<std::map<InstallerSwitchType, Utility::NormalizedString>>(v))[InstallerSwitchType::Repair] = value.as<std::string>(); return{}; });
    433             };
    434         }
    435 
    436         return result;
    437     }
    438 
    439     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetExpectedReturnCodesFieldProcessInfo()
    440     {
    441         std::vector<FieldProcessInfo> result = {};
    442 
    443         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 })
    444         {
    445             result.emplace_back("InstallerReturnCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ExpectedReturnCode>(v)->InstallerReturnCode = static_cast<int>(value.as<int>()); return {}; });
    446             result.emplace_back("ReturnResponse", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ExpectedReturnCode>(v)->ReturnResponse = ConvertToExpectedReturnCodeEnum(value.as<std::string>()); return {}; });
    447         }
    448 
    449         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 })
    450         {
    451             result.emplace_back("ReturnResponseUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ExpectedReturnCode>(v)->ReturnResponseUrl = value.as<std::string>(); return {}; });
    452         }
    453 
    454         return result;
    455     }
    456 
    457     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetLocalizationFieldProcessInfo(bool forRootFields)
    458     {
    459         // Common fields across versions
    460         std::vector<FieldProcessInfo> result =
    461         {
    462             { "Description", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Description>(Utility::Trim(value.as<std::string>())); return {}; } },
    463             { "LicenseUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::LicenseUrl>(value.as<std::string>()); return {}; } },
    464         };
    465 
    466         // Additional version specific fields
    467         if (m_manifestVersion.get().Major() == 0)
    468         {
    469             // Root level and Localization node level
    470             result.emplace_back("Homepage", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PackageUrl>(value.as<std::string>()); return {}; });
    471 
    472             if (!forRootFields)
    473             {
    474                 // Localization node only
    475                 result.emplace_back("Language", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<ManifestLocalization>(v)->Locale = value.as<std::string>(); return {}; });
    476             }
    477             else
    478             {
    479                 // Root node only
    480                 std::vector<FieldProcessInfo> rootOnlyFields =
    481                 {
    482                     { "Name", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::PackageName>(Utility::Trim(value.as<std::string>())); return {}; } },
    483                     { "Publisher", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::Publisher>(value.as<std::string>()); return {}; } },
    484                     { "Author", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::Author>(value.as<std::string>()); return {}; } },
    485                     { "License", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::License>(value.as<std::string>()); return {}; } },
    486                     { "Tags", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtrFromManifest(v)->Add<Localization::Tags>(SplitMultiValueField(value.as<std::string>())); return {}; } },
    487                 };
    488 
    489                 std::move(rootOnlyFields.begin(), rootOnlyFields.end(), std::inserter(result, result.end()));
    490             }
    491         }
    492         else if (m_manifestVersion.get().Major() == 1)
    493         {
    494             // Starting v1, we should be only adding new fields for each minor version increase
    495             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 })
    496             {
    497                 // Root level and Localization node level
    498                 std::vector<FieldProcessInfo> v1CommonFields =
    499                 {
    500                     { "PackageLocale", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Locale = value.as<std::string>(); return {}; } },
    501                     { "Publisher", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Publisher>(value.as<std::string>()); return {}; } },
    502                     { "PublisherUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PublisherUrl>(value.as<std::string>()); return {}; } },
    503                     { "PublisherSupportUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PublisherSupportUrl>(value.as<std::string>()); return {}; } },
    504                     { "PrivacyUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PrivacyUrl>(value.as<std::string>()); return {}; } },
    505                     { "Author", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Author>(value.as<std::string>()); return {}; } },
    506                     { "PackageName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PackageName>(Utility::Trim(value.as<std::string>())); return {}; } },
    507                     { "PackageUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PackageUrl>(value.as<std::string>()); return {}; } },
    508                     { "License", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::License>(value.as<std::string>()); return {}; } },
    509                     { "Copyright", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Copyright>(value.as<std::string>()); return {}; } },
    510                     { "CopyrightUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::CopyrightUrl>(value.as<std::string>()); return {}; } },
    511                     { "ShortDescription", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::ShortDescription>(Utility::Trim(value.as<std::string>())); return {}; } },
    512                     { "Tags", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::Tags>(ProcessStringSequenceNode(value)); return {}; } },
    513                 };
    514 
    515                 std::move(v1CommonFields.begin(), v1CommonFields.end(), std::inserter(result, result.end()));
    516             }
    517 
    518             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 })
    519             {
    520                 std::vector<FieldProcessInfo> fields_v1_1 =
    521                 {
    522                     { "Agreements", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessAgreementsNode(value, GetManifestLocalizationPtr(v)); } },
    523                     { "ReleaseNotes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::ReleaseNotes>(value.as<std::string>()); return {}; } },
    524                     { "ReleaseNotesUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::ReleaseNotesUrl>(value.as<std::string>()); return {}; } },
    525                 };
    526 
    527                 std::move(fields_v1_1.begin(), fields_v1_1.end(), std::inserter(result, result.end()));
    528             }
    529 
    530             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 })
    531             {
    532                 std::vector<FieldProcessInfo> fields_v1_2 =
    533                 {
    534                     { "PurchaseUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::PurchaseUrl>(value.as<std::string>()); return {}; } },
    535                     { "InstallationNotes", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Add<Localization::InstallationNotes>(value.as<std::string>()); return {}; } },
    536                     { "Documentations", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessDocumentationsNode(value, GetManifestLocalizationPtr(v)); } },
    537                 };
    538 
    539                 std::move(fields_v1_2.begin(), fields_v1_2.end(), std::inserter(result, result.end()));
    540             }
    541 
    542             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 })
    543             {
    544                 std::vector<FieldProcessInfo> fields_v1_5 =
    545                 {
    546                     { "Icons", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessIconsNode(value, GetManifestLocalizationPtr(v)); }, true },
    547                 };
    548 
    549                 std::move(fields_v1_5.begin(), fields_v1_5.end(), std::inserter(result, result.end()));
    550             }
    551         }
    552 
    553         return result;
    554     }
    555 
    556     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetDependenciesFieldProcessInfo()
    557     {
    558         std::vector<FieldProcessInfo> result = {};
    559 
    560         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 })
    561         {
    562             result =
    563             {
    564                 { "WindowsFeatures", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessDependenciesNode(DependencyType::WindowsFeature, value, variant_ptr<DependencyList>(v)); return {}; } },
    565                 { "WindowsLibraries", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessDependenciesNode(DependencyType::WindowsLibrary, value, variant_ptr<DependencyList>(v)); return {}; } },
    566                 { "PackageDependencies", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessPackageDependenciesNode(value, variant_ptr<DependencyList>(v)); return {}; } },
    567                 { "ExternalDependencies", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { ProcessDependenciesNode(DependencyType::External, value, variant_ptr<DependencyList>(v)); return {}; } },
    568             };
    569         }
    570 
    571         return result;
    572     }
    573 
    574     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetPackageDependenciesFieldProcessInfo()
    575     {
    576         std::vector<FieldProcessInfo> result = {};
    577 
    578         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1 })
    579         {
    580             result =
    581             {
    582                 { "PackageIdentifier", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Dependency>(v)->SetId(Utility::Trim(value.as<std::string>())); return {}; } },
    583                 { "MinimumVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Dependency>(v)->MinVersion = Utility::Version(Utility::Trim(value.as<std::string>())); return {}; } },
    584             };
    585         }
    586 
    587         return result;
    588     }
    589 
    590     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetAgreementFieldProcessInfo()
    591     {
    592         std::vector<FieldProcessInfo> result = {};
    593 
    594         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 })
    595         {
    596             result =
    597             {
    598                 { "AgreementLabel", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Agreement>(v)->Label = Utility::Trim(value.as<std::string>()); return {}; } },
    599                 { "Agreement", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Agreement>(v)->AgreementText = Utility::Trim(value.as<std::string>()); return {}; }, true },
    600                 { "AgreementUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Agreement>(v)->AgreementUrl = Utility::Trim(value.as<std::string>()); return {}; } },
    601             };
    602         }
    603 
    604         return result;
    605     }
    606 
    607     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetMarketsFieldProcessInfo()
    608     {
    609         std::vector<FieldProcessInfo> result = {};
    610 
    611         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 })
    612         {
    613             result =
    614             {
    615                 { "AllowedMarkets", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<MarketsInfo>(v)->AllowedMarkets = ProcessStringSequenceNode(value); return {}; } },
    616                 { "ExcludedMarkets", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<MarketsInfo>(v)->ExcludedMarkets = ProcessStringSequenceNode(value); return {}; } },
    617             };
    618         }
    619 
    620         return result;
    621     }
    622 
    623     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetAppsAndFeaturesEntryFieldProcessInfo()
    624     {
    625         std::vector<FieldProcessInfo> result = {};
    626 
    627         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_1 })
    628         {
    629             result =
    630             {
    631                 { "DisplayName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->DisplayName = Utility::Trim(value.as<std::string>()); return {}; } },
    632                 { "Publisher", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->Publisher = Utility::Trim(value.as<std::string>()); return {}; } },
    633                 { "DisplayVersion", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->DisplayVersion = Utility::Trim(value.as<std::string>()); return {}; } },
    634                 { "ProductCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->ProductCode = Utility::Trim(value.as<std::string>()); return {}; } },
    635                 { "UpgradeCode", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->UpgradeCode = Utility::Trim(value.as<std::string>()); return {}; } },
    636                 { "InstallerType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<AppsAndFeaturesEntry>(v)->InstallerType = ConvertToInstallerTypeEnum(value.as<std::string>()); return {}; } },
    637             };
    638         }
    639 
    640         return result;
    641     }
    642 
    643     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetDocumentationFieldProcessInfo()
    644     {
    645         std::vector<FieldProcessInfo> result = {};
    646 
    647         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_2 })
    648         {
    649             result =
    650             {
    651                 { "DocumentLabel", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Documentation>(v)->DocumentLabel = Utility::Trim(value.as<std::string>()); return {}; } },
    652                 { "DocumentUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Documentation>(v)->DocumentUrl = Utility::Trim(value.as<std::string>()); return {}; } },
    653             };
    654         }
    655 
    656         return result;
    657     }
    658 
    659     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetIconFieldProcessInfo()
    660     {
    661         std::vector<FieldProcessInfo> result = {};
    662 
    663         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 })
    664         {
    665             result =
    666             {
    667                 { "IconUrl", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Url = Utility::Trim(value.as<std::string>()); return {}; } },
    668                 { "IconFileType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->FileType = ConvertToIconFileTypeEnum(value.as<std::string>()); return {}; } },
    669                 { "IconResolution", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Resolution = ConvertToIconResolutionEnum(value.as<std::string>()); return {}; } },
    670                 { "IconTheme", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Theme = ConvertToIconThemeEnum(value.as<std::string>()); return {}; } },
    671                 { "IconSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Icon>(v)->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } },
    672             };
    673         }
    674 
    675         return result;
    676     }
    677 
    678     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetNestedInstallerFileFieldProcessInfo()
    679     {
    680         std::vector<FieldProcessInfo> result = {};
    681 
    682         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 })
    683         {
    684             result =
    685             {
    686                 { "RelativeFilePath", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<NestedInstallerFile>(v)->RelativeFilePath = Utility::Trim(value.as<std::string>()); return {}; } },
    687                 { "PortableCommandAlias", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<NestedInstallerFile>(v)->PortableCommandAlias = Utility::Trim(value.as<std::string>()); return {}; } },
    688             };
    689         }
    690 
    691         return result;
    692     }
    693 
    694     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetInstallationMetadataFieldProcessInfo()
    695     {
    696         std::vector<FieldProcessInfo> result = {};
    697 
    698         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 })
    699         {
    700             result =
    701             {
    702                 { "DefaultInstallLocation", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstallationMetadataInfo>(v)->DefaultInstallLocation = Utility::Trim(value.as<std::string>()); return {}; } },
    703                 { "Files", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessInstallationMetadataFilesNode(value, variant_ptr<InstallationMetadataInfo>(v)); } },
    704             };
    705         }
    706 
    707         return result;
    708     }
    709 
    710     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetInstallationMetadataFilesFieldProcessInfo()
    711     {
    712         std::vector<FieldProcessInfo> result = {};
    713 
    714         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_4 })
    715         {
    716             result =
    717             {
    718                 { "RelativeFilePath", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->RelativeFilePath = Utility::Trim(value.as<std::string>()); return {}; } },
    719                 { "FileSha256", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->FileSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); return {}; } },
    720                 { "FileType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->FileType = ConvertToInstalledFileTypeEnum(value.as<std::string>()); return {}; } },
    721                 { "InvocationParameter", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->InvocationParameter = Utility::Trim(value.as<std::string>()); return {}; } },
    722                 { "DisplayName", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<InstalledFile>(v)->DisplayName = Utility::Trim(value.as<std::string>()); return {}; } },
    723             };
    724         }
    725 
    726         return result;
    727     }
    728 
    729     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetAuthenticationFieldInfos()
    730     {
    731         std::vector<FieldProcessInfo> result = {};
    732 
    733         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_10 })
    734         {
    735             result =
    736             {
    737                 { "AuthenticationType", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::AuthenticationInfo>(v)->Type = Authentication::ConvertToAuthenticationType(value.as<std::string>()); return {}; } },
    738                 { "MicrosoftEntraIdAuthenticationInfo", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::AuthenticationInfo>(v)->MicrosoftEntraIdInfo.emplace(); return ValidateAndProcessFields(value, MicrosoftEntraIdAuthenticationInfoFieldInfos, VariantManifestPtr(&(variant_ptr<Authentication::AuthenticationInfo>(v)->MicrosoftEntraIdInfo.value()))); }},
    739             };
    740         }
    741 
    742         return result;
    743     }
    744 
    745     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetMicrosoftEntraIdAuthenticationInfoFieldInfos()
    746     {
    747         std::vector<FieldProcessInfo> result = {};
    748 
    749         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_10 })
    750         {
    751             result =
    752             {
    753                 { "Resource", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::MicrosoftEntraIdAuthenticationInfo>(v)->Resource = Utility::Trim(value.as<std::string>()); return {}; } },
    754                 { "Scope", [](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { variant_ptr<Authentication::MicrosoftEntraIdAuthenticationInfo>(v)->Scope = Utility::Trim(value.as<std::string>()); return {}; } },
    755             };
    756         }
    757 
    758         return result;
    759     }
    760 
    761     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetShadowRootFieldProcessInfo()
    762     {
    763         std::vector<FieldProcessInfo> result;
    764 
    765         if (m_manifestVersion.get().Major() == 1)
    766         {
    767             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 })
    768             {
    769                 std::vector<FieldProcessInfo> fields_v1_5 =
    770                 {
    771                     {
    772                         { "Localization", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessShadowLocalizationNode(value, variant_ptr<Manifest>(v)); } },
    773                         { "ManifestType", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } },
    774                         { "PackageIdentifier", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } },
    775                         { "PackageVersion", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } },
    776                         { "ManifestVersion", [](const YAML::Node&, const VariantManifestPtr&)->ValidationErrors { return {}; } },
    777                     },
    778                 };
    779 
    780                 std::move(fields_v1_5.begin(), fields_v1_5.end(), std::inserter(result, result.end()));
    781             }
    782         }
    783 
    784         auto rootLocalizationFields = GetShadowLocalizationFieldProcessInfo();
    785         std::move(rootLocalizationFields.begin(), rootLocalizationFields.end(), std::inserter(result, result.end()));
    786 
    787         return result;
    788     }
    789 
    790     std::vector<ManifestYamlPopulator::FieldProcessInfo> ManifestYamlPopulator::GetShadowLocalizationFieldProcessInfo()
    791     {
    792         std::vector<FieldProcessInfo> result;
    793 
    794         if (m_manifestVersion.get().Major() == 1)
    795         {
    796             if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 })
    797             {
    798                 std::vector<FieldProcessInfo> fields_v1_5 =
    799                 {
    800                     { "PackageLocale", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { GetManifestLocalizationPtr(v)->Locale = value.as<std::string>(); return {}; } },
    801                     { "Icons", [this](const YAML::Node& value, const VariantManifestPtr& v)->ValidationErrors { return ProcessIconsNode(value, GetManifestLocalizationPtr(v)); } },
    802                 };
    803 
    804                 std::move(fields_v1_5.begin(), fields_v1_5.end(), std::inserter(result, result.end()));
    805             }
    806         }
    807 
    808         return result;
    809     }
    810 
    811     ValidationErrors ManifestYamlPopulator::ValidateAndProcessFields(
    812         const YAML::Node& rootNode,
    813         const std::vector<FieldProcessInfo>& fieldInfos,
    814         const VariantManifestPtr& v)
    815     {
    816         ValidationErrors resultErrors;
    817 
    818         if (!rootNode.IsMap() || rootNode.size() == 0)
    819         {
    820             resultErrors.emplace_back(ManifestError::InvalidRootNode, "", "", m_isMergedManifest ? 0 : rootNode.Mark().line, m_isMergedManifest ? 0 : rootNode.Mark().column);
    821             return resultErrors;
    822         }
    823 
    824         // Keeps track of already processed fields. Used to check duplicate fields.
    825         std::set<std::string> processedFields;
    826 
    827         for (auto const& keyValuePair : rootNode.Mapping())
    828         {
    829             std::string key = keyValuePair.first.as<std::string>();
    830             const YAML::Node& valueNode = keyValuePair.second;
    831 
    832             // We'll do case-insensitive search first and validate correct case later.
    833             auto fieldIter = std::find_if(fieldInfos.begin(), fieldInfos.end(),
    834                 [&](auto const& s)
    835                 {
    836                     return Utility::CaseInsensitiveEquals(s.Name, key);
    837                 });
    838 
    839             if (fieldIter != fieldInfos.end())
    840             {
    841                 const FieldProcessInfo& fieldInfo = *fieldIter;
    842 
    843                 // Make sure the found key is in Pascal Case
    844                 if (key != fieldInfo.Name)
    845                 {
    846                     resultErrors.emplace_back(ManifestError::FieldIsNotPascalCase, key, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column);
    847                 }
    848 
    849                 // Make sure it's not a duplicate key
    850                 if (!processedFields.insert(fieldInfo.Name).second)
    851                 {
    852                     resultErrors.emplace_back(ManifestError::FieldDuplicate, fieldInfo.Name, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column);
    853                 }
    854 
    855                 if (fieldInfo.RequireVerifiedPublisher)
    856                 {
    857                     resultErrors.emplace_back(ManifestError::FieldRequireVerifiedPublisher, fieldInfo.Name, "",
    858                         m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column,
    859                         m_validateOption.ErrorOnVerifiedPublisherFields ? ValidationError::Level::Error : ValidationError::Level::Warning);
    860                 }
    861 
    862                 if (!valueNode.IsNull())
    863                 {
    864                     try
    865                     {
    866                         auto errors = fieldInfo.ProcessFunc(valueNode, v);
    867                         std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
    868                     }
    869                     catch (const std::exception&)
    870                     {
    871                         resultErrors.emplace_back(ManifestError::FieldFailedToProcess, fieldInfo.Name);
    872                     }
    873                 }
    874             }
    875             else
    876             {
    877                 // For full validation, also reports unrecognized fields as warning
    878                 if (m_validateOption.FullValidation)
    879                 {
    880                     resultErrors.emplace_back(ManifestError::FieldUnknown, key, "", m_isMergedManifest ? 0 : keyValuePair.first.Mark().line, m_isMergedManifest ? 0 : keyValuePair.first.Mark().column, ValidationError::Level::Warning);
    881                 }
    882             }
    883         }
    884 
    885         return resultErrors;
    886     }
    887 
    888     ValidationErrors ManifestYamlPopulator::ProcessPackageDependenciesNode(const YAML::Node& rootNode, DependencyList* dependencyList)
    889     {
    890         ValidationErrors resultErrors;
    891 
    892         for (auto const& entry : rootNode.Sequence())
    893         {
    894             Dependency packageDependency = Dependency(DependencyType::Package);
    895             auto errors = ValidateAndProcessFields(entry, PackageDependenciesFieldInfos, VariantManifestPtr(&packageDependency));
    896             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
    897             dependencyList->Add(std::move(packageDependency));
    898         }
    899 
    900         return resultErrors;
    901     }
    902 
    903     ValidationErrors ManifestYamlPopulator::ProcessAgreementsNode(const YAML::Node& agreementsNode, ManifestLocalization* localization)
    904     {
    905         THROW_HR_IF(E_INVALIDARG, !agreementsNode.IsSequence());
    906 
    907         ValidationErrors resultErrors;
    908         std::vector<Agreement> agreements;
    909 
    910         for (auto const& entry : agreementsNode.Sequence())
    911         {
    912             Agreement agreement;
    913             auto errors = ValidateAndProcessFields(entry, AgreementFieldInfos, VariantManifestPtr(&agreement));
    914             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
    915             agreements.emplace_back(std::move(agreement));
    916         }
    917 
    918         if (!agreements.empty())
    919         {
    920             localization->Add<Localization::Agreements>(std::move(agreements));
    921         }
    922 
    923         return resultErrors;
    924     }
    925 
    926     std::vector<ValidationError> ManifestYamlPopulator::ProcessMarketsNode(const YAML::Node& marketsNode, ManifestInstaller* installer)
    927     {
    928         MarketsInfo markets;
    929         auto errors = ValidateAndProcessFields(marketsNode, MarketsFieldInfos, VariantManifestPtr(&markets));
    930         installer->Markets = markets;
    931         return errors;
    932     }
    933 
    934     std::vector<ValidationError> ManifestYamlPopulator::ProcessAppsAndFeaturesEntriesNode(const YAML::Node& appsAndFeaturesEntriesNode, ManifestInstaller* installer)
    935     {
    936         THROW_HR_IF(E_INVALIDARG, !appsAndFeaturesEntriesNode.IsSequence());
    937 
    938         ValidationErrors resultErrors;
    939         std::vector<AppsAndFeaturesEntry> appsAndFeaturesEntries;
    940 
    941         for (auto const& entry : appsAndFeaturesEntriesNode.Sequence())
    942         {
    943             AppsAndFeaturesEntry appsAndFeaturesEntry;
    944             auto errors = ValidateAndProcessFields(entry, AppsAndFeaturesEntryFieldInfos, VariantManifestPtr(&appsAndFeaturesEntry));
    945             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
    946             appsAndFeaturesEntries.emplace_back(std::move(appsAndFeaturesEntry));
    947         }
    948 
    949         installer->AppsAndFeaturesEntries = appsAndFeaturesEntries;
    950 
    951         return resultErrors;
    952     }
    953 
    954     ValidationErrors ManifestYamlPopulator::ProcessExpectedReturnCodesNode(const YAML::Node& returnCodesNode, ManifestInstaller* installer)
    955     {
    956         THROW_HR_IF(E_INVALIDARG, !returnCodesNode.IsSequence());
    957 
    958         ValidationErrors resultErrors;
    959         std::map<DWORD, ExpectedReturnCodeInfo> returnCodes;
    960 
    961         for (auto const& entry : returnCodesNode.Sequence())
    962         {
    963             ExpectedReturnCode returnCode;
    964             auto errors = ValidateAndProcessFields(entry, ExpectedReturnCodesFieldInfos, VariantManifestPtr(&returnCode));
    965             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
    966             if (!returnCodes.insert({ returnCode.InstallerReturnCode, {returnCode.ReturnResponse, returnCode.ReturnResponseUrl} }).second)
    967             {
    968                 resultErrors.emplace_back(ManifestError::DuplicateReturnCodeEntry);
    969             }
    970         }
    971 
    972         installer->ExpectedReturnCodes = returnCodes;
    973 
    974         return resultErrors;
    975     }
    976 
    977     ValidationErrors ManifestYamlPopulator::ProcessDocumentationsNode(const YAML::Node& documentationsNode, ManifestLocalization* localization)
    978     {
    979         THROW_HR_IF(E_INVALIDARG, !documentationsNode.IsSequence());
    980 
    981         ValidationErrors resultErrors;
    982         std::vector<Documentation> documentations;
    983 
    984         for (auto const& entry : documentationsNode.Sequence())
    985         {
    986             Documentation documentation;
    987             auto errors = ValidateAndProcessFields(entry, DocumentationFieldInfos, VariantManifestPtr(&documentation));
    988             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
    989             documentations.emplace_back(std::move(documentation));
    990         }
    991 
    992         if (!documentations.empty())
    993         {
    994             localization->Add<Localization::Documentations>(std::move(documentations));
    995         }
    996 
    997         return resultErrors;
    998     }
    999 
   1000     std::vector<ValidationError> ManifestYamlPopulator::ProcessIconsNode(const YAML::Node& iconsNode, ManifestLocalization* localization)
   1001     {
   1002         THROW_HR_IF(E_INVALIDARG, !iconsNode.IsSequence());
   1003 
   1004         ValidationErrors resultErrors;
   1005         std::vector<Icon> icons;
   1006 
   1007         for (auto const& entry : iconsNode.Sequence())
   1008         {
   1009             Icon icon;
   1010             auto errors = ValidateAndProcessFields(entry, IconFieldInfos, VariantManifestPtr(&icon));
   1011             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
   1012             icons.emplace_back(std::move(icon));
   1013         }
   1014 
   1015         if (!icons.empty())
   1016         {
   1017             localization->Add<Localization::Icons>(std::move(icons));
   1018         }
   1019 
   1020         return resultErrors;
   1021     }
   1022 
   1023     ValidationErrors ManifestYamlPopulator::ProcessNestedInstallerFilesNode(const YAML::Node& nestedInstallerFilesNode, ManifestInstaller* installer)
   1024     {
   1025         THROW_HR_IF(E_INVALIDARG, !nestedInstallerFilesNode.IsSequence());
   1026 
   1027         ValidationErrors resultErrors;
   1028         std::vector<NestedInstallerFile> nestedInstallerFiles;
   1029 
   1030         for (auto const& entry : nestedInstallerFilesNode.Sequence())
   1031         {
   1032             NestedInstallerFile nestedInstallerFile;
   1033             auto errors = ValidateAndProcessFields(entry, NestedInstallerFileFieldInfos, VariantManifestPtr(&nestedInstallerFile));
   1034             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
   1035             nestedInstallerFiles.emplace_back(std::move(nestedInstallerFile));
   1036         }
   1037 
   1038         if (!nestedInstallerFiles.empty())
   1039         {
   1040             installer->NestedInstallerFiles = nestedInstallerFiles;
   1041         }
   1042 
   1043         return resultErrors;
   1044     }
   1045 
   1046     std::vector<ValidationError> ManifestYamlPopulator::ProcessInstallationMetadataFilesNode(const YAML::Node& installedFilesNode, InstallationMetadataInfo* installationMetadata)
   1047     {
   1048         THROW_HR_IF(E_INVALIDARG, !installedFilesNode.IsSequence());
   1049 
   1050         ValidationErrors resultErrors;
   1051         std::vector<InstalledFile> installedFiles;
   1052 
   1053         for (auto const& entry : installedFilesNode.Sequence())
   1054         {
   1055             InstalledFile installedFile;
   1056             auto errors = ValidateAndProcessFields(entry, InstallationMetadataFilesFieldInfos, VariantManifestPtr(&installedFile));
   1057             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
   1058             installedFiles.emplace_back(std::move(installedFile));
   1059         }
   1060 
   1061         if (!installedFiles.empty())
   1062         {
   1063             installationMetadata->Files = installedFiles;
   1064         }
   1065 
   1066         return resultErrors;
   1067     }
   1068 
   1069     std::vector<ValidationError> ManifestYamlPopulator::ProcessShadowLocalizationNode(const YAML::Node& localizationNode, Manifest* manifest)
   1070     {
   1071         THROW_HR_IF(E_INVALIDARG, !localizationNode.IsSequence());
   1072 
   1073         ValidationErrors resultErrors;
   1074         auto shadowLocalizationFields = GetShadowLocalizationFieldProcessInfo();
   1075 
   1076         for (auto const& entry : localizationNode.Sequence())
   1077         {
   1078             ManifestLocalization localization;
   1079             auto errors = ValidateAndProcessFields(entry, shadowLocalizationFields, VariantManifestPtr(&localization));
   1080             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
   1081             manifest->Localizations.emplace_back(std::move(std::move(localization)));
   1082         }
   1083 
   1084         return resultErrors;
   1085     }
   1086 
   1087     ManifestYamlPopulator::ManifestYamlPopulator(YAML::Node& rootNode, Manifest& manifest, const ManifestVer& manifestVersion, ManifestValidateOption validateOption) :
   1088         m_rootNode(rootNode), m_manifest(manifest), m_manifestVersion(manifestVersion), m_validateOption(validateOption)
   1089     {
   1090         m_isMergedManifest = !m_rootNode.get()["ManifestType"sv].IsNull() && m_rootNode.get()["ManifestType"sv].as<std::string>() == "merged";
   1091         m_manifest.get().ManifestVersion = m_manifestVersion;
   1092     }
   1093 
   1094     ValidationErrors ManifestYamlPopulator::PopulateManifestInternal()
   1095     {
   1096         const YAML::Node& rootNode = m_rootNode;
   1097         ValidationErrors resultErrors;
   1098 
   1099         // Prepare field infos
   1100         RootFieldInfos = GetRootFieldProcessInfo();
   1101         InstallerFieldInfos = GetInstallerFieldProcessInfo();
   1102         SwitchesFieldInfos = GetSwitchesFieldProcessInfo();
   1103         ExpectedReturnCodesFieldInfos = GetExpectedReturnCodesFieldProcessInfo();
   1104         DependenciesFieldInfos = GetDependenciesFieldProcessInfo();
   1105         PackageDependenciesFieldInfos = GetPackageDependenciesFieldProcessInfo();
   1106         LocalizationFieldInfos = GetLocalizationFieldProcessInfo();
   1107         AgreementFieldInfos = GetAgreementFieldProcessInfo();
   1108         MarketsFieldInfos = GetMarketsFieldProcessInfo();
   1109         AppsAndFeaturesEntryFieldInfos = GetAppsAndFeaturesEntryFieldProcessInfo();
   1110         DocumentationFieldInfos = GetDocumentationFieldProcessInfo();
   1111         IconFieldInfos = GetIconFieldProcessInfo();
   1112         NestedInstallerFileFieldInfos = GetNestedInstallerFileFieldProcessInfo();
   1113         InstallationMetadataFieldInfos = GetInstallationMetadataFieldProcessInfo();
   1114         InstallationMetadataFilesFieldInfos = GetInstallationMetadataFilesFieldProcessInfo();
   1115         AuthenticationFieldInfos = GetAuthenticationFieldInfos();
   1116         MicrosoftEntraIdAuthenticationInfoFieldInfos = GetMicrosoftEntraIdAuthenticationInfoFieldInfos();
   1117 
   1118         resultErrors = ValidateAndProcessFields(rootNode, RootFieldInfos, VariantManifestPtr(&(m_manifest.get())));
   1119 
   1120         if (!m_p_installersNode)
   1121         {
   1122             return resultErrors;
   1123         }
   1124 
   1125         // Populate installers
   1126         for (auto const& entry : m_p_installersNode->Sequence())
   1127         {
   1128             ManifestInstaller installer = m_manifest.get().DefaultInstallerInfo;
   1129 
   1130             // Clear these defaults as PackageFamilyName, ProductCode, AppsAndFeaturesEntries need to be copied based on InstallerType
   1131             installer.PackageFamilyName.clear();
   1132             installer.ProductCode.clear();
   1133             installer.AppsAndFeaturesEntries.clear();
   1134             // Clear dependencies as installer overrides root dependencies
   1135             installer.Dependencies.Clear();
   1136             // Clear nested installers as it should only be copied for zip installerType.
   1137             installer.NestedInstallerType = InstallerTypeEnum::Unknown;
   1138             installer.NestedInstallerFiles.clear();
   1139 
   1140             auto errors = ValidateAndProcessFields(entry, InstallerFieldInfos, VariantManifestPtr(&installer));
   1141             std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
   1142 
   1143             // Copy in system reference strings from the root if not set in the installer and appropriate
   1144             if (installer.PackageFamilyName.empty() && DoesInstallerTypeUsePackageFamilyName(installer.EffectiveInstallerType()))
   1145             {
   1146                 installer.PackageFamilyName = m_manifest.get().DefaultInstallerInfo.PackageFamilyName;
   1147             }
   1148 
   1149             if (installer.ProductCode.empty() && DoesInstallerTypeUseProductCode(installer.EffectiveInstallerType()))
   1150             {
   1151                 installer.ProductCode = m_manifest.get().DefaultInstallerInfo.ProductCode;
   1152             }
   1153 
   1154             if (installer.AppsAndFeaturesEntries.empty() && DoesInstallerTypeWriteAppsAndFeaturesEntry(installer.EffectiveInstallerType()))
   1155             {
   1156                 installer.AppsAndFeaturesEntries = m_manifest.get().DefaultInstallerInfo.AppsAndFeaturesEntries;
   1157             }
   1158 
   1159             if (IsArchiveType(installer.BaseInstallerType))
   1160             {
   1161                 if (installer.NestedInstallerFiles.empty())
   1162                 {
   1163                     installer.NestedInstallerFiles = m_manifest.get().DefaultInstallerInfo.NestedInstallerFiles;
   1164                 }
   1165 
   1166                 if (installer.NestedInstallerType == InstallerTypeEnum::Unknown)
   1167                 {
   1168                     installer.NestedInstallerType = m_manifest.get().DefaultInstallerInfo.NestedInstallerType;
   1169                 }
   1170             }
   1171 
   1172             // If there are no dependencies on installer use default ones
   1173             if (!installer.Dependencies.HasAny())
   1174             {
   1175                 installer.Dependencies = m_manifest.get().DefaultInstallerInfo.Dependencies;
   1176             }
   1177 
   1178             // Populate installer default switches if not exists
   1179             auto defaultSwitches = GetDefaultKnownSwitches(installer.EffectiveInstallerType());
   1180             for (auto const& defaultSwitch : defaultSwitches)
   1181             {
   1182                 if (installer.Switches.find(defaultSwitch.first) == installer.Switches.end())
   1183                 {
   1184                     installer.Switches[defaultSwitch.first] = defaultSwitch.second;
   1185                 }
   1186             }
   1187 
   1188             // Populate installer default return codes if not present in ExpectedReturnCodes and InstallerSuccessCodes
   1189             auto defaultReturnCodes = GetDefaultKnownReturnCodes(installer.EffectiveInstallerType());
   1190             for (auto const& defaultReturnCode : defaultReturnCodes)
   1191             {
   1192                 if (installer.ExpectedReturnCodes.find(defaultReturnCode.first) == installer.ExpectedReturnCodes.end() &&
   1193                     std::find(installer.InstallerSuccessCodes.begin(), installer.InstallerSuccessCodes.end(), defaultReturnCode.first) == installer.InstallerSuccessCodes.end())
   1194                 {
   1195                     installer.ExpectedReturnCodes[defaultReturnCode.first].ReturnResponseEnum = defaultReturnCode.second;
   1196                 }
   1197             }
   1198 
   1199             m_manifest.get().Installers.emplace_back(std::move(installer));
   1200         }
   1201 
   1202         // Populate additional localizations
   1203         if (m_p_localizationsNode && m_p_localizationsNode->IsSequence())
   1204         {
   1205             for (auto const& entry : m_p_localizationsNode->Sequence())
   1206             {
   1207                 ManifestLocalization localization;
   1208                 auto errors = ValidateAndProcessFields(entry, LocalizationFieldInfos, VariantManifestPtr(&localization));
   1209                 std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end()));
   1210                 m_manifest.get().Localizations.emplace_back(std::move(std::move(localization)));
   1211             }
   1212         }
   1213 
   1214         return resultErrors;
   1215     }
   1216 
   1217     ValidationErrors ManifestYamlPopulator::InsertShadow(const YAML::Node& shadowNode)
   1218     {
   1219         Manifest shadowManifest;
   1220 
   1221         // Process shadow node.
   1222         auto resultErrors = ValidateAndProcessFields(shadowNode, GetShadowRootFieldProcessInfo(), VariantManifestPtr(&shadowManifest));
   1223 
   1224         // Merge.
   1225         if (m_manifestVersion.get() >= ManifestVer{ s_ManifestVersionV1_5 })
   1226         {
   1227             // Default localization
   1228             if (Utility::ICUCaseInsensitiveEquals(m_manifest.get().DefaultLocalization.Locale, shadowManifest.DefaultLocalization.Locale))
   1229             {
   1230                 // Icons
   1231                 if (!m_manifest.get().DefaultLocalization.Contains(Localization::Icons) &&
   1232                     shadowManifest.DefaultLocalization.Contains(Localization::Icons))
   1233                 {
   1234                     m_manifest.get().DefaultLocalization.Add<Localization::Icons>(std::move(shadowManifest.DefaultLocalization.Get<Localization::Icons>()));
   1235 
   1236                     YAML::Node key{ YAML::Node::Type::Scalar, "", YAML::Mark() };
   1237                     key.SetScalar("Icons");
   1238                     YAML::Node value = shadowNode.GetChildNode("Icons");
   1239                     m_rootNode.get().AddMappingNode(std::move(key), std::move(value));
   1240                 }
   1241             }
   1242 
   1243             // Localizations
   1244             if (!shadowManifest.Localizations.empty())
   1245             {
   1246                 // Merge manifest object
   1247                 for (auto const& shadowLocalization : shadowManifest.Localizations)
   1248                 {
   1249                     // Manifest
   1250                     if (auto iter = std::find_if(m_manifest.get().Localizations.begin(), m_manifest.get().Localizations.end(), [&](auto const& l) { return Utility::ICUCaseInsensitiveEquals(l.Locale, shadowLocalization.Locale); }); iter != m_manifest.get().Localizations.end())
   1251                     {
   1252                         if (!(*iter).Contains(Localization::Icons) &&
   1253                             shadowLocalization.Contains(Localization::Icons))
   1254                         {
   1255                             (*iter).Add<Localization::Icons>(std::move(shadowLocalization.Get<Localization::Icons>()));
   1256                         }
   1257                     }
   1258                     else
   1259                     {
   1260                         ManifestLocalization localization = shadowLocalization;
   1261                         m_manifest.get().Localizations.emplace_back(std::move(std::move(localization)));
   1262                     }
   1263                 }
   1264 
   1265                 // Merge yaml
   1266                 auto shadowLocalizationsNode = shadowNode.GetChildNode("Localization");
   1267                 if (m_p_localizationsNode)
   1268                 {
   1269                     m_rootNode.get().GetChildNode("Localization").MergeSequenceNode(shadowLocalizationsNode, "PackageLocale", true);
   1270                 }
   1271                 else
   1272                 {
   1273                     YAML::Node key{ YAML::Node::Type::Scalar, "", YAML::Mark() };
   1274                     key.SetScalar("Localization");
   1275                     m_rootNode.get().AddMappingNode(std::move(key), std::move(shadowLocalizationsNode));
   1276                 }
   1277             }
   1278         }
   1279 
   1280         return resultErrors;
   1281     }
   1282 
   1283     ValidationErrors ManifestYamlPopulator::PopulateManifest(
   1284         YAML::Node& rootNode,
   1285         Manifest& manifest,
   1286         const ManifestVer& manifestVersion,
   1287         ManifestValidateOption validateOption,
   1288         const std::optional<YAML::Node>& shadowNode)
   1289     {
   1290         ManifestYamlPopulator manifestPopulator(rootNode, manifest, manifestVersion, validateOption);
   1291         auto errors = manifestPopulator.PopulateManifestInternal();
   1292 
   1293         if (shadowNode.has_value())
   1294         {
   1295             auto shadowErrors = manifestPopulator.InsertShadow(shadowNode.value());
   1296             std::move(shadowErrors.begin(), shadowErrors.end(), std::inserter(errors, errors.end()));
   1297         }
   1298 
   1299         return errors;
   1300     }
   1301 }