winget-cli

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

ManifestCommon.cpp (40858B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "winget/ManifestCommon.h"
      5 #include "winget/ManifestValidation.h"
      6 
      7 namespace AppInstaller::Manifest
      8 {
      9     namespace
     10     {
     11         enum class CompatibilitySet
     12         {
     13             None,
     14             Exe,
     15             Msi,
     16             Msix,
     17         };
     18 
     19         CompatibilitySet GetCompatibilitySet(InstallerTypeEnum type)
     20         {
     21             switch (type)
     22             {
     23             case InstallerTypeEnum::Inno:
     24             case InstallerTypeEnum::Nullsoft:
     25             case InstallerTypeEnum::Exe:
     26             case InstallerTypeEnum::Burn:
     27                 return CompatibilitySet::Exe;
     28             case InstallerTypeEnum::Wix:
     29             case InstallerTypeEnum::Msi:
     30                 return CompatibilitySet::Msi;
     31             case InstallerTypeEnum::Msix:
     32             case InstallerTypeEnum::MSStore:
     33                 return CompatibilitySet::Msix;
     34             default:
     35                 return CompatibilitySet::None;
     36             }
     37         }
     38     }
     39 
     40     ManifestVer::ManifestVer(std::string_view version)
     41     {
     42         bool validationSuccess = true;
     43 
     44         // Separate the extensions out
     45         size_t hyphenPos = version.find_first_of('-');
     46         if (hyphenPos != std::string_view::npos)
     47         {
     48             // The first part is the main version
     49             Assign(std::string{ version.substr(0, hyphenPos) }, ".");
     50 
     51             // The second part is the extensions
     52             hyphenPos += 1;
     53             while (hyphenPos < version.length())
     54             {
     55                 size_t newPos = version.find_first_of('-', hyphenPos);
     56 
     57                 size_t length = (newPos == std::string::npos ? version.length() : newPos) - hyphenPos;
     58                 m_extensions.emplace_back(std::string{ version.substr(hyphenPos, length) }, ".");
     59 
     60                 hyphenPos += length + 1;
     61             }
     62         }
     63         else
     64         {
     65             Assign(std::string{ version }, ".");
     66         }
     67 
     68         if (m_parts.size() > 3)
     69         {
     70             validationSuccess = false;
     71         }
     72         else
     73         {
     74             for (size_t i = 0; i < m_parts.size(); i++)
     75             {
     76                 if (!m_parts[i].Other.empty())
     77                 {
     78                     validationSuccess = false;
     79                     break;
     80                 }
     81             }
     82 
     83             for (const RawVersion& ext : m_extensions)
     84             {
     85                 if (ext.GetParts().empty() || ext.GetParts()[0].Integer != 0)
     86                 {
     87                     validationSuccess = false;
     88                     break;
     89                 }
     90             }
     91         }
     92 
     93         if (!validationSuccess)
     94         {
     95             std::vector<ValidationError> errors;
     96             errors.emplace_back(ManifestError::InvalidFieldValue, "ManifestVersion", std::string{ version });
     97             THROW_EXCEPTION(ManifestException(std::move(errors)));
     98         }
     99     }
    100 
    101     bool ManifestVer::HasExtension() const
    102     {
    103         return !m_extensions.empty();
    104     }
    105 
    106     bool ManifestVer::HasExtension(std::string_view extension) const
    107     {
    108         for (const RawVersion& ext : m_extensions)
    109         {
    110             const auto& parts = ext.GetParts();
    111             if (!parts.empty() && parts[0].Integer == 0 && parts[0].Other == extension)
    112             {
    113                 return true;
    114             }
    115         }
    116 
    117         return false;
    118     }
    119 
    120     InstallerTypeEnum ConvertToInstallerTypeEnum(const std::string& in)
    121     {
    122         std::string inStrLower = Utility::ToLower(in);
    123         InstallerTypeEnum result = InstallerTypeEnum::Unknown;
    124 
    125         if (inStrLower == "inno")
    126         {
    127             result = InstallerTypeEnum::Inno;
    128         }
    129         else if (inStrLower == "wix")
    130         {
    131             result = InstallerTypeEnum::Wix;
    132         }
    133         else if (inStrLower == "msi")
    134         {
    135             result = InstallerTypeEnum::Msi;
    136         }
    137         else if (inStrLower == "nullsoft")
    138         {
    139             result = InstallerTypeEnum::Nullsoft;
    140         }
    141         else if (inStrLower == "zip")
    142         {
    143             result = InstallerTypeEnum::Zip;
    144         }
    145         else if (inStrLower == "appx" || inStrLower == "msix")
    146         {
    147             result = InstallerTypeEnum::Msix;
    148         }
    149         else if (inStrLower == "exe")
    150         {
    151             result = InstallerTypeEnum::Exe;
    152         }
    153         else if (inStrLower == "burn")
    154         {
    155             result = InstallerTypeEnum::Burn;
    156         }
    157         else if (inStrLower == "msstore")
    158         {
    159             result = InstallerTypeEnum::MSStore;
    160         }
    161         else if (inStrLower == "portable") 
    162         {
    163             result = InstallerTypeEnum::Portable;
    164         }
    165         else if (inStrLower == "font")
    166         {
    167             result = InstallerTypeEnum::Font;
    168         }
    169 
    170         return result;
    171     }
    172 
    173     UpdateBehaviorEnum ConvertToUpdateBehaviorEnum(const std::string& in)
    174     {
    175         UpdateBehaviorEnum result = UpdateBehaviorEnum::Unknown;
    176 
    177         if (Utility::CaseInsensitiveEquals(in, "install"))
    178         {
    179             result = UpdateBehaviorEnum::Install;
    180         }
    181         else if (Utility::CaseInsensitiveEquals(in, "uninstallprevious"))
    182         {
    183             result = UpdateBehaviorEnum::UninstallPrevious;
    184         }
    185         else if (Utility::CaseInsensitiveEquals(in, "deny"))
    186         {
    187             result = UpdateBehaviorEnum::Deny;
    188         }
    189 
    190         return result;
    191     }
    192 
    193     ScopeEnum ConvertToScopeEnum(std::string_view in)
    194     {
    195         ScopeEnum result = ScopeEnum::Unknown;
    196 
    197         if (Utility::CaseInsensitiveEquals(in, "user"))
    198         {
    199             result = ScopeEnum::User;
    200         }
    201         else if (Utility::CaseInsensitiveEquals(in, "machine"))
    202         {
    203             result = ScopeEnum::Machine;
    204         }
    205 
    206         return result;
    207     }
    208 
    209     InstallModeEnum ConvertToInstallModeEnum(const std::string& in)
    210     {
    211         InstallModeEnum result = InstallModeEnum::Unknown;
    212 
    213         if (Utility::CaseInsensitiveEquals(in, "interactive"))
    214         {
    215             result = InstallModeEnum::Interactive;
    216         }
    217         else if (Utility::CaseInsensitiveEquals(in, "silent"))
    218         {
    219             result = InstallModeEnum::Silent;
    220         }
    221         else if (Utility::CaseInsensitiveEquals(in, "silentWithProgress"))
    222         {
    223             result = InstallModeEnum::SilentWithProgress;
    224         }
    225 
    226         return result;
    227     }
    228 
    229     PlatformEnum ConvertToPlatformEnum(std::string_view in)
    230     {
    231         std::string inStrLower = Utility::ToLower(in);
    232 
    233         if (inStrLower == "windows.desktop")
    234         {
    235             return PlatformEnum::Desktop;
    236         }
    237         else if (inStrLower == "windows.universal")
    238         {
    239             return PlatformEnum::Universal;
    240         }
    241 
    242         return PlatformEnum::Unknown;
    243     }
    244 
    245     PlatformEnum ConvertToPlatformEnumForMSStoreDownload(std::string_view in)
    246     {
    247         std::string inStrLower = Utility::ToLower(in);
    248 
    249         if (inStrLower == "windows.desktop")
    250         {
    251             return PlatformEnum::Desktop;
    252         }
    253         else if (inStrLower == "windows.universal")
    254         {
    255             return PlatformEnum::Universal;
    256         }
    257         else if (inStrLower == "windows.iot")
    258         {
    259             return PlatformEnum::IoT;
    260         }
    261         else if (inStrLower == "windows.team")
    262         {
    263             return PlatformEnum::Team;
    264         }
    265         else if (inStrLower == "windows.holographic")
    266         {
    267             return PlatformEnum::Holographic;
    268         }
    269 
    270         return PlatformEnum::Unknown;
    271     }
    272 
    273     ElevationRequirementEnum ConvertToElevationRequirementEnum(const std::string& in)
    274     {
    275         ElevationRequirementEnum result = ElevationRequirementEnum::Unknown;
    276 
    277         if (Utility::CaseInsensitiveEquals(in, "elevationRequired"))
    278         {
    279             result = ElevationRequirementEnum::ElevationRequired;
    280         }
    281         else if (Utility::CaseInsensitiveEquals(in, "elevationProhibited"))
    282         {
    283             result = ElevationRequirementEnum::ElevationProhibited;
    284         }
    285         else if (Utility::CaseInsensitiveEquals(in, "elevatesSelf"))
    286         {
    287             result = ElevationRequirementEnum::ElevatesSelf;
    288         }
    289 
    290         return result;
    291     }
    292 
    293     UnsupportedArgumentEnum ConvertToUnsupportedArgumentEnum(const std::string& in)
    294     {
    295         UnsupportedArgumentEnum result = UnsupportedArgumentEnum::Unknown;
    296 
    297         if (Utility::CaseInsensitiveEquals(in, "log"))
    298         {
    299             result = UnsupportedArgumentEnum::Log;
    300         }
    301         else if (Utility::CaseInsensitiveEquals(in, "location"))
    302         {
    303             result = UnsupportedArgumentEnum::Location;
    304         }
    305 
    306         return result;
    307     }
    308 
    309     ManifestTypeEnum ConvertToManifestTypeEnum(const std::string& in)
    310     {
    311         if (in == "singleton")
    312         {
    313             return ManifestTypeEnum::Singleton;
    314         }
    315         else if (in == "version")
    316         {
    317             return ManifestTypeEnum::Version;
    318         }
    319         else if (in == "installer")
    320         {
    321             return ManifestTypeEnum::Installer;
    322         }
    323         else if (in == "defaultLocale")
    324         {
    325             return ManifestTypeEnum::DefaultLocale;
    326         }
    327         else if (in == "locale")
    328         {
    329             return ManifestTypeEnum::Locale;
    330         }
    331         else if (in == "merged")
    332         {
    333             return ManifestTypeEnum::Merged;
    334         }
    335         else if (in == "shadow")
    336         {
    337             return ManifestTypeEnum::Shadow;
    338         }
    339         else
    340         {
    341             THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported ManifestType: %hs", in.c_str());
    342         }
    343     }
    344 
    345     ExpectedReturnCodeEnum ConvertToExpectedReturnCodeEnum(const std::string& in)
    346     {
    347         std::string inStrLower = Utility::ToLower(in);
    348         ExpectedReturnCodeEnum result = ExpectedReturnCodeEnum::Unknown;
    349 
    350         if (inStrLower == "packageinuse")
    351         {
    352             result = ExpectedReturnCodeEnum::PackageInUse;
    353         }
    354         else if (inStrLower == "packageinusebyapplication")
    355         {
    356             result = ExpectedReturnCodeEnum::PackageInUseByApplication;
    357         }
    358         else if (inStrLower == "installinprogress")
    359         {
    360             result = ExpectedReturnCodeEnum::InstallInProgress;
    361         }
    362         else if (inStrLower == "fileinuse")
    363         {
    364             result = ExpectedReturnCodeEnum::FileInUse;
    365         }
    366         else if (inStrLower == "missingdependency")
    367         {
    368             result = ExpectedReturnCodeEnum::MissingDependency;
    369         }
    370         else if (inStrLower == "diskfull")
    371         {
    372             result = ExpectedReturnCodeEnum::DiskFull;
    373         }
    374         else if (inStrLower == "insufficientmemory")
    375         {
    376             result = ExpectedReturnCodeEnum::InsufficientMemory;
    377         }
    378         else if (inStrLower == "invalidparameter")
    379         {
    380             result = ExpectedReturnCodeEnum::InvalidParameter;
    381         }
    382         else if (inStrLower == "nonetwork")
    383         {
    384             result = ExpectedReturnCodeEnum::NoNetwork;
    385         }
    386         else if (inStrLower == "contactsupport")
    387         {
    388             result = ExpectedReturnCodeEnum::ContactSupport;
    389         }
    390         else if (inStrLower == "rebootrequiredtofinish")
    391         {
    392             result = ExpectedReturnCodeEnum::RebootRequiredToFinish;
    393         }
    394         else if (inStrLower == "rebootrequiredforinstall")
    395         {
    396             result = ExpectedReturnCodeEnum::RebootRequiredForInstall;
    397         }
    398         else if (inStrLower == "rebootinitiated")
    399         {
    400             result = ExpectedReturnCodeEnum::RebootInitiated;
    401         }
    402         else if (inStrLower == "cancelledbyuser")
    403         {
    404             result = ExpectedReturnCodeEnum::CancelledByUser;
    405         }
    406         else if (inStrLower == "alreadyinstalled")
    407         {
    408             result = ExpectedReturnCodeEnum::AlreadyInstalled;
    409         }
    410         else if (inStrLower == "downgrade")
    411         {
    412             result = ExpectedReturnCodeEnum::Downgrade;
    413         }
    414         else if (inStrLower == "blockedbypolicy")
    415         {
    416             result = ExpectedReturnCodeEnum::BlockedByPolicy;
    417         }
    418         else if (inStrLower == "systemnotsupported")
    419         {
    420             result = ExpectedReturnCodeEnum::SystemNotSupported;
    421         }
    422         else if (inStrLower == "custom")
    423         {
    424             result = ExpectedReturnCodeEnum::Custom;
    425         }
    426 
    427         return result;
    428     }
    429 
    430     InstalledFileTypeEnum ConvertToInstalledFileTypeEnum(const std::string& in)
    431     {
    432         std::string inStrLower = Utility::ToLower(in);
    433         InstalledFileTypeEnum result = InstalledFileTypeEnum::Unknown;
    434 
    435         if (inStrLower == "launch")
    436         {
    437             result = InstalledFileTypeEnum::Launch;
    438         }
    439         else if (inStrLower == "uninstall")
    440         {
    441             result = InstalledFileTypeEnum::Uninstall;
    442         }
    443         else if (inStrLower == "other")
    444         {
    445             result = InstalledFileTypeEnum::Other;
    446         }
    447 
    448         return result;
    449     }
    450 
    451     IconFileTypeEnum ConvertToIconFileTypeEnum(std::string_view in)
    452     {
    453         std::string inStrLower = Utility::ToLower(in);
    454         IconFileTypeEnum result = IconFileTypeEnum::Unknown;
    455 
    456         if (inStrLower == "jpeg")
    457         {
    458             result = IconFileTypeEnum::Jpeg;
    459         }
    460         else if (inStrLower == "png")
    461         {
    462             result = IconFileTypeEnum::Png;
    463         }
    464         else if (inStrLower == "ico")
    465         {
    466             result = IconFileTypeEnum::Ico;
    467         }
    468 
    469         return result;
    470     }
    471 
    472     IconThemeEnum ConvertToIconThemeEnum(std::string_view in)
    473     {
    474         std::string inStrLower = Utility::ToLower(in);
    475         IconThemeEnum result = IconThemeEnum::Unknown;
    476 
    477         if (inStrLower == "default")
    478         {
    479             result = IconThemeEnum::Default;
    480         }
    481         else if (inStrLower == "dark")
    482         {
    483             result = IconThemeEnum::Dark;
    484         }
    485         else if (inStrLower == "light")
    486         {
    487             result = IconThemeEnum::Light;
    488         }
    489         else if (inStrLower == "highcontrast")
    490         {
    491             result = IconThemeEnum::HighContrast;
    492         }
    493 
    494         return result;
    495     }
    496 
    497     IconResolutionEnum ConvertToIconResolutionEnum(std::string_view in)
    498     {
    499         std::string inStrLower = Utility::ToLower(in);
    500         IconResolutionEnum result = IconResolutionEnum::Unknown;
    501 
    502         if (inStrLower == "custom")
    503         {
    504             result = IconResolutionEnum::Custom;
    505         }
    506         else if (inStrLower == "16x16")
    507         {
    508             result = IconResolutionEnum::Square16;
    509         }
    510         else if (inStrLower == "20x20")
    511         {
    512             result = IconResolutionEnum::Square20;
    513         }
    514         else if (inStrLower == "24x24")
    515         {
    516             result = IconResolutionEnum::Square24;
    517         }
    518         else if (inStrLower == "30x30")
    519         {
    520             result = IconResolutionEnum::Square30;
    521         }
    522         else if (inStrLower == "32x32")
    523         {
    524             result = IconResolutionEnum::Square32;
    525         }
    526         else if (inStrLower == "36x36")
    527         {
    528             result = IconResolutionEnum::Square36;
    529         }
    530         else if (inStrLower == "40x40")
    531         {
    532             result = IconResolutionEnum::Square40;
    533         }
    534         else if (inStrLower == "48x48")
    535         {
    536             result = IconResolutionEnum::Square48;
    537         }
    538         else if (inStrLower == "60x60")
    539         {
    540             result = IconResolutionEnum::Square60;
    541         }
    542         else if (inStrLower == "64x64")
    543         {
    544             result = IconResolutionEnum::Square64;
    545         }
    546         else if (inStrLower == "72x72")
    547         {
    548             result = IconResolutionEnum::Square72;
    549         }
    550         else if (inStrLower == "80x80")
    551         {
    552             result = IconResolutionEnum::Square80;
    553         }
    554         else if (inStrLower == "96x96")
    555         {
    556             result = IconResolutionEnum::Square96;
    557         }
    558         else if (inStrLower == "256x256")
    559         {
    560             result = IconResolutionEnum::Square256;
    561         }
    562 
    563         return result;
    564     }
    565 
    566     std::string_view InstallerTypeToString(InstallerTypeEnum installerType)
    567     {
    568         switch (installerType)
    569         {
    570         case InstallerTypeEnum::Exe:
    571             return "exe"sv;
    572         case InstallerTypeEnum::Inno:
    573             return "inno"sv;
    574         case InstallerTypeEnum::Msi:
    575             return "msi"sv;
    576         case InstallerTypeEnum::Msix:
    577             return "msix"sv;
    578         case InstallerTypeEnum::Nullsoft:
    579             return "nullsoft"sv;
    580         case InstallerTypeEnum::Wix:
    581             return "wix"sv;
    582         case InstallerTypeEnum::Zip:
    583             return "zip"sv;
    584         case InstallerTypeEnum::Burn:
    585             return "burn"sv;
    586         case InstallerTypeEnum::MSStore:
    587             return "msstore"sv;
    588         case InstallerTypeEnum::Portable:
    589             return "portable"sv;
    590         case InstallerTypeEnum::Font:
    591             return "font"sv;
    592         }
    593 
    594         return "unknown"sv;
    595     }
    596 
    597     std::string_view InstallerSwitchTypeToString(InstallerSwitchType installerSwitchType)
    598     {
    599         switch (installerSwitchType)
    600         {
    601         case InstallerSwitchType::Custom:
    602             return "Custom"sv;
    603         case InstallerSwitchType::Silent:
    604             return "Silent"sv;
    605         case InstallerSwitchType::SilentWithProgress:
    606             return "SilentWithProgress"sv;
    607         case InstallerSwitchType::Interactive:
    608             return "Interactive"sv;
    609         case InstallerSwitchType::Language:
    610             return "Language"sv;
    611         case InstallerSwitchType::Log:
    612             return "Log"sv;
    613         case InstallerSwitchType::InstallLocation:
    614             return "InstallLocation"sv;
    615         case InstallerSwitchType::Update:
    616             return "Upgrade"sv;
    617         case InstallerSwitchType::Repair:
    618             return "Repair"sv;
    619         }
    620 
    621         return "Unknown"sv;
    622     }
    623 
    624     std::string_view ElevationRequirementToString(ElevationRequirementEnum elevationRequirement)
    625     {
    626         switch (elevationRequirement)
    627         {
    628         case ElevationRequirementEnum::ElevationRequired:
    629             return "elevationRequired"sv;
    630         case ElevationRequirementEnum::ElevationProhibited:
    631             return "elevationProhibited"sv;
    632         case ElevationRequirementEnum::ElevatesSelf:
    633             return "elevatesSelf"sv;
    634         }
    635 
    636         return "unknown"sv;
    637     }
    638 
    639     std::string_view UnsupportedArgumentToString(UnsupportedArgumentEnum unsupportedArgument)
    640     {
    641         switch (unsupportedArgument)
    642         {
    643         case UnsupportedArgumentEnum::Log:
    644             return "log"sv;
    645         case UnsupportedArgumentEnum::Location:
    646             return "location"sv;
    647         }
    648 
    649         return "unknown"sv;
    650     }
    651 
    652     std::string_view InstallModeToString(InstallModeEnum installMode)
    653     {
    654         switch (installMode)
    655         {
    656         case InstallModeEnum::Interactive:
    657             return "interactive"sv;
    658         case InstallModeEnum::Silent:
    659             return "silent"sv;
    660         case InstallModeEnum::SilentWithProgress:
    661             return "silentWithProgress"sv;
    662         }
    663 
    664         return "unknown"sv;
    665     }
    666 
    667     std::string_view PlatformToString(PlatformEnum platform, bool shortString)
    668     {
    669         switch (platform)
    670         {
    671         case PlatformEnum::Desktop:
    672             return shortString ? "Desktop" : "Windows.Desktop"sv;
    673         case PlatformEnum::Universal:
    674             return shortString ? "Universal" : "Windows.Universal"sv;
    675         case PlatformEnum::IoT:
    676             return shortString ? "IoT" : "Windows.IoT"sv;
    677         case PlatformEnum::Holographic:
    678             return shortString ? "Holographic" : "Windows.Holographic"sv;
    679         case PlatformEnum::Team:
    680             return shortString ? "Team" : "Windows.Team"sv;
    681         }
    682 
    683         return "Unknown"sv;
    684     }
    685 
    686     std::string_view UpdateBehaviorToString(UpdateBehaviorEnum updateBehavior)
    687     {
    688         switch (updateBehavior)
    689         {
    690         case UpdateBehaviorEnum::Install:
    691             return "install"sv;
    692         case UpdateBehaviorEnum::UninstallPrevious:
    693             return "uninstallPrevious"sv;
    694         case UpdateBehaviorEnum::Deny:
    695             return "deny"sv;
    696         }
    697 
    698         return "unknown"sv;
    699     }
    700 
    701     std::string_view RepairBehaviorToString(RepairBehaviorEnum repairBehavior)
    702     {
    703         switch (repairBehavior)
    704         {
    705         case AppInstaller::Manifest::RepairBehaviorEnum::Modify:
    706             return "modify"sv;
    707         case AppInstaller::Manifest::RepairBehaviorEnum::Installer:
    708             return "installer"sv;
    709         case AppInstaller::Manifest::RepairBehaviorEnum::Uninstaller:
    710             return "uninstaller"sv;
    711         }
    712 
    713         return "unknown"sv;
    714     }
    715 
    716     std::string_view ScopeToString(ScopeEnum scope)
    717     {
    718         switch (scope)
    719         {
    720         case ScopeEnum::User:
    721             return "User"sv;
    722         case ScopeEnum::Machine:
    723             return "Machine"sv;
    724         }
    725 
    726         return "Unknown"sv;
    727     }
    728 
    729     std::string_view InstalledFileTypeToString(InstalledFileTypeEnum installedFileType)
    730     {
    731         switch (installedFileType)
    732         {
    733         case InstalledFileTypeEnum::Launch:
    734             return "launch"sv;
    735         case InstalledFileTypeEnum::Uninstall:
    736             return "uninstall"sv;
    737         case InstalledFileTypeEnum::Other:
    738             return "other"sv;
    739         }
    740 
    741         return "unknown"sv;
    742     }
    743 
    744     std::string_view IconFileTypeToString(IconFileTypeEnum iconFileType)
    745     {
    746         switch (iconFileType)
    747         {
    748         case IconFileTypeEnum::Ico:
    749             return "ico"sv;
    750         case IconFileTypeEnum::Jpeg:
    751             return "jpeg"sv;
    752         case IconFileTypeEnum::Png:
    753             return "png"sv;
    754         }
    755 
    756         return "unknown"sv;
    757     }
    758 
    759     std::string_view IconThemeToString(IconThemeEnum iconTheme)
    760     {
    761         switch (iconTheme)
    762         {
    763         case IconThemeEnum::Default:
    764             return "default"sv;
    765         case IconThemeEnum::Dark:
    766             return "dark"sv;
    767         case IconThemeEnum::Light:
    768             return "light"sv;
    769         case IconThemeEnum::HighContrast:
    770             return "highContrast"sv;
    771         }
    772 
    773         return "unknown"sv;
    774     }
    775 
    776     std::string_view IconResolutionToString(IconResolutionEnum iconResolution)
    777     {
    778         switch (iconResolution)
    779         {
    780         case IconResolutionEnum::Custom:
    781             return "custom"sv;
    782         case IconResolutionEnum::Square16:
    783             return "16x16"sv;
    784         case IconResolutionEnum::Square20:
    785             return "20x20"sv;
    786         case IconResolutionEnum::Square24:
    787             return "24x24"sv;
    788         case IconResolutionEnum::Square30:
    789             return "30x30"sv;
    790         case IconResolutionEnum::Square32:
    791             return "32x32"sv;
    792         case IconResolutionEnum::Square36:
    793             return "36x36"sv;
    794         case IconResolutionEnum::Square40:
    795             return "40x40"sv;
    796         case IconResolutionEnum::Square48:
    797             return "48x48"sv;
    798         case IconResolutionEnum::Square60:
    799             return "60x60"sv;
    800         case IconResolutionEnum::Square64:
    801             return "64x64"sv;
    802         case IconResolutionEnum::Square72:
    803             return "72x72"sv;
    804         case IconResolutionEnum::Square80:
    805             return "80x80"sv;
    806         case IconResolutionEnum::Square96:
    807             return "96x96"sv;
    808         case IconResolutionEnum::Square256:
    809             return "256x256"sv;
    810         }
    811 
    812         return "unknown"sv;
    813     }
    814 
    815     std::string_view ExpectedReturnCodeToString(ExpectedReturnCodeEnum expectedReturnCode)
    816     {
    817         switch (expectedReturnCode)
    818         {
    819         case ExpectedReturnCodeEnum::AlreadyInstalled:
    820             return "alreadyInstalled"sv;
    821         case ExpectedReturnCodeEnum::PackageInUse:
    822             return "packageInUse"sv;
    823         case ExpectedReturnCodeEnum::PackageInUseByApplication:
    824             return "packageInUseByApplication"sv;
    825         case ExpectedReturnCodeEnum::InstallInProgress:
    826             return "installInProgress"sv;
    827         case ExpectedReturnCodeEnum::FileInUse:
    828             return "fileInUse"sv;
    829         case ExpectedReturnCodeEnum::MissingDependency:
    830             return "missingDependency"sv;
    831         case ExpectedReturnCodeEnum::DiskFull:
    832             return "diskFull"sv;
    833         case ExpectedReturnCodeEnum::InsufficientMemory:
    834             return "insufficientMemory"sv;
    835         case ExpectedReturnCodeEnum::InvalidParameter:
    836             return "invalidParameter"sv;
    837         case ExpectedReturnCodeEnum::NoNetwork:
    838             return "noNetwork"sv;
    839         case ExpectedReturnCodeEnum::ContactSupport:
    840             return "contactSupport"sv;
    841         case ExpectedReturnCodeEnum::RebootRequiredToFinish:
    842             return "rebootRequiredToFinish"sv;
    843         case ExpectedReturnCodeEnum::RebootRequiredForInstall:
    844             return "rebootRequiredForInstall"sv;
    845         case ExpectedReturnCodeEnum::RebootInitiated:
    846             return "rebootInitiated"sv;
    847         case ExpectedReturnCodeEnum::CancelledByUser:
    848             return "cancelledByUser"sv;
    849         case ExpectedReturnCodeEnum::Downgrade:
    850             return "downgrade"sv;
    851         case ExpectedReturnCodeEnum::BlockedByPolicy:
    852             return "blockedByPolicy"sv;
    853         case ExpectedReturnCodeEnum::SystemNotSupported:
    854             return "systemNotSupported"sv;
    855         case ExpectedReturnCodeEnum::Custom:
    856             return "custom"sv;
    857         }
    858 
    859         return "unknown"sv;
    860     }
    861 
    862     std::string_view ManifestTypeToString(ManifestTypeEnum manifestType)
    863     {
    864         switch (manifestType)
    865         {
    866         case ManifestTypeEnum::DefaultLocale:
    867             return "defaultLocale"sv;
    868         case ManifestTypeEnum::Installer:
    869             return "installer"sv;
    870         case ManifestTypeEnum::Locale:
    871             return "locale"sv;
    872         case ManifestTypeEnum::Merged:
    873             return "merged"sv;
    874         case ManifestTypeEnum::Singleton:
    875             return "singleton"sv;
    876         case ManifestTypeEnum::Version:
    877             return "version"sv;
    878         }
    879 
    880         return "unknown"sv;
    881     }
    882 
    883     bool DoesInstallerTypeUsePackageFamilyName(InstallerTypeEnum installerType)
    884     {
    885         return (installerType == InstallerTypeEnum::Msix || installerType == InstallerTypeEnum::MSStore);
    886     }
    887 
    888     bool DoesInstallerTypeUseProductCode(InstallerTypeEnum installerType)
    889     {
    890         return (
    891             installerType == InstallerTypeEnum::Exe ||
    892             installerType == InstallerTypeEnum::Inno ||
    893             installerType == InstallerTypeEnum::Msi ||
    894             installerType == InstallerTypeEnum::Nullsoft ||
    895             installerType == InstallerTypeEnum::Wix ||
    896             installerType == InstallerTypeEnum::Burn ||
    897             installerType == InstallerTypeEnum::Portable
    898             );
    899     }
    900 
    901     bool DoesInstallerTypeWriteAppsAndFeaturesEntry(InstallerTypeEnum installerType)
    902     {
    903         return (
    904             installerType == InstallerTypeEnum::Exe ||
    905             installerType == InstallerTypeEnum::Inno ||
    906             installerType == InstallerTypeEnum::Msi ||
    907             installerType == InstallerTypeEnum::Nullsoft ||
    908             installerType == InstallerTypeEnum::Wix ||
    909             installerType == InstallerTypeEnum::Burn ||
    910             installerType == InstallerTypeEnum::Portable
    911             );
    912     }
    913 
    914     bool DoesInstallerTypeSupportArpVersionRange(InstallerTypeEnum installerType)
    915     {
    916         return (
    917             installerType == InstallerTypeEnum::Exe ||
    918             installerType == InstallerTypeEnum::Inno ||
    919             installerType == InstallerTypeEnum::Msi ||
    920             installerType == InstallerTypeEnum::Nullsoft ||
    921             installerType == InstallerTypeEnum::Wix ||
    922             installerType == InstallerTypeEnum::Burn
    923             );
    924     }
    925 
    926     bool DoesInstallerTypeIgnoreScopeFromManifest(InstallerTypeEnum installerType)
    927     {
    928         return
    929             installerType == InstallerTypeEnum::Portable ||
    930             installerType == InstallerTypeEnum::Msix ||
    931             installerType == InstallerTypeEnum::MSStore;
    932     }
    933 
    934     bool DoesInstallerTypeRequireAdminForMachineScopeInstall(InstallerTypeEnum installerType)
    935     {
    936         return
    937             installerType == InstallerTypeEnum::Portable ||
    938             installerType == InstallerTypeEnum::MSStore ||
    939             installerType == InstallerTypeEnum::Msix;
    940     }
    941 
    942     bool DoesInstallerTypeRequireRepairBehaviorForRepair(InstallerTypeEnum installerType)
    943     {
    944         return
    945             installerType == InstallerTypeEnum::Burn ||
    946             installerType == InstallerTypeEnum::Inno ||
    947             installerType == InstallerTypeEnum::Nullsoft ||
    948             installerType == InstallerTypeEnum::Exe;
    949     }
    950 
    951     bool IsArchiveType(InstallerTypeEnum installerType)
    952     {
    953         return (installerType == InstallerTypeEnum::Zip);
    954     }
    955 
    956     bool IsPortableType(InstallerTypeEnum installerType)
    957     {
    958         return (installerType == InstallerTypeEnum::Portable);
    959     }
    960 
    961     bool IsNestedInstallerTypeSupported(InstallerTypeEnum nestedInstallerType)
    962     {
    963         return (
    964             nestedInstallerType == InstallerTypeEnum::Exe ||
    965             nestedInstallerType == InstallerTypeEnum::Inno ||
    966             nestedInstallerType == InstallerTypeEnum::Msi ||
    967             nestedInstallerType == InstallerTypeEnum::Nullsoft ||
    968             nestedInstallerType == InstallerTypeEnum::Wix ||
    969             nestedInstallerType == InstallerTypeEnum::Burn ||
    970             nestedInstallerType == InstallerTypeEnum::Portable ||
    971             nestedInstallerType == InstallerTypeEnum::Msix ||
    972             nestedInstallerType == InstallerTypeEnum::Font
    973             );
    974     }
    975 
    976     bool IsInstallerTypeCompatible(InstallerTypeEnum type1, InstallerTypeEnum type2)
    977     {
    978         // Unknown type cannot be compatible with any other
    979         if (type1 == InstallerTypeEnum::Unknown || type2 == InstallerTypeEnum::Unknown)
    980         {
    981             return false;
    982         }
    983 
    984         // Not unknown, so must be compatible
    985         if (type1 == type2)
    986         {
    987             return true;
    988         }
    989 
    990         CompatibilitySet set1 = GetCompatibilitySet(type1);
    991         CompatibilitySet set2 = GetCompatibilitySet(type2);
    992 
    993         // If either is none, they can't be compatible
    994         if (set1 == CompatibilitySet::None || set2 == CompatibilitySet::None)
    995         {
    996             return false;
    997         }
    998 
    999         return set1 == set2;
   1000     }
   1001 
   1002     std::map<InstallerSwitchType, Utility::NormalizedString> GetDefaultKnownSwitches(InstallerTypeEnum installerType)
   1003     {
   1004         switch (installerType)
   1005         {
   1006         case InstallerTypeEnum::Burn:
   1007         case InstallerTypeEnum::Wix:
   1008         case InstallerTypeEnum::Msi:
   1009             return
   1010             {
   1011                 {InstallerSwitchType::Silent, ManifestInstaller::string_t("/quiet /norestart")},
   1012                 {InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/passive /norestart")},
   1013                 {InstallerSwitchType::Log, ManifestInstaller::string_t("/log \"" + std::string(ARG_TOKEN_LOGPATH) + "\"")},
   1014                 {InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("TARGETDIR=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")}
   1015             };
   1016         case InstallerTypeEnum::Nullsoft:
   1017             return
   1018             {
   1019                 {InstallerSwitchType::Silent, ManifestInstaller::string_t("/S")},
   1020                 {InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/S")},
   1021                 {InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("/D=" + std::string(ARG_TOKEN_INSTALLPATH))}
   1022             };
   1023         case InstallerTypeEnum::Inno:
   1024             return
   1025             {
   1026                 {InstallerSwitchType::Silent, ManifestInstaller::string_t("/SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART")},
   1027                 {InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/SP- /SILENT /SUPPRESSMSGBOXES /NORESTART")},
   1028                 {InstallerSwitchType::Log, ManifestInstaller::string_t("/LOG=\"" + std::string(ARG_TOKEN_LOGPATH) + "\"")},
   1029                 {InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("/DIR=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")}
   1030             };
   1031         default:
   1032             return {};
   1033         }
   1034     }
   1035 
   1036     RepairBehaviorEnum ConvertToRepairBehaviorEnum(std::string_view in)
   1037     {
   1038         std::string inStrLower = Utility::ToLower(in);
   1039         RepairBehaviorEnum result = RepairBehaviorEnum::Unknown;
   1040 
   1041         if (inStrLower == "installer")
   1042         {
   1043             result = RepairBehaviorEnum::Installer;
   1044         }
   1045         else if (inStrLower == "uninstaller")
   1046         {
   1047             result = RepairBehaviorEnum::Uninstaller;
   1048         }
   1049         else if (inStrLower == "modify")
   1050         {
   1051             result = RepairBehaviorEnum::Modify;
   1052         }
   1053 
   1054         return result;
   1055     }
   1056 
   1057     std::map<DWORD, ExpectedReturnCodeEnum> GetDefaultKnownReturnCodes(InstallerTypeEnum installerType)
   1058     {
   1059         switch (installerType)
   1060         {
   1061         case InstallerTypeEnum::Burn:
   1062         case InstallerTypeEnum::Wix:
   1063         case InstallerTypeEnum::Msi:
   1064             // See https://docs.microsoft.com/windows/win32/msi/error-codes
   1065             return
   1066             {
   1067                 { ERROR_INSTALL_ALREADY_RUNNING, ExpectedReturnCodeEnum::InstallInProgress },
   1068                 { ERROR_DISK_FULL, ExpectedReturnCodeEnum::DiskFull },
   1069                 { ERROR_INSTALL_SERVICE_FAILURE, ExpectedReturnCodeEnum::ContactSupport },
   1070                 { ERROR_SUCCESS_REBOOT_REQUIRED, ExpectedReturnCodeEnum::RebootRequiredToFinish },
   1071                 { ERROR_SUCCESS_REBOOT_INITIATED, ExpectedReturnCodeEnum::RebootInitiated },
   1072                 { ERROR_INSTALL_USEREXIT, ExpectedReturnCodeEnum::CancelledByUser },
   1073                 { ERROR_PRODUCT_VERSION, ExpectedReturnCodeEnum::AlreadyInstalled },
   1074                 { ERROR_INSTALL_REJECTED, ExpectedReturnCodeEnum::SystemNotSupported },
   1075                 { ERROR_INSTALL_PACKAGE_REJECTED, ExpectedReturnCodeEnum::BlockedByPolicy },
   1076                 { ERROR_INSTALL_TRANSFORM_REJECTED, ExpectedReturnCodeEnum::BlockedByPolicy },
   1077                 { ERROR_PATCH_PACKAGE_REJECTED, ExpectedReturnCodeEnum::BlockedByPolicy },
   1078                 { ERROR_PATCH_REMOVAL_DISALLOWED, ExpectedReturnCodeEnum::BlockedByPolicy },
   1079                 { ERROR_INSTALL_REMOTE_DISALLOWED, ExpectedReturnCodeEnum::BlockedByPolicy },
   1080                 { ERROR_INVALID_PARAMETER, ExpectedReturnCodeEnum::InvalidParameter },
   1081                 { ERROR_INVALID_TABLE, ExpectedReturnCodeEnum::InvalidParameter },
   1082                 { ERROR_INVALID_COMMAND_LINE, ExpectedReturnCodeEnum::InvalidParameter },
   1083                 { ERROR_INVALID_PATCH_XML, ExpectedReturnCodeEnum::InvalidParameter },
   1084                 { ERROR_INSTALL_LANGUAGE_UNSUPPORTED, ExpectedReturnCodeEnum::SystemNotSupported },
   1085                 { ERROR_INSTALL_PLATFORM_UNSUPPORTED, ExpectedReturnCodeEnum::SystemNotSupported },
   1086             };
   1087         case InstallerTypeEnum::Inno:
   1088             // See https://jrsoftware.org/ishelp/index.php?topic=setupexitcodes
   1089             return
   1090             {
   1091                 { 2, ExpectedReturnCodeEnum::CancelledByUser },
   1092                 { 5, ExpectedReturnCodeEnum::CancelledByUser },
   1093                 { 8, ExpectedReturnCodeEnum::RebootRequiredForInstall },
   1094             };
   1095         case InstallerTypeEnum::Msix:
   1096             // See https://docs.microsoft.com/en-us/windows/win32/appxpkg/troubleshooting
   1097             return
   1098             {
   1099                 { HRESULT_FROM_WIN32(ERROR_INSTALL_PREREQUISITE_FAILED), ExpectedReturnCodeEnum::MissingDependency },
   1100                 { HRESULT_FROM_WIN32(ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED), ExpectedReturnCodeEnum::MissingDependency },
   1101                 { HRESULT_FROM_WIN32(ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE), ExpectedReturnCodeEnum::MissingDependency },
   1102                 { HRESULT_FROM_WIN32(ERROR_INSTALL_OUT_OF_DISK_SPACE), ExpectedReturnCodeEnum::DiskFull },
   1103                 { HRESULT_FROM_WIN32(ERROR_INSTALL_CANCEL), ExpectedReturnCodeEnum::CancelledByUser },
   1104                 { HRESULT_FROM_WIN32(ERROR_PACKAGE_ALREADY_EXISTS), ExpectedReturnCodeEnum::AlreadyInstalled },
   1105                 { HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_DOWNGRADE), ExpectedReturnCodeEnum::Downgrade },
   1106                 { HRESULT_FROM_WIN32(ERROR_DEPLOYMENT_BLOCKED_BY_POLICY), ExpectedReturnCodeEnum::BlockedByPolicy},
   1107                 { HRESULT_FROM_WIN32(ERROR_INSTALL_POLICY_FAILURE), ExpectedReturnCodeEnum::BlockedByPolicy},
   1108                 { HRESULT_FROM_WIN32(ERROR_PACKAGES_IN_USE), ExpectedReturnCodeEnum::PackageInUse },
   1109                 { HRESULT_FROM_WIN32(ERROR_INSTALL_WRONG_PROCESSOR_ARCHITECTURE), ExpectedReturnCodeEnum::SystemNotSupported },
   1110                 { HRESULT_FROM_WIN32(ERROR_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM), ExpectedReturnCodeEnum::SystemNotSupported },
   1111                 { HRESULT_FROM_WIN32(ERROR_DEPLOYMENT_OPTION_NOT_SUPPORTED), ExpectedReturnCodeEnum::SystemNotSupported },
   1112                 { HRESULT_FROM_WIN32(ERROR_PACKAGE_LACKS_CAPABILITY_TO_DEPLOY_ON_HOST), ExpectedReturnCodeEnum::SystemNotSupported },
   1113             };
   1114         default:
   1115             return {};
   1116         }
   1117     }
   1118 
   1119     void DependencyList::Add(const Dependency& newDependency)
   1120     {
   1121         Dependency* existingDependency = this->HasDependency(newDependency);
   1122 
   1123         if (existingDependency != NULL)
   1124         {
   1125             if (newDependency.MinVersion > existingDependency->MinVersion)
   1126             {
   1127                 existingDependency->MinVersion = newDependency.MinVersion;
   1128             }
   1129         }
   1130         else
   1131         {
   1132             m_dependencies.push_back(newDependency);
   1133         }
   1134     }
   1135 
   1136     void DependencyList::Add(const DependencyList& otherDependencyList)
   1137     {
   1138         for (const auto& dependency : otherDependencyList.m_dependencies)
   1139         {
   1140             this->Add(dependency);
   1141         }
   1142     }
   1143 
   1144     bool DependencyList::HasAny() const { return !m_dependencies.empty(); }
   1145     bool DependencyList::HasAnyOf(DependencyType type) const
   1146     {
   1147         for (const auto& dependency : m_dependencies)
   1148         {
   1149             if (dependency.Type == type) return true;
   1150         };
   1151         return false;
   1152     }
   1153 
   1154     Dependency* DependencyList::HasDependency(const Dependency& dependencyToSearch)
   1155     {
   1156         for (auto& dependency : m_dependencies)
   1157         {
   1158             if (dependency.Type == dependencyToSearch.Type && ICUCaseInsensitiveEquals(dependency.Id(), dependencyToSearch.Id()))
   1159             {
   1160                 return &dependency;
   1161             }
   1162         }
   1163         return nullptr;
   1164     }
   1165 
   1166     // for testing purposes
   1167     bool DependencyList::HasExactDependency(DependencyType type, const string_t& id, const string_t& minVersion)
   1168     {
   1169         for (const auto& dependency : m_dependencies)
   1170         {
   1171             if (dependency.Type == type && Utility::ICUCaseInsensitiveEquals(dependency.Id(), id))
   1172             {
   1173                 if (!minVersion.empty())
   1174                 {
   1175                     return dependency.MinVersion == Utility::Version{ minVersion };
   1176                 }
   1177                 else
   1178                 {
   1179                     return true;
   1180                 }
   1181             }
   1182         }
   1183         return false;
   1184     }
   1185 
   1186     size_t DependencyList::Size()
   1187     {
   1188         return m_dependencies.size();
   1189     }
   1190 
   1191     void DependencyList::ApplyToType(DependencyType type, std::function<void(const Dependency&)> func) const
   1192     {
   1193         for (const auto& dependency : m_dependencies)
   1194         {
   1195             if (dependency.Type == type) func(dependency);
   1196         }
   1197     }
   1198 
   1199     void DependencyList::ApplyToAll(std::function<void(const Dependency&)> func) const
   1200     {
   1201         for (const auto& dependency : m_dependencies)
   1202         {
   1203             func(dependency);
   1204         }
   1205     }
   1206 
   1207     bool DependencyList::Empty() const
   1208     {
   1209         return m_dependencies.empty();
   1210     }
   1211 
   1212     void DependencyList::Clear() { m_dependencies.clear(); }
   1213 }