commit f3b159574719f07d45f4e93a640d138767cda4ec parent 7c3a8317b353a43d0a0e0d2066e84fb0db2bd6b5 Author: JohnMcPMS <johnmcp@microsoft.com> Date: Mon, 24 Aug 2020 11:14:00 -0700 Add fuzzing project for YAML manifest loading (#547) This change adds a fuzzing project for YAML manifest loading, with the goal of exercising our code that sits atop libyaml (as well as libyaml). It uses [libFuzzer](http://llvm.org/docs/LibFuzzer.html) to do this, which enables instrumented, coverage driven fuzzing. Outside of the relatively simple fuzzing project, the major change is moving the manifest parsing logic from Repository to Common. In addition, many small changes were required to make clang happy with our C++. The biggest of these small changes is that all WinRT use is removed when building the fuzzing version of the lib. Finally, both the WIL and C++/WinRT NuGet packages across all projects were updated to the latest available. Diffstat:
66 files changed, 1678 insertions(+), 1219 deletions(-)
diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln @@ -50,6 +50,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IndexCreationTool", "IndexC EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonCppLib", "JsonCppLib\JsonCppLib.vcxproj", "{82B39FDA-E86B-4713-A873-9D56DE00247A}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fuzzing", "Fuzzing", "{6D7776A8-42FE-46DD-B0F8-712F35EA0C79}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinGetYamlFuzzing", "WinGetYamlFuzzing\WinGetYamlFuzzing.vcxproj", "{1622DA16-914F-4F57-A259-D5169003CC8C}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution catch2\catch2.vcxitems*{5295e21e-9868-4de2-a177-fbb97b36579b}*SharedItemsImports = 9 @@ -63,6 +67,10 @@ Global Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Fuzzing|ARM = Fuzzing|ARM + Fuzzing|ARM64 = Fuzzing|ARM64 + Fuzzing|x64 = Fuzzing|x64 + Fuzzing|x86 = Fuzzing|x86 Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 @@ -81,6 +89,10 @@ Global {6AA3791A-0713-4548-A357-87A323E7AC3A}.Debug|x86.ActiveCfg = Debug|x86 {6AA3791A-0713-4548-A357-87A323E7AC3A}.Debug|x86.Build.0 = Debug|x86 {6AA3791A-0713-4548-A357-87A323E7AC3A}.Debug|x86.Deploy.0 = Debug|x86 + {6AA3791A-0713-4548-A357-87A323E7AC3A}.Fuzzing|ARM.ActiveCfg = Release|ARM + {6AA3791A-0713-4548-A357-87A323E7AC3A}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {6AA3791A-0713-4548-A357-87A323E7AC3A}.Fuzzing|x64.ActiveCfg = Release|x64 + {6AA3791A-0713-4548-A357-87A323E7AC3A}.Fuzzing|x86.ActiveCfg = Release|x86 {6AA3791A-0713-4548-A357-87A323E7AC3A}.Release|ARM.ActiveCfg = Release|ARM {6AA3791A-0713-4548-A357-87A323E7AC3A}.Release|ARM.Build.0 = Release|ARM {6AA3791A-0713-4548-A357-87A323E7AC3A}.Release|ARM.Deploy.0 = Release|ARM @@ -101,6 +113,10 @@ Global {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Debug|x64.Build.0 = Debug|x64 {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Debug|x86.ActiveCfg = Debug|Win32 {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Debug|x86.Build.0 = Debug|Win32 + {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Fuzzing|ARM.ActiveCfg = Release|ARM + {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Fuzzing|x64.ActiveCfg = Release|x64 + {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Fuzzing|x86.ActiveCfg = Release|Win32 {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Release|ARM.ActiveCfg = Release|ARM {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Release|ARM.Build.0 = Release|ARM {5B6F90DF-FD19-4BAE-83D9-24DAD128E777}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -117,6 +133,10 @@ Global {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Debug|x64.Build.0 = Debug|x64 {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Debug|x86.ActiveCfg = Debug|Win32 {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Debug|x86.Build.0 = Debug|Win32 + {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Fuzzing|ARM.ActiveCfg = Release|ARM + {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Fuzzing|x64.ActiveCfg = Release|x64 + {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Fuzzing|x86.ActiveCfg = Release|Win32 {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Release|ARM.ActiveCfg = Release|ARM {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Release|ARM.Build.0 = Release|ARM {1C6E0108-2860-4B17-9F7E-FA5C6C1F3D3D}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -133,6 +153,10 @@ Global {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Debug|x64.Build.0 = Debug|x64 {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Debug|x86.ActiveCfg = Debug|Win32 {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Debug|x86.Build.0 = Debug|Win32 + {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Fuzzing|ARM.ActiveCfg = Release|ARM + {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Fuzzing|x64.ActiveCfg = Release|x64 + {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Fuzzing|x86.ActiveCfg = Release|Win32 {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Release|ARM.ActiveCfg = Release|ARM {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Release|ARM.Build.0 = Release|ARM {5EB88068-5FB9-4E69-89B2-72DBC5E068F9}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -147,6 +171,10 @@ Global {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Debug|x64.Build.0 = Debug|x64 {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Debug|x86.ActiveCfg = Debug|Win32 {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Debug|x86.Build.0 = Debug|Win32 + {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Fuzzing|ARM.ActiveCfg = Release|Win32 + {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Fuzzing|ARM64.ActiveCfg = Release|Win32 + {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Fuzzing|x64.ActiveCfg = Release|x64 + {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Fuzzing|x86.ActiveCfg = Release|Win32 {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Release|ARM.ActiveCfg = Release|Win32 {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Release|ARM64.ActiveCfg = Release|Win32 {89B1AAB4-2BBC-4B65-9ED7-A01D5CF88230}.Release|x64.ActiveCfg = Release|x64 @@ -161,6 +189,11 @@ Global {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Debug|x64.Build.0 = Debug|x64 {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Debug|x86.ActiveCfg = Debug|Win32 {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Debug|x86.Build.0 = Debug|Win32 + {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Fuzzing|ARM.ActiveCfg = Release|ARM + {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Fuzzing|x64.Build.0 = Fuzzing|x64 + {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Fuzzing|x86.ActiveCfg = Release|Win32 {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Release|ARM.ActiveCfg = Release|ARM {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Release|ARM.Build.0 = Release|ARM {8BB94BB8-374F-4294-BCA1-C7811514A6B7}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -177,6 +210,11 @@ Global {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Debug|x64.Build.0 = Debug|x64 {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Debug|x86.ActiveCfg = Debug|Win32 {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Debug|x86.Build.0 = Debug|Win32 + {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Fuzzing|ARM.ActiveCfg = Release|ARM + {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Fuzzing|x64.Build.0 = Fuzzing|x64 + {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Fuzzing|x86.ActiveCfg = Release|Win32 {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Release|ARM.ActiveCfg = Release|ARM {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Release|ARM.Build.0 = Release|ARM {5890D6ED-7C3B-40F3-B436-B54F640D9E65}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -193,6 +231,10 @@ Global {FB313532-38B0-4676-9303-AB200AA13576}.Debug|x64.Build.0 = Debug|x64 {FB313532-38B0-4676-9303-AB200AA13576}.Debug|x86.ActiveCfg = Debug|Win32 {FB313532-38B0-4676-9303-AB200AA13576}.Debug|x86.Build.0 = Debug|Win32 + {FB313532-38B0-4676-9303-AB200AA13576}.Fuzzing|ARM.ActiveCfg = Release|ARM + {FB313532-38B0-4676-9303-AB200AA13576}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {FB313532-38B0-4676-9303-AB200AA13576}.Fuzzing|x64.ActiveCfg = Release|x64 + {FB313532-38B0-4676-9303-AB200AA13576}.Fuzzing|x86.ActiveCfg = Release|Win32 {FB313532-38B0-4676-9303-AB200AA13576}.Release|ARM.ActiveCfg = Release|ARM {FB313532-38B0-4676-9303-AB200AA13576}.Release|ARM.Build.0 = Release|ARM {FB313532-38B0-4676-9303-AB200AA13576}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -209,6 +251,10 @@ Global {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x64.Build.0 = Debug|x64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x86.ActiveCfg = Debug|Win32 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x86.Build.0 = Debug|Win32 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Fuzzing|ARM.ActiveCfg = Release|ARM + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Fuzzing|x64.ActiveCfg = Release|x64 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Fuzzing|x86.ActiveCfg = Release|Win32 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM.ActiveCfg = Release|ARM {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM.Build.0 = Release|ARM {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -223,6 +269,10 @@ Global {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x64.Build.0 = Debug|x64 {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x86.ActiveCfg = Debug|x86 {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x86.Build.0 = Debug|x86 + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Fuzzing|ARM.ActiveCfg = Release|x86 + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Fuzzing|ARM64.ActiveCfg = Release|x86 + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Fuzzing|x64.ActiveCfg = Release|x64 + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Fuzzing|x86.ActiveCfg = Release|x86 {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|ARM.ActiveCfg = Release|x86 {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|ARM64.ActiveCfg = Release|x86 {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|x64.ActiveCfg = Release|x64 @@ -241,6 +291,10 @@ Global {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x86.ActiveCfg = Debug|x86 {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x86.Build.0 = Debug|x86 {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x86.Deploy.0 = Debug|x86 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Fuzzing|ARM.ActiveCfg = Release|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Fuzzing|x64.ActiveCfg = Release|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Fuzzing|x86.ActiveCfg = Release|x86 {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM.ActiveCfg = Release|ARM {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM.Build.0 = Release|ARM {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM.Deploy.0 = Release|ARM @@ -257,6 +311,10 @@ Global {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|ARM64.ActiveCfg = Debug {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|x64.ActiveCfg = Debug {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|x86.ActiveCfg = Debug + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Fuzzing|ARM.ActiveCfg = Release + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Fuzzing|ARM64.ActiveCfg = Release + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Fuzzing|x64.ActiveCfg = Release + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Fuzzing|x86.ActiveCfg = Release {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|ARM.ActiveCfg = Release {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|ARM64.ActiveCfg = Release {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|x64.ActiveCfg = Release @@ -267,6 +325,10 @@ Global {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x64.Build.0 = Debug|x64 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x86.ActiveCfg = Debug|x86 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x86.Build.0 = Debug|x86 + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Fuzzing|ARM.ActiveCfg = Release|x86 + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Fuzzing|ARM64.ActiveCfg = Release|x86 + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Fuzzing|x64.ActiveCfg = Release|x64 + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Fuzzing|x86.ActiveCfg = Release|x86 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|ARM.ActiveCfg = Release|x86 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|ARM64.ActiveCfg = Release|x86 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|x64.ActiveCfg = Release|x64 @@ -281,6 +343,10 @@ Global {82B39FDA-E86B-4713-A873-9D56DE00247A}.Debug|x64.Build.0 = Debug|x64 {82B39FDA-E86B-4713-A873-9D56DE00247A}.Debug|x86.ActiveCfg = Debug|Win32 {82B39FDA-E86B-4713-A873-9D56DE00247A}.Debug|x86.Build.0 = Debug|Win32 + {82B39FDA-E86B-4713-A873-9D56DE00247A}.Fuzzing|ARM.ActiveCfg = Release|ARM + {82B39FDA-E86B-4713-A873-9D56DE00247A}.Fuzzing|ARM64.ActiveCfg = Release|ARM64 + {82B39FDA-E86B-4713-A873-9D56DE00247A}.Fuzzing|x64.ActiveCfg = Release|x64 + {82B39FDA-E86B-4713-A873-9D56DE00247A}.Fuzzing|x86.ActiveCfg = Release|Win32 {82B39FDA-E86B-4713-A873-9D56DE00247A}.Release|ARM.ActiveCfg = Release|ARM {82B39FDA-E86B-4713-A873-9D56DE00247A}.Release|ARM.Build.0 = Release|ARM {82B39FDA-E86B-4713-A873-9D56DE00247A}.Release|ARM64.ActiveCfg = Release|ARM64 @@ -289,6 +355,19 @@ Global {82B39FDA-E86B-4713-A873-9D56DE00247A}.Release|x64.Build.0 = Release|x64 {82B39FDA-E86B-4713-A873-9D56DE00247A}.Release|x86.ActiveCfg = Release|Win32 {82B39FDA-E86B-4713-A873-9D56DE00247A}.Release|x86.Build.0 = Release|Win32 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Debug|ARM.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Debug|ARM64.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Debug|x64.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Debug|x86.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Fuzzing|ARM.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Fuzzing|ARM64.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Fuzzing|x64.Build.0 = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Fuzzing|x86.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|ARM.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|ARM64.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|x64.ActiveCfg = Fuzzing|x64 + {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|x86.ActiveCfg = Fuzzing|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -299,6 +378,7 @@ Global {6E36DDD7-1602-474E-B1D7-D0A7E1D5AD86} = {8D53D749-D51C-46F8-A162-9371AAA6C2E7} {3B8466CF-4FDD-4329-9C80-91321C4AAC99} = {EA8CD934-0702-4911-A2C5-A40600E616DE} {82B39FDA-E86B-4713-A873-9D56DE00247A} = {60618CAC-2995-4DF9-9914-45C6FC02C995} + {1622DA16-914F-4F57-A259-D5169003CC8C} = {6D7776A8-42FE-46DD-B0F8-712F35EA0C79} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B6FDB70C-A751-422C-ACD1-E35419495857} diff --git a/src/AppInstallerCLI/AppInstallerCLI.vcxproj b/src/AppInstallerCLI/AppInstallerCLI.vcxproj @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" /> <PropertyGroup Label="Globals"> <CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> @@ -133,6 +133,9 @@ <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">false</ControlFlowGuard> <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">false</ControlFlowGuard> <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -155,6 +158,7 @@ <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir);..\AppInstallerCLICore\Public\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</TreatWarningAsError> <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">stdcpp17</LanguageStandard> </ClCompile> <Manifest> <AdditionalManifestFiles Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\manifest\shared.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles> @@ -178,6 +182,10 @@ <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Guard</ControlFlowGuard> <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Guard</ControlFlowGuard> <ControlFlowGuard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Guard</ControlFlowGuard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpp17</LanguageStandard> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -203,6 +211,7 @@ <ClCompile Include="main.cpp" /> </ItemGroup> <ItemGroup> + <None Include="packages.config" /> <None Include="PropertySheet.props" /> </ItemGroup> <ItemGroup> @@ -225,13 +234,13 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" /> </ImportGroup> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" /> </Target> </Project> \ No newline at end of file diff --git a/src/AppInstallerCLI/AppInstallerCLI.vcxproj.filters b/src/AppInstallerCLI/AppInstallerCLI.vcxproj.filters @@ -21,5 +21,6 @@ </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> + <None Include="packages.config" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/src/AppInstallerCLI/packages.config b/src/AppInstallerCLI/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" /> +</packages>+ \ No newline at end of file diff --git a/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj b/src/AppInstallerCLICore/AppInstallerCLICore.vcxproj @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" /> <PropertyGroup Label="Globals"> <CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> @@ -256,15 +256,15 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" /> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> </ImportGroup> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> </Target> </Project> \ No newline at end of file diff --git a/src/AppInstallerCLICore/ExecutionContext.h b/src/AppInstallerCLICore/ExecutionContext.h @@ -4,7 +4,7 @@ #include <AppInstallerLogging.h> #include <AppInstallerRepositorySearch.h> #include <AppInstallerRepositorySource.h> -#include <Manifest/Manifest.h> +#include <winget/Manifest.h> #include "ExecutionReporter.h" #include "ExecutionArgs.h" #include "CompletionData.h" diff --git a/src/AppInstallerCLICore/Workflows/ManifestComparator.h b/src/AppInstallerCLICore/Workflows/ManifestComparator.h @@ -2,7 +2,7 @@ // Licensed under the MIT License. #pragma once #include "ExecutionArgs.h" -#include <Manifest/Manifest.h> +#include <winget/Manifest.h> #include <optional> diff --git a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp @@ -5,7 +5,7 @@ #include "ExecutionContext.h" #include "ManifestComparator.h" #include "TableOutput.h" -#include "Manifest/YamlParser.h" +#include <winget/ManifestYamlParser.h> namespace AppInstaller::CLI::Workflow diff --git a/src/AppInstallerCLICore/packages.config b/src/AppInstallerCLICore/packages.config @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Microsoft.Windows.CppWinRT" version="2.0.191111.2" targetFramework="native" /> - <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.191107.2" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" /> </packages> \ No newline at end of file diff --git a/src/AppInstallerCLICore/pch.h b/src/AppInstallerCLICore/pch.h @@ -46,6 +46,6 @@ #include <AppInstallerSHA256.h> #include <AppInstallerStrings.h> #include <AppInstallerTelemetry.h> -#include <Manifest/YamlParser.h> -#include <winget/LocIndependent.h> #include <winget/ExperimentalFeature.h> +#include <winget/LocIndependent.h> +#include <winget/ManifestYamlParser.h> diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" /> <PropertyGroup Label="Globals"> <CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> @@ -429,15 +429,15 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> - <Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.targets')" /> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> </ImportGroup> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> - <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.props'))" /> - <Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.191202.6\build\native\Microsoft.Windows.CppWinRT.targets'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> </Target> </Project> \ No newline at end of file diff --git a/src/AppInstallerCLITests/SQLiteIndex.cpp b/src/AppInstallerCLITests/SQLiteIndex.cpp @@ -3,8 +3,8 @@ #include "pch.h" #include "TestCommon.h" #include <SQLiteWrapper.h> -#include <Manifest/Manifest.h> #include <Microsoft/SQLiteIndex.h> +#include <winget/Manifest.h> #include <Microsoft/Schema/1_0/IdTable.h> #include <Microsoft/Schema/1_0/NameTable.h> diff --git a/src/AppInstallerCLITests/SQLiteIndexSource.cpp b/src/AppInstallerCLITests/SQLiteIndexSource.cpp @@ -2,8 +2,8 @@ // Licensed under the MIT License. #include "pch.h" #include "TestCommon.h" -#include <Manifest/YamlParser.h> #include <Microsoft/SQLiteIndexSource.h> +#include <winget/ManifestYamlParser.h> using namespace std::string_literals; using namespace TestCommon; diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp @@ -3,7 +3,6 @@ #include "pch.h" #include "TestCommon.h" #include <AppInstallerLogging.h> -#include <Manifest/YamlParser.h> #include <AppInstallerDownloader.h> #include <AppInstallerStrings.h> #include <Workflows/InstallFlow.h> @@ -15,6 +14,7 @@ #include <Commands/InstallCommand.h> #include <Commands/ShowCommand.h> #include <winget/LocIndependent.h> +#include <winget/ManifestYamlParser.h> #include <Resources.h> using namespace winrt::Windows::Foundation; diff --git a/src/AppInstallerCLITests/YamlManifest.cpp b/src/AppInstallerCLITests/YamlManifest.cpp @@ -2,8 +2,8 @@ // Licensed under the MIT License. #include "pch.h" #include "TestCommon.h" -#include "Manifest/YamlParser.h" -#include "AppInstallerSHA256.h" +#include <AppInstallerSHA256.h> +#include <winget/ManifestYamlParser.h> using namespace TestCommon; using namespace AppInstaller::Manifest; diff --git a/src/AppInstallerCLITests/packages.config b/src/AppInstallerCLITests/packages.config @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Microsoft.Windows.CppWinRT" version="2.0.191202.6" targetFramework="native" /> - <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.191107.2" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" /> </packages> \ No newline at end of file diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="'$(Configuration)'!='Fuzzing' And Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" /> <PropertyGroup Label="Globals"> <CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> @@ -28,6 +28,22 @@ <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|ARM"> + <Configuration>Fuzzing</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|ARM64"> + <Configuration>Fuzzing</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|Win32"> + <Configuration>Fuzzing</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|x64"> + <Configuration>Fuzzing</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> <ProjectConfiguration Include="Release|ARM"> <Configuration>Release</Configuration> <Platform>ARM</Platform> @@ -53,7 +69,8 @@ <ConfigurationType>StaticLibrary</ConfigurationType> <PlatformToolset>v140</PlatformToolset> <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset> - <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0' And '$(Configuration)'!='Fuzzing'">v142</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0' And '$(Configuration)'=='Fuzzing'">ClangCL</PlatformToolset> <CharacterSet>Unicode</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> @@ -65,6 +82,11 @@ <WholeProgramOptimization>true</WholeProgramOptimization> <LinkIncremental>false</LinkIncremental> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Fuzzing'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>false</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> @@ -96,18 +118,34 @@ <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <ItemDefinitionGroup> <ClCompile> <PrecompiledHeader>Use</PrecompiledHeader> @@ -171,6 +209,37 @@ <SubSystem Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Windows</SubSystem> </Link> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)'=='Fuzzing'"> + <ClCompile> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD;WINGET_DISABLE_FOR_FUZZING</PreprocessorDefinitions> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'">$(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'">$(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'">$(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'">$(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'">true</TreatWarningAsError> + <TreatWarningAsError Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'">true</TreatWarningAsError> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'">stdcpp17</LanguageStandard> + <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'">stdcpp17</LanguageStandard> + <RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'">MultiThreaded</RuntimeLibrary> + <AdditionalOptions>%(AdditionalOptions) -fsanitize=fuzzer,address</AdditionalOptions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateWindowsMetadata>false</GenerateWindowsMetadata> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'">Windows</SubSystem> + <SubSystem Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'">Windows</SubSystem> + </Link> + </ItemDefinitionGroup> <ItemGroup> <ClInclude Include="HttpStream\HttpClientWrapper.h" /> <ClInclude Include="HttpStream\HttpLocalCache.h" /> @@ -196,6 +265,11 @@ <ClInclude Include="Public\winget\ExperimentalFeature.h" /> <ClInclude Include="Public\winget\ExtensionCatalog.h" /> <ClInclude Include="Public\winget\LocIndependent.h" /> + <ClInclude Include="Public\winget\Manifest.h" /> + <ClInclude Include="Public\winget\ManifestInstaller.h" /> + <ClInclude Include="Public\winget\ManifestLocalization.h" /> + <ClInclude Include="Public\winget\ManifestValidation.h" /> + <ClInclude Include="Public\winget\ManifestYamlParser.h" /> <ClInclude Include="Public\winget\Settings.h" /> <ClInclude Include="Public\winget\UserSettings.h" /> <ClInclude Include="Public\winget\Yaml.h" /> @@ -208,17 +282,33 @@ <ClCompile Include="AppInstallerLogging.cpp" /> <ClCompile Include="AppInstallerStrings.cpp" /> <ClCompile Include="DateTime.cpp" /> - <ClCompile Include="Deployment.cpp" /> + <ClCompile Include="Deployment.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> + </ClCompile> <ClCompile Include="Downloader.cpp" /> <ClCompile Include="Errors.cpp" /> <ClCompile Include="ExperimentalFeature.cpp" /> - <ClCompile Include="ExtensionCatalog.cpp" /> + <ClCompile Include="ExtensionCatalog.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> + </ClCompile> <ClCompile Include="FileLogger.cpp" /> - <ClCompile Include="HttpStream\HttpClientWrapper.cpp" /> - <ClCompile Include="HttpStream\HttpLocalCache.cpp" /> - <ClCompile Include="HttpStream\HttpRandomAccessStream.cpp" /> + <ClCompile Include="HttpStream\HttpClientWrapper.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="HttpStream\HttpLocalCache.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> + </ClCompile> + <ClCompile Include="HttpStream\HttpRandomAccessStream.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> + </ClCompile> <ClCompile Include="JsonUtil.cpp" /> - <ClCompile Include="MsixInfo.cpp" /> + <ClCompile Include="Manifest\Manifest.cpp" /> + <ClCompile Include="Manifest\ManifestInstaller.cpp" /> + <ClCompile Include="Manifest\ManifestValidation.cpp" /> + <ClCompile Include="Manifest\YamlParser.cpp" /> + <ClCompile Include="MsixInfo.cpp"> + <ExcludedFromBuild Condition="'$(Configuration)'=='Fuzzing'">true</ExcludedFromBuild> + </ClCompile> <ClCompile Include="Runtime.cpp" /> <ClCompile Include="pch.cpp"> <PrecompiledHeader>Create</PrecompiledHeader> @@ -240,15 +330,15 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" /> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="'$(Configuration)'!='Fuzzing' And Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> </ImportGroup> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> </Target> </Project> \ No newline at end of file diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -25,6 +25,9 @@ <Filter Include="Public\winget"> <UniqueIdentifier>{41035fd6-dc74-4464-b9b1-4ffe95d6789c}</UniqueIdentifier> </Filter> + <Filter Include="Manifest"> + <UniqueIdentifier>{9b8e2682-3eb7-4530-bc9a-a57fafc44177}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClInclude Include="pch.h"> @@ -120,6 +123,21 @@ <ClInclude Include="Public\winget\Yaml.h"> <Filter>Public\winget</Filter> </ClInclude> + <ClInclude Include="Public\winget\Manifest.h"> + <Filter>Public\winget</Filter> + </ClInclude> + <ClInclude Include="Public\winget\ManifestInstaller.h"> + <Filter>Public\winget</Filter> + </ClInclude> + <ClInclude Include="Public\winget\ManifestLocalization.h"> + <Filter>Public\winget</Filter> + </ClInclude> + <ClInclude Include="Public\winget\ManifestValidation.h"> + <Filter>Public\winget</Filter> + </ClInclude> + <ClInclude Include="Public\winget\ManifestYamlParser.h"> + <Filter>Public\winget</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="pch.cpp"> @@ -200,6 +218,18 @@ <ClCompile Include="Yaml.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="Manifest\Manifest.cpp"> + <Filter>Manifest</Filter> + </ClCompile> + <ClCompile Include="Manifest\ManifestInstaller.cpp"> + <Filter>Manifest</Filter> + </ClCompile> + <ClCompile Include="Manifest\ManifestValidation.cpp"> + <Filter>Manifest</Filter> + </ClCompile> + <ClCompile Include="Manifest\YamlParser.cpp"> + <Filter>Manifest</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/AppInstallerCommonCore/AppInstallerLogging.cpp b/src/AppInstallerCommonCore/AppInstallerLogging.cpp @@ -31,7 +31,7 @@ namespace AppInstaller::Logging } } - char const* const GetChannelName(Channel channel) + char const* GetChannelName(Channel channel) { switch(channel) { diff --git a/src/AppInstallerCommonCore/Errors.cpp b/src/AppInstallerCommonCore/Errors.cpp @@ -10,7 +10,7 @@ namespace AppInstaller { namespace { - const char* const GetMessageForAppInstallerHR(HRESULT hr) + const char* GetMessageForAppInstallerHR(HRESULT hr) { switch (hr) { @@ -99,13 +99,15 @@ namespace AppInstaller return strstr.str(); } - std::string GetUserPresentableMessage(const winrt::hresult_error& hre) + std::string GetUserPresentableMessage(const std::exception& e) { - return Utility::ConvertToUTF8(hre.message()); + return e.what(); } - std::string GetUserPresentableMessage(const std::exception& e) +#ifndef WINGET_DISABLE_FOR_FUZZING + std::string GetUserPresentableMessage(const winrt::hresult_error& hre) { - return e.what(); + return Utility::ConvertToUTF8(hre.message()); } +#endif } diff --git a/src/AppInstallerCommonCore/Manifest/Manifest.cpp b/src/AppInstallerCommonCore/Manifest/Manifest.cpp @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/Manifest.h" +#include "winget/ManifestValidation.h" + +namespace AppInstaller::Manifest +{ + ManifestVer::ManifestVer(std::string version, bool fullValidation) : Version(std::move(version), ".") + { + bool validationSuccess = true; + + if (m_parts.size() > 3) + { + validationSuccess = false; + } + else + { + for (size_t i = 0; i < m_parts.size(); i++) + { + if (!m_parts[i].Other.empty() && + (i < 2 || fullValidation)) + { + validationSuccess = false; + break; + } + } + } + + if (!validationSuccess) + { + std::vector<ValidationError> errors; + errors.emplace_back(ManifestError::InvalidFieldValue, "ManifestVersion", m_version); + THROW_EXCEPTION(ManifestException(std::move(errors))); + } + } + + bool ManifestVer::HasTag() const + { + return m_parts.size() == 3 && !m_parts[2].Other.empty(); + } +} diff --git a/src/AppInstallerCommonCore/Manifest/ManifestInstaller.cpp b/src/AppInstallerCommonCore/Manifest/ManifestInstaller.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/ManifestInstaller.h" + +namespace AppInstaller::Manifest +{ + ManifestInstaller::InstallerTypeEnum ManifestInstaller::ConvertToInstallerTypeEnum(const std::string& in) + { + std::string inStrLower = Utility::ToLower(in); + InstallerTypeEnum result = InstallerTypeEnum::Unknown; + + if (inStrLower == "inno") + { + result = InstallerTypeEnum::Inno; + } + else if (inStrLower == "wix") + { + result = InstallerTypeEnum::Wix; + } + else if (inStrLower == "msi") + { + result = InstallerTypeEnum::Msi; + } + else if (inStrLower == "nullsoft") + { + result = InstallerTypeEnum::Nullsoft; + } + else if (inStrLower == "zip") + { + result = InstallerTypeEnum::Zip; + } + else if (inStrLower == "appx" || inStrLower == "msix") + { + result = InstallerTypeEnum::Msix; + } + else if (inStrLower == "exe") + { + result = InstallerTypeEnum::Exe; + } + else if (inStrLower == "burn") + { + result = InstallerTypeEnum::Burn; + } + else if (inStrLower == "msstore") + { + result = InstallerTypeEnum::MSStore; + } + + return result; + } + + std::string ManifestInstaller::InstallerTypeToString(ManifestInstaller::InstallerTypeEnum installerType) + { + std::string result = "Unknown"; + + switch (installerType) + { + case ManifestInstaller::InstallerTypeEnum::Exe: + result = "Exe"; + break; + case ManifestInstaller::InstallerTypeEnum::Inno: + result = "Inno"; + break; + case ManifestInstaller::InstallerTypeEnum::Msi: + result = "Msi"; + break; + case ManifestInstaller::InstallerTypeEnum::Msix: + result = "Msix"; + break; + case ManifestInstaller::InstallerTypeEnum::Nullsoft: + result = "Nullsoft"; + break; + case ManifestInstaller::InstallerTypeEnum::Wix: + result = "Wix"; + break; + case ManifestInstaller::InstallerTypeEnum::Zip: + result = "Zip"; + break; + case ManifestInstaller::InstallerTypeEnum::Burn: + result = "Burn"; + break; + case ManifestInstaller::InstallerTypeEnum::MSStore: + result = "MSStore"; + break; + default: + break; + } + + return result; + } +} diff --git a/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp b/src/AppInstallerCommonCore/Manifest/ManifestValidation.cpp @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/ManifestValidation.h" + +namespace AppInstaller::Manifest +{ + std::vector<ValidationError> ValidateManifest(const Manifest& manifest) + { + std::vector<ValidationError> resultErrors; + + // Channel is not supported currently + if (!manifest.Channel.empty()) + { + resultErrors.emplace_back(ManifestError::FieldNotSupported, "Channel", manifest.Channel); + } + + try + { + // Version value should be successfully parsed + Utility::Version test{ manifest.Version }; + } + catch (const std::exception&) + { + resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Version", manifest.Version); + } + + // License field is required + if (manifest.License.empty()) + { + resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "License"); + } + + // Comparation function to check duplicate installer entry. {installerType, arch, language and scope} combination is the key. + // Todo: use the comparator from ManifestComparator when that one is fully implemented. + auto installerCmp = [](const ManifestInstaller& in1, const ManifestInstaller& in2) + { + if (in1.InstallerType != in2.InstallerType) + { + return in1.InstallerType < in2.InstallerType; + } + + if (in1.Arch != in2.Arch) + { + return in1.Arch < in2.Arch; + } + + if (in1.Language != in2.Language) + { + return in1.Language < in2.Language; + } + + if (in1.Scope != in2.Scope) + { + return in1.Scope < in2.Scope; + } + + return false; + }; + + std::set<ManifestInstaller, decltype(installerCmp)> installerSet(installerCmp); + bool duplicateInstallerFound = false; + + // Validate installers + for (auto const& installer : manifest.Installers) + { + if (!duplicateInstallerFound && !installerSet.insert(installer).second) + { + resultErrors.emplace_back(ManifestError::DuplicateInstallerEntry); + duplicateInstallerFound = true; + } + + if (installer.Arch == Utility::Architecture::Unknown) + { + resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Arch"); + } + + if (installer.InstallerType == ManifestInstaller::InstallerTypeEnum::Unknown) + { + resultErrors.emplace_back(ManifestError::InvalidFieldValue, "InstallerType"); + } + + if (installer.InstallerType == ManifestInstaller::InstallerTypeEnum::MSStore) + { + // MSStore type is not supported in community repo + resultErrors.emplace_back( + ManifestError::FieldValueNotSupported, "InstallerType", + ManifestInstaller::InstallerTypeToString(installer.InstallerType)); + + if (installer.ProductId.empty()) + { + resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "ProductId"); + } + } + else + { + // For other types, Url and Sha256 are required + if (installer.Url.empty()) + { + resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "Url"); + } + if (installer.Sha256.empty()) + { + resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "Sha256"); + } + // ProductId should not be used + if (!installer.ProductId.empty()) + { + resultErrors.emplace_back(ManifestError::FieldNotSupported, "ProductId"); + } + } + + if (installer.InstallerType == ManifestInstaller::InstallerTypeEnum::Exe && + (installer.Switches.find(ManifestInstaller::InstallerSwitchType::SilentWithProgress) == installer.Switches.end() || + installer.Switches.find(ManifestInstaller::InstallerSwitchType::Silent) == installer.Switches.end())) + { + resultErrors.emplace_back(ManifestError::ExeInstallerMissingSilentSwitches, ValidationError::Level::Warning); + } + + // Check empty string before calling IsValidUrl to avoid duplicate error reporting. + if (!installer.Url.empty() && IsValidURL(NULL, Utility::ConvertToUTF16(installer.Url).c_str(), 0) == S_FALSE) + { + resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Url", installer.Url); + } + } + + return resultErrors; + } +}+ \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Manifest/YamlParser.cpp b/src/AppInstallerCommonCore/Manifest/YamlParser.cpp @@ -0,0 +1,441 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "AppInstallerSHA256.h" +#include "winget/Yaml.h" +#include "winget/ManifestYamlParser.h" + +namespace AppInstaller::Manifest +{ + namespace + { + std::vector<Manifest::string_t> SplitMultiValueField(const std::string& input) + { + if (input.empty()) + { + return {}; + } + + std::vector<Manifest::string_t> result; + size_t currentPos = 0; + while (currentPos < input.size()) + { + size_t splitPos = input.find(',', currentPos); + if (splitPos == std::string::npos) + { + splitPos = input.size(); + } + + std::string splitVal = input.substr(currentPos, splitPos - currentPos); + Utility::Trim(splitVal); + if (!splitVal.empty()) + { + result.emplace_back(std::move(splitVal)); + } + currentPos = splitPos + 1; + } + + return result; + } + } + + void YamlParser::PrepareManifestFieldInfos(const ManifestVer& manifestVer) + { + RootFieldInfos = + { + { "ManifestVersion", PreviewManifestVersion, [](const YAML::Node&) { /* ManifestVersion already processed */ }, false, + // Regex here is to prevent leading 0s in the version, this also keeps consistent with other versions in the manifest + "^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){2}$" }, + { "Id", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Id = value.as<std::string>(); Utility::Trim(m_p_manifest->Id); }, true, "^[\\S]+\\.[\\S]+$" }, + { "Name", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Name = value.as<std::string>(); Utility::Trim(m_p_manifest->Name); }, true }, + { "Version", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Version = value.as<std::string>(); Utility::Trim(m_p_manifest->Version); }, true, + /* File name chars not allowed */ "^[^\\\\/:\\*\\?\"<>\\|\\x01-\\x1f]+$" }, + { "Publisher", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Publisher = value.as<std::string>(); }, true }, + { "AppMoniker", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->AppMoniker = value.as<std::string>(); Utility::Trim(m_p_manifest->AppMoniker); } }, + { "Channel", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Channel = value.as<std::string>(); Utility::Trim(m_p_manifest->Channel); } }, + { "Author", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Author = value.as<std::string>(); } }, + { "License", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->License = value.as<std::string>(); } }, + { "MinOSVersion", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->MinOSVersion = value.as<std::string>(); Utility::Trim(m_p_manifest->MinOSVersion); }, false, + "^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){0,3}$" }, + { "Tags", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Tags = SplitMultiValueField(value.as<std::string>()); } }, + { "Commands", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Commands = SplitMultiValueField(value.as<std::string>()); } }, + { "Protocols", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Protocols = SplitMultiValueField(value.as<std::string>()); } }, + { "FileExtensions", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->FileExtensions = SplitMultiValueField(value.as<std::string>()); } }, + { "InstallerType", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->InstallerType = ManifestInstaller::ConvertToInstallerTypeEnum(value.as<std::string>()); } }, + { "Description", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Description = value.as<std::string>(); } }, + { "Homepage", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Homepage = value.as<std::string>(); } }, + { "LicenseUrl", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->LicenseUrl = value.as<std::string>(); } }, + { "Switches", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_switchesNode = value; } }, + { "Installers", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_installersNode = value; }, true }, + { "Localization", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_localizationsNode = value; } }, + }; + + InstallerFieldInfos = + { + { "Arch", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Arch = Utility::ConvertToArchitectureEnum(value.as<std::string>()); }, true }, + { "Url", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Url = value.as<std::string>(); } }, + { "Sha256", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); }, false, "^[A-Fa-f0-9]{64}$" }, + { "SignatureSha256", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->SignatureSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); }, false, "^[A-Fa-f0-9]{64}$" }, + { "Language", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Language = value.as<std::string>(); } }, + { "Scope", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Scope = value.as<std::string>(); } }, + { "InstallerType", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->InstallerType = ManifestInstaller::ConvertToInstallerTypeEnum(value.as<std::string>()); } }, + { "ProductId", PreviewManifestVersionMSStore, [this](const YAML::Node& value) { m_p_installer->ProductId = value.as<std::string>(); } }, + { "Switches", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_switchesNode = value; } }, + }; + + SwitchesFieldInfos = + { + { "Custom", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Custom] = value.as<std::string>(); } }, + { "Silent", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Silent] = value.as<std::string>(); } }, + { "SilentWithProgress", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::SilentWithProgress] = value.as<std::string>(); } }, + { "Interactive", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Interactive] = value.as<std::string>(); } }, + { "Language", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Language] = value.as<std::string>(); } }, + { "Log", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Log] = value.as<std::string>(); } }, + { "InstallLocation", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::InstallLocation] = value.as<std::string>(); } }, + }; + + LocalizationFieldInfos = + { + { "Language", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->Language = value.as<std::string>(); }, true }, + { "Description", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->Description = value.as<std::string>(); } }, + { "Homepage", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->Homepage = value.as<std::string>(); } }, + { "LicenseUrl", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->LicenseUrl = value.as<std::string>(); } }, + }; + + FilterManifestFieldInfos(RootFieldInfos, manifestVer); + FilterManifestFieldInfos(InstallerFieldInfos, manifestVer); + FilterManifestFieldInfos(SwitchesFieldInfos, manifestVer); + FilterManifestFieldInfos(LocalizationFieldInfos, manifestVer); + } + + void YamlParser::FilterManifestFieldInfos( + std::vector<ManifestFieldInfo>& source, + const ManifestVer& manifestVer) + { + auto it = std::remove_if(source.begin(), source.end(), + [&](ManifestFieldInfo field) + { + if (field.VerIntroduced.HasTag()) + { + // Tagged version should have exact match + return field.VerIntroduced != manifestVer; + } + else + { + return manifestVer < field.VerIntroduced; + } + }); + source.erase(it, source.end()); + } + + Manifest YamlParser::CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation, bool throwOnWarning) + { + Manifest manifest; + std::vector<ValidationError> errors; + + try + { + YAML::Node rootNode = YAML::Load(inputFile); + YamlParser parser; + errors = parser.ParseManifest(rootNode, manifest, fullValidation); + } + catch (const ManifestException&) + { + // Prevent ManifestException from being wrapped in another ManifestException + throw; + } + catch (const std::exception& e) + { + THROW_EXCEPTION_MSG(ManifestException(), e.what()); + } + + if (!errors.empty()) + { + ManifestException ex{ std::move(errors) }; + + if (throwOnWarning || !ex.IsWarningOnly()) + { + THROW_EXCEPTION(ex); + } + } + + return manifest; + } + + Manifest YamlParser::Create(const std::string& input, bool fullValidation, bool throwOnWarning) + { + Manifest manifest; + std::vector<ValidationError> errors; + + try + { + YAML::Node rootNode = YAML::Load(input); + YamlParser parser; + errors = parser.ParseManifest(rootNode, manifest, fullValidation); + } + catch (const ManifestException&) + { + // Prevent ManifestException from being wrapped in another ManifestException + throw; + } + catch (const std::exception& e) + { + THROW_EXCEPTION_MSG(ManifestException(), e.what()); + } + + if (!errors.empty()) + { + ManifestException ex{ std::move(errors) }; + + if (throwOnWarning || !ex.IsWarningOnly()) + { + THROW_EXCEPTION(ex); + } + } + + return manifest; + } + + std::vector<ValidationError> YamlParser::ParseManifest(const YAML::Node& rootNode, Manifest& manifest, bool fullValidation) + { + // Detects empty files with a better error. + if (!rootNode.IsMap()) + { + THROW_EXCEPTION_MSG(ManifestException(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST), "The manifest does not contain a valid root."); + } + + // Detect manifest version first to determine expected fields + // Use index to access ManifestVersion directly. If there're duplicates or other general errors, it'll be detected in later + // processing of iterating the whole manifest. + // Todo: make ManifestVersion required when all manifests in our repo have been updated to contain a ManifestVersion + if (rootNode["ManifestVersion"sv]) + { + auto manifestVersionValue = rootNode["ManifestVersion"sv].as<std::string>(); + manifest.ManifestVersion = ManifestVer(manifestVersionValue, false); + } + else + { + manifest.ManifestVersion = PreviewManifestVersion; + } + + // Check manifest version is supported + if (manifest.ManifestVersion.Major() > MaxSupportedMajorVersion) + { + THROW_EXCEPTION_MSG(ManifestException(APPINSTALLER_CLI_ERROR_UNSUPPORTED_MANIFESTVERSION), "Unsupported ManifestVersion: %S", manifest.ManifestVersion.ToString().c_str()); + } + + PrepareManifestFieldInfos(manifest.ManifestVersion); + + // Populate root fields + YAML::Node switchesNode; + YAML::Node installersNode; + YAML::Node localizationsNode; + m_p_switchesNode = &switchesNode; + m_p_installersNode = &installersNode; + m_p_localizationsNode = &localizationsNode; + m_p_manifest = &manifest; + auto resultErrors = ValidateAndProcessFields(rootNode, RootFieldInfos, fullValidation); + + // Populate root switches + if (!switchesNode.IsNull()) + { + m_p_switches = &manifest.Switches; + auto errors = ValidateAndProcessFields(switchesNode, SwitchesFieldInfos, fullValidation); + std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); + } + + // Populate installers + for (std::size_t i = 0; i < installersNode.size(); i++) + { + YAML::Node installerNode = installersNode[i]; + ManifestInstaller installer; + YAML::Node installerSwitchesNode; + + // Populate defaults + installer.InstallerType = manifest.InstallerType; + installer.Scope = "user"; + + m_p_installer = &installer; + m_p_switchesNode = &installerSwitchesNode; + auto errors = ValidateAndProcessFields(installerNode, InstallerFieldInfos, fullValidation); + std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); + + // Populate default known switches + installer.Switches = GetDefaultKnownSwitches(installer.InstallerType); + + // Override with switches from manifest root if applicable + for (auto const& keyValuePair : manifest.Switches) + { + installer.Switches[keyValuePair.first] = keyValuePair.second; + } + + // Override with switches from installer declaration if applicable + if (!installerSwitchesNode.IsNull()) + { + m_p_switches = &installer.Switches; + auto switchesErrors = ValidateAndProcessFields(installerSwitchesNode, SwitchesFieldInfos, fullValidation); + std::move(switchesErrors.begin(), switchesErrors.end(), std::inserter(resultErrors, resultErrors.end())); + } + + manifest.Installers.emplace_back(std::move(installer)); + } + + // Populate localization fields + if (!localizationsNode.IsNull()) + { + for (std::size_t i = 0; i < localizationsNode.size(); i++) + { + YAML::Node localizationNode = localizationsNode[i]; + ManifestLocalization localization; + + // Populates default values from root first + localization.Description = manifest.Description; + localization.Homepage = manifest.Homepage; + localization.LicenseUrl = manifest.LicenseUrl; + + m_p_localization = &localization; + auto errors = ValidateAndProcessFields(localizationNode, LocalizationFieldInfos, fullValidation); + std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); + manifest.Localization.emplace_back(std::move(localization)); + } + } + + // Extra semantic validations after basic validation and field population + if (fullValidation) + { + auto errors = ValidateManifest(manifest); + std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); + } + + return resultErrors; + } + + std::vector<ValidationError> YamlParser::ValidateAndProcessFields( + const YAML::Node& rootNode, + const std::vector<ManifestFieldInfo>& fieldInfos, + bool fullValidation) + { + std::vector<ValidationError> errors; + + if (rootNode.size() == 0 || !rootNode.IsMap()) + { + errors.emplace_back(ManifestError::InvalidRootNode, "", "", rootNode.Mark().line, rootNode.Mark().column); + return errors; + } + + // Keeps track of already processed fields. Used to check duplicate fields or missing required fields. + std::set<std::string> processedFields; + + for (auto const& keyValuePair : rootNode.Mapping()) + { + std::string key = keyValuePair.first.as<std::string>(); + const YAML::Node& valueNode = keyValuePair.second; + + // We'll do case insensitive search first and validate correct case later. + auto fieldIter = std::find_if(fieldInfos.begin(), fieldInfos.end(), + [&](auto const& s) + { + return Utility::CaseInsensitiveEquals(s.Name, key); + }); + + if (fieldIter != fieldInfos.end()) + { + const ManifestFieldInfo& fieldInfo = *fieldIter; + + // Make sure the found key is in Pascal Case + if (key != fieldInfo.Name) + { + errors.emplace_back(ManifestError::FieldIsNotPascalCase, key, "", keyValuePair.first.Mark().line, keyValuePair.first.Mark().column); + } + + // Make sure it's not a duplicate key + if (!processedFields.insert(fieldInfo.Name).second) + { + errors.emplace_back(ManifestError::FieldDuplicate, fieldInfo.Name, "", keyValuePair.first.Mark().line, keyValuePair.first.Mark().column); + } + + // Validate non empty value is provided for required fields + if (fieldInfo.Required) + { + if (!valueNode.IsDefined() || valueNode.IsNull() || // Should be defined and not null + (valueNode.IsScalar() && valueNode.as<std::string>().empty()) || // Scalar type should have content + ((valueNode.IsMap() || valueNode.IsSequence()) && valueNode.size() == 0)) // Map or sequence type should have size greater than 0 + { + errors.emplace_back(ManifestError::RequiredFieldEmpty, fieldInfo.Name, "", valueNode.Mark().line, valueNode.Mark().column); + } + } + + // Validate value against regex if applicable + if (fullValidation && !fieldInfo.RegEx.empty()) + { + std::string value = valueNode.as<std::string>(); + std::regex pattern{ fieldInfo.RegEx }; + if (!std::regex_match(value, pattern)) + { + errors.emplace_back(ManifestError::InvalidFieldValue, fieldInfo.Name, value, valueNode.Mark().line, valueNode.Mark().column); + continue; + } + } + + if (!valueNode.IsNull()) + { + fieldInfo.ProcessFunc(valueNode); + } + } + else + { + // For full validation, also reports unrecognized fields as warning + if (fullValidation) + { + errors.emplace_back(ManifestError::FieldUnknown, key, "", keyValuePair.first.Mark().line, keyValuePair.first.Mark().column, ValidationError::Level::Warning); + } + } + } + + // Make sure required fields are provided + for (auto const& fieldInfo : fieldInfos) + { + if (fieldInfo.Required && processedFields.find(fieldInfo.Name) == processedFields.end()) + { + errors.emplace_back(ManifestError::RequiredFieldMissing, fieldInfo.Name); + } + } + + return errors; + } + + std::map<ManifestInstaller::InstallerSwitchType, ManifestInstaller::string_t> YamlParser::GetDefaultKnownSwitches( + ManifestInstaller::InstallerTypeEnum installerType) + { + switch (installerType) + { + case ManifestInstaller::InstallerTypeEnum::Burn: + case ManifestInstaller::InstallerTypeEnum::Wix: + case ManifestInstaller::InstallerTypeEnum::Msi: + return + { + {ManifestInstaller::InstallerSwitchType::Silent, ManifestInstaller::string_t("/quiet")}, + {ManifestInstaller::InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/passive")}, + {ManifestInstaller::InstallerSwitchType::Log, ManifestInstaller::string_t("/log \"" + std::string(ARG_TOKEN_LOGPATH) + "\"")}, + {ManifestInstaller::InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("TARGETDIR=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")} + }; + case ManifestInstaller::InstallerTypeEnum::Nullsoft: + return + { + {ManifestInstaller::InstallerSwitchType::Silent, ManifestInstaller::string_t("/S")}, + {ManifestInstaller::InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/S")}, + {ManifestInstaller::InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("/D=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")} + }; + case ManifestInstaller::InstallerTypeEnum::Inno: + return + { + {ManifestInstaller::InstallerSwitchType::Silent, ManifestInstaller::string_t("/VERYSILENT")}, + {ManifestInstaller::InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/SILENT")}, + {ManifestInstaller::InstallerSwitchType::Log, ManifestInstaller::string_t("/LOG=\"" + std::string(ARG_TOKEN_LOGPATH) + "\"")}, + {ManifestInstaller::InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("/DIR=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")} + }; + default: + return {}; + } + } +}+ \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/AppInstallerErrors.h b/src/AppInstallerCommonCore/Public/AppInstallerErrors.h @@ -2,7 +2,10 @@ // Licensed under the MIT License. #pragma once #include <wil/result_macros.h> + +#ifndef WINGET_DISABLE_FOR_FUZZING #include <winrt/base.h> +#endif #include <exception> #include <string> @@ -57,6 +60,9 @@ namespace AppInstaller { // Gets error messages that are presentable to the user. std::string GetUserPresentableMessage(const wil::ResultException& re); - std::string GetUserPresentableMessage(const winrt::hresult_error& hre); std::string GetUserPresentableMessage(const std::exception& e); + +#ifndef WINGET_DISABLE_FOR_FUZZING + std::string GetUserPresentableMessage(const winrt::hresult_error& hre); +#endif } diff --git a/src/AppInstallerCommonCore/Public/AppInstallerLogging.h b/src/AppInstallerCommonCore/Public/AppInstallerLogging.h @@ -12,8 +12,8 @@ #define AICLI_LOG(_channel_,_level_,_outstream_) \ do { \ - auto _aicli_log_channel = AppInstaller::Logging::Channel:: ## _channel_; \ - auto _aicli_log_level = AppInstaller::Logging::Level:: ## _level_; \ + auto _aicli_log_channel = AppInstaller::Logging::Channel:: _channel_; \ + auto _aicli_log_level = AppInstaller::Logging::Level:: _level_; \ auto& _aicli_log_log = AppInstaller::Logging::Log(); \ if (_aicli_log_log.IsEnabled(_aicli_log_channel, _aicli_log_level)) \ { \ @@ -40,7 +40,7 @@ namespace AppInstaller::Logging }; // Gets the channel's name as a string. - char const* const GetChannelName(Channel channel); + char const* GetChannelName(Channel channel); // Gets the maximum channel name length in characters. size_t GetMaxChannelNameLength(); diff --git a/src/AppInstallerCommonCore/Public/winget/Manifest.h b/src/AppInstallerCommonCore/Public/winget/Manifest.h @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <AppInstallerStrings.h> +#include <AppInstallerVersions.h> +#include <winget/ManifestInstaller.h> +#include <winget/ManifestLocalization.h> + +#include <vector> + +namespace AppInstaller::Manifest +{ + // ManifestVer is inherited from Utility::Version and is a more restricted version. + // ManifestVer is used to specify the version of app manifest itself. + // ManifestVer is a 3 part version in the format of [0-65535].[0-65535].[0-65535] + // and optionally a following tag in the format of -[SomeString] for experimental purpose. + struct ManifestVer : public Utility::Version + { + ManifestVer() = default; + + ManifestVer(std::string version, bool fullValidation); + + uint64_t Major() const { return m_parts.size() > 0 ? m_parts[0].Integer : 0; } + uint64_t Minor() const { return m_parts.size() > 1 ? m_parts[1].Integer : 0; } + uint64_t Patch() const { return m_parts.size() > 2 ? m_parts[2].Integer : 0; } + + bool HasTag() const; + }; + + // Representation of the parsed manifest file. + struct Manifest + { + using string_t = Utility::NormalizedString; + + // Required + string_t Id; + + // Required + string_t Name; + + // Required + string_t Version; + + // Required + string_t Publisher; + + string_t AppMoniker; + + string_t Channel; + + string_t Author; + + string_t License; + + string_t MinOSVersion; + + // Comma separated values + std::vector<string_t> Tags; + + // Comma separated values + std::vector<string_t> Commands; + + // Comma separated values + std::vector<string_t> Protocols; + + // Comma separated values + std::vector<string_t> FileExtensions; + + ManifestInstaller::InstallerTypeEnum InstallerType = ManifestInstaller::InstallerTypeEnum::Unknown; + + string_t Description; + + string_t Homepage; + + string_t LicenseUrl; + + ManifestVer ManifestVersion; + + std::map<ManifestInstaller::InstallerSwitchType, string_t> Switches; + + std::vector<ManifestInstaller> Installers; + + std::vector<ManifestLocalization> Localization; + }; +}+ \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h b/src/AppInstallerCommonCore/Public/winget/ManifestInstaller.h @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <AppInstallerArchitecture.h> +#include <AppInstallerStrings.h> + +#include <map> +#include <string> + +namespace AppInstaller::Manifest +{ + using namespace std::string_view_literals; + + // Token specified in installer args will be replaced by proper value. + static constexpr std::string_view ARG_TOKEN_LOGPATH = "<LOGPATH>"sv; + static constexpr std::string_view ARG_TOKEN_INSTALLPATH = "<INSTALLPATH>"sv; + + struct ManifestInstaller + { + using string_t = Utility::NormalizedString; + + enum class InstallerTypeEnum + { + Inno, + Wix, + Msi, + Nullsoft, + Zip, + Msix, + Exe, + Burn, + MSStore, + Unknown + }; + + enum class InstallerSwitchType + { + Custom, + Silent, + SilentWithProgress, + Interactive, + Language, + Log, + InstallLocation, + }; + + // Required. Values: x86, x64, arm, arm64, all. + AppInstaller::Utility::Architecture Arch; + + // Required + string_t Url; + + // Required + std::vector<BYTE> Sha256; + + // Optional. Only used by appx/msix type. If provided, Appinstaller will + // validate appx/msix signature and perform streaming install. + std::vector<BYTE> SignatureSha256; + + // Empty means default + string_t Language; + + // Name TBD + string_t Scope; + + // Store Product Id + string_t ProductId; + + // If present, has more precedence than root + InstallerTypeEnum InstallerType; + + // If present, has more precedence than root + std::map<InstallerSwitchType, string_t> Switches; + + static InstallerTypeEnum ConvertToInstallerTypeEnum(const std::string& in); + + static std::string InstallerTypeToString(InstallerTypeEnum installerType); + }; +}+ \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestLocalization.h b/src/AppInstallerCommonCore/Public/winget/ManifestLocalization.h diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h b/src/AppInstallerCommonCore/Public/winget/ManifestValidation.h @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <AppInstallerErrors.h> +#include <winget/Manifest.h> + +#include <wil/result.h> + +#include <functional> +#include <string> + +namespace YAML { class Node; } + +namespace AppInstaller::Manifest +{ + namespace ManifestError + { + const char* const ErrorMessagePrefix = "Manifest Error: "; + const char* const WarningMessagePrefix = "Manifest Warning: "; + + const char* const InvalidRootNode = "Encountered unexpected root node."; + const char* const FieldUnknown = "Unknown field."; + const char* const FieldIsNotPascalCase = "All field names should be PascalCased."; + const char* const FieldDuplicate = "Duplicate field found in the manifest."; + const char* const RequiredFieldEmpty = "Required field with empty value."; + const char* const RequiredFieldMissing = "Required field missing."; + const char* const InvalidFieldValue = "Invalid field value."; + const char* const ExeInstallerMissingSilentSwitches = "Silent and SilentWithProgress switches are not specified for InstallerType exe. Please make sure the installer can run unattended."; + const char* const FieldNotSupported = "Field is not supported."; + const char* const FieldValueNotSupported = "Field value is not supported."; + const char* const DuplicateInstallerEntry = "Duplicate installer entry found."; + } + + struct ValidationError + { + enum class Level + { + Warning, + Error + }; + + std::string Message; + std::string Field = {}; + std::string Value = {}; + // line and column are 1 based + size_t Line = 0; + size_t Column = 0; + Level ErrorLevel = Level::Error; + + ValidationError(std::string message) : + Message(std::move(message)) {} + + ValidationError(std::string message, Level level) : + Message(std::move(message)), ErrorLevel(level) {} + + ValidationError(std::string message, std::string field) : + Message(std::move(message)), Field(std::move(field)) {} + + ValidationError(std::string message, std::string field, std::string value) : + Message(std::move(message)), Field(std::move(field)), Value(std::move(value)) {} + + ValidationError(std::string message, std::string field, std::string value, size_t line, size_t column) : + Message(std::move(message)), Field(std::move(field)), Value(std::move(value)), Line(line), Column(column) {} + + ValidationError(std::string message, std::string field, std::string value, size_t line, size_t column, Level level) : + Message(std::move(message)), Field(std::move(field)), Value(std::move(value)), Line(line), Column(column), ErrorLevel(level) {} + }; + + struct ManifestException : public wil::ResultException + { + ManifestException(std::vector<ValidationError>&& errors = {}, HRESULT hr = APPINSTALLER_CLI_ERROR_MANIFEST_FAILED) : + wil::ResultException(hr), m_errors(std::move(errors)) + { + auto p = [&](ValidationError const& e) { + return e.ErrorLevel == ValidationError::Level::Error; + }; + + m_warningOnly = !m_errors.empty() && std::find_if(m_errors.begin(), m_errors.end(), p) == m_errors.end(); + } + + ManifestException(HRESULT hr) : ManifestException({}, hr) {} + + // Error message without wil diagnostic info + const std::string& GetManifestErrorMessage() const noexcept + { + if (m_manifestErrorMessage.empty()) + { + if (m_errors.empty()) + { + // Syntax error, yaml parser error is stored in FailureInfo + m_manifestErrorMessage = Utility::ConvertToUTF8(GetFailureInfo().pszMessage); + } + else + { + for (auto const& error : m_errors) + { + if (error.ErrorLevel == ValidationError::Level::Error) + { + m_manifestErrorMessage += ManifestError::ErrorMessagePrefix; + } + else if (error.ErrorLevel == ValidationError::Level::Warning) + { + m_manifestErrorMessage += ManifestError::WarningMessagePrefix; + } + m_manifestErrorMessage += error.Message; + + if (!error.Field.empty()) + { + m_manifestErrorMessage += " Field: " + error.Field; + } + if (!error.Value.empty()) + { + m_manifestErrorMessage += " Value: " + error.Value; + } + if (error.Line > 0 && error.Column > 0) + { + m_manifestErrorMessage += " Line: " + std::to_string(error.Line) + ", Column: " + std::to_string(error.Column); + } + m_manifestErrorMessage += '\n'; + } + } + } + return m_manifestErrorMessage; + } + + bool IsWarningOnly() const noexcept + { + return m_warningOnly; + } + + const char* what() const noexcept override + { + if (m_whatMessage.empty()) + { + m_whatMessage = ResultException::what(); + + if (!m_errors.empty()) + { + m_whatMessage += GetManifestErrorMessage(); + } + } + return m_whatMessage.c_str(); + } + + const std::vector<ValidationError>& Errors() const { return m_errors; } + + private: + std::vector<ValidationError> m_errors; + mutable std::string m_whatMessage; + mutable std::string m_manifestErrorMessage; + bool m_warningOnly; + }; + + std::vector<ValidationError> ValidateManifest(const Manifest& manifest); +}+ \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestYamlParser.h b/src/AppInstallerCommonCore/Public/winget/ManifestYamlParser.h @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <winget/ManifestValidation.h> +#include <winget/Manifest.h> + +#include <filesystem> + +namespace AppInstaller::Manifest +{ + static const uint64_t MaxSupportedMajorVersion = 1; + static const ManifestVer PreviewManifestVersion = ManifestVer("0.1.0", false); + static const ManifestVer PreviewManifestVersionMSStore = ManifestVer("0.2.0-msstore", false); + + struct YamlParser + { + // fullValidation: Bool to set if manifest creation should perform extra validation that client does not need. + // e.g. Channel should be null. Client code does not need this check to work properly. + // throwOnWarning: Bool to indicate if an exception should be thrown with only warnings detected in the manifest. + static Manifest CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation = false, bool throwOnWarning = false); + + static Manifest Create(const std::string& input, bool fullValidation = false, bool throwOnWarning = false); + + private: + // These pointers are referenced in the processing functions in manifest field info table. + YAML::Node* m_p_installersNode = nullptr; + YAML::Node* m_p_switchesNode = nullptr; + YAML::Node* m_p_localizationsNode = nullptr; + AppInstaller::Manifest::Manifest* m_p_manifest = nullptr; + AppInstaller::Manifest::ManifestInstaller* m_p_installer = nullptr; + std::map<ManifestInstaller::InstallerSwitchType, Utility::NormalizedString>* m_p_switches = nullptr; + AppInstaller::Manifest::ManifestLocalization* m_p_localization = nullptr; + + // This struct contains individual app manifest field info + struct ManifestFieldInfo + { + std::string Name; + ManifestVer VerIntroduced; + std::function<void(const YAML::Node&)> ProcessFunc; + bool Required = false; + std::string RegEx = {}; + }; + + std::vector<ManifestFieldInfo> RootFieldInfos; + std::vector<ManifestFieldInfo> InstallerFieldInfos; + std::vector<ManifestFieldInfo> SwitchesFieldInfos; + std::vector<ManifestFieldInfo> LocalizationFieldInfos; + + std::vector<ValidationError> ParseManifest(const YAML::Node& rootNode, Manifest& manifest, bool fullValidation); + + static std::map<ManifestInstaller::InstallerSwitchType, Utility::NormalizedString> GetDefaultKnownSwitches( + ManifestInstaller::InstallerTypeEnum installerType); + + // This method takes YAML root node and list of manifest field info. + // Yaml-cpp does not support case insensitive search and it allows duplicate keys. If duplicate keys exist, + // the value is undefined. So in this method, we will iterate through the node map and process each individual + // pair ourselves. This also helps with generating aggregated error rather than throwing on first failure. + static std::vector<ValidationError> ValidateAndProcessFields( + const YAML::Node& rootNode, + const std::vector<ManifestFieldInfo>& fieldInfos, + bool fullValidation); + + void PrepareManifestFieldInfos(const ManifestVer& manifestVer); + void FilterManifestFieldInfos(std::vector<ManifestFieldInfo>& source, const ManifestVer& manifestVer); + }; +}+ \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -4,9 +4,11 @@ #include "AppInstallerStrings.h" #include <filesystem> -#include <vector> +#include <map> +#include <optional> #include <string> #include <variant> +#include <vector> namespace AppInstaller::Settings { @@ -83,7 +85,7 @@ namespace AppInstaller::Settings // Used to deduce the SettingVariant type; making a variant that includes std::monostate and all SettingMapping types. template <size_t... I> - inline auto Deduce(std::index_sequence<I...>) { return std::variant<std::monostate, SettingMapping<static_cast<Setting>(I)>::value_t...>{}; } + inline auto Deduce(std::index_sequence<I...>) { return std::variant<std::monostate, typename SettingMapping<static_cast<Setting>(I)>::value_t...>{}; } // Holds data of any type listed in a SettingMapping. using SettingVariant = decltype(Deduce(std::make_index_sequence<static_cast<size_t>(Setting::Max)>())); diff --git a/src/AppInstallerCommonCore/Public/winget/Yaml.h b/src/AppInstallerCommonCore/Public/winget/Yaml.h @@ -105,7 +105,8 @@ namespace AppInstaller::YAML T as() const { Require(Type::Scalar); - return as_dispatch(reinterpret_cast<T*>(nullptr)); + T* t = nullptr; + return as_dispatch(t); } bool operator<(const Node& other) const; diff --git a/src/AppInstallerCommonCore/Runtime.cpp b/src/AppInstallerCommonCore/Runtime.cpp @@ -19,8 +19,10 @@ namespace AppInstaller::Runtime constexpr std::string_view s_AppDataDir_State = "State"sv; constexpr std::string_view s_SecureSettings_Base = "Microsoft/WinGet"sv; constexpr std::string_view s_SecureSettings_UserRelative = "settings"sv; - constexpr std::string_view s_SecureSettings_Relative_Packaged = "pkg"sv; constexpr std::string_view s_SecureSettings_Relative_Unpackaged = "win"sv; +#ifndef WINGET_DISABLE_FOR_FUZZING + constexpr std::string_view s_SecureSettings_Relative_Packaged = "pkg"sv; +#endif // Gets a boolean indicating whether the current process has identity. bool DoesCurrentProcessHaveIdentity() @@ -186,6 +188,7 @@ namespace AppInstaller::Runtime } } +#ifndef WINGET_DISABLE_FOR_FUZZING LocIndString GetOSVersion() { winrt::Windows::System::Profile::AnalyticsInfo analyticsInfo{}; @@ -205,12 +208,14 @@ namespace AppInstaller::Runtime return LocIndString{ strstr.str() }; } +#endif std::filesystem::path GetPathTo(PathName path) { std::filesystem::path result; bool create = true; +#ifndef WINGET_DISABLE_FOR_FUZZING if (IsRunningInPackagedContext()) { auto appStorage = winrt::Windows::Storage::ApplicationData::Current(); @@ -247,6 +252,7 @@ namespace AppInstaller::Runtime } } else +#endif { switch (path) { diff --git a/src/AppInstallerCommonCore/Settings.cpp b/src/AppInstallerCommonCore/Settings.cpp @@ -47,6 +47,7 @@ namespace AppInstaller::Settings virtual std::filesystem::path PathTo(const std::filesystem::path& name) = 0; }; +#ifndef WINGET_DISABLE_FOR_FUZZING // A settings container backed by the ApplicationDataContainer functionality. struct ApplicationDataSettingsContainer : public ISettingsContainer { @@ -104,6 +105,7 @@ namespace AppInstaller::Settings private: Container m_root; }; +#endif // A settings container backed by the filesystem. struct FileSettingsContainer : public ISettingsContainer @@ -296,6 +298,7 @@ namespace AppInstaller::Settings return std::make_unique<SecureSettingsContainer>(GetSettingsContainer(Type::Standard)); } +#ifndef WINGET_DISABLE_FOR_FUZZING if (IsRunningInPackagedContext()) { switch (type) @@ -311,6 +314,7 @@ namespace AppInstaller::Settings } } else +#endif { switch (type) { diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp @@ -95,7 +95,7 @@ namespace AppInstaller::Settings Json::Value result = jsonPath.resolve(root); if (!result.isNull()) { - auto jsonValue = GetValue<details::SettingMapping<S>::json_t>(result); + auto jsonValue = GetValue<typename details::SettingMapping<S>::json_t>(result); if (jsonValue.has_value()) { @@ -135,8 +135,15 @@ namespace AppInstaller::Settings std::vector<std::string>& warnings, std::index_sequence<S...>) { +#ifdef WINGET_DISABLE_FOR_FUZZING +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-value" +#endif // Use folding to call each setting validate function. (FoldHelper{}, ..., Validate<static_cast<Setting>(S)>(root, settings, warnings)); +#ifdef WINGET_DISABLE_FOR_FUZZING +#pragma clang diagnostic pop +#endif } } diff --git a/src/AppInstallerCommonCore/Versions.cpp b/src/AppInstallerCommonCore/Versions.cpp @@ -103,15 +103,19 @@ namespace AppInstaller::Utility Version::Part::Part(const std::string& part) { - size_t end = 0; - try + const char* begin = part.c_str(); + char* end = nullptr; + errno = 0; + Integer = strtoull(begin, &end, 10); + + if (errno == ERANGE) { - Integer = std::stoull(part, &end); + Integer = 0; + Other = part; } - CATCH_LOG(); - if (end != part.length()) + else if (static_cast<size_t>(end - begin) != part.length()) { - Other = part.substr(end); + Other = end; } } diff --git a/src/AppInstallerCommonCore/packages.config b/src/AppInstallerCommonCore/packages.config @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Microsoft.Windows.CppWinRT" version="2.0.191111.2" targetFramework="native" /> - <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.191107.2" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" /> </packages> \ No newline at end of file diff --git a/src/AppInstallerCommonCore/pch.h b/src/AppInstallerCommonCore/pch.h @@ -27,6 +27,8 @@ #include <limits> #include <memory> #include <ostream> +#include <regex> +#include <set> #include <string> #include <sstream> #include <stack> @@ -34,13 +36,14 @@ #include <type_traits> #include <vector> -// wil/cppwinrt.h should always be included before any C++/WinRT or WIL header file when both are in use -#include <wil/cppwinrt.h> #include <wil/result_macros.h> #include <wil/safecast.h> #include <wil/resource.h> #include <wil/token_helpers.h> +#ifndef WINGET_DISABLE_FOR_FUZZING +#include <wil/cppwinrt.h> + #include <winrt/Windows.ApplicationModel.h> #include <winrt/Windows.ApplicationModel.AppExtensions.h> #include <winrt/Windows.Foundation.h> @@ -52,6 +55,7 @@ #include <winrt/Windows.Web.Http.h> #include <winrt/Windows.Web.Http.Headers.h> #include <winrt/Windows.Web.Http.Filters.h> +#endif #include <wrl/client.h> diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" /> <PropertyGroup Label="Globals"> <CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> @@ -174,11 +174,6 @@ <ItemGroup> <ClInclude Include="AggregatedSource.h" /> <ClInclude Include="ICU\SQLiteICU.h" /> - <ClInclude Include="Manifest\Manifest.h" /> - <ClInclude Include="Manifest\ManifestInstaller.h" /> - <ClInclude Include="Manifest\ManifestLocalization.h" /> - <ClInclude Include="Manifest\YamlParser.h" /> - <ClInclude Include="Manifest\ManifestValidation.h" /> <ClInclude Include="Microsoft\PreIndexedPackageSourceFactory.h" /> <ClInclude Include="Microsoft\Schema\1_0\ChannelTable.h" /> <ClInclude Include="Microsoft\Schema\1_0\CommandsTable.h" /> @@ -218,10 +213,6 @@ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader> </ClCompile> - <ClCompile Include="Manifest\Manifest.cpp" /> - <ClCompile Include="Manifest\ManifestInstaller.cpp" /> - <ClCompile Include="Manifest\YamlParser.cpp" /> - <ClCompile Include="Manifest\ManifestValidation.cpp" /> <ClCompile Include="Microsoft\PreIndexedPackageSourceFactory.cpp" /> <ClCompile Include="Microsoft\Schema\1_0\Interface.cpp" /> <ClCompile Include="Microsoft\Schema\1_0\ManifestTable.cpp" /> @@ -248,15 +239,15 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" /> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> </ImportGroup> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> </Target> </Project> \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters b/src/AppInstallerRepositoryCore/AppInstallerRepositoryCore.vcxproj.filters @@ -22,9 +22,6 @@ <Filter Include="Microsoft\Schema\1_0"> <UniqueIdentifier>{cff561cd-211b-4cab-87f5-39359eef1e8d}</UniqueIdentifier> </Filter> - <Filter Include="Manifest"> - <UniqueIdentifier>{052eaac1-ec6e-4879-8388-aff5a30401f0}</UniqueIdentifier> - </Filter> <Filter Include="Public"> <UniqueIdentifier>{69ce2e35-fe7f-41af-bd47-91a70131d167}</UniqueIdentifier> </Filter> @@ -54,15 +51,6 @@ <ClInclude Include="Microsoft\Schema\1_0\Interface.h"> <Filter>Microsoft\Schema\1_0</Filter> </ClInclude> - <ClInclude Include="Manifest\Manifest.h"> - <Filter>Manifest</Filter> - </ClInclude> - <ClInclude Include="Manifest\ManifestInstaller.h"> - <Filter>Manifest</Filter> - </ClInclude> - <ClInclude Include="Manifest\ManifestLocalization.h"> - <Filter>Manifest</Filter> - </ClInclude> <ClInclude Include="Microsoft\Schema\1_0\OneToOneTable.h"> <Filter>Microsoft\Schema\1_0</Filter> </ClInclude> @@ -123,12 +111,6 @@ <ClInclude Include="ICU\SQLiteICU.h"> <Filter>ICU</Filter> </ClInclude> - <ClInclude Include="Manifest\ManifestValidation.h"> - <Filter>Manifest</Filter> - </ClInclude> - <ClInclude Include="Manifest\YamlParser.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="AggregatedSource.h"> <Filter>Header Files</Filter> </ClInclude> @@ -152,12 +134,6 @@ <ClCompile Include="Microsoft\Schema\1_0\Interface.cpp"> <Filter>Microsoft\Schema\1_0</Filter> </ClCompile> - <ClCompile Include="Manifest\Manifest.cpp"> - <Filter>Manifest</Filter> - </ClCompile> - <ClCompile Include="Manifest\ManifestInstaller.cpp"> - <Filter>Manifest</Filter> - </ClCompile> <ClCompile Include="Microsoft\Schema\1_0\OneToOneTable.cpp"> <Filter>Microsoft\Schema\1_0</Filter> </ClCompile> @@ -191,12 +167,6 @@ <ClCompile Include="ICU\SQLiteICU.c"> <Filter>ICU</Filter> </ClCompile> - <ClCompile Include="Manifest\ManifestValidation.cpp"> - <Filter>Manifest</Filter> - </ClCompile> - <ClCompile Include="Manifest\YamlParser.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="AggregatedSource.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/src/AppInstallerRepositoryCore/Manifest/Manifest.cpp b/src/AppInstallerRepositoryCore/Manifest/Manifest.cpp @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "Manifest.h" -#include "ManifestValidation.h" - -namespace AppInstaller::Manifest -{ - ManifestVer::ManifestVer(std::string version, bool fullValidation) : Version(std::move(version), ".") - { - bool validationSuccess = true; - - if (m_parts.size() > 3) - { - validationSuccess = false; - } - else - { - for (size_t i = 0; i < m_parts.size(); i++) - { - if (!m_parts[i].Other.empty() && - (i < 2 || fullValidation)) - { - validationSuccess = false; - break; - } - } - } - - if (!validationSuccess) - { - std::vector<ValidationError> errors; - errors.emplace_back(ManifestError::InvalidFieldValue, "ManifestVersion", m_version); - THROW_EXCEPTION(ManifestException(std::move(errors))); - } - } - - bool ManifestVer::HasTag() const - { - return m_parts.size() == 3 && !m_parts[2].Other.empty(); - } -} diff --git a/src/AppInstallerRepositoryCore/Manifest/Manifest.h b/src/AppInstallerRepositoryCore/Manifest/Manifest.h @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include "ManifestInstaller.h" -#include "ManifestLocalization.h" -#include <AppInstallerStrings.h> -#include <AppInstallerVersions.h> -#include <vector> - -namespace AppInstaller::Manifest -{ - // ManifestVer is inherited from Utility::Version and is a more restricted version. - // ManifestVer is used to specify the version of app manifest itself. - // ManifestVer is a 3 part version in the format of [0-65535].[0-65535].[0-65535] - // and optionally a following tag in the format of -[SomeString] for experimental purpose. - struct ManifestVer : public Utility::Version - { - ManifestVer() = default; - - ManifestVer(std::string version, bool fullValidation); - - uint64_t Major() const { return m_parts.size() > 0 ? m_parts[0].Integer : 0; } - uint64_t Minor() const { return m_parts.size() > 1 ? m_parts[1].Integer : 0; } - uint64_t Patch() const { return m_parts.size() > 2 ? m_parts[2].Integer : 0; } - - bool HasTag() const; - }; - - // Representation of the parsed manifest file. - struct Manifest - { - using string_t = Utility::NormalizedString; - - // Required - string_t Id; - - // Required - string_t Name; - - // Required - string_t Version; - - // Required - string_t Publisher; - - string_t AppMoniker; - - string_t Channel; - - string_t Author; - - string_t License; - - string_t MinOSVersion; - - // Comma separated values - std::vector<string_t> Tags; - - // Comma separated values - std::vector<string_t> Commands; - - // Comma separated values - std::vector<string_t> Protocols; - - // Comma separated values - std::vector<string_t> FileExtensions; - - ManifestInstaller::InstallerTypeEnum InstallerType = ManifestInstaller::InstallerTypeEnum::Unknown; - - string_t Description; - - string_t Homepage; - - string_t LicenseUrl; - - ManifestVer ManifestVersion; - - std::map<ManifestInstaller::InstallerSwitchType, string_t> Switches; - - std::vector<ManifestInstaller> Installers; - - std::vector<ManifestLocalization> Localization; - }; -}- \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestInstaller.cpp b/src/AppInstallerRepositoryCore/Manifest/ManifestInstaller.cpp @@ -1,91 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "pch.h" -#include "ManifestInstaller.h" - -namespace AppInstaller::Manifest -{ - ManifestInstaller::InstallerTypeEnum ManifestInstaller::ConvertToInstallerTypeEnum(const std::string& in) - { - std::string inStrLower = Utility::ToLower(in); - InstallerTypeEnum result = InstallerTypeEnum::Unknown; - - if (inStrLower == "inno") - { - result = InstallerTypeEnum::Inno; - } - else if (inStrLower == "wix") - { - result = InstallerTypeEnum::Wix; - } - else if (inStrLower == "msi") - { - result = InstallerTypeEnum::Msi; - } - else if (inStrLower == "nullsoft") - { - result = InstallerTypeEnum::Nullsoft; - } - else if (inStrLower == "zip") - { - result = InstallerTypeEnum::Zip; - } - else if (inStrLower == "appx" || inStrLower == "msix") - { - result = InstallerTypeEnum::Msix; - } - else if (inStrLower == "exe") - { - result = InstallerTypeEnum::Exe; - } - else if (inStrLower == "burn") - { - result = InstallerTypeEnum::Burn; - } - else if (inStrLower == "msstore") - { - result = InstallerTypeEnum::MSStore; - } - - return result; - } - - std::string ManifestInstaller::InstallerTypeToString(ManifestInstaller::InstallerTypeEnum installerType) - { - std::string result = "Unknown"; - - switch (installerType) - { - case ManifestInstaller::InstallerTypeEnum::Exe: - result = "Exe"; - break; - case ManifestInstaller::InstallerTypeEnum::Inno: - result = "Inno"; - break; - case ManifestInstaller::InstallerTypeEnum::Msi: - result = "Msi"; - break; - case ManifestInstaller::InstallerTypeEnum::Msix: - result = "Msix"; - break; - case ManifestInstaller::InstallerTypeEnum::Nullsoft: - result = "Nullsoft"; - break; - case ManifestInstaller::InstallerTypeEnum::Wix: - result = "Wix"; - break; - case ManifestInstaller::InstallerTypeEnum::Zip: - result = "Zip"; - break; - case ManifestInstaller::InstallerTypeEnum::Burn: - result = "Burn"; - break; - case ManifestInstaller::InstallerTypeEnum::MSStore: - result = "MSStore"; - break; - } - - return result; - } -} diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestInstaller.h b/src/AppInstallerRepositoryCore/Manifest/ManifestInstaller.h @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include <AppInstallerArchitecture.h> -#include <AppInstallerStrings.h> - -#include <string> -#include <map> - -namespace AppInstaller::Manifest -{ - using namespace std::string_view_literals; - - // Token specified in installer args will be replaced by proper value. - static constexpr std::string_view ARG_TOKEN_LOGPATH = "<LOGPATH>"sv; - static constexpr std::string_view ARG_TOKEN_INSTALLPATH = "<INSTALLPATH>"sv; - - struct ManifestInstaller - { - using string_t = Utility::NormalizedString; - - enum class InstallerTypeEnum - { - Inno, - Wix, - Msi, - Nullsoft, - Zip, - Msix, - Exe, - Burn, - MSStore, - Unknown - }; - - enum class InstallerSwitchType - { - Custom, - Silent, - SilentWithProgress, - Interactive, - Language, - Log, - InstallLocation, - }; - - // Required. Values: x86, x64, arm, arm64, all. - AppInstaller::Utility::Architecture Arch; - - // Required - string_t Url; - - // Required - std::vector<BYTE> Sha256; - - // Optional. Only used by appx/msix type. If provided, Appinstaller will - // validate appx/msix signature and perform streaming install. - std::vector<BYTE> SignatureSha256; - - // Empty means default - string_t Language; - - // Name TBD - string_t Scope; - - // Store Product Id - string_t ProductId; - - // If present, has more precedence than root - InstallerTypeEnum InstallerType; - - // If present, has more precedence than root - std::map<InstallerSwitchType, string_t> Switches; - - static InstallerTypeEnum ConvertToInstallerTypeEnum(const std::string& in); - - static std::string InstallerTypeToString(InstallerTypeEnum installerType); - }; -}- \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestValidation.cpp b/src/AppInstallerRepositoryCore/Manifest/ManifestValidation.cpp @@ -1,129 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "ManifestValidation.h" - -namespace AppInstaller::Manifest -{ - std::vector<ValidationError> ValidateManifest(const Manifest& manifest) - { - std::vector<ValidationError> resultErrors; - - // Channel is not supported currently - if (!manifest.Channel.empty()) - { - resultErrors.emplace_back(ManifestError::FieldNotSupported, "Channel", manifest.Channel); - } - - try - { - // Version value should be successfully parsed - Utility::Version test{ manifest.Version }; - } - catch (const std::exception&) - { - resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Version", manifest.Version); - } - - // License field is required - if (manifest.License.empty()) - { - resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "License"); - } - - // Comparation function to check duplicate installer entry. {installerType, arch, language and scope} combination is the key. - // Todo: use the comparator from ManifestComparator when that one is fully implemented. - auto installerCmp = [](const ManifestInstaller& in1, const ManifestInstaller& in2) - { - if (in1.InstallerType != in2.InstallerType) - { - return in1.InstallerType < in2.InstallerType; - } - - if (in1.Arch != in2.Arch) - { - return in1.Arch < in2.Arch; - } - - if (in1.Language != in2.Language) - { - return in1.Language < in2.Language; - } - - if (in1.Scope != in2.Scope) - { - return in1.Scope < in2.Scope; - } - - return false; - }; - - std::set<ManifestInstaller, decltype(installerCmp)> installerSet(installerCmp); - bool duplicateInstallerFound = false; - - // Validate installers - for (auto const& installer : manifest.Installers) - { - if (!duplicateInstallerFound && !installerSet.insert(installer).second) - { - resultErrors.emplace_back(ManifestError::DuplicateInstallerEntry); - duplicateInstallerFound = true; - } - - if (installer.Arch == Utility::Architecture::Unknown) - { - resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Arch"); - } - - if (installer.InstallerType == ManifestInstaller::InstallerTypeEnum::Unknown) - { - resultErrors.emplace_back(ManifestError::InvalidFieldValue, "InstallerType"); - } - - if (installer.InstallerType == ManifestInstaller::InstallerTypeEnum::MSStore) - { - // MSStore type is not supported in community repo - resultErrors.emplace_back( - ManifestError::FieldValueNotSupported, "InstallerType", - ManifestInstaller::InstallerTypeToString(installer.InstallerType)); - - if (installer.ProductId.empty()) - { - resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "ProductId"); - } - } - else - { - // For other types, Url and Sha256 are required - if (installer.Url.empty()) - { - resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "Url"); - } - if (installer.Sha256.empty()) - { - resultErrors.emplace_back(ManifestError::RequiredFieldMissing, "Sha256"); - } - // ProductId should not be used - if (!installer.ProductId.empty()) - { - resultErrors.emplace_back(ManifestError::FieldNotSupported, "ProductId"); - } - } - - if (installer.InstallerType == ManifestInstaller::InstallerTypeEnum::Exe && - (installer.Switches.find(ManifestInstaller::InstallerSwitchType::SilentWithProgress) == installer.Switches.end() || - installer.Switches.find(ManifestInstaller::InstallerSwitchType::Silent) == installer.Switches.end())) - { - resultErrors.emplace_back(ManifestError::ExeInstallerMissingSilentSwitches, ValidationError::Level::Warning); - } - - // Check empty string before calling IsValidUrl to avoid duplicate error reporting. - if (!installer.Url.empty() && IsValidURL(NULL, Utility::ConvertToUTF16(installer.Url).c_str(), 0) == S_FALSE) - { - resultErrors.emplace_back(ManifestError::InvalidFieldValue, "Url", installer.Url); - } - } - - return resultErrors; - } -}- \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Manifest/ManifestValidation.h b/src/AppInstallerRepositoryCore/Manifest/ManifestValidation.h @@ -1,152 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once - -#include <string> -#include <functional> -#include <wil/result.h> -#include <AppInstallerErrors.h> -#include "Manifest.h" - -namespace YAML { class Node; } - -namespace AppInstaller::Manifest -{ - namespace ManifestError - { - const char* const ErrorMessagePrefix = "Manifest Error: "; - const char* const WarningMessagePrefix = "Manifest Warning: "; - - const char* const InvalidRootNode = "Encountered unexpected root node."; - const char* const FieldUnknown = "Unknown field."; - const char* const FieldIsNotPascalCase = "All field names should be PascalCased."; - const char* const FieldDuplicate = "Duplicate field found in the manifest."; - const char* const RequiredFieldEmpty = "Required field with empty value."; - const char* const RequiredFieldMissing = "Required field missing."; - const char* const InvalidFieldValue = "Invalid field value."; - const char* const ExeInstallerMissingSilentSwitches = "Silent and SilentWithProgress switches are not specified for InstallerType exe. Please make sure the installer can run unattended."; - const char* const FieldNotSupported = "Field is not supported."; - const char* const FieldValueNotSupported = "Field value is not supported."; - const char* const DuplicateInstallerEntry = "Duplicate installer entry found."; - } - - struct ValidationError - { - enum class Level - { - Warning, - Error - }; - - std::string Message; - std::string Field = {}; - std::string Value = {}; - // line and column are 1 based - size_t Line = 0; - size_t Column = 0; - Level ErrorLevel = Level::Error; - - ValidationError(std::string message) : - Message(std::move(message)) {} - - ValidationError(std::string message, Level level) : - Message(std::move(message)), ErrorLevel(level) {} - - ValidationError(std::string message, std::string field) : - Message(std::move(message)), Field(std::move(field)) {} - - ValidationError(std::string message, std::string field, std::string value) : - Message(std::move(message)), Field(std::move(field)), Value(std::move(value)) {} - - ValidationError(std::string message, std::string field, std::string value, size_t line, size_t column) : - Message(std::move(message)), Field(std::move(field)), Value(std::move(value)), Line(line), Column(column) {} - - ValidationError(std::string message, std::string field, std::string value, size_t line, size_t column, Level level) : - Message(std::move(message)), Field(std::move(field)), Value(std::move(value)), Line(line), Column(column), ErrorLevel(level) {} - }; - - struct ManifestException : public wil::ResultException - { - ManifestException(std::vector<ValidationError>&& errors = {}, HRESULT hr = APPINSTALLER_CLI_ERROR_MANIFEST_FAILED) : - m_errors(std::move(errors)), wil::ResultException(hr) - { - auto p = [&](ValidationError const& e) { - return e.ErrorLevel == ValidationError::Level::Error; - }; - - m_warningOnly = !m_errors.empty() && std::find_if(m_errors.begin(), m_errors.end(), p) == m_errors.end(); - } - - ManifestException(HRESULT hr) : ManifestException({}, hr) {} - - // Error message without wil diagnostic info - const std::string& GetManifestErrorMessage() const noexcept - { - if (m_manifestErrorMessage.empty()) - { - if (m_errors.empty()) - { - // Syntax error, yaml parser error is stored in FailureInfo - m_manifestErrorMessage = Utility::ConvertToUTF8(GetFailureInfo().pszMessage); - } - else - { - for (auto const& error : m_errors) - { - if (error.ErrorLevel == ValidationError::Level::Error) - { - m_manifestErrorMessage += ManifestError::ErrorMessagePrefix; - } - else if (error.ErrorLevel == ValidationError::Level::Warning) - { - m_manifestErrorMessage += ManifestError::WarningMessagePrefix; - } - m_manifestErrorMessage += error.Message; - - if (!error.Field.empty()) - { - m_manifestErrorMessage += " Field: " + error.Field; - } - if (!error.Value.empty()) - { - m_manifestErrorMessage += " Value: " + error.Value; - } - if (error.Line > 0 && error.Column > 0) - { - m_manifestErrorMessage += " Line: " + std::to_string(error.Line) + ", Column: " + std::to_string(error.Column); - } - m_manifestErrorMessage += '\n'; - } - } - } - return m_manifestErrorMessage; - } - - bool IsWarningOnly() const noexcept - { - return m_warningOnly; - } - - const char* what() const noexcept override - { - if (m_whatMessage.empty()) - { - m_whatMessage = ResultException::what(); - - if (!m_errors.empty()) - { - m_whatMessage += GetManifestErrorMessage(); - } - } - return m_whatMessage.c_str(); - } - - private: - std::vector<ValidationError> m_errors; - mutable std::string m_whatMessage; - mutable std::string m_manifestErrorMessage; - bool m_warningOnly; - }; - - std::vector<ValidationError> ValidateManifest(const Manifest& manifest); -}- \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Manifest/YamlParser.cpp b/src/AppInstallerRepositoryCore/Manifest/YamlParser.cpp @@ -1,438 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "YamlParser.h" - -namespace AppInstaller::Manifest -{ - namespace - { - std::vector<Manifest::string_t> SplitMultiValueField(const std::string& input) - { - if (input.empty()) - { - return {}; - } - - std::vector<Manifest::string_t> result; - size_t currentPos = 0; - while (currentPos < input.size()) - { - size_t splitPos = input.find(',', currentPos); - if (splitPos == std::string::npos) - { - splitPos = input.size(); - } - - std::string splitVal = input.substr(currentPos, splitPos - currentPos); - Utility::Trim(splitVal); - if (!splitVal.empty()) - { - result.emplace_back(std::move(splitVal)); - } - currentPos = splitPos + 1; - } - - return result; - } - } - - void YamlParser::PrepareManifestFieldInfos(const ManifestVer& manifestVer) - { - RootFieldInfos = - { - { "ManifestVersion", PreviewManifestVersion, [this](const YAML::Node&) { /* ManifestVersion already processed */ }, false, - // Regex here is to prevent leading 0s in the version, this also keeps consistent with other versions in the manifest - "^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){2}$" }, - { "Id", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Id = value.as<std::string>(); Utility::Trim(m_p_manifest->Id); }, true, "^[\\S]+\\.[\\S]+$" }, - { "Name", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Name = value.as<std::string>(); Utility::Trim(m_p_manifest->Name); }, true }, - { "Version", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Version = value.as<std::string>(); Utility::Trim(m_p_manifest->Version); }, true, - /* File name chars not allowed */ "^[^\\\\/:\\*\\?\"<>\\|\\x01-\\x1f]+$" }, - { "Publisher", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Publisher = value.as<std::string>(); }, true }, - { "AppMoniker", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->AppMoniker = value.as<std::string>(); Utility::Trim(m_p_manifest->AppMoniker); } }, - { "Channel", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Channel = value.as<std::string>(); Utility::Trim(m_p_manifest->Channel); } }, - { "Author", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Author = value.as<std::string>(); } }, - { "License", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->License = value.as<std::string>(); } }, - { "MinOSVersion", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->MinOSVersion = value.as<std::string>(); Utility::Trim(m_p_manifest->MinOSVersion); }, false, - "^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){0,3}$" }, - { "Tags", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Tags = SplitMultiValueField(value.as<std::string>()); } }, - { "Commands", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Commands = SplitMultiValueField(value.as<std::string>()); } }, - { "Protocols", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Protocols = SplitMultiValueField(value.as<std::string>()); } }, - { "FileExtensions", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->FileExtensions = SplitMultiValueField(value.as<std::string>()); } }, - { "InstallerType", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->InstallerType = ManifestInstaller::ConvertToInstallerTypeEnum(value.as<std::string>()); } }, - { "Description", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Description = value.as<std::string>(); } }, - { "Homepage", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->Homepage = value.as<std::string>(); } }, - { "LicenseUrl", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_manifest->LicenseUrl = value.as<std::string>(); } }, - { "Switches", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_switchesNode = value; } }, - { "Installers", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_installersNode = value; }, true }, - { "Localization", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_localizationsNode = value; } }, - }; - - InstallerFieldInfos = - { - { "Arch", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Arch = Utility::ConvertToArchitectureEnum(value.as<std::string>()); }, true }, - { "Url", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Url = value.as<std::string>(); } }, - { "Sha256", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Sha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); }, false, "^[A-Fa-f0-9]{64}$" }, - { "SignatureSha256", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->SignatureSha256 = Utility::SHA256::ConvertToBytes(value.as<std::string>()); }, false, "^[A-Fa-f0-9]{64}$" }, - { "Language", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Language = value.as<std::string>(); } }, - { "Scope", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->Scope = value.as<std::string>(); } }, - { "InstallerType", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_installer->InstallerType = ManifestInstaller::ConvertToInstallerTypeEnum(value.as<std::string>()); } }, - { "ProductId", PreviewManifestVersionMSStore, [this](const YAML::Node& value) { m_p_installer->ProductId = value.as<std::string>(); } }, - { "Switches", PreviewManifestVersion, [this](const YAML::Node& value) { *m_p_switchesNode = value; } }, - }; - - SwitchesFieldInfos = - { - { "Custom", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Custom] = value.as<std::string>(); } }, - { "Silent", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Silent] = value.as<std::string>(); } }, - { "SilentWithProgress", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::SilentWithProgress] = value.as<std::string>(); } }, - { "Interactive", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Interactive] = value.as<std::string>(); } }, - { "Language", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Language] = value.as<std::string>(); } }, - { "Log", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::Log] = value.as<std::string>(); } }, - { "InstallLocation", PreviewManifestVersion, [this](const YAML::Node& value) { (*m_p_switches)[ManifestInstaller::InstallerSwitchType::InstallLocation] = value.as<std::string>(); } }, - }; - - LocalizationFieldInfos = - { - { "Language", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->Language = value.as<std::string>(); }, true }, - { "Description", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->Description = value.as<std::string>(); } }, - { "Homepage", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->Homepage = value.as<std::string>(); } }, - { "LicenseUrl", PreviewManifestVersion, [this](const YAML::Node& value) { m_p_localization->LicenseUrl = value.as<std::string>(); } }, - }; - - FilterManifestFieldInfos(RootFieldInfos, manifestVer); - FilterManifestFieldInfos(InstallerFieldInfos, manifestVer); - FilterManifestFieldInfos(SwitchesFieldInfos, manifestVer); - FilterManifestFieldInfos(LocalizationFieldInfos, manifestVer); - } - - void YamlParser::FilterManifestFieldInfos( - std::vector<ManifestFieldInfo>& source, - const ManifestVer& manifestVer) - { - auto it = std::remove_if(source.begin(), source.end(), - [&](ManifestFieldInfo field) - { - if (field.VerIntroduced.HasTag()) - { - // Tagged version should have exact match - return field.VerIntroduced != manifestVer; - } - else - { - return manifestVer < field.VerIntroduced; - } - }); - source.erase(it, source.end()); - } - - Manifest YamlParser::CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation, bool throwOnWarning) - { - Manifest manifest; - std::vector<ValidationError> errors; - - try - { - YAML::Node rootNode = YAML::Load(inputFile); - YamlParser parser; - errors = parser.ParseManifest(rootNode, manifest, fullValidation); - } - catch (const ManifestException&) - { - // Prevent ManifestException from being wrapped in another ManifestException - throw; - } - catch (const std::exception& e) - { - THROW_EXCEPTION_MSG(ManifestException(), e.what()); - } - - if (!errors.empty()) - { - ManifestException ex{ std::move(errors) }; - - if (throwOnWarning || !ex.IsWarningOnly()) - { - THROW_EXCEPTION(ex); - } - } - - return manifest; - } - - Manifest YamlParser::Create(const std::string& input, bool fullValidation, bool throwOnWarning) - { - Manifest manifest; - std::vector<ValidationError> errors; - - try - { - YAML::Node rootNode = YAML::Load(input); - YamlParser parser; - errors = parser.ParseManifest(rootNode, manifest, fullValidation); - } - catch (const ManifestException&) - { - // Prevent ManifestException from being wrapped in another ManifestException - throw; - } - catch (const std::exception& e) - { - THROW_EXCEPTION_MSG(ManifestException(), e.what()); - } - - if (!errors.empty()) - { - ManifestException ex{ std::move(errors) }; - - if (throwOnWarning || !ex.IsWarningOnly()) - { - THROW_EXCEPTION(ex); - } - } - - return manifest; - } - - std::vector<ValidationError> YamlParser::ParseManifest(const YAML::Node& rootNode, Manifest& manifest, bool fullValidation) - { - // Detects empty files with a better error. - if (!rootNode.IsMap()) - { - THROW_EXCEPTION_MSG(ManifestException(APPINSTALLER_CLI_ERROR_INVALID_MANIFEST), "The manifest does not contain a valid root."); - } - - // Detect manifest version first to determine expected fields - // Use index to access ManifestVersion directly. If there're duplicates or other general errors, it'll be detected in later - // processing of iterating the whole manifest. - // Todo: make ManifestVersion required when all manifests in our repo have been updated to contain a ManifestVersion - if (rootNode["ManifestVersion"sv]) - { - auto manifestVersionValue = rootNode["ManifestVersion"sv].as<std::string>(); - manifest.ManifestVersion = ManifestVer(manifestVersionValue, false); - } - else - { - manifest.ManifestVersion = PreviewManifestVersion; - } - - // Check manifest version is supported - if (manifest.ManifestVersion.Major() > MaxSupportedMajorVersion) - { - THROW_EXCEPTION_MSG(ManifestException(APPINSTALLER_CLI_ERROR_UNSUPPORTED_MANIFESTVERSION), "Unsupported ManifestVersion: %S", manifest.ManifestVersion.ToString().c_str()); - } - - PrepareManifestFieldInfos(manifest.ManifestVersion); - - // Populate root fields - YAML::Node switchesNode; - YAML::Node installersNode; - YAML::Node localizationsNode; - m_p_switchesNode = &switchesNode; - m_p_installersNode = &installersNode; - m_p_localizationsNode = &localizationsNode; - m_p_manifest = &manifest; - auto resultErrors = ValidateAndProcessFields(rootNode, RootFieldInfos, fullValidation); - - // Populate root switches - if (!switchesNode.IsNull()) - { - m_p_switches = &manifest.Switches; - auto errors = ValidateAndProcessFields(switchesNode, SwitchesFieldInfos, fullValidation); - std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); - } - - // Populate installers - for (std::size_t i = 0; i < installersNode.size(); i++) - { - YAML::Node installerNode = installersNode[i]; - ManifestInstaller installer; - YAML::Node installerSwitchesNode; - - // Populate defaults - installer.InstallerType = manifest.InstallerType; - installer.Scope = "user"; - - m_p_installer = &installer; - m_p_switchesNode = &installerSwitchesNode; - auto errors = ValidateAndProcessFields(installerNode, InstallerFieldInfos, fullValidation); - std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); - - // Populate default known switches - installer.Switches = GetDefaultKnownSwitches(installer.InstallerType); - - // Override with switches from manifest root if applicable - for (auto const& keyValuePair : manifest.Switches) - { - installer.Switches[keyValuePair.first] = keyValuePair.second; - } - - // Override with switches from installer declaration if applicable - if (!installerSwitchesNode.IsNull()) - { - m_p_switches = &installer.Switches; - auto switchesErrors = ValidateAndProcessFields(installerSwitchesNode, SwitchesFieldInfos, fullValidation); - std::move(switchesErrors.begin(), switchesErrors.end(), std::inserter(resultErrors, resultErrors.end())); - } - - manifest.Installers.emplace_back(std::move(installer)); - } - - // Populate localization fields - if (!localizationsNode.IsNull()) - { - for (std::size_t i = 0; i < localizationsNode.size(); i++) - { - YAML::Node localizationNode = localizationsNode[i]; - ManifestLocalization localization; - - // Populates default values from root first - localization.Description = manifest.Description; - localization.Homepage = manifest.Homepage; - localization.LicenseUrl = manifest.LicenseUrl; - - m_p_localization = &localization; - auto errors = ValidateAndProcessFields(localizationNode, LocalizationFieldInfos, fullValidation); - std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); - manifest.Localization.emplace_back(std::move(localization)); - } - } - - // Extra semantic validations after basic validation and field population - if (fullValidation) - { - auto errors = ValidateManifest(manifest); - std::move(errors.begin(), errors.end(), std::inserter(resultErrors, resultErrors.end())); - } - - return resultErrors; - } - - std::vector<ValidationError> YamlParser::ValidateAndProcessFields( - const YAML::Node& rootNode, - const std::vector<ManifestFieldInfo>& fieldInfos, - bool fullValidation) - { - std::vector<ValidationError> errors; - - if (rootNode.size() == 0 || !rootNode.IsMap()) - { - errors.emplace_back(ManifestError::InvalidRootNode, "", "", rootNode.Mark().line, rootNode.Mark().column); - return errors; - } - - // Keeps track of already processed fields. Used to check duplicate fields or missing required fields. - std::set<std::string> processedFields; - - for (auto const& keyValuePair : rootNode.Mapping()) - { - std::string key = keyValuePair.first.as<std::string>(); - const YAML::Node& valueNode = keyValuePair.second; - - // We'll do case insensitive search first and validate correct case later. - auto fieldIter = std::find_if(fieldInfos.begin(), fieldInfos.end(), - [&](auto const& s) - { - return Utility::CaseInsensitiveEquals(s.Name, key); - }); - - if (fieldIter != fieldInfos.end()) - { - ManifestFieldInfo fieldInfo = *fieldIter; - - // Make sure the found key is in Pascal Case - if (key != fieldInfo.Name) - { - errors.emplace_back(ManifestError::FieldIsNotPascalCase, key, "", keyValuePair.first.Mark().line, keyValuePair.first.Mark().column); - } - - // Make sure it's not a duplicate key - if (!processedFields.insert(fieldInfo.Name).second) - { - errors.emplace_back(ManifestError::FieldDuplicate, fieldInfo.Name, "", keyValuePair.first.Mark().line, keyValuePair.first.Mark().column); - } - - // Validate non empty value is provided for required fields - if (fieldInfo.Required) - { - if (!valueNode.IsDefined() || valueNode.IsNull() || // Should be defined and not null - (valueNode.IsScalar() && valueNode.as<std::string>().empty()) || // Scalar type should have content - ((valueNode.IsMap() || valueNode.IsSequence()) && valueNode.size() == 0)) // Map or sequence type should have size greater than 0 - { - errors.emplace_back(ManifestError::RequiredFieldEmpty, fieldInfo.Name, "", valueNode.Mark().line, valueNode.Mark().column); - } - } - - // Validate value against regex if applicable - if (fullValidation && !fieldInfo.RegEx.empty()) - { - std::string value = valueNode.as<std::string>(); - std::regex pattern{ fieldInfo.RegEx }; - if (!std::regex_match(value, pattern)) - { - errors.emplace_back(ManifestError::InvalidFieldValue, fieldInfo.Name, value, valueNode.Mark().line, valueNode.Mark().column); - continue; - } - } - - if (!valueNode.IsNull()) - { - fieldInfo.ProcessFunc(valueNode); - } - } - else - { - // For full validation, also reports unrecognized fields as warning - if (fullValidation) - { - errors.emplace_back(ManifestError::FieldUnknown, key, "", keyValuePair.first.Mark().line, keyValuePair.first.Mark().column, ValidationError::Level::Warning); - } - } - } - - // Make sure required fields are provided - for (auto const& fieldInfo : fieldInfos) - { - if (fieldInfo.Required && processedFields.find(fieldInfo.Name) == processedFields.end()) - { - errors.emplace_back(ManifestError::RequiredFieldMissing, fieldInfo.Name); - } - } - - return errors; - } - - std::map<ManifestInstaller::InstallerSwitchType, ManifestInstaller::string_t> YamlParser::GetDefaultKnownSwitches( - ManifestInstaller::InstallerTypeEnum installerType) - { - switch (installerType) - { - case ManifestInstaller::InstallerTypeEnum::Burn: - case ManifestInstaller::InstallerTypeEnum::Wix: - case ManifestInstaller::InstallerTypeEnum::Msi: - return - { - {ManifestInstaller::InstallerSwitchType::Silent, ManifestInstaller::string_t("/quiet")}, - {ManifestInstaller::InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/passive")}, - {ManifestInstaller::InstallerSwitchType::Log, ManifestInstaller::string_t("/log \"" + std::string(ARG_TOKEN_LOGPATH) + "\"")}, - {ManifestInstaller::InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("TARGETDIR=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")} - }; - case ManifestInstaller::InstallerTypeEnum::Nullsoft: - return - { - {ManifestInstaller::InstallerSwitchType::Silent, ManifestInstaller::string_t("/S")}, - {ManifestInstaller::InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/S")}, - {ManifestInstaller::InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("/D=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")} - }; - case ManifestInstaller::InstallerTypeEnum::Inno: - return - { - {ManifestInstaller::InstallerSwitchType::Silent, ManifestInstaller::string_t("/VERYSILENT")}, - {ManifestInstaller::InstallerSwitchType::SilentWithProgress, ManifestInstaller::string_t("/SILENT")}, - {ManifestInstaller::InstallerSwitchType::Log, ManifestInstaller::string_t("/LOG=\"" + std::string(ARG_TOKEN_LOGPATH) + "\"")}, - {ManifestInstaller::InstallerSwitchType::InstallLocation, ManifestInstaller::string_t("/DIR=\"" + std::string(ARG_TOKEN_INSTALLPATH) + "\"")} - }; - } - return {}; - } -}- \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Manifest/YamlParser.h b/src/AppInstallerRepositoryCore/Manifest/YamlParser.h @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include "ManifestValidation.h" -#include "Manifest.h" - -#include <filesystem> - -namespace AppInstaller::Manifest -{ - static const uint64_t MaxSupportedMajorVersion = 1; - static const ManifestVer PreviewManifestVersion = ManifestVer("0.1.0", false); - static const ManifestVer PreviewManifestVersionMSStore = ManifestVer("0.2.0-msstore", false); - - struct YamlParser - { - // fullValidation: Bool to set if manifest creation should perform extra validation that client does not need. - // e.g. Channel should be null. Client code does not need this check to work properly. - // throwOnWarning: Bool to indicate if an exception should be thrown with only warnings detected in the manifest. - static Manifest CreateFromPath(const std::filesystem::path& inputFile, bool fullValidation = false, bool throwOnWarning = false); - - static Manifest Create(const std::string& input, bool fullValidation = false, bool throwOnWarning = false); - - private: - // These pointers are referenced in the processing functions in manifest field info table. - YAML::Node* m_p_installersNode = nullptr; - YAML::Node* m_p_switchesNode = nullptr; - YAML::Node* m_p_localizationsNode = nullptr; - AppInstaller::Manifest::Manifest* m_p_manifest = nullptr; - AppInstaller::Manifest::ManifestInstaller* m_p_installer = nullptr; - std::map<ManifestInstaller::InstallerSwitchType, Utility::NormalizedString>* m_p_switches = nullptr; - AppInstaller::Manifest::ManifestLocalization* m_p_localization = nullptr; - - // This struct contains individual app manifest field info - struct ManifestFieldInfo - { - std::string Name; - ManifestVer VerIntroduced; - std::function<void(const YAML::Node&)> ProcessFunc; - bool Required = false; - std::string RegEx = {}; - }; - - std::vector<ManifestFieldInfo> RootFieldInfos; - std::vector<ManifestFieldInfo> InstallerFieldInfos; - std::vector<ManifestFieldInfo> SwitchesFieldInfos; - std::vector<ManifestFieldInfo> LocalizationFieldInfos; - - std::vector<ValidationError> ParseManifest(const YAML::Node& rootNode, Manifest& manifest, bool fullValidation); - - static std::map<ManifestInstaller::InstallerSwitchType, Utility::NormalizedString> GetDefaultKnownSwitches( - ManifestInstaller::InstallerTypeEnum installerType); - - // This method takes YAML root node and list of manifest field info. - // Yaml-cpp does not support case insensitive search and it allows duplicate keys. If duplicate keys exist, - // the value is undefined. So in this method, we will iterate through the node map and process each individual - // pair ourselves. This also helps with generating aggregated error rather than throwing on first failure. - static std::vector<ValidationError> ValidateAndProcessFields( - const YAML::Node& rootNode, - const std::vector<ManifestFieldInfo>& fieldInfos, - bool fullValidation); - - void PrepareManifestFieldInfos(const ManifestVer& manifestVer); - void FilterManifestFieldInfos(std::vector<ManifestFieldInfo>& source, const ManifestVer& manifestVer); - }; -}- \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp @@ -3,7 +3,7 @@ #include "pch.h" #include "SQLiteIndex.h" #include "Schema/MetadataTable.h" -#include "Manifest/YamlParser.h" +#include <winget/ManifestYamlParser.h> namespace AppInstaller::Repository::Microsoft { diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h @@ -2,12 +2,12 @@ // Licensed under the MIT License. #pragma once #include "SQLiteWrapper.h" -#include "Manifest/Manifest.h" #include "Microsoft/Schema/ISQLiteIndex.h" #include "Microsoft/Schema/Version.h" #include "Public/AppInstallerRepositorySearch.h" #include <AppInstallerLanguageUtilities.h> #include <AppInstallerVersions.h> +#include <winget/Manifest.h> #include <chrono> #include <filesystem> diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp @@ -3,7 +3,7 @@ #include "pch.h" #include "Microsoft/SQLiteIndexSource.h" #include "Microsoft/PreIndexedPackageSourceFactory.h" -#include "Manifest/YamlParser.h" +#include <winget/ManifestYamlParser.h> namespace AppInstaller::Repository::Microsoft diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/ISQLiteIndex.h b/src/AppInstallerRepositoryCore/Microsoft/Schema/ISQLiteIndex.h @@ -2,10 +2,10 @@ // Licensed under the MIT License. #pragma once #include "SQLiteWrapper.h" -#include "Manifest/Manifest.h" #include "Microsoft/Schema/Version.h" #include "Public/AppInstallerRepositorySearch.h" #include <AppInstallerVersions.h> +#include <winget/Manifest.h> #include <filesystem> diff --git a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once -#include <Manifest/Manifest.h> #include <AppInstallerStrings.h> #include <AppInstallerVersions.h> #include <winget/LocIndependent.h> +#include <winget/Manifest.h> #include <memory> #include <optional> diff --git a/src/AppInstallerRepositoryCore/packages.config b/src/AppInstallerRepositoryCore/packages.config @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Microsoft.Windows.CppWinRT" version="2.0.191111.2" targetFramework="native" /> - <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.191107.2" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" /> </packages> \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/pch.h b/src/AppInstallerRepositoryCore/pch.h @@ -40,8 +40,6 @@ #include <initializer_list> #include <iomanip> #include <optional> -#include <regex> -#include <set> #include <string> #include <string_view> #include <sstream> diff --git a/src/WinGetUtil/Exports.cpp b/src/WinGetUtil/Exports.cpp @@ -8,8 +8,8 @@ #include <AppInstallerLogging.h> #include <AppInstallerStrings.h> #include <AppInstallerTelemetry.h> -#include <Manifest/YamlParser.h> #include <Microsoft/SQLiteIndex.h> +#include <winget/ManifestYamlParser.h> using namespace AppInstaller::Utility; using namespace AppInstaller::Manifest; diff --git a/src/WinGetUtil/WinGetUtil.vcxproj b/src/WinGetUtil/WinGetUtil.vcxproj @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" /> <PropertyGroup Label="Globals"> <CppWinRTOptimized>true</CppWinRTOptimized> <CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge> @@ -260,15 +260,15 @@ </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" /> - <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" /> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> </ImportGroup> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <PropertyGroup> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> </PropertyGroup> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.props'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.191111.2\build\native\Microsoft.Windows.CppWinRT.targets'))" /> - <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.191107.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" /> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> </Target> </Project> \ No newline at end of file diff --git a/src/WinGetUtil/packages.config b/src/WinGetUtil/packages.config @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <packages> - <package id="Microsoft.Windows.CppWinRT" version="2.0.191111.2" targetFramework="native" /> - <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.191107.2" targetFramework="native" /> + <package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" /> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" /> </packages> \ No newline at end of file diff --git a/src/WinGetYamlFuzzing/README.md b/src/WinGetYamlFuzzing/README.md @@ -0,0 +1,11 @@ +# WinGetYamlFuzzing +The goal of this project is to create a [libFuzzer](http://llvm.org/docs/LibFuzzer.html) based fuzzer for our YAML manifest loading. + +## Issues +Currently the fuzzer crashes when exceptions are thrown (built using the VS clang 10 package). This is suspected to be caused by the issue mentioned [here](https://github.com/google/oss-fuzz/issues/2328), +which while fixed, was also regressed. While investigation continues, the fuzzer is of little value. + +## Running +A script will be added when the issues are resolved and the fuzzer functions. In order to run it I have been doing the following: +1. Copy the CLITests TestData YAML files to a new corpus directory. +2. Run the following command: `WinGetYamlFuzzing.exe -dict=<full path to dictionary.txt in project> <path to corpus directory>`+ \ No newline at end of file diff --git a/src/WinGetYamlFuzzing/WinGetYamlFuzzing.cpp b/src/WinGetYamlFuzzing/WinGetYamlFuzzing.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include <cstdint> +#include <string> +#include <winget/ManifestYamlParser.h> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) +{ + std::string input{ reinterpret_cast<const char*>(data), size }; + + try + { + AppInstaller::Manifest::Manifest manifest = AppInstaller::Manifest::YamlParser::Create(input, true); + } + catch (...) {} + + return 0; +} diff --git a/src/WinGetYamlFuzzing/WinGetYamlFuzzing.vcxproj b/src/WinGetYamlFuzzing/WinGetYamlFuzzing.vcxproj @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Fuzzing|x64"> + <Configuration>Fuzzing</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <ProjectGuid>{1622da16-914f-4f57-a259-d5169003cc8c}</ProjectGuid> + <RootNamespace>WinGetYamlFuzzing</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>ClangCL</PlatformToolset> + <WholeProgramOptimization>false</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;WINGET_DISABLE_FOR_FUZZING;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <LanguageStandard>stdcpp17</LanguageStandard> + <AdditionalIncludeDirectories>$(ProjectDir)..\AppInstallerCommonCore\Public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <AdditionalOptions>-fsanitize=fuzzer,address %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>$(LLVMInstallDir)\lib\clang\10.0.0\lib\windows\clang_rt.asan-preinit-x86_64.lib;$(LLVMInstallDir)\lib\clang\10.0.0\lib\windows\clang_rt.asan-x86_64.lib;$(LLVMInstallDir)\lib\clang\10.0.0\lib\windows\clang_rt.asan_cxx-x86_64.lib;$(LLVMInstallDir)\lib\clang\10.0.0\lib\windows\clang_rt.fuzzer-x86_64.lib;icuuc.lib;icuin.lib;urlmon.lib;Bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="WinGetYamlFuzzing.cpp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\AppInstallerCommonCore\AppInstallerCommonCore.vcxproj"> + <Project>{5890d6ed-7c3b-40f3-b436-b54f640d9e65}</Project> + </ProjectReference> + <ProjectReference Include="..\YamlCppLib\YamlCppLib.vcxproj"> + <Project>{8bb94bb8-374f-4294-bca1-c7811514a6b7}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + <None Include="README.md" /> + </ItemGroup> + <ItemGroup> + <Text Include="dictionary.txt" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + <Import Project="$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" /> + </ImportGroup> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" /> + </Target> +</Project>+ \ No newline at end of file diff --git a/src/WinGetYamlFuzzing/WinGetYamlFuzzing.vcxproj.filters b/src/WinGetYamlFuzzing/WinGetYamlFuzzing.vcxproj.filters @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="WinGetYamlFuzzing.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + <None Include="README.md" /> + </ItemGroup> + <ItemGroup> + <Text Include="dictionary.txt" /> + </ItemGroup> +</Project>+ \ No newline at end of file diff --git a/src/WinGetYamlFuzzing/dictionary.txt b/src/WinGetYamlFuzzing/dictionary.txt @@ -0,0 +1,18 @@ +"[" +"]" +"{" +"}" +"-" +"," +"&" +"<<" +":" +"|" +"!!" +">" +"\"" +"'" + +integer="123" +float="12.5" +mantissa="1.3e+9" diff --git a/src/WinGetYamlFuzzing/packages.config b/src/WinGetYamlFuzzing/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" /> +</packages>+ \ No newline at end of file diff --git a/src/YamlCppLib/YamlCppLib.vcxproj b/src/YamlCppLib/YamlCppLib.vcxproj @@ -6,6 +6,7 @@ <Keyword>Win32Proj</Keyword> <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> </PropertyGroup> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|ARM"> @@ -20,6 +21,22 @@ <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|ARM"> + <Configuration>Fuzzing</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|ARM64"> + <Configuration>Fuzzing</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|Win32"> + <Configuration>Fuzzing</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Fuzzing|x64"> + <Configuration>Fuzzing</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> <ProjectConfiguration Include="Release|ARM"> <Configuration>Release</Configuration> <Platform>ARM</Platform> @@ -64,7 +81,8 @@ <ConfigurationType>StaticLibrary</ConfigurationType> <PlatformToolset>v140</PlatformToolset> <PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset> - <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0'">v142</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0' And '$(Configuration)'!='Fuzzing'">v142</PlatformToolset> + <PlatformToolset Condition="'$(VisualStudioVersion)' == '16.0' And '$(Configuration)'=='Fuzzing'">ClangCL</PlatformToolset> <CharacterSet>Unicode</CharacterSet> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> @@ -81,6 +99,11 @@ <WholeProgramOptimization>true</WholeProgramOptimization> <LinkIncremental>false</LinkIncremental> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)'=='Fuzzing'" Label="Configuration"> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>false</WholeProgramOptimization> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <LinkIncremental>true</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> @@ -101,18 +124,34 @@ <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)x86\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir> + </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> <ClCompile> <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> @@ -129,6 +168,14 @@ <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> </ClCompile> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM'"> + <ClCompile> + <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> + <LanguageStandard>stdcpp17</LanguageStandard> + <WarningLevel>Level3</WarningLevel> + <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> <ClCompile> <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> @@ -145,6 +192,14 @@ <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> </ClCompile> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|ARM64'"> + <ClCompile> + <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> + <LanguageStandard>stdcpp17</LanguageStandard> + <WarningLevel>Level3</WarningLevel> + <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> @@ -161,6 +216,14 @@ <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> </ClCompile> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> + <LanguageStandard>stdcpp17</LanguageStandard> + <WarningLevel>Level3</WarningLevel> + <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> + </ClCompile> + </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> @@ -177,6 +240,15 @@ <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H %(AdditionalOptions)</AdditionalOptions> </ClCompile> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Fuzzing|x64'"> + <ClCompile> + <AdditionalIncludeDirectories>libyaml\include;$(ProjectDir)</AdditionalIncludeDirectories> + <LanguageStandard>Default</LanguageStandard> + <WarningLevel>Level3</WarningLevel> + <AdditionalOptions>/D YAML_DECLARE_STATIC /D HAVE_CONFIG_H -fsanitize=fuzzer,address %(AdditionalOptions)</AdditionalOptions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + </ItemDefinitionGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup>