diff --git a/Documentation/known-issues.md b/Documentation/known-issues.md
index a5f8bb038..735164987 100644
--- a/Documentation/known-issues.md
+++ b/Documentation/known-issues.md
@@ -1,23 +1,6 @@
Known issues & workarounds
==========================
-## El Capitan support
-If you try to use the `dotnet` commands on El Capitan (OS X 10.11), you will encounter errors as it is not currently
-fully supported for all scenarios.
-
-**Issues tracking this:**
-
-* [#498](https://github.com/dotnet/cli/issues/498)
-* [#291](https://github.com/dotnet/cli/issues/291)
-
-**Affects:** most of the commands, but more than likely you will not be able to
-use `dotnet compile` and `dotnet-run` on El Capitan. For others, there is a
-workaround.
-
-**Workaround:** use the --runtime switch with the value of `osx.10.11-x64` in
-`dotnet restore` and `dotnet publish` and you will be able to run your app from
-the published directory.
-
## Resolving the Standard library packages
The StdLib package is on a MyGet feed. In order to restore it, a MyGet feed needs to be added
to the NuGet feeds, either locally per application or in a central location.
diff --git a/Documentation/specs/runtime-configuration-file.md b/Documentation/specs/runtime-configuration-file.md
index f35de1ec7..ff2df4c33 100644
--- a/Documentation/specs/runtime-configuration-file.md
+++ b/Documentation/specs/runtime-configuration-file.md
@@ -29,7 +29,8 @@ The files are both JSON files stored in UTF-8 encoding. Below are sample files.
"gcConcurrent": false,
"framework": {
"name": "Microsoft.DotNetCore",
- "version": "1.0.1"
+ "version": "1.0.1",
+ "rollForward": false,
}
}
}
@@ -118,7 +119,11 @@ This section is copied verbatim from an identical section in the input `project.
* `gcServer` - Boolean indicating if the server GC should be used (Default: _TBD_). Note: This is designed to mirror the existing [app.config](https://msdn.microsoft.com/en-us/library/ms229357.aspx) setting)
* `gcConcurrent` - Boolean indicating if background garbage collection should be used (Default: _TBD_). Note: This is designed to mirror the existing [app.config](https://msdn.microsoft.com/en-us/library/yhwwzef8.aspx) setting).
-* `framework` - Indicates the name and version of the shared framework to use when activating the application. The presence of this section indicates that the application is a portable app designed to use a shared redistributable framework.
+* `framework` - Indicates the `name`, `version`, and other properties of the shared framework to use when activating the application. The presence of this section indicates that the application is a portable app designed to use a shared redistributable framework.
+ * `rollForward` - When `false`, the framework version is strictly obeyed by the host. When `rollForward` is unspecified or specified as `true`, the framework from either the same or a higher version that differs only in the `SemVer` patch field will be used.
+ * For example, if `version=1.0.1` and `rollForward` is `true`, the host would load the shared framework from `1.0.{n}`, where `n >= 1`, but will not load from `1.1.0`, even if present. When `rollForward` is `false`, the shared framework will be loaded from `1.0.1` strictly.
+ * **Note:** This does not apply to `SemVer`'s `prerelease` versions, but only for `production` releases.
+ * **Note:** This section will not be present for standalone applications that do not rely upon a shared framework.
* Others _TBD_
These settings are read by `corehost` to determine how to initialize the runtime. All versions of `corehost` **must ignore** settings in this section that they do not understand (thus allowing new settings to be added in later versions).
diff --git a/TestAssets/FSharpTestProjects/CompileFail/project.json b/TestAssets/FSharpTestProjects/CompileFail/project.json
index 40621376b..84d87f6df 100644
--- a/TestAssets/FSharpTestProjects/CompileFail/project.json
+++ b/TestAssets/FSharpTestProjects/CompileFail/project.json
@@ -1,20 +1,19 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
- "compilerName": "fsc",
- "compileFiles": [
- "Program.fs"
- ],
- "dependencies": {
- "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221",
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "compilerName": "fsc",
+ "compileFiles": [
+ "Program.fs"
+ ],
+ "dependencies": {
+ "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj b/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj
index 4b792e869..e48ab0105 100644
--- a/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj
+++ b/TestAssets/FSharpTestProjects/TestApp/FSharpTestApp.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
a666217d-2aca-4866-b109-ea476e51c7aa
FSharpTestApp
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/FSharpTestProjects/TestApp/project.json b/TestAssets/FSharpTestProjects/TestApp/project.json
index 141270ca8..90fcb92b9 100644
--- a/TestAssets/FSharpTestProjects/TestApp/project.json
+++ b/TestAssets/FSharpTestProjects/TestApp/project.json
@@ -1,21 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
- "compilerName": "fsc",
- "compileFiles": [
- "Program.fs"
- ],
- "dependencies": {
- "TestLibrary": "1.0.0-*",
- "NETStandard.Library": "1.0.0-rc2-23901",
- "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "compilerName": "fsc",
+ "compileFiles": [
+ "Program.fs"
+ ],
+ "dependencies": {
+ "TestLibrary": "1.0.0-*",
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json b/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json
index 40621376b..84d87f6df 100644
--- a/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json
+++ b/TestAssets/FSharpTestProjects/TestAppWithArgs/project.json
@@ -1,20 +1,19 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
- "compilerName": "fsc",
- "compileFiles": [
- "Program.fs"
- ],
- "dependencies": {
- "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221",
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "compilerName": "fsc",
+ "compileFiles": [
+ "Program.fs"
+ ],
+ "dependencies": {
+ "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj b/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj
index ae10bbff6..de36bbed6 100644
--- a/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj
+++ b/TestAssets/FSharpTestProjects/TestLibrary/FSharpTestLibrary.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
ec801982-096b-4af3-a42b-7881b1a7380e
FSharpTestLibrary
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/FSharpTestProjects/TestLibrary/project.json b/TestAssets/FSharpTestProjects/TestLibrary/project.json
index 61961870b..0b29b1792 100644
--- a/TestAssets/FSharpTestProjects/TestLibrary/project.json
+++ b/TestAssets/FSharpTestProjects/TestLibrary/project.json
@@ -1,17 +1,17 @@
{
- "version": "1.0.0-*",
- "dependencies": {
- "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221",
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
- "compilerName": "fsc",
- "compileFiles": [
- "Helper2.fs",
- "Helper.fs"
- ],
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "compilerName": "fsc",
+ "compileFiles": [
+ "Helper2.fs",
+ "Helper.fs"
+ ],
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json
index d183d244f..7ce8666ac 100644
--- a/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json
+++ b/TestAssets/ProjectModelServer/DthTestProjects/src/BrokenProjectPathSample/project.json
@@ -1,11 +1,11 @@
{
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "EmptyLibrary": "1.0.0-*"
- },
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "EmptyLibrary": "1.0.0-*"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json
index 38a3ba296..a81519a70 100644
--- a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json
+++ b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyConsoleApp/project.json
@@ -1,12 +1,12 @@
{
- "dependencies": { },
+ "dependencies": {},
"frameworks": {
"netstandardapp1.5": {
"imports": "dnxcore50",
"dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
+ "NETStandard.Library": "1.5.0-rc2-23911"
}
},
- "dnx451": { }
+ "dnx451": {}
}
}
diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json
index 667685804..17c4e9e46 100644
--- a/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json
+++ b/TestAssets/ProjectModelServer/DthTestProjects/src/EmptyLibrary/project.json
@@ -1,11 +1,11 @@
{
"version": "1.0.0-*",
- "dependencies": { },
+ "dependencies": {},
"frameworks": {
"netstandard1.3": {
"imports": "dnxcore50",
"dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
+ "NETStandard.Library": "1.5.0-rc2-23911"
}
}
}
diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json
index 505047ad2..83b5d4335 100644
--- a/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json
+++ b/TestAssets/ProjectModelServer/DthTestProjects/src/FailReleaseProject/project.json
@@ -3,9 +3,9 @@
"netstandardapp1.5": {
"imports": "dnxcore50",
"dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
+ "NETStandard.Library": "1.5.0-rc2-23911"
}
}
},
- "dependencies": { }
+ "dependencies": {}
}
diff --git a/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json b/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json
index 58af503dc..37a82e632 100644
--- a/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json
+++ b/TestAssets/ProjectModelServer/DthTestProjects/src/IncompatiblePackageSample/project.json
@@ -1,11 +1,11 @@
{
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "Microsoft.Web.Administration": "7.0.0"
- },
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "Microsoft.Web.Administration": "7.0.0"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json b/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json
index 8c87d36c9..bb3a9cebf 100755
--- a/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json
+++ b/TestAssets/ProjectModelServer/IncorrectGlobalJson/src/Project1/project.json
@@ -1,14 +1,12 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23811"
- },
-
- "frameworks": {
- "dnxcore50": { }
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "dnxcore50": {}
+ }
}
diff --git a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj
index 635819547..d49a161f4 100644
--- a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj
+++ b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/dotnet-hello.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
b8055234-9a66-4ba0-8b4c-d5e431494fe3
dotnet-hello
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json
index ea118a24d..cafaf976b 100644
--- a/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json
+++ b/TestAssets/TestPackages/dotnet-hello/v1/dotnet-hello/project.json
@@ -1,16 +1,14 @@
{
- "version": "1.0.0",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj
index 7011c102d..7c2da659a 100644
--- a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj
+++ b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/dotnet-hello.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
282c5014-d0cd-4dde-af4e-531e4a2e7bcd
dotnet-hello
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json
index 464f94681..c1bd9c205 100644
--- a/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json
+++ b/TestAssets/TestPackages/dotnet-hello/v2/dotnet-hello/project.json
@@ -1,16 +1,14 @@
{
- "version": "2.0.0",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "2.0.0",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json b/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json
index 679acc364..7bcb08e63 100644
--- a/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json
+++ b/TestAssets/TestProjects/AppWithDirectAndToolDependency/project.json
@@ -1,23 +1,25 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "dotnet-hello": { "version": "1.0.0", "target": "package" }
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
- },
-
- "testRunner": "must-be-specified-to-generate-deps",
-
- "tools": {
- "dotnet-hello": { "version": "2.0.0", "target": "package" }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "dotnet-hello": {
+ "version": "1.0.0",
+ "target": "package"
}
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
+ }
+ },
+ "testRunner": "must-be-specified-to-generate-deps",
+ "tools": {
+ "dotnet-hello": {
+ "version": "2.0.0",
+ "target": "package"
+ }
+ }
}
diff --git a/TestAssets/TestProjects/AppWithDirectDependency/project.json b/TestAssets/TestProjects/AppWithDirectDependency/project.json
index 2ce5cf482..14cc1022a 100644
--- a/TestAssets/TestProjects/AppWithDirectDependency/project.json
+++ b/TestAssets/TestProjects/AppWithDirectDependency/project.json
@@ -1,19 +1,19 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "testRunner": "must-be-specified-to-generate-deps",
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "dotnet-hello": {"version": "1.0.0", "target": "package"}
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "testRunner": "must-be-specified-to-generate-deps",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "dotnet-hello": {
+ "version": "1.0.0",
+ "target": "package"
}
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
+ }
+ }
}
diff --git a/TestAssets/TestProjects/AppWithToolDependency/project.json b/TestAssets/TestProjects/AppWithToolDependency/project.json
index 9537feb8f..4628c7718 100644
--- a/TestAssets/TestProjects/AppWithToolDependency/project.json
+++ b/TestAssets/TestProjects/AppWithToolDependency/project.json
@@ -1,20 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
- },
-
- "tools": {
- "dotnet-hello": { "version": "2.0.0", "target": "package" }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ },
+ "tools": {
+ "dotnet-hello": {
+ "version": "2.0.0",
+ "target": "package"
+ }
+ }
}
diff --git a/TestAssets/TestProjects/CompileFail/project.json b/TestAssets/TestProjects/CompileFail/project.json
index c02d0dffe..2e5ebbe30 100644
--- a/TestAssets/TestProjects/CompileFail/project.json
+++ b/TestAssets/TestProjects/CompileFail/project.json
@@ -1,16 +1,14 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj
index c827617ac..8a2f395fd 100644
--- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj
+++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/DependencyContextValidator.xproj
@@ -4,7 +4,7 @@
14.0.24720
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
6d84ef36-a5d5-4eaf-b38b-ced635473785
DependencyContextValidator
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json
index 90a5334e8..00cd67349 100644
--- a/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json
+++ b/TestAssets/TestProjects/DependencyContextValidator/DependencyContextValidator/project.json
@@ -1,16 +1,15 @@
{
- "version": "1.0.0-*",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "Microsoft.Extensions.DependencyModel": {
- "target": "project",
- "version": "1.0.0-*"
- }
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "Microsoft.Extensions.DependencyModel": {
+ "target": "project",
+ "version": "1.0.0-*"
}
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
+ }
+ }
}
diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json
index 4c2908690..965a3f06e 100644
--- a/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json
+++ b/TestAssets/TestProjects/DependencyContextValidator/TestApp/project.json
@@ -1,18 +1,16 @@
-{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true,
- "preserveCompilationContext": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "DependencyContextValidator": "1.0.0-*"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+{
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true,
+ "preserveCompilationContext": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "DependencyContextValidator": "1.0.0-*"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json b/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json
index 9f1f402f6..f41c7127f 100644
--- a/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json
+++ b/TestAssets/TestProjects/DependencyContextValidator/TestAppDeps/project.json
@@ -1,17 +1,15 @@
-{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "DependencyContextValidator": "1.0.0-*"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+{
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "DependencyContextValidator": "1.0.0-*"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj b/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj
index ee6ccb69d..0443b706a 100644
--- a/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj
+++ b/TestAssets/TestProjects/OutputStandardOutputAndError/OutputStandardOutputAndError.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4902145eda4e
OutputStandardOutputAndError
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/OutputStandardOutputAndError/project.json b/TestAssets/TestProjects/OutputStandardOutputAndError/project.json
index c02d0dffe..2e5ebbe30 100644
--- a/TestAssets/TestProjects/OutputStandardOutputAndError/project.json
+++ b/TestAssets/TestProjects/OutputStandardOutputAndError/project.json
@@ -1,16 +1,14 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/PortableTests/PortableApp/project.json b/TestAssets/TestProjects/PortableTests/PortableApp/project.json
index 4386a64ac..3111191ad 100644
--- a/TestAssets/TestProjects/PortableTests/PortableApp/project.json
+++ b/TestAssets/TestProjects/PortableTests/PortableApp/project.json
@@ -1,18 +1,17 @@
{
- "compilationOptions": {
- "emitEntryPoint": true
- },
- "dependencies": {
- },
- "frameworks": {
- "netstandard1.5": {
- "imports": [
- "dnxcore50",
- "portable-net45+win8"
- ],
- "dependencies": {
- "Microsoft.NETCore.App": "1.0.0-rc2-23911"
- }
- }
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {},
+ "frameworks": {
+ "netstandard1.5": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+win8"
+ ],
+ "dependencies": {
+ "Microsoft.NETCore.App": "1.0.0-rc2-23911"
+ }
}
+ }
}
diff --git a/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json b/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json
index eaae7c1cd..2cf04776c 100644
--- a/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json
+++ b/TestAssets/TestProjects/PortableTests/StandaloneApp/project.json
@@ -1,26 +1,26 @@
{
- "compilationOptions": {
- "emitEntryPoint": true
- },
- "frameworks": {
- "netstandardapp1.5": {
- "imports": [
- "dnxcore50",
- "portable-net45+win8"
- ],
- "dependencies": {
- "Microsoft.NETCore.App": "1.0.0-rc2-23911"
- }
- }
- },
- "runtimes": {
- "win7-x64": {},
- "win7-x86": {},
- "osx.10.10-x64": {},
- "osx.10.11-x64": {},
- "ubuntu.14.04-x64": {},
- "centos.7-x64": {},
- "rhel.7.2-x64": {},
- "debian.8.2-x64": {}
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+win8"
+ ],
+ "dependencies": {
+ "Microsoft.NETCore.App": "1.0.0-rc2-23911"
+ }
}
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "win7-x86": { },
+ "osx.10.10-x64": { },
+ "osx.10.11-x64": { },
+ "ubuntu.14.04-x64": { },
+ "centos.7-x64": { },
+ "rhel.7.2-x64": { },
+ "debian.8.2-x64": { }
+ }
}
diff --git a/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json b/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json
index 5ed30dfa4..a081d6a7d 100644
--- a/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json
+++ b/TestAssets/TestProjects/RunTestsApps/TestAppMultiTarget/project.json
@@ -1,16 +1,15 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ }
},
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- }
- },
- "net451": { }
- }
+ "net451": {}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json b/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json
index ded1b2439..6df0b0c6d 100644
--- a/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json
+++ b/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json
@@ -1,19 +1,16 @@
-{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true,
- "preserveCompilationContext": true
- },
-
- "dependencies": {
- "TestLibrary": "1.0.0-*",
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+{
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true,
+ "preserveCompilationContext": true
+ },
+ "dependencies": {
+ "TestLibrary": "1.0.0-*",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj
index eb9f8bc2d..ae7910d0d 100644
--- a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj
+++ b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
947dd232-8d9b-4b78-9c6a-94f807d2dd58
TestLibrary
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json
index dce6a0dad..f0b60ee88 100644
--- a/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json
+++ b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json
@@ -1,17 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "nowarn": [ "CS1591" ],
- "xmlDoc": true,
- "additionalArguments": [ "-highentropyva+" ]
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "nowarn": [
+ "CS1591"
+ ],
+ "xmlDoc": true,
+ "additionalArguments": [
+ "-highentropyva+"
+ ]
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj b/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj
index fbd214cbd..70d47bf5c 100644
--- a/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj
+++ b/TestAssets/TestProjects/TestAppWithArgs/TestAppWithArgs.xproj
@@ -4,7 +4,7 @@
14.0.23107
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
da8e0e9e-a6d6-4583-864c-8f40465e3a48
TestAppWithArgs
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithArgs/project.json b/TestAssets/TestProjects/TestAppWithArgs/project.json
index c02d0dffe..2e5ebbe30 100644
--- a/TestAssets/TestProjects/TestAppWithArgs/project.json
+++ b/TestAssets/TestProjects/TestAppWithArgs/project.json
@@ -1,16 +1,14 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj
index 718199108..7cc51e6eb 100644
--- a/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj
+++ b/TestAssets/TestProjects/TestAppWithContentPackage/TestAppWithContentPackage.xproj
@@ -4,7 +4,7 @@
14.0.24720
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
ea239e10-75e8-4305-966e-fec926a5aee6
TestAppWithContentPackage
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithContentPackage/project.json b/TestAssets/TestProjects/TestAppWithContentPackage/project.json
index 43575128d..6e9d2a179 100644
--- a/TestAssets/TestProjects/TestAppWithContentPackage/project.json
+++ b/TestAssets/TestProjects/TestAppWithContentPackage/project.json
@@ -1,11 +1,10 @@
-{
+{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
-
"dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
+ "NETStandard.Library": "1.5.0-rc2-23911",
"SharedContentA": "1.0.0-*"
},
"frameworks": {
@@ -13,4 +12,4 @@
"imports": "dnxcore50"
}
}
-}
\ No newline at end of file
+}
diff --git a/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj b/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj
index 00103e020..1f1eafbea 100644
--- a/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj
+++ b/TestAssets/TestProjects/TestAppWithContents/TestAppWithContents.xproj
@@ -4,7 +4,7 @@
14.0.23107
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
0138cb8f-4aa9-4029-a21e-c07c30f425ba
TestAppWithContents
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithContents/project.json b/TestAssets/TestProjects/TestAppWithContents/project.json
index c149fddc2..e5f81bb6f 100644
--- a/TestAssets/TestProjects/TestAppWithContents/project.json
+++ b/TestAssets/TestProjects/TestAppWithContents/project.json
@@ -1,18 +1,15 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "content": "testcontentfile.txt",
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "content": "testcontentfile.txt",
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj
index 4cef17daa..75b98c80d 100644
--- a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4902145eda4e
TestApp
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json
index f9f77f358..88dd7cbee 100644
--- a/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json
@@ -1,19 +1,19 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true,
- "preserveCompilationContext": true
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true,
+ "preserveCompilationContext": true
+ },
+ "dependencies": {
+ "TestLibrary": {
+ "target": "project",
+ "version": "1.0.0-*"
},
-
- "dependencies": {
- "TestLibrary": { "target":"project", "version":"1.0.0-*" },
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj
index eb9f8bc2d..ae7910d0d 100644
--- a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
947dd232-8d9b-4b78-9c6a-94f807d2dd58
TestLibrary
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json
index 8e8b984b1..f0b60ee88 100644
--- a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json
@@ -1,17 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "nowarn": [ "CS1591" ],
- "xmlDoc": true,
- "additionalArguments": [ "-highentropyva+" ]
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23811"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "nowarn": [
+ "CS1591"
+ ],
+ "xmlDoc": true,
+ "additionalArguments": [
+ "-highentropyva+"
+ ]
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj b/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj
index 4cef17daa..75b98c80d 100644
--- a/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj
+++ b/TestAssets/TestProjects/TestAppWithScripts/TestApp.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4902145eda4e
TestApp
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/TestAppWithScripts/project.json b/TestAssets/TestProjects/TestAppWithScripts/project.json
index 8de4803d7..11692199c 100644
--- a/TestAssets/TestProjects/TestAppWithScripts/project.json
+++ b/TestAssets/TestProjects/TestAppWithScripts/project.json
@@ -1,24 +1,21 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
- },
-
- "scripts": {
- "prepublish" : ["echoscript prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?"],
- "postpublish" : ["echoscript postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?"],
-
- "precompile" : ["echoscript precompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?"],
- "postcompile" : ["echoscript postcompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?"]
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ },
+ "scripts": {
+ "prepublish": [ "echoscript prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?" ],
+ "postpublish": [ "echoscript postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:TargetFramework%? ?%publish:Runtime%?" ],
+
+ "precompile": [ "echoscript precompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?" ],
+ "postcompile": [ "echoscript postcompile_output ?%compile:ProjectPath%? ?%compile:Configuration%? ?%compile:OutputPath%? ?%compile:TargetFramework%? ?%compile:Runtime%?" ]
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj
index 4cef17daa..75b98c80d 100644
--- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj
+++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/TestApp.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4902145eda4e
TestApp
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json
index a1cb82f95..efafdef41 100644
--- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json
+++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestApp/project.json
@@ -1,24 +1,27 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true,
- "preserveCompilationContext": true
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true,
+ "preserveCompilationContext": true
+ },
+ "dependencies": {
+ "TestLibrary": {
+ "target": "project",
+ "version": "1.0.0-*"
},
-
- "dependencies": {
- "TestLibrary": { "target":"project", "version":"1.0.0-*" },
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
- },
-
- "scripts": {
- "prepublish" : ["echo prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"],
- "postpublish" : ["echo postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"]
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ },
+ "scripts": {
+ "prepublish": [
+ "echo prepublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"
+ ],
+ "postpublish": [
+ "echo postpublish_output ?%publish:ProjectPath%? ?%publish:Configuration%? ?%publish:OutputPath%? ?%publish:Framework%? ?%publish:Runtime%?"
+ ]
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj
index eb9f8bc2d..ae7910d0d 100644
--- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj
+++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/TestLibrary.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
947dd232-8d9b-4b78-9c6a-94f807d2dd58
TestLibrary
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json
index dce6a0dad..f0b60ee88 100644
--- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json
+++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary/project.json
@@ -1,17 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "nowarn": [ "CS1591" ],
- "xmlDoc": true,
- "additionalArguments": [ "-highentropyva+" ]
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "nowarn": [
+ "CS1591"
+ ],
+ "xmlDoc": true,
+ "additionalArguments": [
+ "-highentropyva+"
+ ]
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json
index 06a4d2157..bc94bb833 100644
--- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json
+++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibrary2/project.json
@@ -1,18 +1,18 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "TestLibraryWithAppDependency": {
+ "target": "project",
+ "version": "1.0.0-*"
},
-
- "dependencies": {
- "TestLibraryWithAppDependency": { "target":"project", "version":"1.0.0-*" },
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json
index 42c1b5f55..9b7ae73b7 100644
--- a/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json
+++ b/TestAssets/TestProjects/TestAppWithTransitiveAppDependency/TestLibraryWithAppDependency/project.json
@@ -1,14 +1,15 @@
{
- "version": "1.0.0-*",
- "dependencies": {
- "TestApp": { "target":"project", "version":"1.0.0-*" },
-
- "NETStandard.Library": "1.0.0-rc2-23901"
+ "version": "1.0.0-*",
+ "dependencies": {
+ "TestApp": {
+ "target": "project",
+ "version": "1.0.0-*"
},
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj
index 4cef17daa..75b98c80d 100644
--- a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj
+++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/TestApp.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4902145eda4e
TestApp
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json
index f9f77f358..88dd7cbee 100644
--- a/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json
+++ b/TestAssets/TestProjects/TestAppWithWrapperProjectDependency/TestApp/project.json
@@ -1,19 +1,19 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true,
- "preserveCompilationContext": true
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true,
+ "preserveCompilationContext": true
+ },
+ "dependencies": {
+ "TestLibrary": {
+ "target": "project",
+ "version": "1.0.0-*"
},
-
- "dependencies": {
- "TestLibrary": { "target":"project", "version":"1.0.0-*" },
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json
index 4b957d224..6254293c5 100644
--- a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json
+++ b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryGreater/project.json
@@ -1,20 +1,19 @@
-{
- "version": "1.0.0-*",
- "testRunner": "xunit",
- "dependencies": {
- "Newtonsoft.Json": "7.0.1"
- },
-
- "frameworks": {
- "net451": { },
- "netstandardapp1.5": {
- "imports": [
- "dnxcore50",
- "portable-net45+wp80+win8"
- ],
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- }
- }
+{
+ "version": "1.0.0-*",
+ "testRunner": "xunit",
+ "dependencies": {
+ "Newtonsoft.Json": "7.0.1"
+ },
+ "frameworks": {
+ "net451": {},
+ "netstandardapp1.5": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+wp80+win8"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ }
}
+ }
}
diff --git a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json
index 0cfc9606d..f1bb8120d 100644
--- a/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json
+++ b/TestAssets/TestProjects/TestBindingRedirectGeneration/TestLibraryLesser/project.json
@@ -1,21 +1,22 @@
{
- "version": "1.0.0-*",
- "testRunner": "xunit",
- "dependencies": {
- "Newtonsoft.Json": "6.0.0",
- "TestLibraryGreater": {"target":"project"}
- },
-
- "frameworks": {
- "net451": { },
- "netstandardapp1.5": {
- "imports": [
- "dnxcore50",
- "portable-net45+wp80+win8"
- ],
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- }
- }
+ "version": "1.0.0-*",
+ "testRunner": "xunit",
+ "dependencies": {
+ "Newtonsoft.Json": "6.0.0",
+ "TestLibraryGreater": {
+ "target": "project"
}
+ },
+ "frameworks": {
+ "net451": {},
+ "netstandardapp1.5": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+wp80+win8"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ }
+ }
+ }
}
diff --git a/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json b/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json
index 126757ed1..930858382 100644
--- a/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json
+++ b/TestAssets/TestProjects/TestLibraryWithAnalyzer/project.json
@@ -1,17 +1,18 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.Runtime.Analyzers": { "version": "1.1.0", "type": "build" }
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.Runtime.Analyzers": {
+ "version": "1.1.0",
+ "type": "build"
}
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
+ }
+ }
}
diff --git a/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json b/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json
index 731ac1d10..a4c57dce6 100644
--- a/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json
+++ b/TestAssets/TestProjects/TestLibraryWithConfiguration/project.json
@@ -1,21 +1,23 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "nowarn": [ "CS1591" ],
- "xmlDoc": true,
- "additionalArguments": [ "-highentropyva+" ]
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
- "configurations": {
- "Test": {
-
- }
- },
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "nowarn": [
+ "CS1591"
+ ],
+ "xmlDoc": true,
+ "additionalArguments": [
+ "-highentropyva+"
+ ]
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "configurations": {
+ "Test": {}
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json
index 391a5fc11..f12c8dafa 100644
--- a/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json
+++ b/TestAssets/TestProjects/TestLibraryWithMultipleFrameworks/project.json
@@ -1,21 +1,19 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": false
- },
-
- "dependencies": { },
-
- "frameworks": {
- "net20": { },
- "net35": { },
- "net40": { },
- "net461": { },
- "netstandardapp1.5": {
- "imports": "dnxcore50",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- }
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": false
+ },
+ "dependencies": {},
+ "frameworks": {
+ "net20": {},
+ "net35": {},
+ "net40": {},
+ "net461": {},
+ "netstandardapp1.5": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ }
}
+ }
}
diff --git a/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json b/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json
index 8f97305eb..8d78b8ecc 100644
--- a/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json
+++ b/TestAssets/TestProjects/TestMicrosoftCSharpReference/project.json
@@ -1,17 +1,17 @@
{
- "version": "1.0.0",
- "dependencies": { },
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- }
- },
- "dnx451": {
- "dependencies": {
- "Microsoft.CSharp": "4.0.1-*"
- }
- }
+ "version": "1.0.0",
+ "dependencies": {},
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ }
+ },
+ "dnx451": {
+ "dependencies": {
+ "Microsoft.CSharp": "4.0.1-rc2-23911"
+ }
}
-}
\ No newline at end of file
+ }
+}
diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json
index ef971a748..06f18fa20 100644
--- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json
+++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L0/project.json
@@ -1,19 +1,16 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "L11": "1.0.0-*",
- "L12": "1.0.0-*",
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "L11": "1.0.0-*",
+ "L12": "1.0.0-*",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json
index ed55b003b..ed65c4c04 100644
--- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json
+++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L11/project.json
@@ -1,16 +1,13 @@
{
- "version": "1.0.0-*",
-
- "dependencies": {
- "L12": "1.0.0-*",
- "L21": "1.0.0-*",
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "L12": "1.0.0-*",
+ "L21": "1.0.0-*",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json
index ac03a9cf7..e9486914f 100644
--- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json
+++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L12/project.json
@@ -1,15 +1,12 @@
{
- "version": "1.0.0-*",
-
- "dependencies": {
- "L22": "1.0.0-*",
-
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "L22": "1.0.0-*",
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json
index 8af014e51..155cb2f02 100644
--- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json
+++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L21/project.json
@@ -1,13 +1,11 @@
{
- "version": "1.0.0-*",
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json
index 8af014e51..155cb2f02 100644
--- a/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json
+++ b/TestAssets/TestProjects/TestProjectToProjectDependencies/src/L22/project.json
@@ -1,13 +1,11 @@
{
- "version": "1.0.0-*",
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj
index d8121765f..f09a83c44 100644
--- a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj
+++ b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/TestProjectWithCultureSpecificResource.xproj
@@ -4,7 +4,7 @@
14.0.24720
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
fea4ab27-d004-4580-8abe-b171e30b68cc
TestProjectWithCultureSpecificResource
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json
index c02d0dffe..2e5ebbe30 100644
--- a/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json
+++ b/TestAssets/TestProjects/TestProjectWithCultureSpecificResource/project.json
@@ -1,16 +1,14 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj b/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj
index aee14e286..cc3bb2c74 100644
--- a/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj
+++ b/TestAssets/TestProjects/TestProjectWithResource/TestProjectWithResource.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4909876ed864
TestProjectWithResource
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/TestProjectWithResource/project.json b/TestAssets/TestProjects/TestProjectWithResource/project.json
index c02d0dffe..2e5ebbe30 100644
--- a/TestAssets/TestProjects/TestProjectWithResource/project.json
+++ b/TestAssets/TestProjects/TestProjectWithResource/project.json
@@ -1,16 +1,14 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj b/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj
index 088568e54..518aa7600 100644
--- a/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj
+++ b/TestAssets/TestProjects/TestSimpleIncrementalApp/TestApp.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
58808bbc-371e-47d6-a3d0-4902145edaaa
TestSimpleIncrementalApp
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json b/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json
index 3605210ec..7c888a5ad 100644
--- a/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json
+++ b/TestAssets/TestProjects/TestSimpleIncrementalApp/project.json
@@ -1,17 +1,15 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "emitEntryPoint": true,
- "xmlDoc": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "emitEntryPoint": true,
+ "xmlDoc": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/packaging/host/windows/host.wxs b/packaging/host/windows/host.wxs
index 736beb665..a2bc03f95 100644
--- a/packaging/host/windows/host.wxs
+++ b/packaging/host/windows/host.wxs
@@ -38,6 +38,7 @@
+
diff --git a/packaging/host/windows/registrykeys.wxs b/packaging/host/windows/registrykeys.wxs
index 6f5a3cad0..3d971599b 100644
--- a/packaging/host/windows/registrykeys.wxs
+++ b/packaging/host/windows/registrykeys.wxs
@@ -10,16 +10,18 @@
+
-
+
+
diff --git a/packaging/windows/bundle.wxs b/packaging/windows/bundle.wxs
index 6999e8a3c..664087a99 100644
--- a/packaging/windows/bundle.wxs
+++ b/packaging/windows/bundle.wxs
@@ -32,7 +32,13 @@
-
+
+
+
+
+
+
+
diff --git a/packaging/windows/generatebundle.ps1 b/packaging/windows/generatebundle.ps1
index e50300363..dd73daaaa 100644
--- a/packaging/windows/generatebundle.ps1
+++ b/packaging/windows/generatebundle.ps1
@@ -2,7 +2,9 @@
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
param(
- [Parameter(Mandatory=$true)][string]$DotnetMSIFile,
+ [Parameter(Mandatory=$true)][string]$CLISDKMSIFile,
+ [Parameter(Mandatory=$true)][string]$SharedFxMSIFile,
+ [Parameter(Mandatory=$true)][string]$SharedHostMSIFile,
[Parameter(Mandatory=$true)][string]$DotnetBundleOutput,
[Parameter(Mandatory=$true)][string]$WixRoot,
[Parameter(Mandatory=$true)][string]$DotnetMSIVersion,
@@ -28,7 +30,9 @@ function RunCandleForBundle
-dBuildVersion="$DotnetMSIVersion" `
-dDisplayVersion="$DotnetCLIVersion" `
-dReleaseSuffix="$ReleaseSuffix" `
- -dMsiSourcePath="$DotnetMSIFile" `
+ -dCLISDKMsiSourcePath="$CLISDKMSIFile" `
+ -dSharedFXMsiSourcePath="$SharedFxMSIFile" `
+ -dSharedHostMsiSourcePath="$SharedHostMSIFile" `
-arch "$Architecture" `
-ext WixBalExtension.dll `
-ext WixUtilExtension.dll `
@@ -73,9 +77,9 @@ function RunLightForBundle
}
-if(!(Test-Path $DotnetMSIFile))
+if(!(Test-Path $CLISDKMSIFile))
{
- throw "$DotnetMSIFile not found"
+ throw "$CLISDKMSIFile not found"
}
Write-Host "Creating dotnet Bundle at $DotnetBundleOutput"
@@ -103,6 +107,6 @@ if(!(Test-Path $DotnetBundleOutput))
Write-Host -ForegroundColor Green "Successfully created dotnet bundle - $DotnetBundleOutput"
-_ $RepoRoot\test\Installer\testmsi.ps1 @("$DotnetMSIFile")
+_ $RepoRoot\test\Installer\testmsi.ps1 @("$CLISDKMSIFile")
exit $LastExitCode
diff --git a/packaging/windows/registrykeys.wxs b/packaging/windows/registrykeys.wxs
index 9bd84eb25..efb5c2b39 100644
--- a/packaging/windows/registrykeys.wxs
+++ b/packaging/windows/registrykeys.wxs
@@ -23,8 +23,6 @@
-
-
diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj b/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj
index d4c58d0e8..5e45f32ed 100644
--- a/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj
+++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/Microsoft.DotNet.Cli.Build.Framework.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
49beb486-ab5a-4416-91ea-8cd34abb0c9d
Microsoft.DotNet.Cli.Build.Framework
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json b/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json
index 85a4e9c85..cb16f68b2 100644
--- a/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json
+++ b/scripts/Microsoft.DotNet.Cli.Build.Framework/project.json
@@ -1,15 +1,13 @@
{
- "version": "1.0.0-*",
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.Diagnostics.Process": "4.1.0-rc2-23901",
- "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
- },
-
- "frameworks": {
- "netstandard1.3": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.Diagnostics.Process": "4.1.0-rc2-23911",
+ "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
+ },
+ "frameworks": {
+ "netstandard1.3": {
+ "imports": "dnxcore50"
}
+ }
}
diff --git a/scripts/dotnet-cli-build/CompileTargets.cs b/scripts/dotnet-cli-build/CompileTargets.cs
index 3391a649c..7c6c80bb4 100644
--- a/scripts/dotnet-cli-build/CompileTargets.cs
+++ b/scripts/dotnet-cli-build/CompileTargets.cs
@@ -12,7 +12,7 @@ namespace Microsoft.DotNet.Cli.Build
{
public class CompileTargets
{
- public static readonly string CoreCLRVersion = "1.0.2-rc2-23901";
+ public static readonly string CoreCLRVersion = "1.0.2-rc2-23911";
public static readonly string AppDepSdkVersion = "1.0.6-prerelease-00003";
public static readonly bool IsWinx86 = CurrentPlatform.IsWindows && CurrentArchitecture.Isx86;
@@ -70,15 +70,20 @@ namespace Microsoft.DotNet.Cli.Build
var configuration = c.BuildContext.Get("Configuration");
// Run the build
+ string version = DotNetCli.Stage0.Exec("", "--version").CaptureStdOut().Execute().StdOut;
+ string rid = Array.Find(version.Split(Environment.NewLine.ToCharArray()), (e) => e.Contains("Runtime Id:")).Replace("Runtime Id:", "").Trim();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Why does Windows directly call cmake but Linux/Mac calls "build.sh" in the corehost dir?
// See the comment in "src/corehost/build.sh" for details. It doesn't work for some reason.
var visualStudio = IsWinx86 ? "Visual Studio 14 2015" : "Visual Studio 14 2015 Win64";
var archMacro = IsWinx86 ? "-DCLI_CMAKE_PLATFORM_ARCH_I386=1" : "-DCLI_CMAKE_PLATFORM_ARCH_AMD64=1";
+ var ridMacro = $"-DCLI_CMAKE_RUNTIME_ID:STRING={rid}";
+
ExecIn(cmakeOut, "cmake",
Path.Combine(c.BuildContext.BuildDirectory, "src", "corehost"),
archMacro,
+ ridMacro,
"-G",
visualStudio);
@@ -101,14 +106,21 @@ namespace Microsoft.DotNet.Cli.Build
File.Copy(Path.Combine(cmakeOut, "cli", configuration, "corehost.pdb"), Path.Combine(Dirs.Corehost, "corehost.pdb"), overwrite: true);
File.Copy(Path.Combine(cmakeOut, "cli", "dll", configuration, "hostpolicy.dll"), Path.Combine(Dirs.Corehost, "hostpolicy.dll"), overwrite: true);
File.Copy(Path.Combine(cmakeOut, "cli", "dll", configuration, "hostpolicy.pdb"), Path.Combine(Dirs.Corehost, "hostpolicy.pdb"), overwrite: true);
+ File.Copy(Path.Combine(cmakeOut, "cli", "fxr", configuration, "hostfxr.dll"), Path.Combine(Dirs.Corehost, "hostfxr.dll"), overwrite: true);
+ File.Copy(Path.Combine(cmakeOut, "cli", "fxr", configuration, "hostfxr.pdb"), Path.Combine(Dirs.Corehost, "hostfxr.pdb"), overwrite: true);
}
else
{
- ExecIn(cmakeOut, Path.Combine(c.BuildContext.BuildDirectory, "src", "corehost", "build.sh"));
+ ExecIn(cmakeOut, Path.Combine(c.BuildContext.BuildDirectory, "src", "corehost", "build.sh"),
+ "--arch",
+ "amd64",
+ "--rid",
+ rid);
// Copy the output out
File.Copy(Path.Combine(cmakeOut, "cli", "corehost"), Path.Combine(Dirs.Corehost, "corehost"), overwrite: true);
File.Copy(Path.Combine(cmakeOut, "cli", "dll", $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true);
+ File.Copy(Path.Combine(cmakeOut, "cli", "fxr", $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true);
}
return c.Success();
@@ -193,6 +205,7 @@ namespace Microsoft.DotNet.Cli.Build
// Copy corehost
File.Copy(Path.Combine(Dirs.Corehost, $"corehost{Constants.ExeSuffix}"), Path.Combine(binDir, $"corehost{Constants.ExeSuffix}"), overwrite: true);
File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(binDir, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true);
+ File.Copy(Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(binDir, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true);
// Corehostify binaries
foreach (var binaryToCorehostify in BinariesForCoreHost)
@@ -335,7 +348,7 @@ namespace Microsoft.DotNet.Cli.Build
private static List GetAssembliesToCrossGen()
{
- var list = new List
+ return new List
{
"System.Collections.Immutable.dll",
"System.Reflection.Metadata.dll",
@@ -345,15 +358,6 @@ namespace Microsoft.DotNet.Cli.Build
"csc.dll",
"vbc.dll"
};
-
- // mscorlib is already crossgenned on Windows
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- // mscorlib has to be crossgenned first
- list.Insert(0, "mscorlib.dll");
- }
-
- return list;
}
}
}
diff --git a/scripts/dotnet-cli-build/MsiTargets.cs b/scripts/dotnet-cli-build/MsiTargets.cs
index e0e3ecb37..aa50fcac8 100644
--- a/scripts/dotnet-cli-build/MsiTargets.cs
+++ b/scripts/dotnet-cli-build/MsiTargets.cs
@@ -94,9 +94,10 @@ namespace Microsoft.DotNet.Cli.Build
[BuildPlatforms(BuildPlatform.Windows)]
public static BuildTargetResult GenerateCliSdkMsi(BuildTargetContext c)
{
+ var cliSdkRoot = c.BuildContext.Get("CLISDKRoot");
Cmd("powershell", "-NoProfile", "-NoLogo",
Path.Combine(Dirs.RepoRoot, "packaging", "windows", "generatemsi.ps1"),
- Dirs.Stage2, SdkMsi, WixRoot, MsiVersion, CliVersion, Arch, Channel)
+ cliSdkRoot, SdkMsi, WixRoot, MsiVersion, CliVersion, Arch, Channel)
.Execute()
.EnsureSuccessful();
return c.Success();
@@ -156,7 +157,7 @@ namespace Microsoft.DotNet.Cli.Build
{
Cmd("powershell", "-NoProfile", "-NoLogo",
Path.Combine(Dirs.RepoRoot, "packaging", "windows", "generatebundle.ps1"),
- SdkMsi, SdkBundle, WixRoot, MsiVersion, CliVersion, Arch, Channel)
+ SdkMsi, SharedFrameworkMsi, SharedHostMsi, SdkBundle, WixRoot, MsiVersion, CliVersion, Arch, Channel)
.EnvironmentVariable("Stage2Dir", Dirs.Stage2)
.Execute()
.EnsureSuccessful();
diff --git a/scripts/dotnet-cli-build/PackageTargets.cs b/scripts/dotnet-cli-build/PackageTargets.cs
index 11ba01b43..4b54013cf 100644
--- a/scripts/dotnet-cli-build/PackageTargets.cs
+++ b/scripts/dotnet-cli-build/PackageTargets.cs
@@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Cli.Build
[Target(nameof(PrepareTargets.Init),
nameof(PackageTargets.InitPackage),
nameof(PackageTargets.GenerateVersionBadge),
+ nameof(PackageTargets.CopyCLISDKLayout),
nameof(SharedFrameworkTargets.PublishSharedHost),
nameof(SharedFrameworkTargets.PublishSharedFramework),
nameof(PackageTargets.GenerateCompressedFile),
@@ -47,6 +48,52 @@ namespace Microsoft.DotNet.Cli.Build
return c.Success();
}
+ [Target]
+ public static BuildTargetResult CopyCLISDKLayout(BuildTargetContext c)
+ {
+ var nugetVersion = c.BuildContext.Get("BuildVersion").NuGetVersion;
+ var cliSdkRoot = Path.Combine(Dirs.Output, "obj", "clisdk");
+ var cliSdk = Path.Combine(cliSdkRoot, "sdk", nugetVersion);
+
+ if (Directory.Exists(cliSdkRoot))
+ {
+ string[] files = Directory.GetFiles(cliSdkRoot, "*", SearchOption.AllDirectories);
+ foreach (string file in files)
+ {
+ File.SetAttributes(file, FileAttributes.Normal);
+ File.Delete(file);
+ }
+
+ Directory.Delete(cliSdkRoot, true);
+ }
+
+ Directory.CreateDirectory(cliSdk);
+
+ var binPath = Path.Combine(Dirs.Stage2, "bin");
+ foreach (var file in Directory.GetFiles(binPath, "*", SearchOption.AllDirectories))
+ {
+ string destFile = file.Replace(binPath, cliSdk);
+ Directory.CreateDirectory(Path.GetDirectoryName(destFile));
+ File.Copy(file, destFile, true);
+ }
+
+ File.Copy(Path.Combine(Dirs.Stage2, ".version"), Path.Combine(cliSdk, ".version"), true);
+
+ // copy stage2 to "cliSdkRoot\bin".
+ // this is a temp hack until we fix the build scripts to use the new shared fx and shared host
+ // the current build scripts need the CLI sdk to be in the bin folder.
+
+ foreach (var file in Directory.GetFiles(Dirs.Stage2, "*", SearchOption.AllDirectories))
+ {
+ string destFile = file.Replace(Dirs.Stage2, cliSdkRoot);
+ Directory.CreateDirectory(Path.GetDirectoryName(destFile));
+ File.Copy(file, destFile, true);
+ }
+
+ c.BuildContext["CLISDKRoot"] = cliSdkRoot;
+ return c.Success();
+ }
+
[Target(nameof(PackageTargets.GenerateZip), nameof(PackageTargets.GenerateTarBall))]
public static BuildTargetResult GenerateCompressedFile(BuildTargetContext c)
{
@@ -59,7 +106,7 @@ namespace Microsoft.DotNet.Cli.Build
{
CreateZipFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile"));
CreateZipFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile"));
- CreateZipFromDirectory(Dirs.Stage2, c.BuildContext.Get("SdkCompressedFile"));
+ CreateZipFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile"));
return c.Success();
}
@@ -70,7 +117,7 @@ namespace Microsoft.DotNet.Cli.Build
{
CreateTarBallFromDirectory(c.BuildContext.Get("SharedHostPublishRoot"), c.BuildContext.Get("SharedHostCompressedFile"));
CreateTarBallFromDirectory(c.BuildContext.Get("SharedFrameworkPublishRoot"), c.BuildContext.Get("SharedFrameworkCompressedFile"));
- CreateTarBallFromDirectory(Dirs.Stage2, c.BuildContext.Get("SdkCompressedFile"));
+ CreateTarBallFromDirectory(c.BuildContext.Get("CLISDKRoot"), c.BuildContext.Get("SdkCompressedFile"));
return c.Success();
}
diff --git a/scripts/dotnet-cli-build/PrepareTargets.cs b/scripts/dotnet-cli-build/PrepareTargets.cs
index 08dca3e05..1c87e132f 100644
--- a/scripts/dotnet-cli-build/PrepareTargets.cs
+++ b/scripts/dotnet-cli-build/PrepareTargets.cs
@@ -190,8 +190,8 @@ namespace Microsoft.DotNet.Cli.Build
{
var dotnet = DotNetCli.Stage0;
- dotnet.Restore().WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "src")).Execute().EnsureSuccessful();
- dotnet.Restore().WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "tools")).Execute().EnsureSuccessful();
+ dotnet.Restore("--verbosity", "verbose", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "src")).Execute().EnsureSuccessful();
+ dotnet.Restore("--verbosity", "verbose", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "tools")).Execute().EnsureSuccessful();
return c.Success();
}
diff --git a/scripts/dotnet-cli-build/PublishTargets.cs b/scripts/dotnet-cli-build/PublishTargets.cs
index b90e0c56c..b624656ad 100644
--- a/scripts/dotnet-cli-build/PublishTargets.cs
+++ b/scripts/dotnet-cli-build/PublishTargets.cs
@@ -46,6 +46,9 @@ namespace Microsoft.DotNet.Cli.Build
[Target(nameof(PublishTargets.PublishVersionBadge),
nameof(PublishTargets.PublishCompressedFile),
nameof(PublishTargets.PublishSdkInstallerFile),
+ nameof(PublishTargets.PublishDebFileToDebianRepo),
+ nameof(PublishTargets.PublishSharedFrameworkCompressedFile),
+ nameof(PublishTargets.PublishSharedHostCompressedFile),
nameof(PublishTargets.PublishLatestVersionTextFile))]
public static BuildTargetResult PublishArtifacts(BuildTargetContext c)
{
@@ -140,6 +143,32 @@ namespace Microsoft.DotNet.Cli.Build
return uploadJson;
}
+ [Target]
+ public static BuildTargetResult PublishSharedFrameworkCompressedFile(BuildTargetContext c)
+ {
+ var compressedFile = c.BuildContext.Get("SharedFrameworkCompressedFile");
+ var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}";
+ var latestCompressedFile = compressedFile.Replace(Version, "latest");
+ var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}";
+
+ PublishFileAzure(compressedFileBlob, compressedFile);
+ PublishFileAzure(latestCompressedFileBlob, compressedFile);
+ return c.Success();
+ }
+
+ [Target]
+ public static BuildTargetResult PublishSharedHostCompressedFile(BuildTargetContext c)
+ {
+ var compressedFile = c.BuildContext.Get("SharedHostCompressedFile");
+ var compressedFileBlob = $"{Channel}/Binaries/{Version}/{Path.GetFileName(compressedFile)}";
+ var latestCompressedFile = compressedFile.Replace(Version, "latest");
+ var latestCompressedFileBlob = $"{Channel}/Binaries/Latest/{Path.GetFileName(latestCompressedFile)}";
+
+ PublishFileAzure(compressedFileBlob, compressedFile);
+ PublishFileAzure(latestCompressedFileBlob, compressedFile);
+ return c.Success();
+ }
+
private static BuildTargetResult PublishFile(BuildTargetContext c, string file)
{
var env = PackageTargets.GetCommonEnvVars(c);
diff --git a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs
index a2ff2e67c..2892bc2f2 100644
--- a/scripts/dotnet-cli-build/SharedFrameworkTargets.cs
+++ b/scripts/dotnet-cli-build/SharedFrameworkTargets.cs
@@ -9,6 +9,8 @@ using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.Extensions.PlatformAbstractions;
using static Microsoft.DotNet.Cli.Build.Framework.BuildHelpers;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
namespace Microsoft.DotNet.Cli.Build
{
@@ -17,6 +19,8 @@ namespace Microsoft.DotNet.Cli.Build
public const string SharedFrameworkName = "Microsoft.NETCore.App";
private const string CoreHostBaseName = "corehost";
+ private const string DotnetHostFxrBaseName = "hostfxr";
+ private const string HostPolicyBaseName = "hostpolicy";
[Target(nameof(PackageSharedFramework), nameof(CrossGenAllManagedAssemblies))]
public static BuildTargetResult PublishSharedFramework(BuildTargetContext c)
@@ -63,16 +67,36 @@ namespace Microsoft.DotNet.Cli.Build
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, $"framework{Constants.ExeSuffix}"));
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.dll"));
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.pdb"));
+ File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.runtimeconfig.json"));
// Rename the .deps file
+ var destinationDeps = Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json");
File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps"));
- File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{SharedFrameworkName}.deps.json"));
+ File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, "framework.deps.json"), destinationDeps);
- // corehost will be renamed to dotnet at some point and then this can be removed.
- File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}"));
+ // Merge in the RID fallback graph
+ var fallbackFileName = PlatformServices.Default.Runtime.OperatingSystemPlatform.ToString().ToLowerInvariant() + ".json";
+ var fallbackFile = Path.Combine(Dirs.RepoRoot, "src", "sharedframework", "rid-fallbacks", fallbackFileName);
+ if (File.Exists(fallbackFile))
+ {
+ c.Info($"Merging in RID fallback graph: {fallbackFile}");
+ var deps = JObject.Parse(File.ReadAllText(destinationDeps));
+ var ridfallback = JObject.Parse(File.ReadAllText(fallbackFile));
+ deps["runtimes"] = ridfallback["runtimes"];
+ File.WriteAllText(destinationDeps, deps.ToString(Formatting.Indented));
+ }
+ else
+ {
+ c.Warn($"RID fallback graph file not found: {fallbackFile}");
+ }
- // hostpolicy will be renamed to dotnet at some point and then this can be removed.
- File.Move(Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}dotnethostimpl{Constants.DynamicLibSuffix}"));
+ // corehost will be renamed to dotnet at some point and then we will not need to rename it here.
+ File.Copy(
+ Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"),
+ Path.Combine(SharedFrameworkNameAndVersionRoot, $"dotnet{Constants.ExeSuffix}"));
+ File.Copy(
+ Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"),
+ Path.Combine(SharedFrameworkNameAndVersionRoot, $"{Constants.DynamicLibPrefix}{HostPolicyBaseName}{Constants.DynamicLibSuffix}"), true);
if (File.Exists(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.ni.dll")))
{
@@ -81,10 +105,6 @@ namespace Microsoft.DotNet.Cli.Build
File.Delete(Path.Combine(SharedFrameworkNameAndVersionRoot, "mscorlib.dll"));
c.BuildContext["SharedFrameworkNameAndVersionRoot"] = SharedFrameworkNameAndVersionRoot;
}
- else
- {
- c.Warn("Shared framework will not be crossgen'd because mscorlib.ni.dll does not exist.");
- }
return c.Success();
}
@@ -93,9 +113,20 @@ namespace Microsoft.DotNet.Cli.Build
public static BuildTargetResult PublishSharedHost(BuildTargetContext c)
{
string SharedHostPublishRoot = Path.Combine(Dirs.Output, "obj", "sharedhost");
+ if (Directory.Exists(SharedHostPublishRoot))
+ {
+ Directory.Delete(SharedHostPublishRoot);
+ }
+
Directory.CreateDirectory(SharedHostPublishRoot);
+
// corehost will be renamed to dotnet at some point and then this can be removed.
- File.Copy(Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"), Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}"));
+ File.Copy(
+ Path.Combine(Dirs.Corehost, $"{CoreHostBaseName}{Constants.ExeSuffix}"),
+ Path.Combine(SharedHostPublishRoot, $"dotnet{Constants.ExeSuffix}"));
+ File.Copy(
+ Path.Combine(Dirs.Corehost, $"{Constants.DynamicLibPrefix}{DotnetHostFxrBaseName}{Constants.DynamicLibSuffix}"),
+ Path.Combine(SharedHostPublishRoot, $"{Constants.DynamicLibPrefix}{DotnetHostFxrBaseName}{Constants.DynamicLibSuffix}"));
c.BuildContext["SharedHostPublishRoot"] = SharedHostPublishRoot;
diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs
index 375a984be..8526400a3 100644
--- a/scripts/dotnet-cli-build/TestTargets.cs
+++ b/scripts/dotnet-cli-build/TestTargets.cs
@@ -60,7 +60,7 @@ namespace Microsoft.DotNet.Cli.Build
CleanNuGetTempCache();
var dotnet = DotNetCli.Stage2;
- dotnet.Restore().WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")).Execute().EnsureSuccessful();
+ dotnet.Restore("--verbosity", "verbose", "--disable-parallel").WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestPackages")).Execute().EnsureSuccessful();
return c.Success();
}
@@ -75,16 +75,16 @@ namespace Microsoft.DotNet.Cli.Build
var dotnet = DotNetCli.Stage2;
- dotnet.Restore("--fallbacksource", Dirs.TestPackages)
+ dotnet.Restore("--verbosity", "verbose", "--disable-parallel", "--fallbacksource", Dirs.TestPackages)
.WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "TestProjects"))
.Execute().EnsureSuccessful();
// The 'ProjectModelServer' directory contains intentionally-unresolved dependencies, so don't check for success. Also, suppress the output
- dotnet.Restore()
+ dotnet.Restore("--verbosity", "verbose", "--disable-parallel")
.WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthTestProjects"))
.Execute();
- dotnet.Restore()
+ dotnet.Restore("--verbosity", "verbose", "--disable-parallel")
.WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "TestAssets", "ProjectModelServer", "DthUpdateSearchPathSample"))
.Execute();
@@ -152,7 +152,7 @@ namespace Microsoft.DotNet.Cli.Build
CleanBinObj(c, Path.Combine(c.BuildContext.BuildDirectory, "test"));
CleanNuGetTempCache();
- DotNetCli.Stage2.Restore("--fallbacksource", Dirs.TestPackages)
+ DotNetCli.Stage2.Restore("--verbosity", "verbose", "--disable-parallel", "--fallbacksource", Dirs.TestPackages)
.WorkingDirectory(Path.Combine(c.BuildContext.BuildDirectory, "test"))
.Execute()
.EnsureSuccessful();
diff --git a/scripts/dotnet-cli-build/dotnet-cli-build.xproj b/scripts/dotnet-cli-build/dotnet-cli-build.xproj
index fd8546624..fdd8f182d 100644
--- a/scripts/dotnet-cli-build/dotnet-cli-build.xproj
+++ b/scripts/dotnet-cli-build/dotnet-cli-build.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
d7b9695d-23eb-4ea8-b8ab-707a0092e1d5
Microsoft.DotNet.Cli.Build
@@ -14,5 +14,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/scripts/dotnet-cli-build/project.json b/scripts/dotnet-cli-build/project.json
index f66171d24..72295b954 100755
--- a/scripts/dotnet-cli-build/project.json
+++ b/scripts/dotnet-cli-build/project.json
@@ -1,23 +1,18 @@
{
- "version": "1.0.0-*",
- "description": "Build scripts for dotnet-cli",
- "compilationOptions": {
- "emitEntryPoint": true
- },
-
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.IO.Compression.ZipFile": "4.0.1-rc2-23901",
- "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901",
- "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537",
- "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*",
- "WindowsAzure.Storage" : "6.2.2-preview",
- "System.Reflection.Metadata" : "1.2.0"
- },
-
- "frameworks": {
- "netstandardapp1.5": {
- "imports": ["dnxcore50", "portable-net45+win8"]
- }
+ "version": "1.0.0-*",
+ "description": "Build scripts for dotnet-cli",
+ "compilationOptions": {
+ "emitEntryPoint": true
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "Microsoft.DotNet.Cli.Build.Framework": "1.0.0-*",
+ "WindowsAzure.Storage": "6.2.2-preview",
+ "System.Reflection.Metadata": "1.2.0"
+ },
+ "frameworks": {
+ "netstandardapp1.5": {
+ "imports": [ "dnxcore50", "portable-net45+win8" ]
}
+ }
}
diff --git a/scripts/package/projectsToPack.ps1 b/scripts/package/projectsToPack.ps1
index 1b8cbe54f..5c08c9573 100644
--- a/scripts/package/projectsToPack.ps1
+++ b/scripts/package/projectsToPack.ps1
@@ -3,10 +3,13 @@
$ProjectsToPack = @(
"Microsoft.DotNet.Cli.Utils",
+ "Microsoft.DotNet.Compiler.Common",
+ "Microsoft.DotNet.Files",
+ "Microsoft.DotNet.InternalAbstractions",
"Microsoft.DotNet.ProjectModel",
"Microsoft.DotNet.ProjectModel.Loader",
"Microsoft.DotNet.ProjectModel.Workspaces",
- "Microsoft.DotNet.InternalAbstractions",
+ "Microsoft.DotNet.TestFramework",
"Microsoft.Extensions.DependencyModel",
"Microsoft.Extensions.Testing.Abstractions"
)
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs
index ee5bd7ecb..8129fa2e5 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs
@@ -98,7 +98,8 @@ namespace Microsoft.DotNet.Cli.Utils
if (depsFilePath != null)
{
- arguments.Add($"--depsfile:{depsFilePath}");
+ arguments.Add("--depsfile");
+ arguments.Add(depsFilePath);
}
arguments.AddRange(commandArguments);
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs
index bf314ee6a..608beb231 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs
@@ -75,7 +75,7 @@ namespace Microsoft.DotNet.Cli.Utils
return null;
}
- var depsFilePath = projectContext.GetOutputPaths(configuration, outputPath: outputPath).RuntimeFiles.Deps;
+ var depsFilePath = projectContext.GetOutputPaths(configuration, outputPath: outputPath).RuntimeFiles.DepsJson;
var dependencyLibraries = GetAllDependencyLibraries(projectContext);
diff --git a/src/Microsoft.DotNet.Cli.Utils/Constants.cs b/src/Microsoft.DotNet.Cli.Utils/Constants.cs
index 9bbb22325..13a349b13 100644
--- a/src/Microsoft.DotNet.Cli.Utils/Constants.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/Constants.cs
@@ -37,7 +37,8 @@ namespace Microsoft.DotNet.Cli.Utils
public static readonly string HostExecutableName = "corehost" + ExeSuffix;
public static readonly string[] HostBinaryNames = new string[] {
HostExecutableName,
- (CurrentPlatform == Platform.Windows ? "hostpolicy" : "libhostpolicy") + DynamicLibSuffix
+ (CurrentPlatform == Platform.Windows ? "hostpolicy" : "libhostpolicy") + DynamicLibSuffix,
+ (CurrentPlatform == Platform.Windows ? "hostfxr" : "libhostfxr") + DynamicLibSuffix
};
}
diff --git a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj
index 68df775cf..e5fda6870 100644
--- a/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj
+++ b/src/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
61b7c351-c77d-43f7-b56f-bb1440178e10
Microsoft.DotNet.Cli.Utils
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json
index 625b48bf4..3e97e0621 100644
--- a/src/Microsoft.DotNet.Cli.Utils/project.json
+++ b/src/Microsoft.DotNet.Cli.Utils/project.json
@@ -1,27 +1,27 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "keyFile": "../../tools/Key.snk",
- "warningsAsErrors": true
- },
- "dependencies": {
- "Microsoft.DotNet.ProjectModel": "1.0.0-*",
- "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
- },
- "frameworks": {
- "net451": {
- "frameworkAssemblies": {
- "System.Runtime": {
- "type": "build"
- }
- }
- },
- "netstandard1.3": {
- "imports": "dnxcore50",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.Diagnostics.Process": "4.1.0-rc2-23901"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "keyFile": "../../tools/Key.snk",
+ "warningsAsErrors": true
+ },
+ "dependencies": {
+ "Microsoft.DotNet.ProjectModel": "1.0.0-*",
+ "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
+ },
+ "frameworks": {
+ "net451": {
+ "frameworkAssemblies": {
+ "System.Runtime": {
+ "type": "build"
}
+ }
+ },
+ "netstandard1.3": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.Diagnostics.Process": "4.1.0-rc2-23911"
+ }
}
+ }
}
diff --git a/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj b/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj
index e7b0225ee..50899a805 100644
--- a/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj
+++ b/src/Microsoft.DotNet.Compiler.Common/Microsoft.Dotnet.Compiler.Common.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
a16958e1-24c7-4f1e-b317-204ad91625dd
Microsoft.Dotnet.Cli.Compiler.Common
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/src/Microsoft.DotNet.Compiler.Common/project.json b/src/Microsoft.DotNet.Compiler.Common/project.json
index 0e15d8637..f0376403a 100644
--- a/src/Microsoft.DotNet.Compiler.Common/project.json
+++ b/src/Microsoft.DotNet.Compiler.Common/project.json
@@ -1,23 +1,23 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "keyFile": "../../tools/Key.snk"
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.CommandLine": "0.1.0-e160119-1",
- "Microsoft.CodeAnalysis.CSharp": "1.2.0-beta1-20160202-02",
- "Microsoft.DotNet.ProjectModel": "1.0.0-*",
- "Microsoft.DotNet.Cli.Utils": "1.0.0-*",
- "Microsoft.DotNet.Files": "1.0.0-*"
- },
- "frameworks": {
- "netstandard1.3": {
- "imports": [
- "dnxcore50",
- "portable-net45+win8"
- ]
- }
- },
- "scripts": {}
-}
\ No newline at end of file
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "keyFile": "../../tools/Key.snk"
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.CommandLine": "0.1.0-e160119-1",
+ "Microsoft.CodeAnalysis.CSharp": "1.2.0-beta1-20160202-02",
+ "Microsoft.DotNet.ProjectModel": "1.0.0-*",
+ "Microsoft.DotNet.Cli.Utils": "1.0.0-*",
+ "Microsoft.DotNet.Files": "1.0.0-*"
+ },
+ "frameworks": {
+ "netstandard1.3": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+win8"
+ ]
+ }
+ },
+ "scripts": {}
+}
diff --git a/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj b/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj
index 0dca981d4..15a95077a 100644
--- a/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj
+++ b/src/Microsoft.DotNet.Files/Microsoft.DotNet.Files.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
d521dd9f-0614-4929-93b4-d8fa5682c174
Microsoft.DotNet.Files
@@ -14,5 +14,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Files/project.json b/src/Microsoft.DotNet.Files/project.json
index 82f1a2b51..1131165e9 100644
--- a/src/Microsoft.DotNet.Files/project.json
+++ b/src/Microsoft.DotNet.Files/project.json
@@ -1,20 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "keyFile": "../../tools/Key.snk"
- },
- "description": "Abstraction to interact with the file system and file paths.",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.Linq.Expressions": "4.0.11-rc2-23901",
- "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996",
- "Microsoft.DotNet.Cli.Utils": "1.0.0-*",
- "Microsoft.DotNet.ProjectModel": "1.0.0-*"
- },
- "frameworks": {
- "netstandard1.3": {
- "imports": "dnxcore50"
- }
- },
- "scripts": {}
-}
\ No newline at end of file
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "keyFile": "../../tools/Key.snk"
+ },
+ "description": "Abstraction to interact with the file system and file paths.",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.Linq.Expressions": "4.0.11-rc2-23911",
+ "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996",
+ "Microsoft.DotNet.Cli.Utils": "1.0.0-*",
+ "Microsoft.DotNet.ProjectModel": "1.0.0-*"
+ },
+ "frameworks": {
+ "netstandard1.3": {
+ "imports": "dnxcore50"
+ }
+ },
+ "scripts": {}
+}
diff --git a/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs b/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs
index 8b6efbeac..867d4eab1 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs
+++ b/src/Microsoft.DotNet.InternalAbstractions/FileWrapper.cs
@@ -16,5 +16,10 @@ namespace Microsoft.Extensions.EnvironmentAbstractions
{
return File.ReadAllText(path);
}
+
+ public Stream OpenRead(string path)
+ {
+ return File.OpenRead(path);
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.InternalAbstractions/IFile.cs b/src/Microsoft.DotNet.InternalAbstractions/IFile.cs
index 26d029eec..5b0328de9 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/IFile.cs
+++ b/src/Microsoft.DotNet.InternalAbstractions/IFile.cs
@@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using System.IO;
+
namespace Microsoft.Extensions.EnvironmentAbstractions
{
internal interface IFile
@@ -8,5 +10,7 @@ namespace Microsoft.Extensions.EnvironmentAbstractions
bool Exists(string path);
string ReadAllText(string path);
+
+ Stream OpenRead(string path);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj
index 2f07cc659..2a323b565 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj
+++ b/src/Microsoft.DotNet.InternalAbstractions/Microsoft.DotNet.InternalAbstractions.xproj
@@ -4,7 +4,7 @@
14.0.24720
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
bd4f0750-4e81-4ad2-90b5-e470881792c3
Microsoft.DotNet.InternalAbstractions
@@ -14,5 +14,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.InternalAbstractions/project.json b/src/Microsoft.DotNet.InternalAbstractions/project.json
index 70b5e7221..3daa0c061 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/project.json
+++ b/src/Microsoft.DotNet.InternalAbstractions/project.json
@@ -13,14 +13,13 @@
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
},
"frameworks": {
- "net451": { },
+ "net451": {},
"netstandard1.3": {
"imports": "dnxcore50",
"dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901"
+ "NETStandard.Library": "1.5.0-rc2-23911"
}
}
},
- "scripts": {
- }
+ "scripts": {}
}
diff --git a/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj b/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj
index 049c639a2..51615b07a 100644
--- a/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj
+++ b/src/Microsoft.DotNet.ProjectModel.Loader/Microsoft.DotNet.ProjectModel.Loader.xproj
@@ -4,7 +4,7 @@
14.0.24720
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
c7af0290-ef0d-44dc-9edc-600803b664f8
Microsoft.DotNet.ProjectModel.Loader
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel.Loader/project.json b/src/Microsoft.DotNet.ProjectModel.Loader/project.json
index efe082435..9d2eca854 100644
--- a/src/Microsoft.DotNet.ProjectModel.Loader/project.json
+++ b/src/Microsoft.DotNet.ProjectModel.Loader/project.json
@@ -1,16 +1,16 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "keyFile": "../../tools/Key.snk"
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "Microsoft.DotNet.ProjectModel": "1.0.0-*",
- "System.Runtime.Loader": "4.0.0-rc2-23901"
- },
- "frameworks": {
- "netstandard1.3": {
- "imports": "dnxcore50"
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "keyFile": "../../tools/Key.snk"
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "Microsoft.DotNet.ProjectModel": "1.0.0-*",
+ "System.Runtime.Loader": "4.0.0-rc2-23911"
+ },
+ "frameworks": {
+ "netstandard1.3": {
+ "imports": "dnxcore50"
}
-}
\ No newline at end of file
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj b/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj
index 3227dea0a..fa941946f 100644
--- a/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj
+++ b/src/Microsoft.DotNet.ProjectModel.Workspaces/Microsoft.DotNet.ProjectModel.Workspaces.xproj
@@ -4,7 +4,7 @@
14.0.23107
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
bd7833f8-3209-4682-bf75-b4bca883e279
Microsoft.DotNet.ProjectModel.Workspaces
@@ -15,5 +15,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json b/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json
index 83f7a2d6e..e14bbe01b 100644
--- a/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json
+++ b/src/Microsoft.DotNet.ProjectModel.Workspaces/project.json
@@ -1,20 +1,20 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "keyFile": "../../tools/Key.snk"
- },
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "Microsoft.DotNet.ProjectModel": "1.0.0-*",
- "Microsoft.DotNet.Compiler.Common": "1.0.0-*",
- "Microsoft.CodeAnalysis.CSharp.Workspaces": "1.2.0-beta1-20160202-02"
- },
- "frameworks": {
- "netstandard1.3": {
- "imports": [
- "dnxcore50",
- "portable-net45+win8"
- ]
- }
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "keyFile": "../../tools/Key.snk"
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "Microsoft.DotNet.ProjectModel": "1.0.0-*",
+ "Microsoft.DotNet.Compiler.Common": "1.0.0-*",
+ "Microsoft.CodeAnalysis.CSharp.Workspaces": "1.2.0-beta1-20160202-02"
+ },
+ "frameworks": {
+ "netstandard1.3": {
+ "imports": [
+ "dnxcore50",
+ "portable-net45+win8"
+ ]
}
-}
\ No newline at end of file
+ }
+}
diff --git a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs
index fcfec2cc4..d36ac6f82 100644
--- a/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs
+++ b/src/Microsoft.DotNet.ProjectModel/DependencyContextBuilder.cs
@@ -55,7 +55,7 @@ namespace Microsoft.Extensions.DependencyModel
compilationOptions,
GetLibraries(compilationExports, dependencyLookup, runtime: false).Cast(),
GetLibraries(runtimeExports, dependencyLookup, runtime: true).Cast(),
- new KeyValuePair[0]);
+ new RuntimeFallbacks[] {});
}
private static CompilationOptions GetCompilationOptions(CommonCompilerOptions compilerOptions)
diff --git a/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj b/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj
index c33400887..d56e4bae5 100644
--- a/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj
+++ b/src/Microsoft.DotNet.ProjectModel/Microsoft.DotNet.ProjectModel.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
303677d5-7312-4c3f-baee-beb1a9bd9fe6
Microsoft.DotNet.ProjectModel
@@ -14,5 +14,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel/project.json b/src/Microsoft.DotNet.ProjectModel/project.json
index 9479b166a..46cd0f97c 100644
--- a/src/Microsoft.DotNet.ProjectModel/project.json
+++ b/src/Microsoft.DotNet.ProjectModel/project.json
@@ -1,47 +1,47 @@
{
- "version": "1.0.0-*",
- "compilationOptions": {
- "keyFile": "../../tools/Key.snk"
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "keyFile": "../../tools/Key.snk"
+ },
+ "description": "Types to model a .NET Project",
+ "dependencies": {
+ "System.Reflection.Metadata": "1.2.0-rc2-23911",
+ "NuGet.Packaging": "3.4.0-rtm-0763",
+ "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996",
+ "Microsoft.Extensions.JsonParser.Sources": {
+ "type": "build",
+ "version": "1.0.0-rc2-16453"
},
- "description": "Types to model a .NET Project",
- "dependencies": {
- "System.Reflection.Metadata": "1.2.0-rc2-23901",
- "NuGet.Packaging": "3.4.0-rtm-0733",
- "Microsoft.Extensions.FileSystemGlobbing": "1.0.0-rc2-15996",
- "Microsoft.Extensions.JsonParser.Sources": {
- "type": "build",
- "version": "1.0.0-rc2-16453"
- },
- "Microsoft.Extensions.HashCodeCombiner.Sources": {
- "type": "build",
- "version": "1.0.0-rc2-16054"
- },
- "Microsoft.Extensions.DependencyModel": "1.0.0-*"
+ "Microsoft.Extensions.HashCodeCombiner.Sources": {
+ "type": "build",
+ "version": "1.0.0-rc2-16054"
},
- "frameworks": {
- "net451": {
- "frameworkAssemblies": {
- "System.Runtime": {
- "type": "build"
- },
- "System.Collections": {
- "type": "build"
- },
- "System.IO": {
- "type": "build"
- }
- }
+ "Microsoft.Extensions.DependencyModel": "1.0.0-*"
+ },
+ "frameworks": {
+ "net451": {
+ "frameworkAssemblies": {
+ "System.Runtime": {
+ "type": "build"
},
- "netstandard1.3": {
- "imports": "dnxcore50",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.Dynamic.Runtime": "4.0.11-rc2-23901",
- "System.Runtime.Loader": "4.0.0-rc2-23901",
- "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23901",
- "Microsoft.CSharp": "4.0.1-rc2-23901",
- "System.Xml.XDocument": "4.0.11-rc2-23901"
- }
+ "System.Collections": {
+ "type": "build"
+ },
+ "System.IO": {
+ "type": "build"
}
+ }
+ },
+ "netstandard1.3": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.Dynamic.Runtime": "4.0.11-rc2-23911",
+ "System.Runtime.Loader": "4.0.0-rc2-23911",
+ "System.Security.Cryptography.Algorithms": "4.0.0-rc2-23911",
+ "Microsoft.CSharp": "4.0.1-rc2-23911",
+ "System.Xml.XDocument": "4.0.11-rc2-23911"
+ }
}
+ }
}
diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj
index e6f1e6339..4fc8570fb 100644
--- a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj
+++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj
@@ -5,7 +5,7 @@
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
0724ed7c-56e3-4604-9970-25e600611383
Microsoft.DotNet.TestFramework
@@ -16,5 +16,5 @@
2.0
-
+
diff --git a/src/Microsoft.DotNet.TestFramework/project.json b/src/Microsoft.DotNet.TestFramework/project.json
index e04e63cb5..2e096995e 100644
--- a/src/Microsoft.DotNet.TestFramework/project.json
+++ b/src/Microsoft.DotNet.TestFramework/project.json
@@ -1,4 +1,4 @@
-{
+{
"version": "1.0.0-*",
"description": "Microsoft.DotNet.TestFramework Class Library",
"authors": [
@@ -11,7 +11,7 @@
"licenseUrl": "",
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",
- "NETStandard.Library": "1.0.0-rc2-23901"
+ "NETStandard.Library": "1.5.0-rc2-23911"
},
"frameworks": {
"netstandard1.3": {
diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs
index c31ea8dc6..f4f3e34ba 100644
--- a/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs
+++ b/src/Microsoft.Extensions.DependencyModel/DependencyContext.cs
@@ -11,9 +11,6 @@ namespace Microsoft.Extensions.DependencyModel
{
public class DependencyContext
{
- private const string DepsJsonExtension = ".deps.json";
- private const string DepsFileExtension = ".deps";
-
private static readonly Lazy _defaultContext = new Lazy(LoadDefault);
public DependencyContext(string targetFramework,
@@ -22,7 +19,7 @@ namespace Microsoft.Extensions.DependencyModel
CompilationOptions compilationOptions,
IEnumerable compileLibraries,
IEnumerable runtimeLibraries,
- IEnumerable> runtimeGraph)
+ IEnumerable runtimeGraph)
{
if (targetFramework == null)
{
@@ -32,6 +29,10 @@ namespace Microsoft.Extensions.DependencyModel
{
throw new ArgumentNullException(nameof(runtime));
}
+ if (compilationOptions == null)
+ {
+ throw new ArgumentNullException(nameof(compilationOptions));
+ }
if (compileLibraries == null)
{
throw new ArgumentNullException(nameof(compileLibraries));
@@ -68,48 +69,47 @@ namespace Microsoft.Extensions.DependencyModel
public IReadOnlyList RuntimeLibraries { get; }
- public IReadOnlyList> RuntimeGraph { get; }
+ public IReadOnlyList RuntimeGraph { get; }
+
+ public DependencyContext Merge(DependencyContext other)
+ {
+ if (other == null)
+ {
+ throw new ArgumentNullException(nameof(other));
+ }
+
+ return new DependencyContext(
+ TargetFramework,
+ Runtime,
+ IsPortable,
+ CompilationOptions,
+ CompileLibraries.Union(other.CompileLibraries, new LibraryMergeEqualityComparer()),
+ RuntimeLibraries.Union(other.RuntimeLibraries, new LibraryMergeEqualityComparer()),
+ RuntimeGraph.Union(other.RuntimeGraph)
+ );
+ }
private static DependencyContext LoadDefault()
{
- var entryAssembly = Assembly.GetEntryAssembly();
- return Load(entryAssembly);
+ return DependencyContextLoader.Default.Load(Assembly.GetEntryAssembly());
}
public static DependencyContext Load(Assembly assembly)
{
- if (assembly == null)
+ return DependencyContextLoader.Default.Load(assembly);
+ }
+
+ private class LibraryMergeEqualityComparer: IEqualityComparer where T:Library
+ {
+ public bool Equals(T x, T y)
{
- throw new ArgumentNullException(nameof(assembly));
+ return string.Equals(x.Name, y.Name, StringComparison.Ordinal);
}
- using (var stream = assembly.GetManifestResourceStream(assembly.GetName().Name + DepsJsonExtension))
+ public int GetHashCode(T obj)
{
- if (stream != null)
- {
- return new DependencyContextJsonReader().Read(stream);
- }
+ return obj.Name.GetHashCode();
}
-
- var depsJsonFile = Path.ChangeExtension(assembly.Location, DepsJsonExtension);
- if (File.Exists(depsJsonFile))
- {
- using (var stream = File.OpenRead(depsJsonFile))
- {
- return new DependencyContextJsonReader().Read(stream);
- }
- }
-
- var depsFile = Path.ChangeExtension(assembly.Location, DepsFileExtension);
- if (File.Exists(depsFile))
- {
- using (var stream = File.OpenRead(depsFile))
- {
- return new DependencyContextCsvReader().Read(stream);
- }
- }
-
- return null;
}
}
}
diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs
index ebab91f2e..0e1e5e54a 100644
--- a/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs
+++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextCsvReader.cs
@@ -9,7 +9,7 @@ using System.Text;
namespace Microsoft.Extensions.DependencyModel
{
- public class DependencyContextCsvReader
+ public class DependencyContextCsvReader: IDependencyContextReader
{
public DependencyContext Read(Stream stream)
{
@@ -62,7 +62,7 @@ namespace Microsoft.Extensions.DependencyModel
compilationOptions: CompilationOptions.Default,
compileLibraries: Enumerable.Empty(),
runtimeLibraries: runtimeLibraries.ToArray(),
- runtimeGraph: Enumerable.Empty>());
+ runtimeGraph: Enumerable.Empty());
}
private Tuple PackageIdentity(DepsFileLine line)
diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs
index ca0d90916..12019b06f 100644
--- a/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs
+++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextJsonReader.cs
@@ -10,7 +10,7 @@ using Newtonsoft.Json.Linq;
namespace Microsoft.Extensions.DependencyModel
{
- public class DependencyContextJsonReader
+ public class DependencyContextJsonReader: IDependencyContextReader
{
public DependencyContext Read(Stream stream)
{
@@ -79,7 +79,7 @@ namespace Microsoft.Extensions.DependencyModel
);
}
- private IEnumerable> ReadRuntimeGraph(JObject runtimes)
+ private IEnumerable ReadRuntimeGraph(JObject runtimes)
{
if (runtimes == null)
{
@@ -90,7 +90,7 @@ namespace Microsoft.Extensions.DependencyModel
var runtime = (JProperty)targets.Single();
foreach (var pair in (JObject)runtime.Value)
{
- yield return new KeyValuePair(pair.Key, pair.Value.Values().ToArray());
+ yield return new RuntimeFallbacks(pair.Key, pair.Value.Values().ToArray());
}
}
diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs
new file mode 100644
index 000000000..4a4256bb1
--- /dev/null
+++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextLoader.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using Microsoft.Extensions.EnvironmentAbstractions;
+
+namespace Microsoft.Extensions.DependencyModel
+{
+ public class DependencyContextLoader
+ {
+ private static Lazy _depsFiles = new Lazy(GetHostDepsList);
+
+ private const string DepsJsonExtension = ".deps.json";
+ private const string DepsExtension = ".deps";
+
+ private readonly string _entryPointDepsLocation;
+ private readonly string _runtimeDepsLocation;
+ private readonly IFileSystem _fileSystem;
+ private readonly IDependencyContextReader _jsonReader;
+ private readonly IDependencyContextReader _csvReader;
+
+ public DependencyContextLoader() : this(
+ GetDefaultEntrypointDepsLocation(),
+ GetDefaultRuntimeDepsLocation(),
+ FileSystemWrapper.Default,
+ new DependencyContextJsonReader(),
+ new DependencyContextCsvReader())
+ {
+ }
+
+ internal DependencyContextLoader(
+ string entryPointDepsLocation,
+ string runtimeDepsLocation,
+ IFileSystem fileSystem,
+ IDependencyContextReader jsonReader,
+ IDependencyContextReader csvReader)
+ {
+ _entryPointDepsLocation = entryPointDepsLocation;
+ _runtimeDepsLocation = runtimeDepsLocation;
+ _fileSystem = fileSystem;
+ _jsonReader = jsonReader;
+ _csvReader = csvReader;
+ }
+
+ public static DependencyContextLoader Default { get; } = new DependencyContextLoader();
+
+ internal virtual bool IsEntryAssembly(Assembly assembly)
+ {
+ return assembly.GetName() == Assembly.GetEntryAssembly().GetName();
+ }
+
+ internal virtual Stream GetResourceStream(Assembly assembly, string name)
+ {
+ return assembly.GetManifestResourceStream(name);
+ }
+
+ public DependencyContext Load(Assembly assembly)
+ {
+ if (assembly == null)
+ {
+ throw new ArgumentNullException(nameof(assembly));
+ }
+
+ DependencyContext context = null;
+
+ if (IsEntryAssembly(assembly))
+ {
+ context = LoadEntryAssemblyContext();
+ }
+
+ if (context == null)
+ {
+ context = LoadAssemblyContext(assembly);
+ }
+
+ if (context?.IsPortable == true)
+ {
+ var runtimeContext = LoadRuntimeContext();
+ if (runtimeContext != null)
+ {
+ context = context.Merge(runtimeContext);
+ }
+ }
+ return context;
+ }
+
+ private DependencyContext LoadEntryAssemblyContext()
+ {
+ if (!string.IsNullOrEmpty(_entryPointDepsLocation))
+ {
+ Debug.Assert(File.Exists(_entryPointDepsLocation));
+ using (var stream = _fileSystem.File.OpenRead(_entryPointDepsLocation))
+ {
+ return _jsonReader.Read(stream);
+ }
+ }
+ return null;
+ }
+
+ private DependencyContext LoadRuntimeContext()
+ {
+ if (!string.IsNullOrEmpty(_runtimeDepsLocation))
+ {
+ Debug.Assert(File.Exists(_runtimeDepsLocation));
+ using (var stream = _fileSystem.File.OpenRead(_runtimeDepsLocation))
+ {
+ return _jsonReader.Read(stream);
+ }
+ }
+ return null;
+ }
+
+ private DependencyContext LoadAssemblyContext(Assembly assembly)
+ {
+ using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension))
+ {
+ if (stream != null)
+ {
+ return _jsonReader.Read(stream);
+ }
+ }
+
+ var depsJsonFile = Path.ChangeExtension(assembly.Location, DepsJsonExtension);
+ if (_fileSystem.File.Exists(depsJsonFile))
+ {
+ using (var stream = _fileSystem.File.OpenRead(depsJsonFile))
+ {
+ return _jsonReader.Read(stream);
+ }
+ }
+
+ var depsFile = Path.ChangeExtension(assembly.Location, DepsExtension);
+ if (_fileSystem.File.Exists(depsFile))
+ {
+ using (var stream = _fileSystem.File.OpenRead(depsFile))
+ {
+ return _csvReader.Read(stream);
+ }
+ }
+
+ return null;
+ }
+
+ private static string GetDefaultRuntimeDepsLocation()
+ {
+ var deps = _depsFiles.Value;
+ if (deps != null && deps.Length > 1)
+ {
+ return deps[1];
+ }
+ return null;
+ }
+
+ private static string GetDefaultEntrypointDepsLocation()
+ {
+ var deps = _depsFiles.Value;
+ if (deps != null && deps.Length > 0)
+ {
+ return deps[0];
+ }
+ return null;
+ }
+
+ private static string[] GetHostDepsList()
+ {
+ // TODO: Were going to replace this with AppContext.GetData
+ var appDomainType = typeof(object).GetTypeInfo().Assembly?.GetType("System.AppDomain");
+ var currentDomain = appDomainType?.GetProperty("CurrentDomain")?.GetValue(null);
+ var deps = appDomainType?.GetMethod("GetData")?.Invoke(currentDomain, new[] { "APP_CONTEXT_DEPS_FILES" });
+
+ return (deps as string)?.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ }
+}
diff --git a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs
index 1a6235345..ecc06a77b 100644
--- a/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs
+++ b/src/Microsoft.Extensions.DependencyModel/DependencyContextWriter.cs
@@ -50,7 +50,7 @@ namespace Microsoft.Extensions.DependencyModel
private JObject WriteRuntimeGraph(DependencyContext context)
{
return new JObject(
- context.RuntimeGraph.Select(g => new JProperty(g.Key, new JArray(g.Value)))
+ context.RuntimeGraph.Select(g => new JProperty(g.Runtime, new JArray(g.Fallbacks)))
);
}
@@ -79,7 +79,7 @@ namespace Microsoft.Extensions.DependencyModel
{
if (value != null)
{
- o[name] = value.ToString();
+ o.Add(new JProperty(name, value));
}
}
@@ -168,7 +168,7 @@ namespace Microsoft.Extensions.DependencyModel
{
return;
}
- libraryObject.Add(
+ libraryObject.AddFirst(
new JProperty(DependencyContextStrings.DependenciesPropertyName,
new JObject(
dependencies.Select(dependency => new JProperty(dependency.Name, dependency.Version))))
@@ -232,8 +232,8 @@ namespace Microsoft.Extensions.DependencyModel
new JObject(runtimeLibrary.RuntimeTargets.SelectMany(WriteRuntimeTarget)))
);
}
- AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies);
AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies);
+ AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies);
libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries));
dependencies.UnionWith(runtimeLibrary.Dependencies);
diff --git a/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs b/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs
new file mode 100644
index 000000000..57b2a442e
--- /dev/null
+++ b/src/Microsoft.Extensions.DependencyModel/IDependencyContextReader.cs
@@ -0,0 +1,9 @@
+using System.IO;
+
+namespace Microsoft.Extensions.DependencyModel
+{
+ public interface IDependencyContextReader
+ {
+ DependencyContext Read(Stream stream);
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj b/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj
index 8c6e7884f..8e2d9aca8 100644
--- a/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj
+++ b/src/Microsoft.Extensions.DependencyModel/Microsoft.Extensions.DependencyModel.xproj
@@ -4,7 +4,7 @@
14.0.23107
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
688870c8-9843-4f9e-8576-d39290ad0f25
Microsoft.Extensions.DependencyModel
@@ -14,5 +14,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs
new file mode 100644
index 000000000..d759b1942
--- /dev/null
+++ b/src/Microsoft.Extensions.DependencyModel/RuntimeFallbacks.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Generic;
+
+namespace Microsoft.Extensions.DependencyModel
+{
+ public class RuntimeFallbacks
+ {
+ public string Runtime { get; set; }
+ public IEnumerable Fallbacks { get; set; }
+
+ public RuntimeFallbacks(string runtime, IEnumerable fallbacks)
+ {
+ Runtime = runtime;
+ Fallbacks = fallbacks;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.Extensions.DependencyModel/project.json b/src/Microsoft.Extensions.DependencyModel/project.json
index 1ad395b56..65fd21652 100644
--- a/src/Microsoft.Extensions.DependencyModel/project.json
+++ b/src/Microsoft.Extensions.DependencyModel/project.json
@@ -1,39 +1,38 @@
{
- "description": "Abstractions for reading `.deps` files.",
- "version": "1.0.0-*",
- "repository": {
- "type": "git",
- "url": "git://github.com/dotnet/cli"
+ "description": "Abstractions for reading `.deps` files.",
+ "version": "1.0.0-*",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/dotnet/cli"
+ },
+ "compilationOptions": {
+ "warningsAsErrors": true,
+ "keyFile": "../../tools/Key.snk"
+ },
+ "dependencies": {
+ "Microsoft.Extensions.HashCodeCombiner.Sources": {
+ "type": "build",
+ "version": "1.0.0-rc2-16054"
},
- "compilationOptions": {
- "warningsAsErrors": true,
- "keyFile": "../../tools/Key.snk"
+ "Microsoft.DotNet.InternalAbstractions": {
+ "target": "project",
+ "version": "1.0.0-*"
},
- "dependencies": {
- "Microsoft.Extensions.HashCodeCombiner.Sources": {
- "type": "build",
- "version": "1.0.0-rc2-16054"
- },
- "Microsoft.DotNet.InternalAbstractions": {
- "target": "project",
- "version": "1.0.0-*"
- },
-
- "Newtonsoft.Json": "7.0.1",
- "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
- },
- "frameworks": {
- "net451": {},
- "netstandard1.3": {
- "imports": "dnxcore50",
- "dependencies": {
- "System.IO.FileSystem": "4.0.1-rc2-23901",
- "System.Linq": "4.0.1-rc2-23901",
- "System.Runtime": "4.0.21-rc2-23901",
- "System.Reflection": "4.1.0-rc2-23901",
- "System.Dynamic.Runtime": "4.0.11-rc2-23901"
- }
- }
- },
- "scripts": {}
-}
\ No newline at end of file
+ "Newtonsoft.Json": "7.0.1",
+ "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-16537"
+ },
+ "frameworks": {
+ "net451": {},
+ "netstandard1.3": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "System.IO.FileSystem": "4.0.1-rc2-23911",
+ "System.Linq": "4.0.1-rc2-23911",
+ "System.Runtime": "4.0.21-rc2-23911",
+ "System.Reflection": "4.1.0-rc2-23911",
+ "System.Dynamic.Runtime": "4.0.11-rc2-23911"
+ }
+ }
+ },
+ "scripts": {}
+}
diff --git a/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj b/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj
index a364b40ec..9d149a5c3 100644
--- a/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj
+++ b/src/Microsoft.Extensions.Testing.Abstractions/Microsoft.Extensions.Testing.Abstractions.xproj
@@ -4,7 +4,7 @@
14.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
+
dcdfe282-03de-4dbc-b90c-cc3ce3ec8162
Microsoft.Extensions.Testing.Abstractions
@@ -14,5 +14,5 @@
2.0
-
+
\ No newline at end of file
diff --git a/src/Microsoft.Extensions.Testing.Abstractions/project.json b/src/Microsoft.Extensions.Testing.Abstractions/project.json
index 7ecb6232e..e392da6d6 100644
--- a/src/Microsoft.Extensions.Testing.Abstractions/project.json
+++ b/src/Microsoft.Extensions.Testing.Abstractions/project.json
@@ -1,29 +1,29 @@
{
- "description": "Abstractions for test runners to communicate to a tool, such as Visual Studio.",
- "version": "1.0.0-*",
- "repository": {
- "type": "git",
- "url": "git://github.com/dotnet/cli"
- },
- "compilationOptions": {
- "warningsAsErrors": true,
- "keyFile": "../../tools/Key.snk"
- },
- "dependencies": {
- "Newtonsoft.Json": "7.0.1",
- "Microsoft.DotNet.ProjectModel": "1.0.0-*",
- "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-16040"
- },
- "frameworks": {
- "net451": {},
- "netstandard1.3": {
- "imports": "dnxcore50",
- "dependencies": {
- "NETStandard.Library": "1.0.0-rc2-23901",
- "System.Resources.ResourceManager": "4.0.1-rc2-23901",
- "System.Runtime.Serialization.Primitives": "4.1.0-rc2-23901"
- }
- }
- },
- "scripts": {}
-}
\ No newline at end of file
+ "description": "Abstractions for test runners to communicate to a tool, such as Visual Studio.",
+ "version": "1.0.0-*",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/dotnet/cli"
+ },
+ "compilationOptions": {
+ "warningsAsErrors": true,
+ "keyFile": "../../tools/Key.snk"
+ },
+ "dependencies": {
+ "Newtonsoft.Json": "7.0.1",
+ "Microsoft.DotNet.ProjectModel": "1.0.0-*",
+ "Microsoft.Extensions.Logging.Abstractions": "1.0.0-rc2-16040"
+ },
+ "frameworks": {
+ "net451": {},
+ "netstandard1.3": {
+ "imports": "dnxcore50",
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-23911",
+ "System.Resources.ResourceManager": "4.0.1-rc2-23911",
+ "System.Reflection.TypeExtensions": "4.1.0-rc2-23911"
+ }
+ }
+ },
+ "scripts": {}
+}
diff --git a/src/corehost/build.sh b/src/corehost/build.sh
index 339838348..7717bdc15 100755
--- a/src/corehost/build.sh
+++ b/src/corehost/build.sh
@@ -14,6 +14,46 @@ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symli
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
+__build_arch=
+__runtime_id=
+
+while [ "$1" != "" ]; do
+ lowerI="$(echo $1 | awk '{print tolower($0)}')"
+ case $lowerI in
+ -h|--help)
+ usage
+ exit 1
+ ;;
+ --arch)
+ shift
+ __build_arch=$1
+ ;;
+ --rid)
+ shift
+ __runtime_id=$1
+ ;;
+ *)
+ echo "Unknown argument to build.sh $1"; exit 1
+ esac
+ shift
+done
+
+__cmake_defines=
+
+case $__build_arch in
+ amd64)
+ __define=-DCLI_CMAKE_PLATFORM_ARCH_AMD64=1
+ ;;
+ x86)
+ __define=-DCLI_CMAKE_PLATFORM_ARCH_I386=1
+ ;;
+ *)
+ echo "Unknown architecture $__build_arch"; exit 1
+ ;;
+esac
+__cmake_defines="${__cmake_defines} ${__define}"
+
+
echo "Building Corehost from $DIR to $(pwd)"
-cmake "$DIR" -G "Unix Makefiles"
+cmake "$DIR" -G "Unix Makefiles" $__cmake_defines -DCLI_CMAKE_RUNTIME_ID:STRING=$__runtime_id
make
diff --git a/src/corehost/cli/CMakeLists.txt b/src/corehost/cli/CMakeLists.txt
index 9c22fc834..12636ae6b 100644
--- a/src/corehost/cli/CMakeLists.txt
+++ b/src/corehost/cli/CMakeLists.txt
@@ -14,13 +14,26 @@ include(setup.cmake)
set (CMAKE_CXX_STANDARD 11)
+include_directories(..)
include_directories(../common)
include_directories(.)
+include_directories(./fxr)
+include_directories(./json/casablanca/include)
# CMake does not recommend using globbing since it messes with the freshness checks
set(SOURCES
- ../corehost.cpp
+ libhost.cpp
+ #deps_format.cpp
+ #./json/casablanca/src/json/json.cpp
+ #./json/casablanca/src/json/json_parsing.cpp
+ #./json/casablanca/src/json/json_serialization.cpp
+ #./json/casablanca/src/utilities/asyncrt_utils.cpp
+
+
+ ./fxr/fx_ver.cpp
+ ../corehost.cpp
+ ../policy_load.cpp
../common/trace.cpp
../common/utils.cpp)
@@ -32,6 +45,9 @@ else()
endif()
add_executable(corehost ${SOURCES})
+install(TARGETS corehost DESTINATION bin)
+add_definitions(-D_NO_ASYNCRTIMP)
+add_definitions(-D_NO_PPLXIMP)
# Older CMake doesn't support CMAKE_CXX_STANDARD and GCC/Clang need a switch to enable C++ 11
if(${CMAKE_CXX_COMPILER_ID} MATCHES "(Clang|GNU)")
@@ -44,3 +60,4 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
endif()
add_subdirectory(dll)
+add_subdirectory(fxr)
diff --git a/src/corehost/cli/args.cpp b/src/corehost/cli/args.cpp
index 086d05fab..569110857 100644
--- a/src/corehost/cli/args.cpp
+++ b/src/corehost/cli/args.cpp
@@ -4,6 +4,7 @@
#include "args.h"
#include "utils.h"
#include "coreclr.h"
+#include "libhost.h"
arguments_t::arguments_t() :
managed_application(_X("")),
@@ -11,11 +12,8 @@ arguments_t::arguments_t() :
app_dir(_X("")),
app_argc(0),
app_argv(nullptr),
- nuget_packages(_X("")),
dotnet_packages_cache(_X("")),
dotnet_servicing(_X("")),
- dotnet_runtime_servicing(_X("")),
- dotnet_home(_X("")),
deps_path(_X(""))
{
}
@@ -26,12 +24,13 @@ void display_help()
_X("Usage: " HOST_EXE_NAME " [ASSEMBLY] [ARGUMENTS]\n")
_X("Execute the specified managed assembly with the passed in arguments\n\n")
_X("The Host's behavior can be altered using the following environment variables:\n")
- _X(" DOTNET_HOME Set the dotnet home directory. The CLR is expected to be in the runtime subdirectory of this directory. Overrides all other values for CLR search paths\n")
_X(" COREHOST_TRACE Set to affect trace levels (0 = Errors only (default), 1 = Warnings, 2 = Info, 3 = Verbose)\n");
}
-bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args)
+bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_dir, host_mode_t mode,
+ const int argc, const pal::char_t* argv[], arguments_t* arg_out)
{
+ arguments_t& args = *arg_out;
// Get the full name of the application
if (!pal::get_own_executable_path(&args.own_path) || !pal::realpath(&args.own_path))
{
@@ -41,8 +40,8 @@ bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& arg
auto own_name = get_filename(args.own_path);
auto own_dir = get_directory(args.own_path);
-
- if (own_name.compare(HOST_EXE_NAME) == 0)
+
+ if (mode != host_mode_t::standalone)
{
// corerun mode. First argument is managed app
if (argc < 2)
@@ -78,23 +77,26 @@ bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& arg
args.app_argc = argc - 1;
}
- if (args.app_argc > 0)
+ std::unordered_map opts;
+ std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath") };
+ int num_args = 0;
+ if (!parse_known_args(args.app_argc, args.app_argv, known_opts, &opts, &num_args))
{
- auto depsfile_candidate = pal::string_t(args.app_argv[0]);
-
- if (starts_with(depsfile_candidate, s_deps_arg_prefix, false))
- {
- args.deps_path = depsfile_candidate.substr(s_deps_arg_prefix.length());
- if (!pal::realpath(&args.deps_path))
- {
- trace::error(_X("Failed to locate deps file: %s"), args.deps_path.c_str());
- return false;
- }
- args.app_dir = get_directory(args.deps_path);
- args.app_argc = args.app_argc - 1;
- args.app_argv = &args.app_argv[1];
- }
+ return false;
}
+
+ args.app_argc -= num_args;
+ args.app_argv += num_args;
+ pal::string_t deps_file = opts.count(_X("--depsfile")) ? opts[_X("--depsfile")] : deps_path;
+ pal::string_t probe_path = opts.count(_X("--additionalprobingpath")) ? opts[_X("--additionalprobingpath")] : probe_dir;
+
+ if (!deps_file.empty())
+ {
+ args.deps_path = deps_file;
+ args.app_dir = get_directory(args.deps_path);
+ }
+
+ args.probe_dir = probe_path;
if (args.deps_path.empty())
{
@@ -105,13 +107,10 @@ bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& arg
args.deps_path.append(app_base);
args.deps_path.push_back(DIR_SEPARATOR);
args.deps_path.append(app_name, 0, app_name.find_last_of(_X(".")));
- args.deps_path.append(_X(".deps"));
+ args.deps_path.append(_X(".deps.json"));
}
- pal::getenv(_X("NUGET_PACKAGES"), &args.nuget_packages);
pal::getenv(_X("DOTNET_PACKAGES_CACHE"), &args.dotnet_packages_cache);
pal::getenv(_X("DOTNET_SERVICING"), &args.dotnet_servicing);
- pal::getenv(_X("DOTNET_RUNTIME_SERVICING"), &args.dotnet_runtime_servicing);
- pal::getenv(_X("DOTNET_HOME"), &args.dotnet_home);
return true;
}
diff --git a/src/corehost/cli/args.h b/src/corehost/cli/args.h
index d510cd6e8..bec56128c 100644
--- a/src/corehost/cli/args.h
+++ b/src/corehost/cli/args.h
@@ -7,8 +7,7 @@
#include "utils.h"
#include "pal.h"
#include "trace.h"
-
-static const pal::string_t s_deps_arg_prefix = _X("--depsfile:");
+#include "libhost.h"
struct arguments_t
{
@@ -18,7 +17,7 @@ struct arguments_t
pal::string_t dotnet_servicing;
pal::string_t dotnet_runtime_servicing;
pal::string_t dotnet_home;
- pal::string_t nuget_packages;
+ pal::string_t probe_dir;
pal::string_t dotnet_packages_cache;
pal::string_t managed_application;
@@ -28,6 +27,6 @@ struct arguments_t
arguments_t();
};
-bool parse_arguments(const int argc, const pal::char_t* argv[], arguments_t& args);
+bool parse_arguments(const pal::string_t& deps_path, const pal::string_t& probe_dir, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args);
#endif // ARGS_H
diff --git a/src/corehost/cli/deps_entry.cpp b/src/corehost/cli/deps_entry.cpp
new file mode 100644
index 000000000..ff5ebbbe3
--- /dev/null
+++ b/src/corehost/cli/deps_entry.cpp
@@ -0,0 +1,144 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "pal.h"
+#include "utils.h"
+#include "deps_entry.h"
+#include "trace.h"
+
+// -----------------------------------------------------------------------------
+// Given a "base" directory, yield the relative path of this file in the package
+// layout.
+//
+// Parameters:
+// base - The base directory to look for the relative path of this entry
+// str - If the method returns true, contains the file path for this deps
+// entry relative to the "base" directory
+//
+// Returns:
+// If the file exists in the path relative to the "base" directory.
+//
+bool deps_entry_t::to_full_path(const pal::string_t& base, pal::string_t* str) const
+{
+ pal::string_t& candidate = *str;
+
+ candidate.clear();
+
+ // Base directory must be present to obtain full path
+ if (base.empty())
+ {
+ return false;
+ }
+
+ // Entry relative path contains '/' separator, sanitize it to use
+ // platform separator. Perf: avoid extra copy if it matters.
+ pal::string_t pal_relative_path = relative_path;
+ if (_X('/') != DIR_SEPARATOR)
+ {
+ replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR);
+ }
+
+ // Reserve space for the path below
+ candidate.reserve(base.length() +
+ library_name.length() +
+ library_version.length() +
+ pal_relative_path.length() + 3);
+
+ candidate.assign(base);
+ append_path(&candidate, library_name.c_str());
+ append_path(&candidate, library_version.c_str());
+ append_path(&candidate, pal_relative_path.c_str());
+
+ bool exists = pal::file_exists(candidate);
+ if (!exists)
+ {
+ candidate.clear();
+ }
+ return exists;
+}
+
+// -----------------------------------------------------------------------------
+// Given a "base" directory, yield the relative path of this file in the package
+// layout if the entry hash matches the hash file in the "base" directory
+//
+// Parameters:
+// base - The base directory to look for the relative path of this entry and
+// the hash file.
+// str - If the method returns true, contains the file path for this deps
+// entry relative to the "base" directory
+//
+// Description:
+// Looks for a file named "{PackageName}.{PackageVersion}.nupkg.{HashAlgorithm}"
+// If the deps entry's {HashAlgorithm}-{HashValue} matches the contents then
+// yields the relative path of this entry in the "base" dir.
+//
+// Returns:
+// If the file exists in the path relative to the "base" directory and there
+// was hash file match with this deps entry.
+//
+// See: to_full_path(base, str)
+//
+bool deps_entry_t::to_hash_matched_path(const pal::string_t& base, pal::string_t* str) const
+{
+ pal::string_t& candidate = *str;
+
+ candidate.clear();
+
+ // Base directory must be present to perform hash lookup.
+ if (base.empty())
+ {
+ return false;
+ }
+
+ // First detect position of hyphen in [Algorithm]-[Hash] in the string.
+ size_t pos = library_hash.find(_X("-"));
+ if (pos == 0 || pos == pal::string_t::npos)
+ {
+ trace::verbose(_X("Invalid hash %s value for deps file entry: %s"), library_hash.c_str(), library_name.c_str());
+ return false;
+ }
+
+ // Build the nupkg file name. Just reserve approx 8 char_t's for the algorithm name.
+ pal::string_t nupkg_filename;
+ nupkg_filename.reserve(library_name.length() + 1 + library_version.length() + 16);
+ nupkg_filename.append(library_name);
+ nupkg_filename.append(_X("."));
+ nupkg_filename.append(library_version);
+ nupkg_filename.append(_X(".nupkg."));
+ nupkg_filename.append(library_hash.substr(0, pos));
+
+ // Build the hash file path str.
+ pal::string_t hash_file;
+ hash_file.reserve(base.length() + library_name.length() + library_version.length() + nupkg_filename.length() + 3);
+ hash_file.assign(base);
+ append_path(&hash_file, library_name.c_str());
+ append_path(&hash_file, library_version.c_str());
+ append_path(&hash_file, nupkg_filename.c_str());
+
+ // Read the contents of the hash file.
+ pal::ifstream_t fstream(hash_file);
+ if (!fstream.good())
+ {
+ trace::verbose(_X("The hash file is invalid [%s]"), hash_file.c_str());
+ return false;
+ }
+
+ // Obtain the hash from the file.
+ std::string hash;
+ hash.assign(pal::istreambuf_iterator_t(fstream),
+ pal::istreambuf_iterator_t());
+ pal::string_t pal_hash;
+ pal::to_palstring(hash.c_str(), &pal_hash);
+
+ // Check if contents match deps entry.
+ pal::string_t entry_hash = library_hash.substr(pos + 1);
+ if (entry_hash != pal_hash)
+ {
+ trace::verbose(_X("The file hash [%s][%d] did not match entry hash [%s][%d]"),
+ pal_hash.c_str(), pal_hash.length(), entry_hash.c_str(), entry_hash.length());
+ return false;
+ }
+
+ // All good, just append the relative dir to base.
+ return to_full_path(base, &candidate);
+}
diff --git a/src/corehost/cli/deps_entry.h b/src/corehost/cli/deps_entry.h
new file mode 100644
index 000000000..81e30e541
--- /dev/null
+++ b/src/corehost/cli/deps_entry.h
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef __DEPS_ENTRY_H_
+#define __DEPS_ENTRY_H_
+
+#include
+#include
+#include "pal.h"
+
+struct deps_entry_t
+{
+ enum asset_types
+ {
+ runtime = 0,
+ resources,
+ native,
+ count
+ };
+
+ pal::string_t library_type;
+ pal::string_t library_name;
+ pal::string_t library_version;
+ pal::string_t library_hash;
+ pal::string_t asset_type;
+ pal::string_t asset_name;
+ pal::string_t relative_path;
+ bool is_serviceable;
+
+ // Given a "base" dir, yield the relative path in the package layout.
+ bool to_full_path(const pal::string_t& root, pal::string_t* str) const;
+
+ // Given a "base" dir, yield the relative path in the package layout only if
+ // the hash matches contents of the hash file.
+ bool to_hash_matched_path(const pal::string_t& root, pal::string_t* str) const;
+};
+
+#endif // __DEPS_ENTRY_H_
diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp
new file mode 100644
index 000000000..c85db98b5
--- /dev/null
+++ b/src/corehost/cli/deps_format.cpp
@@ -0,0 +1,305 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "deps_format.h"
+#include "utils.h"
+#include "trace.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+const std::array deps_json_t::s_known_asset_types = {
+ _X("runtime"), _X("resources"), _X("native") };
+
+const deps_entry_t& deps_json_t::try_ni(const deps_entry_t& entry) const
+{
+ if (m_ni_entries.count(entry.asset_name))
+ {
+ int index = m_ni_entries.at(entry.asset_name);
+ return m_deps_entries[deps_entry_t::asset_types::runtime][index];
+ }
+ return entry;
+}
+
+void deps_json_t::reconcile_libraries_with_targets(
+ const json_value& json,
+ const std::function& library_exists_fn,
+ const std::function&(const pal::string_t&, int)>& get_rel_paths_by_asset_type_fn)
+{
+ const auto& libraries = json.at(_X("libraries")).as_object();
+ for (const auto& library : libraries)
+ {
+ trace::info(_X("Reconciling library %s"), library.first.c_str());
+
+ if (pal::to_lower(library.second.at(_X("type")).as_string()) != _X("package"))
+ {
+ trace::info(_X("Library %s is not a package"), library.first.c_str());
+ continue;
+ }
+ if (!library_exists_fn(library.first))
+ {
+ trace::info(_X("Library %s does not exist"), library.first.c_str());
+ continue;
+ }
+
+ const auto& properties = library.second.as_object();
+
+ const pal::string_t& hash = properties.at(_X("sha512")).as_string();
+ bool serviceable = properties.at(_X("serviceable")).as_bool();
+
+ for (int i = 0; i < s_known_asset_types.size(); ++i)
+ {
+ for (const auto& rel_path : get_rel_paths_by_asset_type_fn(library.first, i))
+ {
+ bool ni_dll = false;
+ auto asset_name = get_filename_without_ext(rel_path);
+ if (ends_with(asset_name, _X(".ni"), false))
+ {
+ ni_dll = true;
+ asset_name = strip_file_ext(asset_name);
+ }
+
+ deps_entry_t entry;
+ size_t pos = library.first.find(_X("/"));
+ entry.library_name = library.first.substr(0, pos);
+ entry.library_version = library.first.substr(pos + 1);
+ entry.library_type = _X("package");
+ entry.library_hash = hash;
+ entry.asset_name = asset_name;
+ entry.asset_type = s_known_asset_types[i];
+ entry.relative_path = rel_path;
+ entry.is_serviceable = serviceable;
+
+ // TODO: Deps file does not follow spec. It uses '\\', should use '/'
+ replace_char(&entry.relative_path, _X('\\'), _X('/'));
+
+ m_deps_entries[i].push_back(entry);
+
+ if (ni_dll)
+ {
+ m_ni_entries[entry.asset_name] = m_deps_entries
+ [deps_entry_t::asset_types::runtime].size() - 1;
+ }
+
+ trace::info(_X("Added %s %s deps entry [%d] [%s, %s, %s]"), s_known_asset_types[i], entry.asset_name.c_str(), m_deps_entries[i].size() - 1, entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
+
+ if (i == deps_entry_t::asset_types::native &&
+ entry.asset_name == LIBCORECLR_FILENAME)
+ {
+ m_coreclr_index = m_deps_entries[i].size() - 1;
+ trace::verbose(_X("Found coreclr from deps %d [%s, %s, %s]"),
+ m_coreclr_index,
+ entry.library_name.c_str(),
+ entry.library_version.c_str(),
+ entry.relative_path.c_str());
+ }
+
+ }
+ }
+ }
+}
+
+pal::string_t get_own_rid()
+{
+#define _STRINGIFY(s) _X(s)
+#if defined(TARGET_RUNTIME_ID)
+ return _STRINGIFY(TARGET_RUNTIME_ID);
+#else
+#error "Cannot build the host without knowing host's root RID"
+#endif
+}
+
+bool deps_json_t::perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph)
+{
+ pal::string_t host_rid = get_own_rid();
+ for (auto& package : *portable_assets)
+ {
+ pal::string_t matched_rid = package.second.count(host_rid) ? host_rid : _X("");
+ if (matched_rid.empty())
+ {
+ if (rid_fallback_graph.count(host_rid) == 0)
+ {
+ trace::error(_X("Did not find fallback rids for package %s for the host rid %s"), package.first.c_str(), host_rid.c_str());
+ return false;
+ }
+ const auto& fallback_rids = rid_fallback_graph.find(host_rid)->second;
+ auto iter = std::find_if(fallback_rids.begin(), fallback_rids.end(), [&package](const pal::string_t& rid) {
+ return package.second.count(rid);
+ });
+ if (iter == fallback_rids.end() || (*iter).empty())
+ {
+ trace::error(_X("Did not find a matching fallback rid for package %s for the host rid %s"), package.first.c_str(), host_rid.c_str());
+ return false;
+ }
+ matched_rid = *iter;
+ }
+ assert(!matched_rid.empty());
+ for (auto iter = package.second.begin(); iter != package.second.end(); /* */)
+ {
+ iter = (iter->first != matched_rid)
+ ? package.second.erase(iter)
+ : iter++;
+ }
+ }
+ return true;
+}
+
+
+bool deps_json_t::process_runtime_targets(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph, rid_specific_assets_t* p_assets)
+{
+ rid_specific_assets_t& assets = *p_assets;
+ for (const auto& package : json.at(_X("targets")).at(target_name).as_object())
+ {
+ const auto& targets = package.second.as_object();
+ auto iter = targets.find(_X("runtimeTargets"));
+ if (iter == targets.end())
+ {
+ continue;
+ }
+
+ const auto& files = iter->second.as_object();
+ for (const auto& file : files)
+ {
+ const auto& type = file.second.at(_X("assetType")).as_string();
+ for (int i = 0; i < s_known_asset_types.size(); ++i)
+ {
+ if (pal::strcasecmp(type.c_str(), s_known_asset_types[i]) == 0)
+ {
+ const auto& rid = file.second.at(_X("rid")).as_string();
+ assets[package.first][rid][i].push_back(file.first);
+ }
+ }
+ }
+ }
+
+ if (!perform_rid_fallback(&assets, rid_fallback_graph))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool deps_json_t::process_targets(const json_value& json, const pal::string_t& target_name, deps_assets_t* p_assets)
+{
+ deps_assets_t& assets = *p_assets;
+ for (const auto& package : json.at(_X("targets")).at(target_name).as_object())
+ {
+ // if (package.second.at(_X("type")).as_string() != _X("package")) continue;
+
+ const auto& asset_types = package.second.as_object();
+ for (int i = 0; i < s_known_asset_types.size(); ++i)
+ {
+ auto iter = asset_types.find(s_known_asset_types[i]);
+ if (iter != asset_types.end())
+ {
+ for (const auto& file : iter->second.as_object())
+ {
+ trace::info(_X("Adding %s asset %s from %s"), s_known_asset_types[i], file.first.c_str(), package.first.c_str());
+ assets[package.first][i].push_back(file.first);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool deps_json_t::load_portable(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph)
+{
+ rid_specific_assets_t rid_assets;
+ if (!process_runtime_targets(json, target_name, rid_fallback_graph, &rid_assets))
+ {
+ return false;
+ }
+
+ deps_assets_t non_rid_assets;
+ if (!process_targets(json, target_name, &non_rid_assets))
+ {
+ return false;
+ }
+
+ auto package_exists = [&rid_assets, &non_rid_assets](const pal::string_t& package) -> bool {
+ return rid_assets.count(package) || non_rid_assets.count(package);
+ };
+ auto get_relpaths = [&rid_assets, &non_rid_assets](const pal::string_t& package, int type_index) -> const std::vector& {
+ return (rid_assets.count(package))
+ ? rid_assets[package].begin()->second[type_index]
+ : non_rid_assets[package][type_index];
+ };
+
+ reconcile_libraries_with_targets(json, package_exists, get_relpaths);
+
+ return true;
+}
+
+bool deps_json_t::load_standalone(const json_value& json, const pal::string_t& target_name)
+{
+ deps_assets_t assets;
+
+ if (!process_targets(json, target_name, &assets))
+ {
+ return false;
+ }
+
+ auto package_exists = [&assets](const pal::string_t& package) -> bool {
+ return assets.count(package);
+ };
+
+ auto get_relpaths = [&assets](const pal::string_t& package, int type_index) -> const std::vector& {
+ return assets[package][type_index];
+ };
+
+ reconcile_libraries_with_targets(json, package_exists, get_relpaths);
+
+ const auto& json_object = json.as_object();
+ const auto iter = json_object.find(_X("runtimes"));
+ if (iter != json_object.end())
+ {
+ for (const auto& rid : iter->second.as_object())
+ {
+ auto& vec = m_rid_fallback_graph[rid.first];
+ for (const auto& fallback : rid.second.as_array())
+ {
+ vec.push_back(fallback.as_string());
+ }
+ }
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// Load the deps file and parse its "entry" lines which contain the "fields" of
+// the entry. Populate an array of these entries.
+//
+bool deps_json_t::load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph)
+{
+ // If file doesn't exist, then assume parsed.
+ if (!pal::file_exists(deps_path))
+ {
+ return true;
+ }
+
+ // Somehow the file stream could not be opened. This is an error.
+ pal::ifstream_t file(deps_path);
+ if (!file.good())
+ {
+ return false;
+ }
+
+ try
+ {
+ const auto json = json_value::parse(file);
+
+ const auto& runtime_target = json.at(_X("runtimeTarget"));
+ const pal::string_t& name = runtime_target.as_string();
+
+ return (portable) ? load_portable(json, name, rid_fallback_graph) : load_standalone(json, name);
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
diff --git a/src/corehost/cli/deps_format.h b/src/corehost/cli/deps_format.h
new file mode 100644
index 000000000..e9c8a0cea
--- /dev/null
+++ b/src/corehost/cli/deps_format.h
@@ -0,0 +1,113 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef __DEPS_FORMAT_H_
+#define __DEPS_FORMAT_H_
+
+#include
+#include
+#include
+#include "pal.h"
+#include "deps_entry.h"
+#include "cpprest/json.h"
+
+class deps_json_t
+{
+ typedef web::json::value json_value;
+ typedef std::array, deps_entry_t::asset_types::count> vectors_t;
+ typedef std::unordered_map str_to_vectors_map_t;
+ typedef std::unordered_map> str_to_vector_map_t;
+
+ typedef str_to_vector_map_t rid_fallback_graph_t;
+ typedef str_to_vectors_map_t deps_assets_t;
+ typedef std::unordered_map rid_specific_assets_t;
+
+public:
+ deps_json_t()
+ : m_valid(false)
+ , m_coreclr_index(-1)
+ {
+ }
+
+ deps_json_t(bool portable, const pal::string_t& deps_path)
+ : deps_json_t(portable, deps_path, m_rid_fallback_graph /* dummy */)
+ {
+ }
+
+ deps_json_t(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& graph)
+ : deps_json_t()
+ {
+ m_valid = load(portable, deps_path, graph);
+ }
+
+ const std::vector& get_entries(deps_entry_t::asset_types type)
+ {
+ assert(type < deps_entry_t::asset_types::count);
+ return m_deps_entries[type];
+ }
+
+ bool has_coreclr_entry()
+ {
+ return m_coreclr_index >= 0;
+ }
+
+ const deps_entry_t& get_coreclr_entry()
+ {
+ assert(has_coreclr_entry());
+ return m_deps_entries[deps_entry_t::asset_types::native][m_coreclr_index];
+ }
+
+ bool is_valid()
+ {
+ return m_valid;
+ }
+
+ const rid_fallback_graph_t& get_rid_fallback_graph()
+ {
+ return m_rid_fallback_graph;
+ }
+
+ const deps_entry_t& try_ni(const deps_entry_t& entry) const;
+
+private:
+ bool load_standalone(const json_value& json, const pal::string_t& target_name);
+ bool load_portable(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph);
+ bool load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph);
+ bool process_runtime_targets(const json_value& json, const pal::string_t& target_name, const rid_fallback_graph_t& rid_fallback_graph, rid_specific_assets_t* p_assets);
+ bool process_targets(const json_value& json, const pal::string_t& target_name, deps_assets_t* p_assets);
+
+ void reconcile_libraries_with_targets(
+ const json_value& json,
+ const std::function& library_exists_fn,
+ const std::function&(const pal::string_t&, int)>& get_rel_paths_by_asset_type_fn);
+
+ bool perform_rid_fallback(rid_specific_assets_t* portable_assets, const rid_fallback_graph_t& rid_fallback_graph);
+
+ static const std::array s_known_asset_types;
+
+ std::vector m_deps_entries[deps_entry_t::asset_types::count];
+
+ std::unordered_map m_ni_entries;
+ rid_fallback_graph_t m_rid_fallback_graph;
+ int m_coreclr_index;
+ bool m_valid;
+};
+
+class deps_text_t
+{
+public:
+ deps_text_t(const pal::string_t& deps_path)
+ : m_valid(load(deps_path))
+ {
+ }
+
+ bool load(const pal::string_t& deps_path);
+ bool is_valid() { return m_valid; }
+ const std::vector& get_entries() { return m_deps_entries; }
+
+private:
+ std::vector m_deps_entries;
+ bool m_valid;
+};
+
+#endif // __DEPS_FORMAT_H_
diff --git a/src/corehost/cli/deps_resolver.cpp b/src/corehost/cli/deps_resolver.cpp
index a43fdab34..fd2901d8a 100644
--- a/src/corehost/cli/deps_resolver.cpp
+++ b/src/corehost/cli/deps_resolver.cpp
@@ -6,80 +6,12 @@
#include
#include "trace.h"
+#include "deps_format.h"
#include "deps_resolver.h"
#include "utils.h"
namespace
{
-// -----------------------------------------------------------------------------
-// Read a single field from the deps entry
-//
-// Parameters:
-// line - A deps file entry line
-// buf - The temporary buffer to use while parsing (with size to contain "line")
-// ofs - The offset that this method will read from "line" on invocation and
-// the offset that has been consumed by this method upon successful exit
-// field - The current field read from the line
-//
-// Assumption:
-// The line should be in a CSV format, with commas separating the fields.
-// The fields themselves will be quoted. The escape character is '\\'
-//
-// Returns:
-// True if parsed successfully. Else, false
-//
-// Note:
-// Callers cannot call with the same "line" upon an unsuccessful exit.
-bool read_field(const pal::string_t& line, pal::char_t* buf, unsigned* ofs, pal::string_t* field)
-{
- unsigned& offset = *ofs;
- pal::string_t& value_recv = *field;
-
- // The first character should be a '"'
- if (line[offset] != '"')
- {
- trace::error(_X("Error reading TPA file"));
- return false;
- }
- offset++;
-
- auto buf_offset = 0;
-
- // Iterate through characters in the string
- for (; offset < line.length(); offset++)
- {
- // Is this a '\'?
- if (line[offset] == '\\')
- {
- // Skip this character and read the next character into the buffer
- offset++;
- buf[buf_offset] = line[offset];
- }
- // Is this a '"'?
- else if (line[offset] == '\"')
- {
- // Done! Advance to the pointer after the input
- offset++;
- break;
- }
- else
- {
- // Take the character
- buf[buf_offset] = line[offset];
- }
- buf_offset++;
- }
- buf[buf_offset] = '\0';
- value_recv.assign(buf);
-
- // Consume the ',' if we have one
- if (line[offset] == ',')
- {
- offset++;
- }
- return true;
-}
-
// -----------------------------------------------------------------------------
// A uniqifying append helper that doesn't let two entries with the same
// "asset_name" be part of the "output" paths.
@@ -106,28 +38,6 @@ void add_tpa_asset(
items->insert(asset_name);
}
-// -----------------------------------------------------------------------------
-// Add mscorlib from the CLR directory. Even if CLR is serviced, we should pick
-// mscorlib from the CLR directory. If mscorlib could not be found in the CLR
-// location, then leave it to the CLR to pick the right mscorlib.
-//
-void add_mscorlib_to_tpa(const pal::string_t& clr_dir, std::set* items, pal::string_t* output)
-{
- pal::string_t mscorlib_ni_path = clr_dir + DIR_SEPARATOR + _X("mscorlib.ni.dll");
- if (pal::file_exists(mscorlib_ni_path))
- {
- add_tpa_asset(_X("mscorlib"), mscorlib_ni_path, items, output);
- return;
- }
-
- pal::string_t mscorlib_path = clr_dir + DIR_SEPARATOR + _X("mscorlib.dll");
- if (pal::file_exists(mscorlib_path))
- {
- add_tpa_asset(_X("mscorlib"), mscorlib_path, items, output);
- return;
- }
-}
-
// -----------------------------------------------------------------------------
// A uniqifying append helper that doesn't let two "paths" to be identical in
// the "output" string.
@@ -157,234 +67,16 @@ void add_unique_path(
} // end of anonymous namespace
-// -----------------------------------------------------------------------------
-// Given a "base" directory, yield the relative path of this file in the package
-// layout.
-//
-// Parameters:
-// base - The base directory to look for the relative path of this entry
-// str - If the method returns true, contains the file path for this deps
-// entry relative to the "base" directory
-//
-// Returns:
-// If the file exists in the path relative to the "base" directory.
-//
-bool deps_entry_t::to_full_path(const pal::string_t& base, pal::string_t* str) const
-{
- pal::string_t& candidate = *str;
-
- candidate.clear();
-
- // Entry relative path contains '/' separator, sanitize it to use
- // platform separator. Perf: avoid extra copy if it matters.
- pal::string_t pal_relative_path = relative_path;
- if (_X('/') != DIR_SEPARATOR)
- {
- replace_char(&pal_relative_path, _X('/'), DIR_SEPARATOR);
- }
-
- // Reserve space for the path below
- candidate.reserve(base.length() +
- library_name.length() +
- library_version.length() +
- pal_relative_path.length() + 3);
-
- candidate.assign(base);
- append_path(&candidate, library_name.c_str());
- append_path(&candidate, library_version.c_str());
- append_path(&candidate, pal_relative_path.c_str());
-
- bool exists = pal::file_exists(candidate);
- if (!exists)
- {
- candidate.clear();
- }
- return exists;
-}
-
-// -----------------------------------------------------------------------------
-// Given a "base" directory, yield the relative path of this file in the package
-// layout if the entry hash matches the hash file in the "base" directory
-//
-// Parameters:
-// base - The base directory to look for the relative path of this entry and
-// the hash file.
-// str - If the method returns true, contains the file path for this deps
-// entry relative to the "base" directory
-//
-// Description:
-// Looks for a file named "{PackageName}.{PackageVersion}.nupkg.{HashAlgorithm}"
-// If the deps entry's {HashAlgorithm}-{HashValue} matches the contents then
-// yields the relative path of this entry in the "base" dir.
-//
-// Returns:
-// If the file exists in the path relative to the "base" directory and there
-// was hash file match with this deps entry.
-//
-// See: to_full_path(base, str)
-//
-bool deps_entry_t::to_hash_matched_path(const pal::string_t& base, pal::string_t* str) const
-{
- pal::string_t& candidate = *str;
-
- candidate.clear();
-
- // Base directory must be present to perform hash lookup.
- if (base.empty())
- {
- return false;
- }
-
- // First detect position of hyphen in [Algorithm]-[Hash] in the string.
- size_t pos = library_hash.find(_X("-"));
- if (pos == 0 || pos == pal::string_t::npos)
- {
- trace::verbose(_X("Invalid hash %s value for deps file entry: %s"), library_hash.c_str(), library_name.c_str());
- return false;
- }
-
- // Build the nupkg file name. Just reserve approx 8 char_t's for the algorithm name.
- pal::string_t nupkg_filename;
- nupkg_filename.reserve(library_name.length() + 1 + library_version.length() + 16);
- nupkg_filename.append(library_name);
- nupkg_filename.append(_X("."));
- nupkg_filename.append(library_version);
- nupkg_filename.append(_X(".nupkg."));
- nupkg_filename.append(library_hash.substr(0, pos));
-
- // Build the hash file path str.
- pal::string_t hash_file;
- hash_file.reserve(base.length() + library_name.length() + library_version.length() + nupkg_filename.length() + 3);
- hash_file.assign(base);
- append_path(&hash_file, library_name.c_str());
- append_path(&hash_file, library_version.c_str());
- append_path(&hash_file, nupkg_filename.c_str());
-
- // Read the contents of the hash file.
- pal::ifstream_t fstream(hash_file);
- if (!fstream.good())
- {
- trace::verbose(_X("The hash file is invalid [%s]"), hash_file.c_str());
- return false;
- }
-
- // Obtain the hash from the file.
- std::string hash;
- hash.assign(pal::istreambuf_iterator_t(fstream),
- pal::istreambuf_iterator_t());
- pal::string_t pal_hash;
- pal::to_palstring(hash.c_str(), &pal_hash);
-
- // Check if contents match deps entry.
- pal::string_t entry_hash = library_hash.substr(pos + 1);
- if (entry_hash != pal_hash)
- {
- trace::verbose(_X("The file hash [%s][%d] did not match entry hash [%s][%d]"),
- pal_hash.c_str(), pal_hash.length(), entry_hash.c_str(), entry_hash.length());
- return false;
- }
-
- // All good, just append the relative dir to base.
- return to_full_path(base, &candidate);
-}
-
-
-// -----------------------------------------------------------------------------
-// Load the deps file and parse its "entry" lines which contain the "fields" of
-// the entry. Populate an array of these entries.
-//
-bool deps_resolver_t::load()
-{
- // If file doesn't exist, then assume parsed.
- if (!pal::file_exists(m_deps_path))
- {
- return true;
- }
-
- // Somehow the file stream could not be opened. This is an error.
- pal::ifstream_t file(m_deps_path);
- if (!file.good())
- {
- return false;
- }
-
- // Parse the "entry" lines of the deps file.
- std::string stdline;
- while (std::getline(file, stdline))
- {
- pal::string_t line;
- pal::to_palstring(stdline.c_str(), &line);
-
- deps_entry_t entry;
- pal::string_t is_serviceable;
- pal::string_t* fields[] = {
- &entry.library_type,
- &entry.library_name,
- &entry.library_version,
- &entry.library_hash,
- &entry.asset_type,
- &entry.asset_name,
- &entry.relative_path,
- // TODO: Add when the deps file support is enabled.
- // &is_serviceable
- };
-
- std::vector buf(line.length());
-
- for (unsigned i = 0, offset = 0; i < sizeof(fields) / sizeof(fields[0]); ++i)
- {
- if (!(read_field(line, buf.data(), &offset, fields[i])))
- {
- return false;
- }
- }
-
- // Serviceable, if not false, default is true.
- entry.is_serviceable = pal::strcasecmp(is_serviceable.c_str(), _X("false")) != 0;
-
- // TODO: Deps file does not follow spec. It uses '\\', should use '/'
- replace_char(&entry.relative_path, _X('\\'), _X('/'));
-
- m_deps_entries.push_back(entry);
-
- trace::verbose(_X("Added deps entry [%d] [%s, %s, %s]"), m_deps_entries.size() - 1, entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str());
-
- static_assert(std::is_same, decltype(m_deps_entries)>::value, "decltype(m_deps_entries) not a vector, took index based on size.");
- if (entry.asset_type == _X("native") &&
- entry.asset_name == LIBCORECLR_FILENAME)
- {
- m_coreclr_index = m_deps_entries.size() - 1;
- trace::verbose(_X("Found coreclr from deps entry [%d] [%s, %s, %s]"),
- m_coreclr_index,
- entry.library_name.c_str(),
- entry.library_version.c_str(),
- entry.relative_path.c_str());
- }
- }
- return true;
-}
-
-// -----------------------------------------------------------------------------
-// Parse the deps file.
-//
-// Returns:
-// True if the file parse is successful or if file doesn't exist. False,
-// when there is an error parsing the file.
-//
-bool deps_resolver_t::parse_deps_file(const arguments_t& args)
-{
- m_deps_path = args.deps_path;
-
- return load();
-}
-
// -----------------------------------------------------------------------------
// Load local assemblies by priority order of their file extensions and
// unique-fied by their simple name.
//
-void deps_resolver_t::get_local_assemblies(const pal::string_t& dir)
+void deps_resolver_t::get_dir_assemblies(
+ const pal::string_t& dir,
+ const pal::string_t& dir_name,
+ std::unordered_map* dir_assemblies)
{
- trace::verbose(_X("Adding files from dir %s"), dir.c_str());
+ trace::verbose(_X("Adding files from %s dir %s"), dir_name.c_str(), dir.c_str());
// Managed extensions in priority order, pick DLL over EXE and NI over IL.
const pal::string_t managed_ext[] = { _X(".ni.dll"), _X(".dll"), _X(".ni.exe"), _X(".exe") };
@@ -412,18 +104,17 @@ void deps_resolver_t::get_local_assemblies(const pal::string_t& dir)
continue;
}
- // TODO: Do a case insensitive lookup.
// Already added entry for this asset, by priority order skip this ext
- if (m_local_assemblies.count(file_name))
+ if (dir_assemblies->count(file_name))
{
- trace::verbose(_X("Skipping %s because the %s already exists in local assemblies"), file.c_str(), m_local_assemblies.find(file_name)->second.c_str());
+ trace::verbose(_X("Skipping %s because the %s already exists in %s assemblies"), file.c_str(), dir_assemblies->find(file_name)->second.c_str(), dir_name.c_str());
continue;
}
// Add entry for this asset
pal::string_t file_path = dir + DIR_SEPARATOR + file;
- trace::verbose(_X("Adding %s to local assembly set from %s"), file_name.c_str(), file_path.c_str());
- m_local_assemblies.emplace(file_name, file_path);
+ trace::verbose(_X("Adding %s to %s assembly set from %s"), file_name.c_str(), dir_name.c_str(), file_path.c_str());
+ dir_assemblies->emplace(file_name, file_path);
}
}
}
@@ -440,43 +131,93 @@ pal::string_t deps_resolver_t::resolve_coreclr_dir(
const pal::string_t& package_dir,
const pal::string_t& package_cache_dir)
{
- // Runtime servicing
- trace::verbose(_X("Probing for CoreCLR in servicing dir=[%s]"), m_runtime_svc.c_str());
- if (!m_runtime_svc.empty())
+ auto process_coreclr = [&]
+ (bool is_portable, const pal::string_t& deps_dir, deps_json_t* deps) -> pal::string_t
{
- pal::string_t svc_clr = m_runtime_svc;
- append_path(&svc_clr, _X("runtime"));
- append_path(&svc_clr, _X("coreclr"));
+ pal::string_t candidate;
- if (coreclr_exists_in_dir(svc_clr))
+ // Servicing override.
+ if (deps->has_coreclr_entry())
{
- return svc_clr;
+ const deps_entry_t& entry = deps->get_coreclr_entry();
+ trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in servicing"), entry.library_name.c_str(), entry.library_version.c_str());
+ if (entry.is_serviceable && m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &candidate))
+ {
+ return get_directory(candidate);
+ }
+ }
+ else
+ {
+ trace::verbose(_X("Deps has no coreclr entry."));
}
- }
- // Package cache.
- trace::verbose(_X("Probing for CoreCLR in package cache=[%s] deps index: [%d]"), package_cache_dir.c_str(), m_coreclr_index);
- pal::string_t coreclr_cache;
- if (m_coreclr_index >= 0 && !package_cache_dir.empty() &&
- m_deps_entries[m_coreclr_index].to_hash_matched_path(package_cache_dir, &coreclr_cache))
- {
- return get_directory(coreclr_cache);
- }
+ // Package cache.
+ pal::string_t coreclr_cache;
+ if (!package_cache_dir.empty())
+ {
+ if (deps->has_coreclr_entry())
+ {
+ const deps_entry_t& entry = deps->get_coreclr_entry();
+ trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in package cache=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), package_cache_dir.c_str());
+ if (entry.to_hash_matched_path(package_cache_dir, &coreclr_cache))
+ {
+ return get_directory(coreclr_cache);
+ }
+ }
+ }
- // App dir.
- trace::verbose(_X("Probing for CoreCLR in app directory=[%s]"), app_dir.c_str());
- if (coreclr_exists_in_dir(app_dir))
- {
- return app_dir;
- }
+ // Deps directory: lookup relative path if portable, else look sxs.
+ if (is_portable)
+ {
+ pal::string_t coreclr_portable;
+ if (deps->has_coreclr_entry())
+ {
+ const deps_entry_t& entry = deps->get_coreclr_entry();
+ trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in portable app dir=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), deps_dir.c_str());
+ if (entry.to_full_path(deps_dir, &coreclr_portable))
+ {
+ return get_directory(coreclr_portable);
+ }
+ }
+ }
+ else
+ {
+ // App main dir or standalone app dir.
+ trace::verbose(_X("Probing for CoreCLR in deps directory=[%s]"), deps_dir.c_str());
+ if (coreclr_exists_in_dir(deps_dir))
+ {
+ return deps_dir;
+ }
+ }
- // Packages dir
- trace::verbose(_X("Probing for CoreCLR in packages=[%s] deps index: [%d]"), package_dir.c_str(), m_coreclr_index);
- pal::string_t coreclr_package;
- if (m_coreclr_index >= 0 && !package_dir.empty() &&
- m_deps_entries[m_coreclr_index].to_full_path(package_dir, &coreclr_package))
+ // Packages dir.
+ pal::string_t coreclr_package;
+ if (!package_dir.empty())
+ {
+ if (deps->has_coreclr_entry())
+ {
+ const deps_entry_t& entry = deps->get_coreclr_entry();
+ trace::verbose(_X("Probing for CoreCLR package=[%s][%s] in packages dir=[%s]"), entry.library_name.c_str(), entry.library_version.c_str(), package_dir.c_str());
+ if (entry.to_full_path(package_dir, &coreclr_package))
+ {
+ return get_directory(coreclr_package);
+ }
+ }
+ }
+
+ return pal::string_t();
+ };
+
+ trace::info(_X("--- Starting CoreCLR Proble from app deps.json"));
+ pal::string_t clr_dir = process_coreclr(m_portable, app_dir, m_deps.get());
+ if (clr_dir.empty() && m_portable)
{
- return get_directory(coreclr_package);
+ trace::info(_X("--- Starting CoreCLR Proble from FX deps.json"));
+ clr_dir = process_coreclr(false, m_fx_dir, m_fx_deps.get());
+ }
+ if (!clr_dir.empty())
+ {
+ return clr_dir;
}
// Use platform-specific search algorithm
@@ -516,19 +257,33 @@ void deps_resolver_t::resolve_tpa_list(
const pal::string_t& clr_dir,
pal::string_t* output)
{
+ std::vector empty(0);
+
+ pal::string_t ni_package_cache_dir;
+ if (!package_cache_dir.empty())
+ {
+ ni_package_cache_dir = package_cache_dir;
+ append_path(&ni_package_cache_dir, get_arch());
+ }
+
// Obtain the local assemblies in the app dir.
- get_local_assemblies(app_dir);
+ if (m_portable)
+ {
+ get_dir_assemblies(m_fx_dir, _X("fx"), &m_sxs_assemblies);
+ }
+ else
+ {
+ get_dir_assemblies(app_dir, _X("local"), &m_sxs_assemblies);
+ }
std::set items;
- add_mscorlib_to_tpa(clr_dir, &items, output);
-
- for (const deps_entry_t& entry : m_deps_entries)
+ auto process_entry = [&](bool is_portable, deps_json_t* deps, const deps_entry_t& entry)
{
// Is this asset a "runtime" type?
- if (entry.asset_type != _X("runtime") || items.count(entry.asset_name))
+ if (items.count(entry.asset_name))
{
- continue;
+ return;
}
pal::string_t candidate;
@@ -539,45 +294,63 @@ void deps_resolver_t::resolve_tpa_list(
{
add_tpa_asset(entry.asset_name, candidate, &items, output);
}
- // Is this entry present in the secondary package cache?
+ // Is an NI image for this entry present in the secondary package cache?
+ else if (entry.to_hash_matched_path(ni_package_cache_dir, &candidate))
+ {
+ add_tpa_asset(entry.asset_name, candidate, &items, output);
+ }
+ // Is this entry present in the secondary package cache? (note: no .ni extension)
else if (entry.to_hash_matched_path(package_cache_dir, &candidate))
{
add_tpa_asset(entry.asset_name, candidate, &items, output);
}
// Is this entry present locally?
- else if (m_local_assemblies.count(entry.asset_name))
+ else if (!is_portable && m_sxs_assemblies.count(entry.asset_name))
{
- // TODO: Case insensitive look up?
- add_tpa_asset(entry.asset_name, m_local_assemblies.find(entry.asset_name)->second, &items, output);
+ add_tpa_asset(entry.asset_name, m_sxs_assemblies.find(entry.asset_name)->second, &items, output);
}
- // Is this entry present in the package restore dir?
- else if (entry.to_full_path(package_dir, &candidate))
+ // The app is portable so the asset should be picked up from relative subpath.
+ else if (is_portable && deps->try_ni(entry).to_full_path(app_dir, &candidate))
{
add_tpa_asset(entry.asset_name, candidate, &items, output);
}
- }
+ // Is this entry present in the package restore dir?
+ else if (!package_dir.empty() && deps->try_ni(entry).to_full_path(package_dir, &candidate))
+ {
+ add_tpa_asset(entry.asset_name, candidate, &items, output);
+ }
+ };
+
+ const auto& deps_entries = m_deps->get_entries(deps_entry_t::asset_types::runtime);
+ std::for_each(deps_entries.begin(), deps_entries.end(), [&](const deps_entry_t& entry) {
+ process_entry(m_portable, m_deps.get(), entry);
+ });
+ const auto& fx_entries = m_portable ? m_fx_deps->get_entries(deps_entry_t::asset_types::runtime) : empty;
+ std::for_each(fx_entries.begin(), fx_entries.end(), [&](const deps_entry_t& entry) {
+ process_entry(false, m_fx_deps.get(), entry);
+ });
// Finally, if the deps file wasn't present or has missing entries, then
// add the app local assemblies to the TPA.
- for (const auto& kv : m_local_assemblies)
+ for (const auto& kv : m_sxs_assemblies)
{
add_tpa_asset(kv.first, kv.second, &items, output);
}
}
// -----------------------------------------------------------------------------
-// Resolve the directories order for culture/native lookup
+// Resolve the directories order for resources/native lookup
//
// Description:
// This general purpose function specifies priority order of directory lookup
-// for both native images and culture specific resource images. Lookup for
-// culture assemblies is done by looking up two levels above from the file
+// for both native images and resources specific resource images. Lookup for
+// resources assemblies is done by looking up two levels above from the file
// path. Lookup for native images is done by looking up one level from the
// file path.
//
// Parameters:
// asset_type - The type of the asset that needs lookup, currently
-// supports "culture" and "native"
+// supports "resources" and "native"
// app_dir - The application local directory
// package_dir - The directory path to where packages are restored
// package_cache_dir - The directory path to secondary cache for packages
@@ -594,60 +367,89 @@ void deps_resolver_t::resolve_probe_dirs(
const pal::string_t& clr_dir,
pal::string_t* output)
{
- assert(asset_type == _X("culture") || asset_type == _X("native"));
+ assert(asset_type == _X("resources") || asset_type == _X("native"));
- // For culture assemblies, we need to provide the base directory of the culture path.
+ // For resources assemblies, we need to provide the base directory of the resources path.
// For example: .../Foo/en-US/Bar.dll, then, the resolved path is .../Foo
- std::function culture = [] (const pal::string_t& str) {
+ std::function resources = [] (const pal::string_t& str) {
return get_directory(get_directory(str));
};
// For native assemblies, obtain the directory path from the file path
std::function native = [] (const pal::string_t& str) {
return get_directory(str);
};
- std::function& action = (asset_type == _X("culture")) ? culture : native;
-
+ std::function& action = (asset_type == _X("resources")) ? resources : native;
+ deps_entry_t::asset_types entry_type = (asset_type == _X("resources")) ? deps_entry_t::asset_types::resources : deps_entry_t::asset_types::native;
std::set items;
+ std::vector empty(0);
+ const auto& entries = m_deps->get_entries(entry_type);
+ const auto& fx_entries = m_portable ? m_fx_deps->get_entries(entry_type) : empty;
+
// Fill the "output" with serviced DLL directories if they are serviceable
// and have an entry present.
- for (const deps_entry_t& entry : m_deps_entries)
+ auto add_serviced_entry = [&](const deps_entry_t& entry)
{
pal::string_t redirection_path;
- if (entry.is_serviceable && entry.asset_type == asset_type && entry.library_type == _X("Package") &&
+ if (entry.is_serviceable && entry.library_type == _X("Package") &&
m_svc.find_redirection(entry.library_name, entry.library_version, entry.relative_path, &redirection_path))
{
add_unique_path(asset_type, action(redirection_path), &items, output);
}
- }
+ };
+
+ std::for_each(entries.begin(), entries.end(), add_serviced_entry);
+ std::for_each(fx_entries.begin(), fx_entries.end(), add_serviced_entry);
pal::string_t candidate;
// Take care of the secondary cache path
if (!package_cache_dir.empty())
{
- for (const deps_entry_t& entry : m_deps_entries)
+ auto add_package_cache_entry = [&](const deps_entry_t& entry)
{
- if (entry.asset_type == asset_type && entry.to_hash_matched_path(package_cache_dir, &candidate))
+ if (entry.to_hash_matched_path(package_cache_dir, &candidate))
{
add_unique_path(asset_type, action(candidate), &items, output);
}
- }
+ };
+ std::for_each(entries.begin(), entries.end(), add_package_cache_entry);
+ std::for_each(fx_entries.begin(), fx_entries.end(), add_package_cache_entry);
}
// App local path
add_unique_path(asset_type, app_dir, &items, output);
- // Take care of the package restore path
- if (!package_dir.empty())
+ // For portable path, the app relative directory must be used.
+ if (m_portable)
{
- for (const deps_entry_t& entry : m_deps_entries)
+ std::for_each(entries.begin(), entries.end(), [&](const deps_entry_t& entry)
{
if (entry.asset_type == asset_type && entry.to_full_path(package_dir, &candidate))
{
add_unique_path(asset_type, action(candidate), &items, output);
}
- }
+ });
+ }
+
+ // FX path if present
+ if (!m_fx_dir.empty())
+ {
+ add_unique_path(asset_type, m_fx_dir, &items, output);
+ }
+
+ // Take care of the package restore path
+ if (!package_dir.empty())
+ {
+ auto add_packages_entry = [&](const deps_entry_t& entry)
+ {
+ if (entry.asset_type == asset_type && entry.to_full_path(package_dir, &candidate))
+ {
+ add_unique_path(asset_type, action(candidate), &items, output);
+ }
+ };
+ std::for_each(entries.begin(), entries.end(), add_packages_entry);
+ std::for_each(fx_entries.begin(), fx_entries.end(), add_packages_entry);
}
// CLR path
@@ -656,7 +458,7 @@ void deps_resolver_t::resolve_probe_dirs(
// -----------------------------------------------------------------------------
-// Entrypoint to resolve TPA, native and culture path ordering to pass to CoreCLR.
+// Entrypoint to resolve TPA, native and resources path ordering to pass to CoreCLR.
//
// Parameters:
// app_dir - The application local directory
@@ -676,6 +478,6 @@ bool deps_resolver_t::resolve_probe_paths(
{
resolve_tpa_list(app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->tpa);
resolve_probe_dirs(_X("native"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->native);
- resolve_probe_dirs(_X("culture"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->culture);
+ resolve_probe_dirs(_X("resources"), app_dir, package_dir, package_cache_dir, clr_dir, &probe_paths->resources);
return true;
}
diff --git a/src/corehost/cli/deps_resolver.h b/src/corehost/cli/deps_resolver.h
index 309fce686..ce3d7c429 100644
--- a/src/corehost/cli/deps_resolver.h
+++ b/src/corehost/cli/deps_resolver.h
@@ -8,48 +8,45 @@
#include "pal.h"
#include "trace.h"
-
+#include "deps_format.h"
+#include "deps_entry.h"
#include "servicing_index.h"
-
-struct deps_entry_t
-{
- pal::string_t library_type;
- pal::string_t library_name;
- pal::string_t library_version;
- pal::string_t library_hash;
- pal::string_t asset_type;
- pal::string_t asset_name;
- pal::string_t relative_path;
- bool is_serviceable;
-
- // Given a "base" dir, yield the relative path in the package layout.
- bool to_full_path(const pal::string_t& root, pal::string_t* str) const;
-
- // Given a "base" dir, yield the relative path in the package layout only if
- // the hash matches contents of the hash file.
- bool to_hash_matched_path(const pal::string_t& root, pal::string_t* str) const;
-};
+#include "runtime_config.h"
// Probe paths to be resolved for ordering
struct probe_paths_t
{
pal::string_t tpa;
pal::string_t native;
- pal::string_t culture;
+ pal::string_t resources;
};
class deps_resolver_t
{
public:
- deps_resolver_t(const arguments_t& args)
+ deps_resolver_t(const pal::string_t& fx_dir, const runtime_config_t* config, const arguments_t& args)
: m_svc(args.dotnet_servicing)
- , m_runtime_svc(args.dotnet_runtime_servicing)
+ , m_fx_dir(fx_dir)
, m_coreclr_index(-1)
+ , m_portable(config->get_portable())
+ , m_deps(nullptr)
+ , m_fx_deps(nullptr)
{
- m_deps_valid = parse_deps_file(args);
+ m_deps_file = args.deps_path;
+ if (m_portable)
+ {
+ m_fx_deps_file = get_fx_deps(fx_dir, config->get_fx_name());
+ m_fx_deps = std::unique_ptr(new deps_json_t(false, m_fx_deps_file));
+ m_deps = std::unique_ptr(new deps_json_t(true, m_deps_file, m_fx_deps->get_rid_fallback_graph()));
+ }
+ else
+ {
+ m_deps = std::unique_ptr(new deps_json_t(false, m_deps_file));
+ }
}
- bool valid() { return m_deps_valid; }
+
+ bool valid() { return m_deps->is_valid() && (!m_portable || m_fx_deps->is_valid()); }
bool resolve_probe_paths(
const pal::string_t& app_dir,
@@ -63,11 +60,24 @@ public:
const pal::string_t& package_dir,
const pal::string_t& package_cache_dir);
+ const pal::string_t& get_fx_deps_file() const
+ {
+ return m_fx_deps_file;
+ }
+
+ const pal::string_t& get_deps_file() const
+ {
+ return m_deps_file;
+ }
private:
- bool load();
-
- bool parse_deps_file(const arguments_t& args);
+ static pal::string_t get_fx_deps(const pal::string_t& fx_dir, const pal::string_t& fx_name)
+ {
+ pal::string_t fx_deps = fx_dir;
+ pal::string_t fx_deps_name = pal::to_lower(fx_name) + _X(".deps.json");
+ append_path(&fx_deps, fx_deps_name.c_str());
+ return fx_deps;
+ }
// Resolve order for TPA lookup.
void resolve_tpa_list(
@@ -86,30 +96,42 @@ private:
const pal::string_t& clr_dir,
pal::string_t* output);
- // Populate local assemblies from app_dir listing.
- void get_local_assemblies(const pal::string_t& dir);
+ // Populate assemblies from the directory.
+ void get_dir_assemblies(
+ const pal::string_t& dir,
+ const pal::string_t& dir_name,
+ std::unordered_map* dir_assemblies);
// Servicing index to resolve serviced assembly paths.
servicing_index_t m_svc;
- // Runtime servicing directory.
- pal::string_t m_runtime_svc;
+ // Framework deps file.
+ pal::string_t m_fx_dir;
- // Map of simple name -> full path of local assemblies populated in priority
- // order of their extensions.
- std::unordered_map m_local_assemblies;
-
- // Entries in the dep file
- std::vector m_deps_entries;
+ // Map of simple name -> full path of local/fx assemblies populated
+ // in priority order of their extensions.
+ std::unordered_map m_sxs_assemblies;
// Special entry for coreclr in the deps entries
int m_coreclr_index;
- // The dep file path
- pal::string_t m_deps_path;
+ // The filepath for the app deps
+ pal::string_t m_deps_file;
+
+ // The filepath for the fx deps
+ pal::string_t m_fx_deps_file;
+
+ // Deps files for the fx
+ std::unique_ptr m_fx_deps;
+
+ // Deps files for the app
+ std::unique_ptr m_deps;
// Is the deps file valid
bool m_deps_valid;
+
+ // Is the deps file portable app?
+ bool m_portable;
};
#endif // DEPS_RESOLVER_H
diff --git a/src/corehost/cli/dll/CMakeLists.txt b/src/corehost/cli/dll/CMakeLists.txt
index 21248df7c..fd19ec602 100644
--- a/src/corehost/cli/dll/CMakeLists.txt
+++ b/src/corehost/cli/dll/CMakeLists.txt
@@ -13,16 +13,24 @@ endif()
include(../setup.cmake)
include_directories(../../common)
+include_directories(../json/casablanca/include)
# CMake does not recommend using globbing since it messes with the freshness checks
set(SOURCES
../../common/trace.cpp
../../common/utils.cpp
-
+ ../libhost.cpp
+ ../runtime_config.cpp
+ ../json/casablanca/src/json/json.cpp
+ ../json/casablanca/src/json/json_parsing.cpp
+ ../json/casablanca/src/json/json_serialization.cpp
+ ../json/casablanca/src/utilities/asyncrt_utils.cpp
../args.cpp
../hostpolicy.cpp
../coreclr.cpp
../deps_resolver.cpp
+ ../deps_format.cpp
+ ../deps_entry.cpp
../servicing_index.cpp)
@@ -32,6 +40,8 @@ else()
list(APPEND SOURCES ../../common/pal.unix.cpp)
endif()
+add_definitions(-D_NO_ASYNCRTIMP)
+add_definitions(-D_NO_PPLXIMP)
add_definitions(-DCOREHOST_MAKE_DLL=1)
add_library(hostpolicy SHARED ${SOURCES})
diff --git a/src/corehost/cli/fxr/CMakeLists.txt b/src/corehost/cli/fxr/CMakeLists.txt
new file mode 100644
index 000000000..43e0b54ca
--- /dev/null
+++ b/src/corehost/cli/fxr/CMakeLists.txt
@@ -0,0 +1,45 @@
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+cmake_minimum_required (VERSION 2.6)
+project(hostpolicy)
+
+if(WIN32)
+ add_compile_options($<$:/MT>)
+ add_compile_options($<$:/MT>)
+ add_compile_options($<$:/MTd>)
+endif()
+
+include(../setup.cmake)
+
+include_directories(../../common)
+include_directories(../json/casablanca/include)
+
+# CMake does not recommend using globbing since it messes with the freshness checks
+set(SOURCES
+ ../../common/trace.cpp
+ ../../common/utils.cpp
+ ../../policy_load.cpp
+ ../libhost.cpp
+ ../runtime_config.cpp
+ ../json/casablanca/src/json/json.cpp
+ ../json/casablanca/src/json/json_parsing.cpp
+ ../json/casablanca/src/json/json_serialization.cpp
+ ../json/casablanca/src/utilities/asyncrt_utils.cpp
+ ./fx_ver.cpp
+ ./fx_muxer.cpp)
+
+
+if(WIN32)
+ list(APPEND SOURCES ../../common/pal.windows.cpp)
+else()
+ list(APPEND SOURCES ../../common/pal.unix.cpp)
+endif()
+
+add_definitions(-D_NO_ASYNCRTIMP)
+add_definitions(-D_NO_PPLXIMP)
+add_definitions(-DCOREHOST_MAKE_DLL=1)
+
+add_library(hostfxr SHARED ${SOURCES})
+
+
diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp
new file mode 100644
index 000000000..84ae55c1b
--- /dev/null
+++ b/src/corehost/cli/fxr/fx_muxer.cpp
@@ -0,0 +1,298 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include
+#include "pal.h"
+#include "utils.h"
+#include "libhost.h"
+#include "args.h"
+#include "fx_ver.h"
+#include "fx_muxer.h"
+#include "trace.h"
+#include "runtime_config.h"
+#include "cpprest/json.h"
+#include "corehost.h"
+#include "policy_load.h"
+
+typedef web::json::value json_value;
+
+pal::string_t fx_muxer_t::resolve_fx_dir(const pal::string_t& muxer_dir, runtime_config_t* runtime, const pal::string_t& app_path)
+{
+ const auto fx_name = runtime->get_fx_name();
+ const auto fx_ver = runtime->get_fx_version();
+ const auto roll_fwd = runtime->get_fx_roll_fwd();
+
+ fx_ver_t specified(-1, -1, -1);
+ if (!fx_ver_t::parse(fx_ver, &specified, false))
+ {
+ return pal::string_t();
+ }
+
+ auto fx_dir = muxer_dir;
+ append_path(&fx_dir, _X("Shared"));
+ append_path(&fx_dir, fx_name.c_str());
+
+ // If not roll forward or if pre-release, just return.
+ if (!roll_fwd || specified.is_prerelease())
+ {
+ append_path(&fx_dir, fx_ver.c_str());
+ }
+ else
+ {
+ std::vector list;
+ pal::readdir(fx_dir, &list);
+ fx_ver_t max_specified = specified;
+ for (const auto& version : list)
+ {
+ fx_ver_t ver(-1, -1, -1);
+ if (fx_ver_t::parse(version, &ver, true) &&
+ ver.get_major() == max_specified.get_major() &&
+ ver.get_minor() == max_specified.get_minor())
+ {
+ max_specified.set_patch(std::max(ver.get_patch(), max_specified.get_patch()));
+ }
+ }
+ pal::string_t max_specified_str = max_specified.as_str();
+ append_path(&fx_dir, max_specified_str.c_str());
+ }
+ trace::verbose(_X("Found fx in: %s"), fx_dir.c_str());
+ return pal::directory_exists(fx_dir) ? fx_dir : pal::string_t();
+}
+
+pal::string_t fx_muxer_t::resolve_cli_version(const pal::string_t& global_json)
+{
+ pal::string_t retval;
+ if (!pal::file_exists(global_json))
+ {
+ return retval;
+ }
+
+ pal::ifstream_t file(global_json);
+ if (!file.good())
+ {
+ return retval;
+ }
+
+ try
+ {
+ const auto root = json_value::parse(file);
+ const auto& json = root.as_object();
+ const auto sdk_iter = json.find(_X("sdk"));
+ if (sdk_iter == json.end() || sdk_iter->second.is_null())
+ {
+ return retval;
+ }
+
+ const auto& sdk_obj = sdk_iter->second.as_object();
+ const auto ver_iter = sdk_obj.find(_X("version"));
+ if (ver_iter == sdk_obj.end() || ver_iter->second.is_null())
+ {
+ return retval;
+ }
+ retval = ver_iter->second.as_string();
+ }
+ catch (...)
+ {
+ }
+ trace::verbose(_X("Found cli in: %s"), retval.c_str());
+ return retval;
+}
+
+bool fx_muxer_t::resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk)
+{
+ pal::string_t cwd;
+ pal::string_t global;
+ if (pal::getcwd(&cwd))
+ {
+ for (pal::string_t parent_dir, cur_dir = cwd; true; cur_dir = parent_dir)
+ {
+ pal::string_t file = cur_dir;
+ append_path(&file, _X("global.json"));
+ if (pal::file_exists(file))
+ {
+ global = file;
+ break;
+ }
+ parent_dir = get_directory(cur_dir);
+ if (parent_dir.empty() || parent_dir.size() == cur_dir.size())
+ {
+ break;
+ }
+ }
+ }
+ pal::string_t retval;
+ if (!global.empty())
+ {
+ pal::string_t cli_version = resolve_cli_version(global);
+ if (!cli_version.empty())
+ {
+ pal::string_t sdk_path = own_dir;
+ append_path(&sdk_path, _X("sdk"));
+ append_path(&sdk_path, cli_version.c_str());
+ if (pal::directory_exists(sdk_path))
+ {
+ retval = sdk_path;
+ }
+ }
+ }
+ if (retval.empty())
+ {
+ pal::string_t sdk_path = own_dir;
+ append_path(&sdk_path, _X("sdk"));
+
+ std::vector versions;
+ pal::readdir(sdk_path, &versions);
+ fx_ver_t max_ver(-1, -1, -1);
+ for (const auto& version : versions)
+ {
+ fx_ver_t ver(-1, -1, -1);
+ if (fx_ver_t::parse(version, &ver, true))
+ {
+ max_ver = std::max(ver, max_ver);
+ }
+ }
+ pal::string_t max_ver_str = max_ver.as_str();
+ append_path(&sdk_path, max_ver_str.c_str());
+ if (pal::directory_exists(sdk_path))
+ {
+ retval = sdk_path;
+ }
+ }
+ cli_sdk->assign(retval);
+ trace::verbose(_X("Found cli sdk in: %s"), cli_sdk->c_str());
+ return !retval.empty();
+}
+
+/* static */
+int fx_muxer_t::execute(const int argc, const pal::char_t* argv[])
+{
+ pal::string_t own_path;
+
+ // Get the full name of the application
+ if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path))
+ {
+ trace::error(_X("Failed to locate current executable"));
+ return StatusCode::LibHostCurExeFindFailure;
+ }
+
+ auto own_dir = get_directory(own_path);
+
+ if (argc <= 1)
+ {
+ return StatusCode::InvalidArgFailure;
+ }
+ if (ends_with(argv[1], _X(".dll"), false))
+ {
+ pal::string_t app_path = argv[1];
+
+ if (!pal::realpath(&app_path))
+ {
+ return StatusCode::LibHostExecModeFailure;
+ }
+
+ runtime_config_t config(get_runtime_config_json(app_path));
+ if (!config.is_valid())
+ {
+ trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str());
+ return StatusCode::InvalidConfigFile;
+ }
+ if (config.get_portable())
+ {
+ pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path);
+ corehost_init_t init(_X(""), _X(""), fx_dir, host_mode_t::muxer, &config);
+ return policy_load_t::execute_app(fx_dir, &init, argc, argv);
+ }
+ else
+ {
+ corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::muxer, &config);
+ return policy_load_t::execute_app(get_directory(app_path), &init, argc, argv);
+ }
+ }
+ else
+ {
+ if (pal::strcasecmp(_X("exec"), argv[1]) == 0)
+ {
+ std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath") };
+
+ int num_args = 0;
+ std::unordered_map opts;
+ if (!parse_known_args(argc - 2, &argv[2], known_opts, &opts, &num_args))
+ {
+ return InvalidArgFailure;
+ }
+ int cur_i = 2 + num_args;
+ if (cur_i >= argc)
+ {
+ return InvalidArgFailure;
+ }
+
+ // Transform dotnet exec [--additionalprobingpath path] [--depsfile file] dll [args] -> dotnet dll [args]
+
+ std::vector new_argv(argc - cur_i + 1); // +1 for dotnet
+ memcpy(new_argv.data() + 1, argv + cur_i, (argc - cur_i) * sizeof(pal::char_t*));
+ new_argv[0] = argv[0];
+
+ pal::string_t deps_file = opts.count(_X("--depsfile")) ? opts[_X("--depsfile")] : _X("");
+ pal::string_t probe_path = opts.count(_X("--additionalprobingpath")) ? opts[_X("--additionalprobingpath")] : _X("");
+
+ pal::string_t app_path = argv[cur_i];
+ runtime_config_t config(get_runtime_config_json(app_path));
+ if (!config.is_valid())
+ {
+ trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str());
+ return StatusCode::InvalidConfigFile;
+ }
+ if (config.get_portable())
+ {
+ pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, app_path);
+ corehost_init_t init(deps_file, probe_path, fx_dir, host_mode_t::muxer, &config);
+ return policy_load_t::execute_app(fx_dir, &init, new_argv.size(), new_argv.data());
+ }
+ else
+ {
+ corehost_init_t init(deps_file, probe_path, _X(""), host_mode_t::muxer, &config);
+ pal::string_t impl_dir = get_directory(deps_file.empty() ? app_path : deps_file);
+ return policy_load_t::execute_app(impl_dir, &init, new_argv.size(), new_argv.data());
+ }
+ }
+ else
+ {
+ pal::string_t sdk_dotnet;
+ if (!resolve_sdk_dotnet_path(own_dir, &sdk_dotnet))
+ {
+ return StatusCode::LibHostSdkFindFailure;
+ }
+ append_path(&sdk_dotnet, _X("dotnet.dll"));
+ // Transform dotnet [command] [args] -> dotnet [dotnet.dll] [command] [args]
+
+ std::vector new_argv(argc + 1);
+ memcpy(&new_argv.data()[2], argv + 1, (argc - 1) * sizeof(pal::char_t*));
+ new_argv[0] = argv[0];
+ new_argv[1] = sdk_dotnet.c_str();
+
+ trace::verbose(_X("Using SDK dll=[%s]"), sdk_dotnet.c_str());
+
+ assert(ends_with(sdk_dotnet, _X(".dll"), false));
+
+ runtime_config_t config(get_runtime_config_json(sdk_dotnet));
+
+ if (config.get_portable())
+ {
+ pal::string_t fx_dir = resolve_fx_dir(own_dir, &config, sdk_dotnet);
+ corehost_init_t init(_X(""), _X(""), fx_dir, host_mode_t::muxer, &config);
+ return policy_load_t::execute_app(fx_dir, &init, new_argv.size(), new_argv.data());
+ }
+ else
+ {
+ corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::muxer, &config);
+ return policy_load_t::execute_app(get_directory(sdk_dotnet), &init, new_argv.size(), new_argv.data());
+ }
+ }
+ }
+}
+
+SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[])
+{
+ trace::setup();
+ return fx_muxer_t().execute(argc, argv);
+}
diff --git a/src/corehost/cli/fxr/fx_muxer.h b/src/corehost/cli/fxr/fx_muxer.h
new file mode 100644
index 000000000..de6518a4c
--- /dev/null
+++ b/src/corehost/cli/fxr/fx_muxer.h
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+class runtime_config_t;
+struct fx_ver_t;
+
+class fx_muxer_t
+{
+public:
+ static int execute(const int argc, const pal::char_t* argv[]);
+private:
+ static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime, const pal::string_t& app_path);
+ static pal::string_t resolve_cli_version(const pal::string_t& global);
+ static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk);
+};
+
diff --git a/src/corehost/cli/fxr/fx_ver.cpp b/src/corehost/cli/fxr/fx_ver.cpp
new file mode 100644
index 000000000..7c81fb287
--- /dev/null
+++ b/src/corehost/cli/fxr/fx_ver.cpp
@@ -0,0 +1,168 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include
+#include "pal.h"
+#include "fx_ver.h"
+
+fx_ver_t::fx_ver_t(int major, int minor, int patch, const pal::string_t& pre, const pal::string_t& build)
+ : m_major(major)
+ , m_minor(minor)
+ , m_patch(patch)
+ , m_pre(pre)
+ , m_build(build)
+{
+}
+
+fx_ver_t::fx_ver_t(int major, int minor, int patch, const pal::string_t& pre)
+ : fx_ver_t(major, minor, patch, pre, _X(""))
+{
+}
+
+fx_ver_t::fx_ver_t(int major, int minor, int patch)
+ : fx_ver_t(major, minor, patch, _X(""), _X(""))
+{
+}
+
+bool fx_ver_t::operator ==(const fx_ver_t& b) const
+{
+ return compare(*this, b) == 0;
+}
+
+bool fx_ver_t::operator !=(const fx_ver_t& b) const
+{
+ return !operator ==(b);
+}
+
+bool fx_ver_t::operator <(const fx_ver_t& b) const
+{
+ return compare(*this, b) < 0;
+}
+
+bool fx_ver_t::operator >(const fx_ver_t& b) const
+{
+ return compare(*this, b) > 0;
+}
+
+pal::string_t fx_ver_t::as_str()
+{
+ pal::stringstream_t stream;
+ stream << m_major << _X(".") << m_minor << _X(".") << m_patch;
+ if (!m_pre.empty())
+ {
+ stream << m_pre;
+ }
+ if (!m_build.empty())
+ {
+ stream << _X("+") << m_build;
+ }
+ return stream.str();
+}
+
+/* static */
+int fx_ver_t::compare(const fx_ver_t&a, const fx_ver_t& b, bool ignore_build)
+{
+ // compare(u.v.w-p+b, x.y.z-q+c)
+ return
+ (a.m_major == b.m_major)
+ ? ((a.m_minor == b.m_minor)
+ ? ((a.m_patch == b.m_patch)
+ ? ((a.m_pre.empty() == b.m_pre.empty())
+ ? ((a.m_pre.empty())
+ ? (ignore_build ? 0 : a.m_build.compare(b.m_build))
+ : a.m_pre.compare(b.m_pre))
+ : a.m_pre.empty() ? 1 : -1)
+ : (a.m_patch > b.m_patch ? 1 : -1))
+ : (a.m_minor > b.m_minor ? 1 : -1))
+ : ((a.m_major > b.m_major) ? 1 : -1)
+ ;
+}
+
+bool try_stou(const pal::string_t& str, unsigned* num)
+{
+ if (str.empty())
+ {
+ return false;
+ }
+ if (str.find_first_not_of(_X("0123456789")) != pal::string_t::npos)
+ {
+ return false;
+ }
+ *num = (unsigned) std::stoul(str);
+ return true;
+}
+
+bool parse_internal(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production)
+{
+ size_t maj_start = 0;
+ size_t maj_sep = ver.find(_X('.'));
+ if (maj_sep == pal::string_t::npos)
+ {
+ return false;
+ }
+ unsigned major = 0;
+ if (!try_stou(ver.substr(maj_start, maj_sep), &major))
+ {
+ return false;
+ }
+
+ size_t min_start = maj_sep + 1;
+ size_t min_sep = ver.find(_X('.'), min_start);
+ if (min_sep == pal::string_t::npos)
+ {
+ return false;
+ }
+
+ unsigned minor = 0;
+ if (!try_stou(ver.substr(min_start, min_sep - min_start), &minor))
+ {
+ return false;
+ }
+
+ unsigned patch = 0;
+ size_t pat_start = min_sep + 1;
+ size_t pat_sep = ver.find_first_not_of(_X("0123456789"), pat_start);
+ if (pat_sep == pal::string_t::npos)
+ {
+ if (!try_stou(ver.substr(pat_start), &patch))
+ {
+ return false;
+ }
+
+ *fx_ver = fx_ver_t(major, minor, patch);
+ return true;
+ }
+
+ if (parse_only_production)
+ {
+ // This is a prerelease or has build suffix.
+ return false;
+ }
+
+ if (!try_stou(ver.substr(pat_start, pat_sep - pat_start), &patch))
+ {
+ return false;
+ }
+
+ size_t pre_start = pat_sep;
+ size_t pre_sep = ver.find(_X('+'), pre_start);
+ if (pre_sep == pal::string_t::npos)
+ {
+ *fx_ver = fx_ver_t(major, minor, patch, ver.substr(pre_start));
+ return true;
+ }
+ else
+ {
+ size_t build_start = pre_sep + 1;
+ *fx_ver = fx_ver_t(major, minor, patch, ver.substr(pre_start, pre_sep - pre_start), ver.substr(build_start));
+ return true;
+ }
+}
+
+/* static */
+bool fx_ver_t::parse(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production)
+{
+ bool valid = parse_internal(ver, fx_ver, parse_only_production);
+ assert(!valid || fx_ver->as_str() == ver);
+ return valid;
+}
diff --git a/src/corehost/cli/fxr/fx_ver.h b/src/corehost/cli/fxr/fx_ver.h
new file mode 100644
index 000000000..180426737
--- /dev/null
+++ b/src/corehost/cli/fxr/fx_ver.h
@@ -0,0 +1,40 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "pal.h"
+
+struct fx_ver_t
+{
+ fx_ver_t(int major, int minor, int patch);
+ fx_ver_t(int major, int minor, int patch, const pal::string_t& pre);
+ fx_ver_t(int major, int minor, int patch, const pal::string_t& pre, const pal::string_t& build);
+
+ int get_major() { return m_major; }
+ int get_minor() { return m_minor; }
+ int get_patch() { return m_patch; }
+
+ void set_major(int m) { m_major = m; }
+ void set_minor(int m) { m_minor = m; }
+ void set_patch(int p) { m_patch = p; }
+
+ bool is_prerelease() { return !m_pre.empty(); }
+
+ pal::string_t as_str();
+
+ bool operator ==(const fx_ver_t& b) const;
+ bool operator !=(const fx_ver_t& b) const;
+ bool operator <(const fx_ver_t& b) const;
+ bool operator >(const fx_ver_t& b) const;
+
+ static bool parse(const pal::string_t& ver, fx_ver_t* fx_ver, bool parse_only_production = false);
+
+private:
+ int m_major;
+ int m_minor;
+ int m_patch;
+ pal::string_t m_pre;
+ pal::string_t m_build;
+
+ static int compare(const fx_ver_t&a, const fx_ver_t& b, bool ignore_build = false);
+};
+
diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp
index b087357c8..32bdb924d 100644
--- a/src/corehost/cli/hostpolicy.cpp
+++ b/src/corehost/cli/hostpolicy.cpp
@@ -5,25 +5,21 @@
#include "args.h"
#include "trace.h"
#include "deps_resolver.h"
+#include "fx_muxer.h"
#include "utils.h"
#include "coreclr.h"
+#include "cpprest/json.h"
+#include "libhost.h"
+#include "error_codes.h"
-enum StatusCode
-{
- // 0x80 prefix to distinguish from corehost main's error codes.
- InvalidArgFailure = 0x81,
- CoreClrResolveFailure = 0x82,
- CoreClrBindFailure = 0x83,
- CoreClrInitFailure = 0x84,
- CoreClrExeFailure = 0x85,
- ResolverInitFailure = 0x86,
- ResolverResolveFailure = 0x87,
-};
-int run(const arguments_t& args)
+corehost_init_t* g_init = nullptr;
+
+int run(const corehost_init_t* init, const runtime_config_t& config, const arguments_t& args)
{
// Load the deps resolver
- deps_resolver_t resolver(args);
+ deps_resolver_t resolver(init->fx_dir(), &config, args);
+
if (!resolver.valid())
{
trace::error(_X("Invalid .deps file"));
@@ -31,8 +27,8 @@ int run(const arguments_t& args)
}
// Add packages directory
- pal::string_t packages_dir = args.nuget_packages;
- if (!pal::directory_exists(packages_dir))
+ pal::string_t packages_dir = init->probe_dir();
+ if (packages_dir.empty() || !pal::directory_exists(packages_dir))
{
(void)pal::get_default_packages_directory(&packages_dir);
}
@@ -55,6 +51,8 @@ int run(const arguments_t& args)
return StatusCode::ResolverResolveFailure;
}
+ // TODO: config.get_runtime_properties();
+
// Build CoreCLR properties
const char* property_keys[] = {
"TRUSTED_PLATFORM_ASSEMBLIES",
@@ -63,20 +61,22 @@ int run(const arguments_t& args)
"NATIVE_DLL_SEARCH_DIRECTORIES",
"PLATFORM_RESOURCE_ROOTS",
"AppDomainCompatSwitch",
- // TODO: pipe this from corehost.json
"SERVER_GC",
// Workaround: mscorlib does not resolve symlinks for AppContext.BaseDirectory dotnet/coreclr/issues/2128
"APP_CONTEXT_BASE_DIRECTORY",
+ "APP_CONTEXT_DEPS_FILES"
};
auto tpa_paths_cstr = pal::to_stdstring(probe_paths.tpa);
auto app_base_cstr = pal::to_stdstring(args.app_dir);
auto native_dirs_cstr = pal::to_stdstring(probe_paths.native);
- auto culture_dirs_cstr = pal::to_stdstring(probe_paths.culture);
+ auto resources_dirs_cstr = pal::to_stdstring(probe_paths.resources);
// Workaround for dotnet/cli Issue #488 and #652
pal::string_t server_gc;
std::string server_gc_cstr = (pal::getenv(_X("COREHOST_SERVER_GC"), &server_gc) && !server_gc.empty()) ? pal::to_stdstring(server_gc) : "0";
+
+ std::string deps = pal::to_stdstring(resolver.get_deps_file() + _X(";") + resolver.get_fx_deps_file());
const char* property_values[] = {
// TRUSTED_PLATFORM_ASSEMBLIES
@@ -88,13 +88,15 @@ int run(const arguments_t& args)
// NATIVE_DLL_SEARCH_DIRECTORIES
native_dirs_cstr.c_str(),
// PLATFORM_RESOURCE_ROOTS
- culture_dirs_cstr.c_str(),
+ resources_dirs_cstr.c_str(),
// AppDomainCompatSwitch
"UseLatestBehaviorWhenTFMNotSpecified",
// SERVER_GC
server_gc_cstr.c_str(),
// APP_CONTEXT_BASE_DIRECTORY
- app_base_cstr.c_str()
+ app_base_cstr.c_str(),
+ // APP_CONTEXT_DEPS_FILES,
+ deps.c_str(),
};
size_t property_size = sizeof(property_keys) / sizeof(property_keys[0]);
@@ -188,16 +190,43 @@ int run(const arguments_t& args)
return exit_code;
}
+SHARED_API int corehost_load(corehost_init_t* init)
+{
+ g_init = init;
+ return 0;
+}
+
SHARED_API int corehost_main(const int argc, const pal::char_t* argv[])
{
trace::setup();
+ assert(g_init);
+
// Take care of arguments
arguments_t args;
- if (!parse_arguments(argc, argv, args))
+ if (!parse_arguments(g_init->deps_file(), g_init->probe_dir(), g_init->host_mode(), argc, argv, &args))
{
- return StatusCode::InvalidArgFailure;
+ return StatusCode::LibHostInvalidArgs;
}
- return run(args);
+ if (g_init->runtime_config())
+ {
+ return run(g_init, *g_init->runtime_config(), args);
+ }
+ else
+ {
+ runtime_config_t config(get_runtime_config_json(args.managed_application));
+ if (!config.is_valid())
+ {
+ trace::error(_X("Invalid runtimeconfig.json [%s]"), config.get_path().c_str());
+ return StatusCode::InvalidConfigFile;
+ }
+ return run(g_init, config, args);
+ }
+}
+
+SHARED_API int corehost_unload()
+{
+ g_init = nullptr;
+ return 0;
}
diff --git a/src/corehost/cli/json/casablanca/LICENSE.txt b/src/corehost/cli/json/casablanca/LICENSE.txt
new file mode 100644
index 000000000..314f8097f
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/LICENSE.txt
@@ -0,0 +1 @@
+https://github.com/Microsoft/cpprestsdk
diff --git a/src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h b/src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h
new file mode 100644
index 000000000..c100ece52
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h
@@ -0,0 +1,600 @@
+/***
+* ==++==
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* ==--==
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* Various common utilities.
+*
+* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "cpprest/details/basic_types.h"
+
+#if !defined(_WIN32) || (_MSC_VER >= 1700)
+#include
+#endif
+
+#ifndef _WIN32
+//#include
+#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269
+#include
+#endif
+#endif
+
+/// Various utilities for string conversions and date and time manipulation.
+namespace utility
+{
+
+// Left over from VS2010 support, remains to avoid breaking.
+typedef std::chrono::seconds seconds;
+
+/// Functions for converting to/from std::chrono::seconds to xml string.
+namespace timespan
+{
+ ///
+ /// Converts a timespan/interval in seconds to xml duration string as specified by
+ /// http://www.w3.org/TR/xmlschema-2/#duration
+ ///
+ _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs);
+
+ ///
+ /// Converts an xml duration to timespan/interval in seconds
+ /// http://www.w3.org/TR/xmlschema-2/#duration
+ ///
+ _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t ×panString);
+}
+
+/// Functions for Unicode string conversions.
+namespace conversions
+{
+ ///
+ /// Converts a UTF-16 string to a UTF-8 string.
+ ///
+ /// A two byte character UTF-16 string.
+ /// A single byte character UTF-8 string.
+ _ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w);
+
+ ///
+ /// Converts a UTF-8 string to a UTF-16
+ ///
+ /// A single byte character UTF-8 string.
+ /// A two byte character UTF-16 string.
+ _ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s);
+
+ ///
+ /// Converts a ASCII (us-ascii) string to a UTF-16 string.
+ ///
+ /// A single byte character us-ascii string.
+ /// A two byte character UTF-16 string.
+ _ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string &s);
+
+ ///
+ /// Converts a Latin1 (iso-8859-1) string to a UTF-16 string.
+ ///
+ /// A single byte character UTF-8 string.
+ /// A two byte character UTF-16 string.
+ _ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string &s);
+
+ ///
+ /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.
+ ///
+ /// A single byte character UTF-8 string.
+ /// A single byte character UTF-8 string.
+ _ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string &s);
+
+ ///
+ /// Converts to a platform dependent Unicode string type.
+ ///
+ /// A single byte character UTF-8 string.
+ /// A platform dependent string type.
+ _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s);
+
+ ///
+ /// Converts to a platform dependent Unicode string type.
+ ///
+ /// A two byte character UTF-16 string.
+ /// A platform dependent string type.
+ _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s);
+
+ ///
+ /// Converts to a platform dependent Unicode string type.
+ ///
+ /// A single byte character UTF-8 string.
+ /// A platform dependent string type.
+ _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s);
+
+ ///
+ /// Converts to a platform dependent Unicode string type.
+ ///
+ /// A two byte character UTF-16 string.
+ /// A platform dependent string type.
+ _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s);
+
+ ///
+ /// Converts to a UTF-16 from string.
+ ///
+ /// A single byte character UTF-8 string.
+ /// A two byte character UTF-16 string.
+ _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string &value);
+
+ ///
+ /// Converts to a UTF-16 from string.
+ ///
+ /// A two byte character UTF-16 string.
+ /// A two byte character UTF-16 string.
+ _ASYNCRTIMP utf16string __cdecl to_utf16string(utf16string value);
+
+ ///
+ /// Converts to a UTF-8 string.
+ ///
+ /// A single byte character UTF-8 string.
+ /// A single byte character UTF-8 string.
+ _ASYNCRTIMP std::string __cdecl to_utf8string(std::string value);
+
+ ///
+ /// Converts to a UTF-8 string.
+ ///
+ /// A two byte character UTF-16 string.
+ /// A single byte character UTF-8 string.
+ _ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string &value);
+
+ ///
+ /// Encode the given byte array into a base64 string
+ ///
+ _ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector& data);
+
+ ///
+ /// Encode the given 8-byte integer into a base64 string
+ ///
+ _ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data);
+
+ ///
+ /// Decode the given base64 string to a byte array
+ ///
+ _ASYNCRTIMP std::vector __cdecl from_base64(const utility::string_t& str);
+
+ template
+ utility::string_t print_string(const Source &val, const std::locale &loc)
+ {
+ utility::ostringstream_t oss;
+ oss.imbue(loc);
+ oss << val;
+ if (oss.bad())
+ {
+ throw std::bad_cast();
+ }
+ return oss.str();
+ }
+
+ template
+ utility::string_t print_string(const Source &val)
+ {
+ return print_string(val, std::locale());
+ }
+
+ template
+ Target scan_string(const utility::string_t &str, const std::locale &loc)
+ {
+ Target t;
+ utility::istringstream_t iss(str);
+ iss.imbue(loc);
+ iss >> t;
+ if (iss.bad())
+ {
+ throw std::bad_cast();
+ }
+ return t;
+ }
+
+ template
+ Target scan_string(const utility::string_t &str)
+ {
+ return scan_string(str, std::locale());
+ }
+}
+
+namespace details
+{
+ ///
+ /// Cross platform RAII container for setting thread local locale.
+ ///
+ class scoped_c_thread_locale
+ {
+ public:
+ _ASYNCRTIMP scoped_c_thread_locale();
+ _ASYNCRTIMP ~scoped_c_thread_locale();
+
+#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269
+#ifdef _WIN32
+ typedef _locale_t xplat_locale;
+#else
+ typedef locale_t xplat_locale;
+#endif
+
+ static _ASYNCRTIMP xplat_locale __cdecl c_locale();
+#endif
+ private:
+#ifdef _WIN32
+ std::string m_prevLocale;
+ int m_prevThreadSetting;
+#elif !(defined(ANDROID) || defined(__ANDROID__))
+ locale_t m_prevLocale;
+#endif
+ scoped_c_thread_locale(const scoped_c_thread_locale &);
+ scoped_c_thread_locale & operator=(const scoped_c_thread_locale &);
+ };
+
+ ///
+ /// Our own implementation of alpha numeric instead of std::isalnum to avoid
+ /// taking global lock for performance reasons.
+ ///
+ inline bool __cdecl is_alnum(char ch)
+ {
+ return (ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'Z')
+ || (ch >= 'a' && ch <= 'z');
+ }
+
+ ///
+ /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
+ /// and therefore not be compatible with Dev10.
+ ///
+ template
+ std::unique_ptr<_Type> make_unique() {
+ return std::unique_ptr<_Type>(new _Type());
+ }
+
+ template
+ std::unique_ptr<_Type> make_unique(_Arg1&& arg1) {
+ return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));
+ }
+
+ template
+ std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2) {
+ return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2)));
+ }
+
+ template
+ std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3) {
+ return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3)));
+ }
+
+ template
+ std::unique_ptr<_Type> make_unique(_Arg1&& arg1, _Arg2&& arg2, _Arg3&& arg3, _Arg4&& arg4) {
+ return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1), std::forward<_Arg2>(arg2), std::forward<_Arg3>(arg3), std::forward<_Arg4>(arg4)));
+ }
+
+ ///
+ /// Cross platform utility function for performing case insensitive string comparision.
+ ///
+ /// First string to compare.
+ /// Second strong to compare.
+ /// true if the strings are equivalent, false otherwise
+/* inline bool str_icmp(const utility::string_t &left, const utility::string_t &right)
+ {
+#ifdef _WIN32
+ return _wcsicmp(left.c_str(), right.c_str()) == 0;
+#else
+ return boost::iequals(left, right);
+#endif
+ }
+*/
+#ifdef _WIN32
+
+///
+/// Category error type for Windows OS errors.
+///
+class windows_category_impl : public std::error_category
+{
+public:
+ virtual const char *name() const CPPREST_NOEXCEPT { return "windows"; }
+
+ _ASYNCRTIMP virtual std::string message(int errorCode) const CPPREST_NOEXCEPT;
+
+ _ASYNCRTIMP virtual std::error_condition default_error_condition(int errorCode) const CPPREST_NOEXCEPT;
+};
+
+///
+/// Gets the one global instance of the windows error category.
+///
+/// An error category instance.
+_ASYNCRTIMP const std::error_category & __cdecl windows_category();
+
+#else
+
+///
+/// Gets the one global instance of the linux error category.
+///
+/// An error category instance.
+_ASYNCRTIMP const std::error_category & __cdecl linux_category();
+
+#endif
+
+///
+/// Gets the one global instance of the current platform's error category.
+///
+_ASYNCRTIMP const std::error_category & __cdecl platform_category();
+
+///
+/// Creates an instance of std::system_error from a OS error code.
+///
+inline std::system_error __cdecl create_system_error(unsigned long errorCode)
+{
+ std::error_code code((int)errorCode, platform_category());
+ return std::system_error(code, code.message());
+}
+
+///
+/// Creates a std::error_code from a OS error code.
+///
+inline std::error_code __cdecl create_error_code(unsigned long errorCode)
+{
+ return std::error_code((int)errorCode, platform_category());
+}
+
+///
+/// Creates the corresponding error message from a OS error code.
+///
+inline utility::string_t __cdecl create_error_message(unsigned long errorCode)
+{
+ return utility::conversions::to_string_t(create_error_code(errorCode).message());
+}
+
+}
+
+class datetime
+{
+public:
+ typedef uint64_t interval_type;
+
+ ///
+ /// Defines the supported date and time string formats.
+ ///
+ enum date_format { RFC_1123, ISO_8601 };
+
+ ///
+ /// Returns the current UTC time.
+ ///
+ // static _ASYNCRTIMP datetime __cdecl utc_now();
+
+ ///
+ /// An invalid UTC timestamp value.
+ ///
+ enum:interval_type { utc_timestamp_invalid = static_cast(-1) };
+
+ ///
+ /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.
+ /// If time is before epoch, utc_timestamp_invalid is returned.
+ ///
+ /*
+ static interval_type utc_timestamp()
+ {
+ const auto seconds = utc_now().to_interval() / _secondTicks;
+ if (seconds >= 11644473600LL)
+ {
+ return seconds - 11644473600LL;
+ }
+ else
+ {
+ return utc_timestamp_invalid;
+ }
+ }
+ */
+
+ datetime() : m_interval(0)
+ {
+ }
+
+ ///
+ /// Creates datetime from a string representing time in UTC in RFC 1123 format.
+ ///
+ /// Returns a datetime of zero if not successful.
+ // static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);
+
+ ///
+ /// Returns a string representation of the datetime.
+ ///
+ _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const;
+
+ ///
+ /// Returns the integral time value.
+ ///
+ interval_type to_interval() const
+ {
+ return m_interval;
+ }
+
+ datetime operator- (interval_type value) const
+ {
+ return datetime(m_interval - value);
+ }
+
+ datetime operator+ (interval_type value) const
+ {
+ return datetime(m_interval + value);
+ }
+
+ bool operator== (datetime dt) const
+ {
+ return m_interval == dt.m_interval;
+ }
+
+ bool operator!= (const datetime& dt) const
+ {
+ return !(*this == dt);
+ }
+
+ static interval_type from_milliseconds(unsigned int milliseconds)
+ {
+ return milliseconds*_msTicks;
+ }
+
+ static interval_type from_seconds(unsigned int seconds)
+ {
+ return seconds*_secondTicks;
+ }
+
+ static interval_type from_minutes(unsigned int minutes)
+ {
+ return minutes*_minuteTicks;
+ }
+
+ static interval_type from_hours(unsigned int hours)
+ {
+ return hours*_hourTicks;
+ }
+
+ static interval_type from_days(unsigned int days)
+ {
+ return days*_dayTicks;
+ }
+
+ bool is_initialized() const
+ {
+ return m_interval != 0;
+ }
+
+private:
+
+ friend int operator- (datetime t1, datetime t2);
+
+ static const interval_type _msTicks = static_cast(10000);
+ static const interval_type _secondTicks = 1000*_msTicks;
+ static const interval_type _minuteTicks = 60*_secondTicks;
+ static const interval_type _hourTicks = 60*60*_secondTicks;
+ static const interval_type _dayTicks = 24*60*60*_secondTicks;
+
+
+#ifdef _WIN32
+ // void* to avoid pulling in windows.h
+ static _ASYNCRTIMP bool __cdecl datetime::system_type_to_datetime(/*SYSTEMTIME*/ void* psysTime, uint64_t seconds, datetime * pdt);
+#else
+ static datetime timeval_to_datetime(const timeval &time);
+#endif
+
+ // Private constructor. Use static methods to create an instance.
+ datetime(interval_type interval) : m_interval(interval)
+ {
+ }
+
+ // Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.
+ interval_type m_interval;
+};
+
+#ifndef _WIN32
+
+// temporary workaround for the fact that
+// utf16char is not fully supported in GCC
+class cmp
+{
+public:
+
+ static int icmp(std::string left, std::string right)
+ {
+ size_t i;
+ for (i = 0; i < left.size(); ++i)
+ {
+ if (i == right.size()) return 1;
+
+ auto l = cmp::tolower(left[i]);
+ auto r = cmp::tolower(right[i]);
+ if (l > r) return 1;
+ if (l < r) return -1;
+ }
+ if (i < right.size()) return -1;
+ return 0;
+ }
+
+private:
+ static char tolower(char c)
+ {
+ if (c >= 'A' && c <= 'Z')
+ return static_cast(c - 'A' + 'a');
+ return c;
+ }
+};
+
+#endif
+
+inline int operator- (datetime t1, datetime t2)
+{
+ auto diff = (t1.m_interval - t2.m_interval);
+
+ // Round it down to seconds
+ diff /= 10 * 1000 * 1000;
+
+ return static_cast(diff);
+}
+
+/*
+///
+/// Nonce string generator class.
+///
+class nonce_generator
+{
+public:
+
+ ///
+ /// Define default nonce length.
+ ///
+ enum { default_length = 32 };
+
+ ///
+ /// Nonce generator constructor.
+ ///
+ /// Length of the generated nonce string.
+ nonce_generator(int length=default_length) :
+ m_random(static_cast(utility::datetime::utc_timestamp())),
+ m_length(length)
+ {}
+
+ ///
+ /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).
+ /// Length of the generated string is set by length().
+ ///
+ /// The generated nonce string.
+ _ASYNCRTIMP utility::string_t generate();
+
+ ///
+ /// Get length of generated nonce string.
+ ///
+ /// Nonce string length.
+ int length() const { return m_length; }
+
+ ///
+ /// Set length of the generated nonce string.
+ ///
+ /// Lenght of nonce string.
+ void set_length(int length) { m_length = length; }
+
+private:
+ static const utility::string_t c_allowed_chars;
+ std::mt19937 m_random;
+ int m_length;
+};
+*/
+} // namespace utility;
diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp b/src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp
new file mode 100755
index 000000000..798012bed
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp
@@ -0,0 +1,7048 @@
+/*-----------------------------------------------------------------------------------------------------------
+SafeInt.hpp
+Version 3.0.18p
+
+This software is licensed under the Microsoft Public License (Ms-PL).
+For more information about Microsoft open source licenses, refer to
+http://www.microsoft.com/opensource/licenses.mspx
+
+This license governs use of the accompanying software. If you use the software, you accept this license.
+If you do not accept the license, do not use the software.
+
+Definitions
+The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here
+as under U.S. copyright law. A "contribution" is the original software, or any additions or changes to
+the software. A "contributor" is any person that distributes its contribution under this license.
+"Licensed patents" are a contributor's patent claims that read directly on its contribution.
+
+Grant of Rights
+(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations
+in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to
+reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution
+or any derivative works that you create.
+
+(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in
+section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed
+patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution
+in the software or derivative works of the contribution in the software.
+
+Conditions and Limitations
+(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo,
+ or trademarks.
+(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the
+ software, your patent license from such contributor to the software ends automatically.
+(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and
+ attribution notices that are present in the software.
+(D) If you distribute any portion of the software in source code form, you may do so only under this license
+ by including a complete copy of this license with your distribution. If you distribute any portion of the
+ software in compiled or object code form, you may only do so under a license that complies with this license.
+(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties,
+ guarantees, or conditions. You may have additional consumer rights under your local laws which this license
+ cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties
+ of merchantability, fitness for a particular purpose and non-infringement.
+
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+This header implements an integer handling class designed to catch
+unsafe integer operations
+
+This header compiles properly at Wall on Visual Studio, -Wall on gcc, and -Weverything on clang.
+
+Please read the leading comments before using the class.
+---------------------------------------------------------------*/
+#pragma once
+
+// It is a bit tricky to sort out what compiler we are actually using,
+// do this once here, and avoid cluttering the code
+#define VISUAL_STUDIO_COMPILER 0
+#define CLANG_COMPILER 1
+#define GCC_COMPILER 2
+#define UNKNOWN_COMPILER -1
+
+// Clang will sometimes pretend to be Visual Studio
+// and does pretend to be gcc. Check it first, as nothing else pretends to be clang
+#if defined __clang__
+#define SAFEINT_COMPILER CLANG_COMPILER
+#elif defined __GNUC__
+#define SAFEINT_COMPILER GCC_COMPILER
+#elif defined _MSC_VER
+#define SAFEINT_COMPILER VISUAL_STUDIO_COMPILER
+#else
+#define SAFEINT_COMPILER UNKNOWN_COMPILER
+#endif
+
+// Enable compiling with /Wall under VC
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+#pragma warning( push )
+// Disable warnings coming from headers
+#pragma warning( disable:4987 4820 4987 4820 )
+
+#endif
+
+// Need this for ptrdiff_t on some compilers
+#include
+#include
+
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER && defined _M_AMD64
+ #include
+ #define SAFEINT_USE_INTRINSICS 1
+#else
+ #define SAFEINT_USE_INTRINSICS 0
+#endif
+
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+#pragma warning( pop )
+#endif
+
+// Various things needed for GCC
+#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER
+
+#define NEEDS_INT_DEFINED
+
+#if !defined NULL
+#define NULL 0
+#endif
+
+// GCC warning suppression
+#if SAFEINT_COMPILER == GCC_COMPILER
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
+#endif
+
+#include
+
+// clang only
+#if SAFEINT_COMPILER == CLANG_COMPILER
+
+#if __has_feature(cxx_nullptr)
+ #define NEEDS_NULLPTR_DEFINED 0
+#endif
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#pragma clang diagnostic ignored "-Wold-style-cast"
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
+#endif
+
+#endif
+
+// If the user made a choice, respect it #if !defined
+#if !defined NEEDS_NULLPTR_DEFINED
+ // Visual Studio 2010 and higher support this
+ #if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+ #if (_MSC_VER < 1600)
+ #define NEEDS_NULLPTR_DEFINED 1
+ #else
+ #define NEEDS_NULLPTR_DEFINED 0
+ #endif
+ #else
+ // Let everything else trigger based on whether we use c++11 or above
+ #if __cplusplus >= 201103L
+ #define NEEDS_NULLPTR_DEFINED 0
+ #else
+ #define NEEDS_NULLPTR_DEFINED 1
+ #endif
+ #endif
+#endif
+
+#if NEEDS_NULLPTR_DEFINED
+#define nullptr NULL
+#endif
+
+#ifndef C_ASSERT
+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+#endif
+
+// Let's test some assumptions
+// We're assuming two's complement negative numbers
+C_ASSERT( -1 == static_cast(0xffffffff) );
+
+/************* Compiler Options *****************************************************************************************************
+
+SafeInt supports several compile-time options that can change the behavior of the class.
+
+Compiler options:
+SAFEINT_WARN_64BIT_PORTABILITY - this re-enables various warnings that happen when /Wp64 is used. Enabling this option is not
+ recommended.
+NEEDS_INT_DEFINED - if your compiler does not support __int8, __int16, __int32 and __int64, you can enable this.
+SAFEINT_ASSERT_ON_EXCEPTION - it is often easier to stop on an assert and figure out a problem than to try and figure out
+ how you landed in the catch block.
+SafeIntDefaultExceptionHandler - if you'd like to replace the exception handlers SafeInt provides, define your replacement and
+ define this. Note - two built in (Windows-specific) options exist:
+ - SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an exception
+ - SAFEINT_RAISE_EXCEPTION - throws Win32 exceptions, which can be caught
+SAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to completely fail
+ to compile, define this.
+ANSI_CONVERSIONS - This changes the class to use default comparison behavior, which may be unsafe. Enabling this
+ option is not recommended.
+SAFEINT_DISABLE_BINARY_ASSERT - binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do
+ this, the default is to assert. Set this if you prefer not to assert under these conditions.
+SIZE_T_CAST_NEEDED - some compilers complain if there is not a cast to size_t, others complain if there is one.
+ This lets you not have your compiler complain.
+SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert when shifting more bits than the type has. Enabling
+ this option is not recommended.
+
+************************************************************************************************************************************/
+
+/*
+* The SafeInt class is designed to have as low an overhead as possible
+* while still ensuring that all integer operations are conducted safely.
+* Nearly every operator has been overloaded, with a very few exceptions.
+*
+* A usability-safety trade-off has been made to help ensure safety. This
+* requires that every operation return either a SafeInt or a bool. If we
+* allowed an operator to return a base integer type T, then the following
+* can happen:
+*
+* char i = SafeInt(32) * 2 + SafeInt(16) * 4;
+*
+* The * operators take precedence, get overloaded, return a char, and then
+* you have:
+*
+* char i = (char)64 + (char)64; //overflow!
+*
+* This situation would mean that safety would depend on usage, which isn't
+* acceptable.
+*
+* One key operator that is missing is an implicit cast to type T. The reason for
+* this is that if there is an implicit cast operator, then we end up with
+* an ambiguous compile-time precedence. Because of this amiguity, there
+* are two methods that are provided:
+*
+* Casting operators for every native integer type
+* Version 3 note - it now compiles correctly for size_t without warnings
+*
+* SafeInt::Ptr() - returns the address of the internal integer
+* Note - the '&' (address of) operator has been overloaded and returns
+* the address of the internal integer.
+*
+* The SafeInt class should be used in any circumstances where ensuring
+* integrity of the calculations is more important than performance. See Performance
+* Notes below for additional information.
+*
+* Many of the conditionals will optimize out or be inlined for a release
+* build (especially with /Ox), but it does have significantly more overhead,
+* especially for signed numbers. If you do not _require_ negative numbers, use
+* unsigned integer types - certain types of problems cannot occur, and this class
+* performs most efficiently.
+*
+* Here's an example of when the class should ideally be used -
+*
+* void* AllocateMemForStructs(int StructSize, int HowMany)
+* {
+* SafeInt s(StructSize);
+*
+* s *= HowMany;
+*
+* return malloc(s);
+*
+* }
+*
+* Here's when it should NOT be used:
+*
+* void foo()
+* {
+* int i;
+*
+* for(i = 0; i < 0xffff; i++)
+* ....
+* }
+*
+* Error handling - a SafeInt class will throw exceptions if something
+* objectionable happens. The exceptions are SafeIntException classes,
+* which contain an enum as a code.
+*
+* Typical usage might be:
+*
+* bool foo()
+* {
+* SafeInt s; //note that s == 0 unless set
+*
+* try{
+* s *= 23;
+* ....
+* }
+* catch(SafeIntException err)
+* {
+* //handle errors here
+* }
+* }
+*
+* Update for 3.0 - the exception class is now a template parameter.
+* You can replace the exception class with any exception class you like. This is accomplished by:
+* 1) Create a class that has the following interface:
+*
+ template <> class YourSafeIntExceptionHandler < YourException >
+ {
+ public:
+ static __declspec(noreturn) void __stdcall SafeIntOnOverflow()
+ {
+ throw YourException( YourSafeIntArithmeticOverflowError );
+ }
+
+ static __declspec(noreturn) void __stdcall SafeIntOnDivZero()
+ {
+ throw YourException( YourSafeIntDivideByZeroError );
+ }
+ };
+*
+* Note that you don't have to throw C++ exceptions, you can throw Win32 exceptions, or do
+* anything you like, just don't return from the call back into the code.
+*
+* 2) Either explicitly declare SafeInts like so:
+* SafeInt< int, YourSafeIntExceptionHandler > si;
+* or
+* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler
+*
+* Performance:
+*
+* Due to the highly nested nature of this class, you can expect relatively poor
+* performance in unoptimized code. In tests of optimized code vs. correct inline checks
+* in native code, this class has been found to take approximately 8% more CPU time (this varies),
+* most of which is due to exception handling. Solutions:
+*
+* 1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1
+* (optimize for size) does not work as well.
+* 2) If that 8% hit is really a serious problem, walk through the code and inline the
+* exact same checks as the class uses.
+* 3) Some operations are more difficult than others - avoid using signed integers, and if
+* possible keep them all the same size. 64-bit integers are also expensive. Mixing
+* different integer sizes and types may prove expensive. Be aware that literals are
+* actually ints. For best performance, cast literals to the type desired.
+*
+*
+* Performance update
+* The current version of SafeInt uses template specialization to force the compiler to invoke only the
+* operator implementation needed for any given pair of types. This will dramatically improve the perf
+* of debug builds.
+*
+* 3.0 update - not only have we maintained the specialization, there were some cases that were overly complex,
+* and using some additional cases (e.g. signed __int64 and unsigned __int64) resulted in some simplification.
+* Additionally, there was a lot of work done to better optimize the 64-bit multiplication.
+*
+* Binary Operators
+*
+* All of the binary operators have certain assumptions built into the class design.
+* This is to ensure correctness. Notes on each class of operator follow:
+*
+* Arithmetic Operators (*,/,+,-,%)
+* There are three possible variants:
+* SafeInt< T, E > op SafeInt< T, E >
+* SafeInt< T, E > op U
+* U op SafeInt< T, E >
+*
+* The SafeInt< T, E > op SafeInt< U, E > variant is explicitly not supported, and if you try to do
+* this the compiler with throw the following error:
+*
+* error C2593: 'operator *' is ambiguous
+*
+* This is because the arithmetic operators are required to return a SafeInt of some type.
+* The compiler cannot know whether you'd prefer to get a type T or a type U returned. If
+* you need to do this, you need to extract the value contained within one of the two using
+* the casting operator. For example:
+*
+* SafeInt< T, E > t, result;
+* SafeInt< U, E > u;
+*
+* result = t * (U)u;
+*
+* Comparison Operators
+* Because each of these operators return type bool, mixing SafeInts of differing types is
+* allowed.
+*
+* Shift Operators
+* Shift operators always return the type on the left hand side of the operator. Mixed type
+* operations are allowed because the return type is always known.
+*
+* Boolean Operators
+* Like comparison operators, these overloads always return type bool, and mixed-type SafeInts
+* are allowed. Additionally, specific overloads exist for type bool on both sides of the
+* operator.
+*
+* Binary Operators
+* Mixed-type operations are discouraged, however some provision has been made in order to
+* enable things like:
+*
+* SafeInt c = 2;
+*
+* if(c & 0x02)
+* ...
+*
+* The "0x02" is actually an int, and it needs to work.
+* In the case of binary operations on integers smaller than 32-bit, or of mixed type, corner
+* cases do exist where you could get unexpected results. In any case where SafeInt returns a different
+* result than the underlying operator, it will call assert(). You should examine your code and cast things
+* properly so that you are not programming with side effects.
+*
+* Documented issues:
+*
+* This header compiles correctly at /W4 using VC++ 8 (Version 14.00.50727.42) and later.
+* As of this writing, I believe it will also work for VC 7.1, but not for VC 7.0 or below.
+* If you need a version that will work with lower level compilers, try version 1.0.7. None
+* of them work with Visual C++ 6, and gcc didn't work very well, either, though this hasn't
+* been tried recently.
+*
+* It is strongly recommended that any code doing integer manipulation be compiled at /W4
+* - there are a number of warnings which pertain to integer manipulation enabled that are
+* not enabled at /W3 (default for VC++)
+*
+* Perf note - postfix operators are slightly more costly than prefix operators.
+* Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++
+*
+* The comparison operator behavior in this class varies from the ANSI definition, which is
+* arguably broken. As an example, consider the following:
+*
+* unsigned int l = 0xffffffff;
+* char c = -1;
+*
+* if(c == l)
+* printf("Why is -1 equal to 4 billion???\n");
+*
+* The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets
+* cast again to an unsigned int, losing the true value. This behavior is despite the fact that
+* an __int64 exists, and the following code will yield a different (and intuitively correct)
+* answer:
+*
+* if((__int64)c == (__int64)l))
+* printf("Why is -1 equal to 4 billion???\n");
+* else
+* printf("Why doesn't the compiler upcast to 64-bits when needed?\n");
+*
+* Note that combinations with smaller integers won't display the problem - if you
+* changed "unsigned int" above to "unsigned short", you'd get the right answer.
+*
+* If you prefer to retain the ANSI standard behavior insert
+* #define ANSI_CONVERSIONS
+* into your source. Behavior differences occur in the following cases:
+* 8, 16, and 32-bit signed int, unsigned 32-bit int
+* any signed int, unsigned 64-bit int
+* Note - the signed int must be negative to show the problem
+*
+*
+* Revision history:
+*
+* Oct 12, 2003 - Created
+* Author - David LeBlanc - dleblanc@microsoft.com
+*
+* Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson
+* Dec 28, 2003 - 1.0
+* added support for mixed-type operations
+* thanks to vikramh
+* also fixed broken __int64 multiplication section
+* added extended support for mixed-type operations where possible
+* Jan 28, 2004 - 1.0.1
+* changed WCHAR to wchar_t
+* fixed a construct in two mixed-type assignment overloads that was
+* not compiling on some compilers
+* Also changed name of private method to comply with standards on
+* reserved names
+* Thanks to Niels Dekker for the input
+* Feb 12, 2004 - 1.0.2
+* Minor changes to remove dependency on Windows headers
+* Consistently used __int16, __int32 and __int64 to ensure
+* portability
+* May 10, 2004 - 1.0.3
+* Corrected bug in one case of GreaterThan
+* July 22, 2004 - 1.0.4
+* Tightened logic in addition check (saving 2 instructions)
+* Pulled error handler out into function to enable user-defined replacement
+* Made internal type of SafeIntException an enum (as per Niels' suggestion)
+* Added casts for base integer types (as per Scott Meyers' suggestion)
+* Updated usage information - see important new perf notes.
+* Cleaned up several const issues (more thanks to Niels)
+*
+* Oct 1, 2004 - 1.0.5
+* Added support for SEH exceptions instead of C++ exceptions - Win32 only
+* Made handlers for DIV0 and overflows individually overridable
+* Commented out the destructor - major perf gains here
+* Added cast operator for type long, since long != __int32
+* Corrected a couple of missing const modifiers
+* Fixed broken >= and <= operators for type U op SafeInt< T, E >
+* Nov 5, 2004 - 1.0.6
+* Implemented new logic in binary operators to resolve issues with
+* implicit casts
+* Fixed casting operator because char != signed char
+* Defined __int32 as int instead of long
+* Removed unsafe SafeInt::Value method
+* Re-implemented casting operator as a result of removing Value method
+* Dec 1, 2004 - 1.0.7
+* Implemented specialized operators for pointer arithmetic
+* Created overloads for cases of U op= SafeInt. What you do with U
+* after that may be dangerous.
+* Fixed bug in corner case of MixedSizeModulus
+* Fixed bug in MixedSizeMultiply and MixedSizeDivision with input of 0
+* Added throw() decorations
+*
+* Apr 12, 2005 - 2.0
+* Extensive revisions to leverage template specialization.
+* April, 2007 Extensive revisions for version 3.0
+* Nov 22, 2009 Forked from MS internal code
+* Changes needed to support gcc compiler - many thanks to Niels Dekker
+* for determining not just the issues, but also suggesting fixes.
+* Also updating some of the header internals to be the same as the upcoming Visual Studio version.
+*
+* Jan 16, 2010 64-bit gcc has long == __int64, which means that many of the existing 64-bit
+* templates are over-specialized. This forces a redefinition of all the 64-bit
+* multiplication routines to use pointers instead of references for return
+* values. Also, let's use some intrinsics for x64 Microsoft compiler to
+* reduce code size, and hopefully improve efficiency.
+*
+* June 21, 2014 Better support for clang, higher warning levels supported for all 3 primary supported
+ compilers (Visual Studio, clang, gcc).
+ Also started to converge the code base such that the public CodePlex version will
+ be a drop-in replacement for the Visual Studio version.
+
+* Note about code style - throughout this class, casts will be written using C-style (T),
+* not C++ style static_cast< T >. This is because the class is nearly always dealing with integer
+* types, and in this case static_cast and a C cast are equivalent. Given the large number of casts,
+* the code is a little more readable this way. In the event a cast is needed where static_cast couldn't
+* be substituted, we'll use the new templatized cast to make it explicit what the operation is doing.
+*
+************************************************************************************************************
+* Version 3.0 changes:
+*
+* 1) The exception type thrown is now replacable, and you can throw your own exception types. This should help
+* those using well-developed exception classes.
+* 2) The 64-bit multiplication code has had a lot of perf work done, and should be faster than 2.0.
+* 3) There is now limited floating point support. You can initialize a SafeInt with a floating point type,
+* and you can cast it out (or assign) to a float as well.
+* 4) There is now an Align method. I noticed people use this a lot, and rarely check errors, so now you have one.
+*
+* Another major improvement is the addition of external functions - if you just want to check an operation, this can now happen:
+* All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially handy
+* for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for 64-bit.
+*
+* inline bool SafeCast( const T From, U& To ) throw()
+* inline bool SafeEquals( const T t, const U u ) throw()
+* inline bool SafeNotEquals( const T t, const U u ) throw()
+* inline bool SafeGreaterThan( const T t, const U u ) throw()
+* inline bool SafeGreaterThanEquals( const T t, const U u ) throw()
+* inline bool SafeLessThan( const T t, const U u ) throw()
+* inline bool SafeLessThanEquals( const T t, const U u ) throw()
+* inline bool SafeModulus( const T& t, const U& u, T& result ) throw()
+* inline bool SafeMultiply( T t, U u, T& result ) throw()
+* inline bool SafeDivide( T t, U u, T& result ) throw()
+* inline bool SafeAdd( T t, U u, T& result ) throw()
+* inline bool SafeSubtract( T t, U u, T& result ) throw()
+*
+*/
+
+//use these if the compiler does not support _intXX
+#ifdef NEEDS_INT_DEFINED
+#define __int8 char
+#define __int16 short
+#define __int32 int
+#define __int64 long long
+#endif
+
+namespace msl
+{
+
+namespace safeint3
+{
+
+// catch these to handle errors
+// Currently implemented code values:
+// ERROR_ARITHMETIC_OVERFLOW
+// EXCEPTION_INT_DIVIDE_BY_ZERO
+enum SafeIntError
+{
+ SafeIntNoError = 0,
+ SafeIntArithmeticOverflow,
+ SafeIntDivideByZero
+};
+
+} // safeint3
+} // msl
+
+
+/*
+* Error handler classes
+* Using classes to deal with exceptions is going to allow the most
+* flexibility, and we can mix different error handlers in the same project
+* or even the same file. It isn't advisable to do this in the same function
+* because a SafeInt< int, MyExceptionHandler > isn't the same thing as
+* SafeInt< int, YourExceptionHander >.
+* If for some reason you have to translate between the two, cast one of them back to its
+* native type.
+*
+* To use your own exception class with SafeInt, first create your exception class,
+* which may look something like the SafeIntException class below. The second step is to
+* create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero.
+* For example:
+*
+* template <> class SafeIntExceptionHandler < YourExceptionClass >
+* {
+* static __declspec(noreturn) void __stdcall SafeIntOnOverflow()
+* {
+* throw YourExceptionClass( EXCEPTION_INT_OVERFLOW );
+* }
+*
+* static __declspec(noreturn) void __stdcall SafeIntOnDivZero()
+* {
+* throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO );
+* }
+* };
+*
+* typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler
+* You'd then declare your SafeInt objects like this:
+* SafeInt< int, YourSafeIntExceptionHandler >
+*
+* Unfortunately, there is no such thing as partial template specialization in typedef
+* statements, so you have three options if you find this cumbersome:
+*
+* 1) Create a holder class:
+*
+* template < typename T >
+* class MySafeInt
+* {
+* public:
+* SafeInt< T, MyExceptionClass> si;
+* };
+*
+* You'd then declare an instance like so:
+* MySafeInt< int > i;
+*
+* You'd lose handy things like initialization - it would have to be initialized as:
+*
+* i.si = 0;
+*
+* 2) You could create a typedef for every int type you deal with:
+*
+* typedef SafeInt< int, MyExceptionClass > MySafeInt;
+* typedef SafeInt< char, MyExceptionClass > MySafeChar;
+*
+* and so on. The second approach is probably more usable, and will just drop into code
+* better, which is the original intent of the SafeInt class.
+*
+* 3) If you're going to consistently use a different class to handle your exceptions,
+* you can override the default typedef like so:
+*
+* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler
+*
+* Overall, this is probably the best approach.
+* */
+
+// On the Microsoft compiler, violating a throw() annotation is a silent error.
+// Other compilers might turn these into exceptions, and some users may want to not have throw() enabled.
+// In addition, some error handlers may not throw C++ exceptions, which makes everything no throw.
+#if defined SAFEINT_REMOVE_NOTHROW
+#define SAFEINT_NOTHROW
+#else
+#define SAFEINT_NOTHROW throw()
+#endif
+
+namespace msl
+{
+
+namespace safeint3
+{
+
+// If you would like to use your own custom assert
+// Define SAFEINT_ASSERT
+#if !defined SAFEINT_ASSERT
+#include
+#define SAFEINT_ASSERT(x) assert(x)
+#endif
+
+#if defined SAFEINT_ASSERT_ON_EXCEPTION
+ inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); }
+#else
+ inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {}
+#endif
+
+#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER
+ #define SAFEINT_NORETURN __attribute__((noreturn))
+ #define SAFEINT_STDCALL
+ #define SAFEINT_VISIBLE __attribute__ ((__visibility__("default")))
+ #define SAFEINT_WEAK __attribute__ ((weak))
+#else
+ #define SAFEINT_NORETURN __declspec(noreturn)
+ #define SAFEINT_STDCALL __stdcall
+ #define SAFEINT_VISIBLE
+ #define SAFEINT_WEAK
+#endif
+
+class SAFEINT_VISIBLE SafeIntException
+{
+public:
+ SafeIntException() SAFEINT_NOTHROW { m_code = SafeIntNoError; }
+ SafeIntException( SafeIntError code ) SAFEINT_NOTHROW
+ {
+ m_code = code;
+ }
+ SafeIntError m_code;
+};
+
+namespace SafeIntInternal
+{
+ // Visual Studio version of SafeInt provides for two possible error
+ // handlers:
+ // SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined
+ // SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers,
+ // exits the app with a crash
+ template < typename E > class SafeIntExceptionHandler;
+
+ template <> class SafeIntExceptionHandler < SafeIntException >
+ {
+ public:
+
+ static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow()
+ {
+ SafeIntExceptionAssert();
+ throw SafeIntException( SafeIntArithmeticOverflow );
+ }
+
+ static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero()
+ {
+ SafeIntExceptionAssert();
+ throw SafeIntException( SafeIntDivideByZero );
+ }
+ };
+
+#if !defined _CRT_SECURE_INVALID_PARAMETER
+ // Calling fail fast is somewhat more robust than calling abort,
+ // but abort is the closest we can manage without Visual Studio support
+ // Need the header for abort()
+ #include
+ #define _CRT_SECURE_INVALID_PARAMETER(msg) abort()
+#endif
+
+ class SafeInt_InvalidParameter
+ {
+ public:
+ static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW
+ {
+ SafeIntExceptionAssert();
+ _CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow");
+ }
+
+ static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW
+ {
+ SafeIntExceptionAssert();
+ _CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero");
+ }
+ };
+
+#if defined _WINDOWS_
+
+ class SafeIntWin32ExceptionHandler
+ {
+ public:
+ static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW
+ {
+ SafeIntExceptionAssert();
+ RaiseException( static_cast(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0);
+ }
+
+ static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW
+ {
+ SafeIntExceptionAssert();
+ RaiseException( static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0);
+ }
+ };
+
+#endif
+
+} // namespace SafeIntInternal
+
+// both of these have cross-platform support
+typedef SafeIntInternal::SafeIntExceptionHandler < SafeIntException > CPlusPlusExceptionHandler;
+typedef SafeIntInternal::SafeInt_InvalidParameter InvalidParameterExceptionHandler;
+
+// This exception handler is no longer recommended, but is left here in order not to break existing users
+#if defined _WINDOWS_
+typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler;
+#endif
+
+// For Visual Studio compatibility
+#if defined VISUAL_STUDIO_SAFEINT_COMPAT
+ typedef CPlusPlusExceptionHandler SafeIntErrorPolicy_SafeIntException;
+ typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter;
+#endif
+
+// If the user hasn't defined a default exception handler,
+// define one now, depending on whether they would like Win32 or C++ exceptions
+
+// This library will use conditional noexcept soon, but not in this release
+// Some users might mix exception handlers, which is not advised, but is supported
+#if !defined SafeIntDefaultExceptionHandler
+ #if defined SAFEINT_RAISE_EXCEPTION
+ #if !defined _WINDOWS_
+ #error Include windows.h in order to use Win32 exceptions
+ #endif
+
+ #define SafeIntDefaultExceptionHandler Win32ExceptionHandler
+ #elif defined SAFEINT_FAILFAST
+ #define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler
+ #else
+ #define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler
+ #if !defined SAFEINT_EXCEPTION_HANDLER_CPP
+ #define SAFEINT_EXCEPTION_HANDLER_CPP 1
+ #endif
+ #endif
+#endif
+
+#if !defined SAFEINT_EXCEPTION_HANDLER_CPP
+#define SAFEINT_EXCEPTION_HANDLER_CPP 0
+#endif
+
+// If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast,
+// or abort, then all methods become no throw. Some teams track throw() annotations closely,
+// and the following option provides for this.
+#if SAFEINT_EXCEPTION_HANDLER_CPP
+#define SAFEINT_CPP_THROW
+#else
+#define SAFEINT_CPP_THROW SAFEINT_NOTHROW
+#endif
+
+// Turns out we can fool the compiler into not seeing compile-time constants with
+// a simple template specialization
+template < int method > class CompileConst;
+template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return true; } };
+template <> class CompileConst { public: static bool Value() SAFEINT_NOTHROW { return false; } };
+
+// The following template magic is because we're now not allowed
+// to cast a float to an enum. This means that if we happen to assign
+// an enum to a SafeInt of some type, it won't compile, unless we prevent
+// isFloat = ( (T)( (float)1.1 ) > (T)1 )
+// from compiling in the case of an enum, which is the point of the specialization
+// that follows.
+
+// If we have support for std, then we can do this easily, and detect enums as well
+template < typename T > class NumericType;
+
+#if defined _LIBCPP_TYPE_TRAITS || defined _TYPE_TRAITS_
+// Continue to special case bool
+template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; };
+template < typename T > class NumericType
+{
+ public:
+ enum
+ {
+ isBool = false, // We specialized out a bool
+ isFloat = std::is_floating_point::value,
+ // If it is an enum, then consider it an int type
+ // This does allow someone to make a SafeInt from an enum type, which is not recommended,
+ // but it also allows someone to add an enum value to a SafeInt, which is handy.
+ isInt = std::is_integral::value || std::is_enum::value
+ };
+};
+
+#else
+
+template <> class NumericType { public: enum{ isBool = true, isFloat = false, isInt = false }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+#endif
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType<__int64> { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = false, isInt = true }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; };
+template <> class NumericType { public: enum{ isBool = false, isFloat = true, isInt = false }; };
+// Catch-all for anything not supported
+template < typename T > class NumericType
+{
+public:
+ // We have some unknown type, which could be an enum. For parity with the code that uses ,
+ // We can try a static_cast - it if compiles, then it might be an enum, and should work.
+ // If it is something else that just happens to have a constructor that takes an int, and a casting operator,
+ // then it is possible something will go wrong, and for best results, cast it directly to an int before letting it
+ // interact with a SafeInt
+
+ enum
+ {
+ isBool = false,
+ isFloat = false,
+ isInt = static_cast( static_cast(0) ) == 0
+ };
+};
+#endif // type traits
+
+// Use this to avoid compile-time const truncation warnings
+template < int fSigned, int bits > class SafeIntMinMax;
+
+template <> class SafeIntMinMax< true, 8 > { public: const static signed __int8 min = (-0x7f - 1);
+ const static signed __int8 max = 0x7f; };
+template <> class SafeIntMinMax< true, 16 > { public: const static __int16 min = ( -0x7fff - 1 );
+ const static __int16 max = 0x7fff; };
+template <> class SafeIntMinMax< true, 32 > { public: const static __int32 min = ( -0x7fffffff -1 );
+ const static __int32 max = 0x7fffffff; };
+template <> class SafeIntMinMax< true, 64 > { public: const static __int64 min = static_cast<__int64>(0x8000000000000000LL);
+ const static __int64 max = 0x7fffffffffffffffLL; };
+
+template <> class SafeIntMinMax< false, 8 > { public: const static unsigned __int8 min = 0;
+ const static unsigned __int8 max = 0xff; };
+template <> class SafeIntMinMax< false, 16 > { public: const static unsigned __int16 min = 0;
+ const static unsigned __int16 max = 0xffff; };
+template <> class SafeIntMinMax< false, 32 > { public: const static unsigned __int32 min = 0;
+ const static unsigned __int32 max = 0xffffffff; };
+template <> class SafeIntMinMax< false, 64 > { public: const static unsigned __int64 min = 0;
+ const static unsigned __int64 max = 0xffffffffffffffffULL; };
+
+template < typename T > class IntTraits
+{
+public:
+ C_ASSERT( NumericType::isInt );
+ enum
+ {
+ isSigned = ( (T)(-1) < 0 ),
+ is64Bit = ( sizeof(T) == 8 ),
+ is32Bit = ( sizeof(T) == 4 ),
+ is16Bit = ( sizeof(T) == 2 ),
+ is8Bit = ( sizeof(T) == 1 ),
+ isLT32Bit = ( sizeof(T) < 4 ),
+ isLT64Bit = ( sizeof(T) < 8 ),
+ isInt8 = ( sizeof(T) == 1 && isSigned ),
+ isUint8 = ( sizeof(T) == 1 && !isSigned ),
+ isInt16 = ( sizeof(T) == 2 && isSigned ),
+ isUint16 = ( sizeof(T) == 2 && !isSigned ),
+ isInt32 = ( sizeof(T) == 4 && isSigned ),
+ isUint32 = ( sizeof(T) == 4 && !isSigned ),
+ isInt64 = ( sizeof(T) == 8 && isSigned ),
+ isUint64 = ( sizeof(T) == 8 && !isSigned ),
+ bitCount = ( sizeof(T)*8 ),
+ isBool = ( (T)2 == (T)1 )
+ };
+
+ // On version 13.10 enums cannot define __int64 values
+ // so we'll use const statics instead!
+ // These must be cast to deal with the possibility of a SafeInt being given an enum as an argument
+ const static T maxInt = static_cast(SafeIntMinMax< isSigned, bitCount >::max);
+ const static T minInt = static_cast(SafeIntMinMax< isSigned, bitCount >::min);
+};
+
+template < typename T >
+const T IntTraits< T >::maxInt;
+template < typename T >
+const T IntTraits< T >::minInt;
+
+template < typename T, typename U > class SafeIntCompare
+{
+public:
+ enum
+ {
+ isBothSigned = (IntTraits< T >::isSigned && IntTraits< U >::isSigned),
+ isBothUnsigned = (!IntTraits< T >::isSigned && !IntTraits< U >::isSigned),
+ isLikeSigned = ((bool)(IntTraits< T >::isSigned) == (bool)(IntTraits< U >::isSigned)),
+ isCastOK = ((isLikeSigned && sizeof(T) >= sizeof(U)) ||
+ (IntTraits< T >::isSigned && sizeof(T) > sizeof(U))),
+ isBothLT32Bit = (IntTraits< T >::isLT32Bit && IntTraits< U >::isLT32Bit),
+ isBothLT64Bit = (IntTraits< T >::isLT64Bit && IntTraits< U >::isLT64Bit)
+ };
+};
+
+//all of the arithmetic operators can be solved by the same code within
+//each of these regions without resorting to compile-time constant conditionals
+//most operators collapse the problem into less than the 22 zones, but this is used
+//as the first cut
+//using this also helps ensure that we handle all of the possible cases correctly
+
+template < typename T, typename U > class IntRegion
+{
+public:
+ enum
+ {
+ //unsigned-unsigned zone
+ IntZone_UintLT32_UintLT32 = SafeIntCompare< T,U >::isBothUnsigned && SafeIntCompare< T,U >::isBothLT32Bit,
+ IntZone_Uint32_UintLT64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,
+ IntZone_UintLT32_Uint32 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,
+ IntZone_Uint64_Uint = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::is64Bit,
+ IntZone_UintLT64_Uint64 = SafeIntCompare< T,U >::isBothUnsigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,
+ //unsigned-signed
+ IntZone_UintLT32_IntLT32 = !IntTraits< T >::isSigned && IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,
+ IntZone_Uint32_IntLT64 = IntTraits< T >::isUint32 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
+ IntZone_UintLT32_Int32 = !IntTraits< T >::isSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::isInt32,
+ IntZone_Uint64_Int = IntTraits< T >::isUint64 && IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
+ IntZone_UintLT64_Int64 = !IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isInt64,
+ IntZone_Uint64_Int64 = IntTraits< T >::isUint64 && IntTraits< U >::isInt64,
+ //signed-signed
+ IntZone_IntLT32_IntLT32 = SafeIntCompare< T,U >::isBothSigned && SafeIntCompare< T, U >::isBothLT32Bit,
+ IntZone_Int32_IntLT64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is32Bit && IntTraits< U >::isLT64Bit,
+ IntZone_IntLT32_Int32 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT32Bit && IntTraits< U >::is32Bit,
+ IntZone_Int64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isInt64 && IntTraits< U >::isInt64,
+ IntZone_Int64_Int = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::is64Bit && IntTraits< U >::isLT64Bit,
+ IntZone_IntLT64_Int64 = SafeIntCompare< T,U >::isBothSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::is64Bit,
+ //signed-unsigned
+ IntZone_IntLT32_UintLT32 = IntTraits< T >::isSigned && !IntTraits< U >::isSigned && SafeIntCompare< T,U >::isBothLT32Bit,
+ IntZone_Int32_UintLT32 = IntTraits< T >::isInt32 && !IntTraits< U >::isSigned && IntTraits< U >::isLT32Bit,
+ IntZone_IntLT64_Uint32 = IntTraits< T >::isSigned && IntTraits< T >::isLT64Bit && IntTraits< U >::isUint32,
+ IntZone_Int64_UintLT64 = IntTraits< T >::isInt64 && !IntTraits< U >::isSigned && IntTraits< U >::isLT64Bit,
+ IntZone_Int_Uint64 = IntTraits< T >::isSigned && IntTraits< U >::isUint64 && IntTraits< T >::isLT64Bit,
+ IntZone_Int64_Uint64 = IntTraits< T >::isInt64 && IntTraits< U >::isUint64
+ };
+};
+
+
+// In all of the following functions, we have two versions
+// One for SafeInt, which throws C++ (or possibly SEH) exceptions
+// The non-throwing versions are for use by the helper functions that return success and failure.
+// Some of the non-throwing functions are not used, but are maintained for completeness.
+
+// There's no real alternative to duplicating logic, but keeping the two versions
+// immediately next to one another will help reduce problems
+
+
+// useful function to help with getting the magnitude of a negative number
+enum AbsMethod
+{
+ AbsMethodInt,
+ AbsMethodInt64,
+ AbsMethodNoop
+};
+
+template < typename T >
+class GetAbsMethod
+{
+public:
+ enum
+ {
+ method = IntTraits< T >::isLT64Bit && IntTraits< T >::isSigned ? AbsMethodInt :
+ IntTraits< T >::isInt64 ? AbsMethodInt64 : AbsMethodNoop
+ };
+};
+
+// let's go ahead and hard-code a dependency on the
+// representation of negative numbers to keep compilers from getting overly
+// happy with optimizing away things like -MIN_INT.
+template < typename T, int > class AbsValueHelper;
+
+template < typename T > class AbsValueHelper < T, AbsMethodInt>
+{
+public:
+ static unsigned __int32 Abs( T t ) SAFEINT_NOTHROW
+ {
+ SAFEINT_ASSERT( t < 0 );
+ return ~(unsigned __int32)t + 1;
+ }
+};
+
+template < typename T > class AbsValueHelper < T, AbsMethodInt64 >
+{
+public:
+ static unsigned __int64 Abs( T t ) SAFEINT_NOTHROW
+ {
+ SAFEINT_ASSERT( t < 0 );
+ return ~(unsigned __int64)t + 1;
+ }
+};
+
+template < typename T > class AbsValueHelper < T, AbsMethodNoop >
+{
+public:
+ static T Abs( T t ) SAFEINT_NOTHROW
+ {
+ // Why are you calling Abs on an unsigned number ???
+ SAFEINT_ASSERT( false );
+ return t;
+ }
+};
+
+template < typename T, bool > class NegationHelper;
+// Previous versions had an assert that the type being negated was 32-bit or higher
+// In retrospect, this seems like something to just document
+// Negation will normally upcast to int
+// For example -(unsigned short)0xffff == (int)0xffff0001
+// This class will retain the type, and will truncate, which may not be what
+// you wanted
+// If you want normal operator casting behavior, do this:
+// SafeInt ss = 0xffff;
+// then:
+// -(SafeInt(ss))
+// will then emit a signed int with the correct value and bitfield
+
+template < typename T > class NegationHelper // Signed
+{
+public:
+ template
+ static T NegativeThrow( T t ) SAFEINT_CPP_THROW
+ {
+ // corner case
+ if( t != IntTraits< T >::minInt )
+ {
+ // cast prevents unneeded checks in the case of small ints
+ return -t;
+ }
+ E::SafeIntOnOverflow();
+ }
+
+ static bool Negative( T t, T& ret ) SAFEINT_NOTHROW
+ {
+ // corner case
+ if( t != IntTraits< T >::minInt )
+ {
+ // cast prevents unneeded checks in the case of small ints
+ ret = -t;
+ return true;
+ }
+ return false;
+ }
+};
+
+// Helper classes to work keep compilers from
+// optimizing away negation
+template < typename T > class SignedNegation;
+
+template <>
+class SignedNegation
+{
+public:
+ static signed __int32 Value(unsigned __int64 in) SAFEINT_NOTHROW
+ {
+ return (signed __int32)(~(unsigned __int32)in + 1);
+ }
+
+ static signed __int32 Value(unsigned __int32 in) SAFEINT_NOTHROW
+ {
+ return (signed __int32)(~in + 1);
+ }
+};
+
+template <>
+class SignedNegation
+{
+public:
+ static signed __int64 Value(unsigned __int64 in) SAFEINT_NOTHROW
+ {
+ return (signed __int64)(~in + 1);
+ }
+};
+
+template < typename T > class NegationHelper // unsigned
+{
+public:
+ template
+ static T NegativeThrow( T t ) SAFEINT_CPP_THROW
+ {
+#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION
+ C_ASSERT( sizeof(T) == 0 );
+#endif
+
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+#pragma warning(push)
+//this avoids warnings from the unary '-' operator being applied to unsigned numbers
+#pragma warning(disable:4146)
+#endif
+ // Note - this could be quenched on gcc
+ // by doing something like:
+ // return (T)-((__int64)t);
+ // but it seems like you would want a warning when doing this.
+ return (T)-t;
+
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+#pragma warning(pop)
+#endif
+ }
+
+ static bool Negative( T t, T& ret ) SAFEINT_NOTHROW
+ {
+ if( IntTraits::isLT32Bit )
+ {
+ // See above
+ SAFEINT_ASSERT( false );
+ }
+#if defined SAFEINT_DISALLOW_UNSIGNED_NEGATION
+ C_ASSERT( sizeof(T) == 0 );
+#endif
+ // Do it this way to avoid warning
+ ret = -t;
+ return true;
+ }
+};
+
+//core logic to determine casting behavior
+enum CastMethod
+{
+ CastOK = 0,
+ CastCheckLTZero,
+ CastCheckGTMax,
+ CastCheckSafeIntMinMaxUnsigned,
+ CastCheckSafeIntMinMaxSigned,
+ CastToFloat,
+ CastFromFloat,
+ CastToBool,
+ CastFromBool
+};
+
+
+template < typename ToType, typename FromType >
+class GetCastMethod
+{
+public:
+ enum
+ {
+ method = ( IntTraits< FromType >::isBool &&
+ !IntTraits< ToType >::isBool ) ? CastFromBool :
+
+ ( !IntTraits< FromType >::isBool &&
+ IntTraits< ToType >::isBool ) ? CastToBool :
+
+ ( SafeIntCompare< ToType, FromType >::isCastOK ) ? CastOK :
+
+ ( ( IntTraits< ToType >::isSigned &&
+ !IntTraits< FromType >::isSigned &&
+ sizeof( FromType ) >= sizeof( ToType ) ) ||
+ ( SafeIntCompare< ToType, FromType >::isBothUnsigned &&
+ sizeof( FromType ) > sizeof( ToType ) ) ) ? CastCheckGTMax :
+
+ ( !IntTraits< ToType >::isSigned &&
+ IntTraits< FromType >::isSigned &&
+ sizeof( ToType ) >= sizeof( FromType ) ) ? CastCheckLTZero :
+
+ ( !IntTraits< ToType >::isSigned ) ? CastCheckSafeIntMinMaxUnsigned
+ : CastCheckSafeIntMinMaxSigned
+ };
+};
+
+template < typename FromType > class GetCastMethod < float, FromType >
+{
+public:
+ enum{ method = CastOK };
+};
+
+template < typename FromType > class GetCastMethod < double, FromType >
+{
+public:
+ enum{ method = CastOK };
+};
+
+template < typename FromType > class GetCastMethod < long double, FromType >
+{
+public:
+ enum{ method = CastOK };
+};
+
+template < typename ToType > class GetCastMethod < ToType, float >
+{
+public:
+ enum{ method = CastFromFloat };
+};
+
+template < typename ToType > class GetCastMethod < ToType, double >
+{
+public:
+ enum{ method = CastFromFloat };
+};
+
+template < typename ToType > class GetCastMethod < ToType, long double >
+{
+public:
+ enum{ method = CastFromFloat };
+};
+
+template < typename T, typename U, int > class SafeCastHelper;
+
+template < typename T, typename U > class SafeCastHelper < T, U, CastOK >
+{
+public:
+ static bool Cast( U u, T& t ) SAFEINT_NOTHROW
+ {
+ t = (T)u;
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
+ {
+ t = (T)u;
+ }
+};
+
+// special case floats and doubles
+// tolerate loss of precision
+template < typename T, typename U > class SafeCastHelper < T, U, CastFromFloat >
+{
+public:
+ static bool Cast( U u, T& t ) SAFEINT_NOTHROW
+ {
+ if( u <= (U)IntTraits< T >::maxInt &&
+ u >= (U)IntTraits< T >::minInt )
+ {
+ t = (T)u;
+ return true;
+ }
+ return false;
+ }
+
+ template < typename E >
+ static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
+ {
+ if( u <= (U)IntTraits< T >::maxInt &&
+ u >= (U)IntTraits< T >::minInt )
+ {
+ t = (T)u;
+ return;
+ }
+ E::SafeIntOnOverflow();
+ }
+};
+
+// Match on any method where a bool is cast to type T
+template < typename T > class SafeCastHelper < T, bool, CastFromBool >
+{
+public:
+ static bool Cast( bool b, T& t ) SAFEINT_NOTHROW
+ {
+ t = (T)( b ? 1 : 0 );
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW
+ {
+ t = (T)( b ? 1 : 0 );
+ }
+};
+
+template < typename T > class SafeCastHelper < bool, T, CastToBool >
+{
+public:
+ static bool Cast( T t, bool& b ) SAFEINT_NOTHROW
+ {
+ b = !!t;
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( bool b, T& t ) SAFEINT_CPP_THROW
+ {
+ b = !!t;
+ }
+};
+
+template < typename T, typename U > class SafeCastHelper < T, U, CastCheckLTZero >
+{
+public:
+ static bool Cast( U u, T& t ) SAFEINT_NOTHROW
+ {
+ if( u < 0 )
+ return false;
+
+ t = (T)u;
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
+ {
+ if( u < 0 )
+ E::SafeIntOnOverflow();
+
+ t = (T)u;
+ }
+};
+
+template < typename T, typename U > class SafeCastHelper < T, U, CastCheckGTMax >
+{
+public:
+ static bool Cast( U u, T& t ) SAFEINT_NOTHROW
+ {
+ if( u > (U)IntTraits< T >::maxInt )
+ return false;
+
+ t = (T)u;
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
+ {
+ if( u > (U)IntTraits< T >::maxInt )
+ E::SafeIntOnOverflow();
+
+ t = (T)u;
+ }
+};
+
+template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxUnsigned >
+{
+public:
+ static bool Cast( U u, T& t ) SAFEINT_NOTHROW
+ {
+ // U is signed - T could be either signed or unsigned
+ if( u > IntTraits< T >::maxInt || u < 0 )
+ return false;
+
+ t = (T)u;
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
+ {
+ // U is signed - T could be either signed or unsigned
+ if( u > IntTraits< T >::maxInt || u < 0 )
+ E::SafeIntOnOverflow();
+
+ t = (T)u;
+ }
+};
+
+template < typename T, typename U > class SafeCastHelper < T, U, CastCheckSafeIntMinMaxSigned >
+{
+public:
+ static bool Cast( U u, T& t ) SAFEINT_NOTHROW
+ {
+ // T, U are signed
+ if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt )
+ return false;
+
+ t = (T)u;
+ return true;
+ }
+
+ template < typename E >
+ static void CastThrow( U u, T& t ) SAFEINT_CPP_THROW
+ {
+ //T, U are signed
+ if( u > IntTraits< T >::maxInt || u < IntTraits< T >::minInt )
+ E::SafeIntOnOverflow();
+
+ t = (T)u;
+ }
+};
+
+//core logic to determine whether a comparison is valid, or needs special treatment
+enum ComparisonMethod
+{
+ ComparisonMethod_Ok = 0,
+ ComparisonMethod_CastInt,
+ ComparisonMethod_CastInt64,
+ ComparisonMethod_UnsignedT,
+ ComparisonMethod_UnsignedU
+};
+
+ // Note - the standard is arguably broken in the case of some integer
+ // conversion operations
+ // For example, signed char a = -1 = 0xff
+ // unsigned int b = 0xffffffff
+ // If you then test if a < b, a value-preserving cast
+ // is made, and you're essentially testing
+ // (unsigned int)a < b == false
+ //
+ // I do not think this makes sense - if you perform
+ // a cast to an __int64, which can clearly preserve both value and signedness
+ // then you get a different and intuitively correct answer
+ // IMHO, -1 should be less than 4 billion
+ // If you prefer to retain the ANSI standard behavior
+ // insert #define ANSI_CONVERSIONS into your source
+ // Behavior differences occur in the following cases:
+ // 8, 16, and 32-bit signed int, unsigned 32-bit int
+ // any signed int, unsigned 64-bit int
+ // Note - the signed int must be negative to show the problem
+
+template < typename T, typename U >
+class ValidComparison
+{
+public:
+ enum
+ {
+#ifdef ANSI_CONVERSIONS
+ method = ComparisonMethod_Ok
+#else
+ method = ( ( SafeIntCompare< T, U >::isLikeSigned ) ? ComparisonMethod_Ok :
+ ( ( IntTraits< T >::isSigned && sizeof(T) < 8 && sizeof(U) < 4 ) ||
+ ( IntTraits< U >::isSigned && sizeof(T) < 4 && sizeof(U) < 8 ) ) ? ComparisonMethod_CastInt :
+ ( ( IntTraits< T >::isSigned && sizeof(U) < 8 ) ||
+ ( IntTraits< U >::isSigned && sizeof(T) < 8 ) ) ? ComparisonMethod_CastInt64 :
+ ( !IntTraits< T >::isSigned ) ? ComparisonMethod_UnsignedT :
+ ComparisonMethod_UnsignedU )
+#endif
+ };
+};
+
+template class EqualityTest;
+
+template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_Ok >
+{
+public:
+ static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( t == u ); }
+};
+
+template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt >
+{
+public:
+ static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t == (int)u ); }
+};
+
+template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_CastInt64 >
+{
+public:
+ static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t == (__int64)u ); }
+};
+
+template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedT >
+{
+public:
+ static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW
+ {
+ //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
+ if( u < 0 )
+ return false;
+
+ //else safe to cast to type T
+ return ( t == (T)u );
+ }
+};
+
+template < typename T, typename U > class EqualityTest< T, U, ComparisonMethod_UnsignedU>
+{
+public:
+ static bool IsEquals( const T t, const U u ) SAFEINT_NOTHROW
+ {
+ //one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
+ if( t < 0 )
+ return false;
+
+ //else safe to cast to type U
+ return ( (U)t == u );
+ }
+};
+
+template class GreaterThanTest;
+
+template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_Ok >
+{
+public:
+ static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( t > u ); }
+};
+
+template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt >
+{
+public:
+ static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (int)t > (int)u ); }
+};
+
+template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_CastInt64 >
+{
+public:
+ static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW { return ( (__int64)t > (__int64)u ); }
+};
+
+template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedT >
+{
+public:
+ static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW
+ {
+ // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
+ if( u < 0 )
+ return true;
+
+ // else safe to cast to type T
+ return ( t > (T)u );
+ }
+};
+
+template < typename T, typename U > class GreaterThanTest< T, U, ComparisonMethod_UnsignedU >
+{
+public:
+ static bool GreaterThan( const T t, const U u ) SAFEINT_NOTHROW
+ {
+ // one operand is 32 or 64-bit unsigned, and the other is signed and the same size or smaller
+ if( t < 0 )
+ return false;
+
+ // else safe to cast to type U
+ return ( (U)t > u );
+ }
+};
+
+// Modulus is simpler than comparison, but follows much the same logic
+// using this set of functions, it can't fail except in a div 0 situation
+template class ModulusHelper;
+
+template class ModulusHelper
+{
+public:
+ static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if(u == 0)
+ return SafeIntDivideByZero;
+
+ //trap corner case
+ if( CompileConst< IntTraits< U >::isSigned >::Value() )
+ {
+ // Some compilers don't notice that this only compiles when u is signed
+ // Add cast to make them happy
+ if( u == (U)-1 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+ }
+
+ result = (T)(t % u);
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if(u == 0)
+ E::SafeIntOnDivZero();
+
+ //trap corner case
+ if( CompileConst< IntTraits< U >::isSigned >::Value() )
+ {
+ if( u == (U)-1 )
+ {
+ result = 0;
+ return;
+ }
+ }
+
+ result = (T)(t % u);
+ }
+};
+
+template class ModulusHelper
+{
+public:
+ static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if(u == 0)
+ return SafeIntDivideByZero;
+
+ //trap corner case
+ if( CompileConst< IntTraits< U >::isSigned >::Value() )
+ {
+ if( u == (U)-1 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+ }
+
+ result = (T)(t % u);
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if(u == 0)
+ E::SafeIntOnDivZero();
+
+ //trap corner case
+ if( CompileConst< IntTraits< U >::isSigned >::Value() )
+ {
+ if( u == (U)-1 )
+ {
+ result = 0;
+ return;
+ }
+ }
+
+ result = (T)(t % u);
+ }
+};
+
+template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_CastInt64>
+{
+public:
+ static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if(u == 0)
+ return SafeIntDivideByZero;
+
+ //trap corner case
+ if( CompileConst< IntTraits< U >::isSigned >::Value() )
+ {
+ if( u == (U)-1 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+ }
+
+ result = (T)((__int64)t % (__int64)u);
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if(u == 0)
+ E::SafeIntOnDivZero();
+
+ if( CompileConst< IntTraits< U >::isSigned >::Value() )
+ {
+ if( u == (U)-1 )
+ {
+ result = 0;
+ return;
+ }
+ }
+
+ result = (T)((__int64)t % (__int64)u);
+ }
+};
+
+// T is unsigned __int64, U is any signed int
+template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedT>
+{
+public:
+ static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if(u == 0)
+ return SafeIntDivideByZero;
+
+ // u could be negative - if so, need to convert to positive
+ // casts below are always safe due to the way modulus works
+ if(u < 0)
+ result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs(u));
+ else
+ result = (T)(t % u);
+
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if(u == 0)
+ E::SafeIntOnDivZero();
+
+ // u could be negative - if so, need to convert to positive
+ if(u < 0)
+ result = (T)(t % AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ));
+ else
+ result = (T)(t % u);
+ }
+};
+
+// U is unsigned __int64, T any signed int
+template < typename T, typename U > class ModulusHelper< T, U, ComparisonMethod_UnsignedU>
+{
+public:
+ static SafeIntError Modulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if(u == 0)
+ return SafeIntDivideByZero;
+
+ //t could be negative - if so, need to convert to positive
+ if(t < 0)
+ result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1 );
+ else
+ result = (T)((T)t % u);
+
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void ModulusThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if(u == 0)
+ E::SafeIntOnDivZero();
+
+ //t could be negative - if so, need to convert to positive
+ if(t < 0)
+ result = (T)( ~( AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( t ) % u ) + 1);
+ else
+ result = (T)( (T)t % u );
+ }
+};
+
+//core logic to determine method to check multiplication
+enum MultiplicationState
+{
+ MultiplicationState_CastInt = 0, // One or both signed, smaller than 32-bit
+ MultiplicationState_CastInt64, // One or both signed, smaller than 64-bit
+ MultiplicationState_CastUint, // Both are unsigned, smaller than 32-bit
+ MultiplicationState_CastUint64, // Both are unsigned, both 32-bit or smaller
+ MultiplicationState_Uint64Uint, // Both are unsigned, lhs 64-bit, rhs 32-bit or smaller
+ MultiplicationState_Uint64Uint64, // Both are unsigned int64
+ MultiplicationState_Uint64Int, // lhs is unsigned int64, rhs int32
+ MultiplicationState_Uint64Int64, // lhs is unsigned int64, rhs signed int64
+ MultiplicationState_UintUint64, // Both are unsigned, lhs 32-bit or smaller, rhs 64-bit
+ MultiplicationState_UintInt64, // lhs unsigned 32-bit or less, rhs int64
+ MultiplicationState_Int64Uint, // lhs int64, rhs unsigned int32
+ MultiplicationState_Int64Int64, // lhs int64, rhs int64
+ MultiplicationState_Int64Int, // lhs int64, rhs int32
+ MultiplicationState_IntUint64, // lhs int, rhs unsigned int64
+ MultiplicationState_IntInt64, // lhs int, rhs int64
+ MultiplicationState_Int64Uint64, // lhs int64, rhs uint64
+ MultiplicationState_Error
+};
+
+template < typename T, typename U >
+class MultiplicationMethod
+{
+public:
+ enum
+ {
+ // unsigned-unsigned
+ method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? MultiplicationState_CastUint :
+ (IntRegion< T,U >::IntZone_Uint32_UintLT64 ||
+ IntRegion< T,U >::IntZone_UintLT32_Uint32) ? MultiplicationState_CastUint64 :
+ SafeIntCompare< T,U >::isBothUnsigned &&
+ IntTraits< T >::isUint64 && IntTraits< U >::isUint64 ? MultiplicationState_Uint64Uint64 :
+ (IntRegion< T,U >::IntZone_Uint64_Uint) ? MultiplicationState_Uint64Uint :
+ (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? MultiplicationState_UintUint64 :
+ // unsigned-signed
+ (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? MultiplicationState_CastInt :
+ (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
+ IntRegion< T,U >::IntZone_UintLT32_Int32) ? MultiplicationState_CastInt64 :
+ (IntRegion< T,U >::IntZone_Uint64_Int) ? MultiplicationState_Uint64Int :
+ (IntRegion< T,U >::IntZone_UintLT64_Int64) ? MultiplicationState_UintInt64 :
+ (IntRegion< T,U >::IntZone_Uint64_Int64) ? MultiplicationState_Uint64Int64 :
+ // signed-signed
+ (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? MultiplicationState_CastInt :
+ (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
+ IntRegion< T,U >::IntZone_IntLT32_Int32) ? MultiplicationState_CastInt64 :
+ (IntRegion< T,U >::IntZone_Int64_Int64) ? MultiplicationState_Int64Int64 :
+ (IntRegion< T,U >::IntZone_Int64_Int) ? MultiplicationState_Int64Int :
+ (IntRegion< T,U >::IntZone_IntLT64_Int64) ? MultiplicationState_IntInt64 :
+ // signed-unsigned
+ (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? MultiplicationState_CastInt :
+ (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
+ IntRegion< T,U >::IntZone_IntLT64_Uint32) ? MultiplicationState_CastInt64 :
+ (IntRegion< T,U >::IntZone_Int64_UintLT64) ? MultiplicationState_Int64Uint :
+ (IntRegion< T,U >::IntZone_Int_Uint64) ? MultiplicationState_IntUint64 :
+ (IntRegion< T,U >::IntZone_Int64_Uint64 ? MultiplicationState_Int64Uint64 :
+ MultiplicationState_Error ) )
+ };
+};
+
+template class MultiplicationHelper;
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt>
+{
+public:
+ //accepts signed, both less than 32-bit
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ int tmp = t * u;
+
+ if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt )
+ return false;
+
+ ret = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ int tmp = t * u;
+
+ if( tmp > IntTraits< T >::maxInt || tmp < IntTraits< T >::minInt )
+ E::SafeIntOnOverflow();
+
+ ret = (T)tmp;
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint >
+{
+public:
+ //accepts unsigned, both less than 32-bit
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ unsigned int tmp = (unsigned int)(t * u);
+
+ if( tmp > IntTraits< T >::maxInt )
+ return false;
+
+ ret = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ unsigned int tmp = (unsigned int)( t * u );
+
+ if( tmp > IntTraits< T >::maxInt )
+ E::SafeIntOnOverflow();
+
+ ret = (T)tmp;
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastInt64>
+{
+public:
+ //mixed signed or both signed where at least one argument is 32-bit, and both a 32-bit or less
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ __int64 tmp = (__int64)t * (__int64)u;
+
+ if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt)
+ return false;
+
+ ret = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ __int64 tmp = (__int64)t * (__int64)u;
+
+ if(tmp > (__int64)IntTraits< T >::maxInt || tmp < (__int64)IntTraits< T >::minInt)
+ E::SafeIntOnOverflow();
+
+ ret = (T)tmp;
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_CastUint64>
+{
+public:
+ //both unsigned where at least one argument is 32-bit, and both are 32-bit or less
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;
+
+ if(tmp > (unsigned __int64)IntTraits< T >::maxInt)
+ return false;
+
+ ret = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ unsigned __int64 tmp = (unsigned __int64)t * (unsigned __int64)u;
+
+ if(tmp > (unsigned __int64)IntTraits< T >::maxInt)
+ E::SafeIntOnOverflow();
+
+ ret = (T)tmp;
+ }
+};
+
+// T = left arg and return type
+// U = right arg
+template < typename T, typename U > class LargeIntRegMultiply;
+
+#if SAFEINT_USE_INTRINSICS
+// As usual, unsigned is easy
+inline bool IntrinsicMultiplyUint64( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW
+{
+ unsigned __int64 ulHigh = 0;
+ *pRet = _umul128(a , b, &ulHigh);
+ return ulHigh == 0;
+}
+
+// Signed, is not so easy
+inline bool IntrinsicMultiplyInt64( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW
+{
+ __int64 llHigh = 0;
+ *pRet = _mul128(a , b, &llHigh);
+
+ // Now we need to figure out what we expect
+ // If llHigh is 0, then treat *pRet as unsigned
+ // If llHigh is < 0, then treat *pRet as signed
+
+ if( (a ^ b) < 0 )
+ {
+ // Negative result expected
+ if( llHigh == -1 && *pRet < 0 ||
+ llHigh == 0 && *pRet == 0 )
+ {
+ // Everything is within range
+ return true;
+ }
+ }
+ else
+ {
+ // Result should be positive
+ // Check for overflow
+ if( llHigh == 0 && (unsigned __int64)*pRet <= IntTraits< signed __int64 >::maxInt )
+ return true;
+ }
+ return false;
+}
+
+#endif
+
+template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int64 >
+{
+public:
+ static bool RegMultiply( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_NOTHROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyUint64( a, b, pRet );
+#else
+ unsigned __int32 aHigh, aLow, bHigh, bLow;
+
+ // Consider that a*b can be broken up into:
+ // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
+ // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
+ // Note - same approach applies for 128 bit math on a 64-bit system
+
+ aHigh = (unsigned __int32)(a >> 32);
+ aLow = (unsigned __int32)a;
+ bHigh = (unsigned __int32)(b >> 32);
+ bLow = (unsigned __int32)b;
+
+ *pRet = 0;
+
+ if(aHigh == 0)
+ {
+ if(bHigh != 0)
+ {
+ *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh;
+ }
+ }
+ else if(bHigh == 0)
+ {
+ if(aHigh != 0)
+ {
+ *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ if(*pRet != 0)
+ {
+ unsigned __int64 tmp;
+
+ if((unsigned __int32)(*pRet >> 32) != 0)
+ return false;
+
+ *pRet <<= 32;
+ tmp = (unsigned __int64)aLow * (unsigned __int64)bLow;
+ *pRet += tmp;
+
+ if(*pRet < tmp)
+ return false;
+
+ return true;
+ }
+
+ *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow;
+ return true;
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const unsigned __int64& a, const unsigned __int64& b, unsigned __int64* pRet ) SAFEINT_CPP_THROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyUint64( a, b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ unsigned __int32 aHigh, aLow, bHigh, bLow;
+
+ // Consider that a*b can be broken up into:
+ // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
+ // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
+ // Note - same approach applies for 128 bit math on a 64-bit system
+
+ aHigh = (unsigned __int32)(a >> 32);
+ aLow = (unsigned __int32)a;
+ bHigh = (unsigned __int32)(b >> 32);
+ bLow = (unsigned __int32)b;
+
+ *pRet = 0;
+
+ if(aHigh == 0)
+ {
+ if(bHigh != 0)
+ {
+ *pRet = (unsigned __int64)aLow * (unsigned __int64)bHigh;
+ }
+ }
+ else if(bHigh == 0)
+ {
+ if(aHigh != 0)
+ {
+ *pRet = (unsigned __int64)aHigh * (unsigned __int64)bLow;
+ }
+ }
+ else
+ {
+ E::SafeIntOnOverflow();
+ }
+
+ if(*pRet != 0)
+ {
+ unsigned __int64 tmp;
+
+ if((unsigned __int32)(*pRet >> 32) != 0)
+ E::SafeIntOnOverflow();
+
+ *pRet <<= 32;
+ tmp = (unsigned __int64)aLow * (unsigned __int64)bLow;
+ *pRet += tmp;
+
+ if(*pRet < tmp)
+ E::SafeIntOnOverflow();
+
+ return;
+ }
+
+ *pRet = (unsigned __int64)aLow * (unsigned __int64)bLow;
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< unsigned __int64, unsigned __int32 >
+{
+public:
+ static bool RegMultiply( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet );
+#else
+ unsigned __int32 aHigh, aLow;
+
+ // Consider that a*b can be broken up into:
+ // (aHigh * 2^32 + aLow) * b
+ // => (aHigh * b * 2^32) + (aLow * b)
+
+ aHigh = (unsigned __int32)(a >> 32);
+ aLow = (unsigned __int32)a;
+
+ *pRet = 0;
+
+ if(aHigh != 0)
+ {
+ *pRet = (unsigned __int64)aHigh * (unsigned __int64)b;
+
+ unsigned __int64 tmp;
+
+ if((unsigned __int32)(*pRet >> 32) != 0)
+ return false;
+
+ *pRet <<= 32;
+ tmp = (unsigned __int64)aLow * (unsigned __int64)b;
+ *pRet += tmp;
+
+ if(*pRet < tmp)
+ return false;
+
+ return true;
+ }
+
+ *pRet = (unsigned __int64)aLow * (unsigned __int64)b;
+ return true;
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const unsigned __int64& a, unsigned __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ unsigned __int32 aHigh, aLow;
+
+ // Consider that a*b can be broken up into:
+ // (aHigh * 2^32 + aLow) * b
+ // => (aHigh * b * 2^32) + (aLow * b)
+
+ aHigh = (unsigned __int32)(a >> 32);
+ aLow = (unsigned __int32)a;
+
+ *pRet = 0;
+
+ if(aHigh != 0)
+ {
+ *pRet = (unsigned __int64)aHigh * (unsigned __int64)b;
+
+ unsigned __int64 tmp;
+
+ if((unsigned __int32)(*pRet >> 32) != 0)
+ E::SafeIntOnOverflow();
+
+ *pRet <<= 32;
+ tmp = (unsigned __int64)aLow * (unsigned __int64)b;
+ *pRet += tmp;
+
+ if(*pRet < tmp)
+ E::SafeIntOnOverflow();
+
+ return;
+ }
+
+ *pRet = (unsigned __int64)aLow * (unsigned __int64)b;
+ return;
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< unsigned __int64, signed __int32 >
+{
+public:
+ // Intrinsic not needed
+ static bool RegMultiply( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_NOTHROW
+ {
+ if( b < 0 && a != 0 )
+ return false;
+
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet );
+#else
+ return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply(a, (unsigned __int32)b, pRet);
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const unsigned __int64& a, signed __int32 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW
+ {
+ if( b < 0 && a != 0 )
+ E::SafeIntOnOverflow();
+
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( a, (unsigned __int32)b, pRet );
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< unsigned __int64, signed __int64 >
+{
+public:
+ static bool RegMultiply( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_NOTHROW
+ {
+ if( b < 0 && a != 0 )
+ return false;
+
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet );
+#else
+ return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply(a, (unsigned __int64)b, pRet);
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const unsigned __int64& a, signed __int64 b, unsigned __int64* pRet ) SAFEINT_CPP_THROW
+ {
+ if( b < 0 && a != 0 )
+ E::SafeIntOnOverflow();
+
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyUint64( a, (unsigned __int64)b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet );
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< signed __int32, unsigned __int64 >
+{
+public:
+ // Devolves into ordinary 64-bit calculation
+ static bool RegMultiply( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW
+ {
+ unsigned __int32 bHigh, bLow;
+ bool fIsNegative = false;
+
+ // Consider that a*b can be broken up into:
+ // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
+ // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
+ // aHigh == 0 implies:
+ // ( aLow * bHigh * 2^32 ) + ( aLow + bLow )
+ // If the first part is != 0, fail
+
+ bHigh = (unsigned __int32)(b >> 32);
+ bLow = (unsigned __int32)b;
+
+ *pRet = 0;
+
+ if(bHigh != 0 && a != 0)
+ return false;
+
+ if( a < 0 )
+ {
+
+ a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);
+ fIsNegative = true;
+ }
+
+ unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;
+
+ if( !fIsNegative )
+ {
+ if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt )
+ {
+ *pRet = (signed __int32)tmp;
+ return true;
+ }
+ }
+ else
+ {
+ if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 )
+ {
+ *pRet = SignedNegation< signed __int32 >::Value( tmp );
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( signed __int32 a, const unsigned __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW
+ {
+ unsigned __int32 bHigh, bLow;
+ bool fIsNegative = false;
+
+ // Consider that a*b can be broken up into:
+ // (aHigh * 2^32 + aLow) * (bHigh * 2^32 + bLow)
+ // => (aHigh * bHigh * 2^64) + (aLow * bHigh * 2^32) + (aHigh * bLow * 2^32) + (aLow * bLow)
+
+ bHigh = (unsigned __int32)(b >> 32);
+ bLow = (unsigned __int32)b;
+
+ *pRet = 0;
+
+ if(bHigh != 0 && a != 0)
+ E::SafeIntOnOverflow();
+
+ if( a < 0 )
+ {
+ a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);
+ fIsNegative = true;
+ }
+
+ unsigned __int64 tmp = (unsigned __int32)a * (unsigned __int64)bLow;
+
+ if( !fIsNegative )
+ {
+ if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt )
+ {
+ *pRet = (signed __int32)tmp;
+ return;
+ }
+ }
+ else
+ {
+ if( tmp <= (unsigned __int64)IntTraits< signed __int32 >::maxInt+1 )
+ {
+ *pRet = SignedNegation< signed __int32 >::Value( tmp );
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template<> class LargeIntRegMultiply< unsigned __int32, unsigned __int64 >
+{
+public:
+ // Becomes ordinary 64-bit multiplication, intrinsic not needed
+ static bool RegMultiply( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW
+ {
+ // Consider that a*b can be broken up into:
+ // (bHigh * 2^32 + bLow) * a
+ // => (bHigh * a * 2^32) + (bLow * a)
+ // In this case, the result must fit into 32-bits
+ // If bHigh != 0 && a != 0, immediate error.
+
+ if( (unsigned __int32)(b >> 32) != 0 && a != 0 )
+ return false;
+
+ unsigned __int64 tmp = b * (unsigned __int64)a;
+
+ if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow
+ return false;
+
+ *pRet = (unsigned __int32)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( unsigned __int32 a, const unsigned __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW
+ {
+ if( (unsigned __int32)(b >> 32) != 0 && a != 0 )
+ E::SafeIntOnOverflow();
+
+ unsigned __int64 tmp = b * (unsigned __int64)a;
+
+ if( (unsigned __int32)(tmp >> 32) != 0 ) // overflow
+ E::SafeIntOnOverflow();
+
+ *pRet = (unsigned __int32)tmp;
+ }
+};
+
+template<> class LargeIntRegMultiply< unsigned __int32, signed __int64 >
+{
+public:
+ static bool RegMultiply( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_NOTHROW
+ {
+ if( b < 0 && a != 0 )
+ return false;
+ return LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( a, (unsigned __int64)b, pRet );
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( unsigned __int32 a, const signed __int64& b, unsigned __int32* pRet ) SAFEINT_CPP_THROW
+ {
+ if( b < 0 && a != 0 )
+ E::SafeIntOnOverflow();
+
+ LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( a, (unsigned __int64)b, pRet );
+ }
+};
+
+template<> class LargeIntRegMultiply< signed __int64, signed __int64 >
+{
+public:
+ static bool RegMultiply( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyInt64( a, b, pRet );
+#else
+ bool aNegative = false;
+ bool bNegative = false;
+
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+ __int64 b1 = b;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ if( b1 < 0 )
+ {
+ bNegative = true;
+ b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);
+ }
+
+ if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b1, &tmp ) )
+ {
+ // The unsigned multiplication didn't overflow
+ if( aNegative ^ bNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return true;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return true;
+ }
+ }
+ }
+
+ return false;
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const signed __int64& a, const signed __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyInt64( a, b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ bool aNegative = false;
+ bool bNegative = false;
+
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+ __int64 b1 = b;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ if( b1 < 0 )
+ {
+ bNegative = true;
+ b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);
+ }
+
+ LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, (unsigned __int64)b1, &tmp );
+
+ // The unsigned multiplication didn't overflow or we'd be in the exception handler
+ if( aNegative ^ bNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< signed __int64, unsigned __int32 >
+{
+public:
+ static bool RegMultiply( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet );
+#else
+ bool aNegative = false;
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, b, &tmp ) )
+ {
+ // The unsigned multiplication didn't overflow
+ if( aNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return true;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return true;
+ }
+ }
+ }
+
+ return false;
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const signed __int64& a, unsigned __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ bool aNegative = false;
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a1, b, &tmp );
+
+ // The unsigned multiplication didn't overflow
+ if( aNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< signed __int64, signed __int32 >
+{
+public:
+ static bool RegMultiply( const signed __int64& a, signed __int32 b, signed __int64* pRet ) SAFEINT_NOTHROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ return IntrinsicMultiplyInt64( a, (signed __int64)b, pRet );
+#else
+ bool aNegative = false;
+ bool bNegative = false;
+
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+ __int64 b1 = b;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ if( b1 < 0 )
+ {
+ bNegative = true;
+ b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);
+ }
+
+ if( LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( (unsigned __int64)a1, (unsigned __int32)b1, &tmp ) )
+ {
+ // The unsigned multiplication didn't overflow
+ if( aNegative ^ bNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return true;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return true;
+ }
+ }
+ }
+
+ return false;
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( signed __int64 a, signed __int32 b, signed __int64* pRet ) SAFEINT_CPP_THROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ if( !IntrinsicMultiplyInt64( a, (signed __int64)b, pRet ) )
+ E::SafeIntOnOverflow();
+#else
+ bool aNegative = false;
+ bool bNegative = false;
+
+ unsigned __int64 tmp;
+
+ if( a < 0 )
+ {
+ aNegative = true;
+ a = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a);
+ }
+
+ if( b < 0 )
+ {
+ bNegative = true;
+ b = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(b);
+ }
+
+ LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( (unsigned __int64)a, (unsigned __int32)b, &tmp );
+
+ // The unsigned multiplication didn't overflow
+ if( aNegative ^ bNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< signed __int32, signed __int64 >
+{
+public:
+ static bool RegMultiply( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_NOTHROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ __int64 tmp;
+
+ if( IntrinsicMultiplyInt64( a, b, &tmp ) )
+ {
+ if( tmp > IntTraits< signed __int32 >::maxInt ||
+ tmp < IntTraits< signed __int32 >::minInt )
+ {
+ return false;
+ }
+
+ *pRet = (__int32)tmp;
+ return true;
+ }
+ return false;
+#else
+ bool aNegative = false;
+ bool bNegative = false;
+
+ unsigned __int32 tmp;
+ __int64 b1 = b;
+
+ if( a < 0 )
+ {
+ aNegative = true;
+ a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);
+ }
+
+ if( b1 < 0 )
+ {
+ bNegative = true;
+ b1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b1);
+ }
+
+ if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( (unsigned __int32)a, (unsigned __int64)b1, &tmp ) )
+ {
+ // The unsigned multiplication didn't overflow
+ if( aNegative ^ bNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int32 >::Value( tmp );
+ return true;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt )
+ {
+ *pRet = (signed __int32)tmp;
+ return true;
+ }
+ }
+ }
+
+ return false;
+#endif
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( signed __int32 a, const signed __int64& b, signed __int32* pRet ) SAFEINT_CPP_THROW
+ {
+#if SAFEINT_USE_INTRINSICS
+ __int64 tmp;
+
+ if( IntrinsicMultiplyInt64( a, b, &tmp ) )
+ {
+ if( tmp > IntTraits< signed __int32 >::maxInt ||
+ tmp < IntTraits< signed __int32 >::minInt )
+ {
+ E::SafeIntOnOverflow();
+ }
+
+ *pRet = (__int32)tmp;
+ return;
+ }
+ E::SafeIntOnOverflow();
+#else
+ bool aNegative = false;
+ bool bNegative = false;
+
+ unsigned __int32 tmp;
+ signed __int64 b2 = b;
+
+ if( a < 0 )
+ {
+ aNegative = true;
+ a = (signed __int32)AbsValueHelper< signed __int32, GetAbsMethod< signed __int32 >::method >::Abs(a);
+ }
+
+ if( b < 0 )
+ {
+ bNegative = true;
+ b2 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(b2);
+ }
+
+ LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)a, (unsigned __int64)b2, &tmp );
+
+ // The unsigned multiplication didn't overflow
+ if( aNegative ^ bNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int32 >::Value( tmp );
+ return;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int32)IntTraits< signed __int32 >::maxInt )
+ {
+ *pRet = (signed __int32)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+#endif
+ }
+};
+
+template<> class LargeIntRegMultiply< signed __int64, unsigned __int64 >
+{
+public:
+ // Leave this one as-is - will call unsigned intrinsic internally
+ static bool RegMultiply( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_NOTHROW
+ {
+ bool aNegative = false;
+
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) )
+ {
+ // The unsigned multiplication didn't overflow
+ if( aNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return true;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void RegMultiplyThrow( const signed __int64& a, const unsigned __int64& b, signed __int64* pRet ) SAFEINT_CPP_THROW
+ {
+ bool aNegative = false;
+ unsigned __int64 tmp;
+ __int64 a1 = a;
+
+ if( a1 < 0 )
+ {
+ aNegative = true;
+ a1 = (signed __int64)AbsValueHelper< signed __int64, GetAbsMethod< signed __int64 >::method >::Abs(a1);
+ }
+
+ if( LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( (unsigned __int64)a1, (unsigned __int64)b, &tmp ) )
+ {
+ // The unsigned multiplication didn't overflow
+ if( aNegative )
+ {
+ // Result must be negative
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::minInt )
+ {
+ *pRet = SignedNegation< signed __int64 >::Value( tmp );
+ return;
+ }
+ }
+ else
+ {
+ // Result must be positive
+ if( tmp <= (unsigned __int64)IntTraits< signed __int64 >::maxInt )
+ {
+ *pRet = (signed __int64)tmp;
+ return;
+ }
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+// In all of the following functions where LargeIntRegMultiply methods are called,
+// we need to properly transition types. The methods need __int64, __int32, etc.
+// but the variables being passed to us could be long long, long int, or long, depending on
+// the compiler. Microsoft compiler knows that long long is the same type as __int64, but gcc doesn't
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint64 >
+{
+public:
+ // T, U are unsigned __int64
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 );
+ unsigned __int64 t1 = t;
+ unsigned __int64 u1 = u;
+ return LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast(&ret) );
+ }
+
+ template < typename E >
+ static void MultiplyThrow(const unsigned __int64& t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isUint64 && IntTraits::isUint64 );
+ unsigned __int64 t1 = t;
+ unsigned __int64 u1 = u;
+ LargeIntRegMultiply< unsigned __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast(&ret) );
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Uint >
+{
+public:
+ // T is unsigned __int64
+ // U is any unsigned int 32-bit or less
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 t1 = t;
+ return LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast(&ret) );
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 t1 = t;
+ LargeIntRegMultiply< unsigned __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast(&ret) );
+ }
+};
+
+// converse of the previous function
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintUint64 >
+{
+public:
+ // T is any unsigned int up to 32-bit
+ // U is unsigned __int64
+ static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 u1 = u;
+ unsigned __int32 tmp;
+
+ if( LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::RegMultiply( t, u1, &tmp ) &&
+ SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 u1 = u;
+ unsigned __int32 tmp;
+
+ LargeIntRegMultiply< unsigned __int32, unsigned __int64 >::template RegMultiplyThrow< E >( t, u1, &tmp );
+ SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret);
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int >
+{
+public:
+ // T is unsigned __int64
+ // U is any signed int, up to 64-bit
+ static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 t1 = t;
+ return LargeIntRegMultiply< unsigned __int64, signed __int32 >::RegMultiply(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret));
+ }
+
+ template < typename E >
+ static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 t1 = t;
+ LargeIntRegMultiply< unsigned __int64, signed __int32 >::template RegMultiplyThrow< E >(t1, (signed __int32)u, reinterpret_cast< unsigned __int64* >(&ret));
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Uint64Int64 >
+{
+public:
+ // T is unsigned __int64
+ // U is __int64
+ static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 );
+ unsigned __int64 t1 = t;
+ __int64 u1 = u;
+ return LargeIntRegMultiply< unsigned __int64, __int64 >::RegMultiply(t1, u1, reinterpret_cast< unsigned __int64* >(&ret));
+ }
+
+ template < typename E >
+ static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isUint64 && IntTraits::isInt64 );
+ unsigned __int64 t1 = t;
+ __int64 u1 = u;
+ LargeIntRegMultiply< unsigned __int64, __int64 >::template RegMultiplyThrow< E >(t1, u1, reinterpret_cast< unsigned __int64* >(&ret));
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_UintInt64 >
+{
+public:
+ // T is unsigned up to 32-bit
+ // U is __int64
+ static bool Multiply(const T& t, const U& u, T& ret) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 u1 = u;
+ unsigned __int32 tmp;
+
+ if( LargeIntRegMultiply< unsigned __int32, __int64 >::RegMultiply( (unsigned __int32)t, u1, &tmp ) &&
+ SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::Cast(tmp, ret) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void MultiplyThrow(const T& t, const U& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 u1 = u;
+ unsigned __int32 tmp;
+
+ LargeIntRegMultiply< unsigned __int32, __int64 >::template RegMultiplyThrow< E >( (unsigned __int32)t, u1, &tmp );
+ SafeCastHelper< T, unsigned __int32, GetCastMethod< T, unsigned __int32 >::method >::template CastThrow< E >(tmp, ret);
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint >
+{
+public:
+ // T is __int64
+ // U is unsigned up to 32-bit
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 t1 = t;
+ return LargeIntRegMultiply< __int64, unsigned __int32 >::RegMultiply( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) );
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 t1 = t;
+ LargeIntRegMultiply< __int64, unsigned __int32 >::template RegMultiplyThrow< E >( t1, (unsigned __int32)u, reinterpret_cast< __int64* >(&ret) );
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int64 >
+{
+public:
+ // T, U are __int64
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 );
+ __int64 t1 = t;
+ __int64 u1 = u;
+ return LargeIntRegMultiply< __int64, __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) );
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const T& t, const U& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isInt64 && IntTraits::isInt64 );
+ __int64 t1 = t;
+ __int64 u1 = u;
+ LargeIntRegMultiply< __int64, __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret));
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Int >
+{
+public:
+ // T is __int64
+ // U is signed up to 32-bit
+ static bool Multiply( const T& t, U u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 t1 = t;
+ return LargeIntRegMultiply< __int64, __int32 >::RegMultiply( t1, (__int32)u, reinterpret_cast< __int64* >(&ret));
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const __int64& t, U u, T& ret ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 t1 = t;
+ LargeIntRegMultiply< __int64, __int32 >::template RegMultiplyThrow< E >(t1, (__int32)u, reinterpret_cast< __int64* >(&ret));
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntUint64 >
+{
+public:
+ // T is signed up to 32-bit
+ // U is unsigned __int64
+ static bool Multiply(T t, const U& u, T& ret) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 u1 = u;
+ __int32 tmp;
+
+ if( LargeIntRegMultiply< __int32, unsigned __int64 >::RegMultiply( (__int32)t, u1, &tmp ) &&
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void MultiplyThrow(T t, const unsigned __int64& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isUint64 );
+ unsigned __int64 u1 = u;
+ __int32 tmp;
+
+ LargeIntRegMultiply< __int32, unsigned __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp );
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret );
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_Int64Uint64>
+{
+public:
+ // T is __int64
+ // U is unsigned __int64
+ static bool Multiply( const T& t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 );
+ __int64 t1 = t;
+ unsigned __int64 u1 = u;
+ return LargeIntRegMultiply< __int64, unsigned __int64 >::RegMultiply( t1, u1, reinterpret_cast< __int64* >(&ret) );
+ }
+
+ template < typename E >
+ static void MultiplyThrow( const __int64& t, const unsigned __int64& u, T& ret ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isInt64 && IntTraits::isUint64 );
+ __int64 t1 = t;
+ unsigned __int64 u1 = u;
+ LargeIntRegMultiply< __int64, unsigned __int64 >::template RegMultiplyThrow< E >( t1, u1, reinterpret_cast< __int64* >(&ret) );
+ }
+};
+
+template < typename T, typename U > class MultiplicationHelper< T, U, MultiplicationState_IntInt64>
+{
+public:
+ // T is signed, up to 32-bit
+ // U is __int64
+ static bool Multiply( T t, const U& u, T& ret ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 u1 = u;
+ __int32 tmp;
+
+ if( LargeIntRegMultiply< __int32, __int64 >::RegMultiply( (__int32)t, u1, &tmp ) &&
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, ret ) )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void MultiplyThrow(T t, const U& u, T& ret) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits::isInt64 );
+ __int64 u1 = u;
+ __int32 tmp;
+
+ LargeIntRegMultiply< __int32, __int64 >::template RegMultiplyThrow< E >( (__int32)t, u1, &tmp );
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, ret );
+ }
+};
+
+enum DivisionState
+{
+ DivisionState_OK,
+ DivisionState_UnsignedSigned,
+ DivisionState_SignedUnsigned32,
+ DivisionState_SignedUnsigned64,
+ DivisionState_SignedUnsigned,
+ DivisionState_SignedSigned
+};
+
+template < typename T, typename U > class DivisionMethod
+{
+public:
+ enum
+ {
+ method = (SafeIntCompare< T, U >::isBothUnsigned ? DivisionState_OK :
+ (!IntTraits< T >::isSigned && IntTraits< U >::isSigned) ? DivisionState_UnsignedSigned :
+ (IntTraits< T >::isSigned &&
+ IntTraits< U >::isUint32 &&
+ IntTraits< T >::isLT64Bit) ? DivisionState_SignedUnsigned32 :
+ (IntTraits< T >::isSigned && IntTraits< U >::isUint64) ? DivisionState_SignedUnsigned64 :
+ (IntTraits< T >::isSigned && !IntTraits< U >::isSigned) ? DivisionState_SignedUnsigned :
+ DivisionState_SignedSigned)
+ };
+};
+
+template < typename T, typename U, int state > class DivisionHelper;
+
+template < typename T, typename U > class DivisionHelper< T, U, DivisionState_OK >
+{
+public:
+ static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if( u == 0 )
+ return SafeIntDivideByZero;
+
+ if( t == 0 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ result = (T)( t/u );
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if( u == 0 )
+ E::SafeIntOnDivZero();
+
+ if( t == 0 )
+ {
+ result = 0;
+ return;
+ }
+
+ result = (T)( t/u );
+ }
+};
+
+template < typename T, typename U > class DivisionHelper< T, U, DivisionState_UnsignedSigned>
+{
+public:
+ static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+
+ if( u == 0 )
+ return SafeIntDivideByZero;
+
+ if( t == 0 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ if( u > 0 )
+ {
+ result = (T)( t/u );
+ return SafeIntNoError;
+ }
+
+ // it is always an error to try and divide an unsigned number by a negative signed number
+ // unless u is bigger than t
+ if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ return SafeIntArithmeticOverflow;
+ }
+
+ template < typename E >
+ static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+
+ if( u == 0 )
+ E::SafeIntOnDivZero();
+
+ if( t == 0 )
+ {
+ result = 0;
+ return;
+ }
+
+ if( u > 0 )
+ {
+ result = (T)( t/u );
+ return;
+ }
+
+ // it is always an error to try and divide an unsigned number by a negative signed number
+ // unless u is bigger than t
+ if( AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( u ) > t )
+ {
+ result = 0;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned32 >
+{
+public:
+ static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if( u == 0 )
+ return SafeIntDivideByZero;
+
+ if( t == 0 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ // Test for t > 0
+ // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors
+ // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional
+
+ if( t > 0 )
+ result = (T)( t/u );
+ else
+ result = (T)( (__int64)t/(__int64)u );
+
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if( u == 0 )
+ {
+ E::SafeIntOnDivZero();
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return;
+ }
+
+ // Test for t > 0
+ // If t < 0, must explicitly upcast, or implicit upcast to ulong will cause errors
+ // As it turns out, 32-bit division is about twice as fast, which justifies the extra conditional
+
+ if( t > 0 )
+ result = (T)( t/u );
+ else
+ result = (T)( (__int64)t/(__int64)u );
+ }
+};
+
+template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned64 >
+{
+public:
+ static SafeIntError Divide( const T& t, const unsigned __int64& u, T& result ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits< U >::isUint64 );
+
+ if( u == 0 )
+ {
+ return SafeIntDivideByZero;
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ if( u <= (unsigned __int64)IntTraits< T >::maxInt )
+ {
+ // Else u can safely be cast to T
+ if( CompileConst< sizeof( T ) < sizeof( __int64 )>::Value() )
+ result = (T)( (int)t/(int)u );
+ else
+ result = (T)((__int64)t/(__int64)u);
+ }
+ else // Corner case
+ if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt )
+ {
+ // Min int divided by it's own magnitude is -1
+ result = -1;
+ }
+ else
+ {
+ result = 0;
+ }
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void DivideThrow( const T& t, const unsigned __int64& u, T& result ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits< U >::isUint64 );
+
+ if( u == 0 )
+ {
+ E::SafeIntOnDivZero();
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return;
+ }
+
+ if( u <= (unsigned __int64)IntTraits< T >::maxInt )
+ {
+ // Else u can safely be cast to T
+ if( CompileConst< sizeof( T ) < sizeof( __int64 ) >::Value() )
+ result = (T)( (int)t/(int)u );
+ else
+ result = (T)((__int64)t/(__int64)u);
+ }
+ else // Corner case
+ if( t == IntTraits< T >::minInt && u == (unsigned __int64)IntTraits< T >::minInt )
+ {
+ // Min int divided by it's own magnitude is -1
+ result = -1;
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+};
+
+template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedUnsigned>
+{
+public:
+ // T is any signed, U is unsigned and smaller than 32-bit
+ // In this case, standard operator casting is correct
+ static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if( u == 0 )
+ {
+ return SafeIntDivideByZero;
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ result = (T)( t/u );
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if( u == 0 )
+ {
+ E::SafeIntOnDivZero();
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return;
+ }
+
+ result = (T)( t/u );
+ }
+};
+
+template < typename T, typename U > class DivisionHelper< T, U, DivisionState_SignedSigned>
+{
+public:
+ static SafeIntError Divide( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+ {
+ if( u == 0 )
+ {
+ return SafeIntDivideByZero;
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return SafeIntNoError;
+ }
+
+ // Must test for corner case
+ if( t == IntTraits< T >::minInt && u == (U)-1 )
+ return SafeIntArithmeticOverflow;
+
+ result = (T)( t/u );
+ return SafeIntNoError;
+ }
+
+ template < typename E >
+ static void DivideThrow( const T& t, const U& u, T& result ) SAFEINT_CPP_THROW
+ {
+ if(u == 0)
+ {
+ E::SafeIntOnDivZero();
+ }
+
+ if( t == 0 )
+ {
+ result = 0;
+ return;
+ }
+
+ // Must test for corner case
+ if( t == IntTraits< T >::minInt && u == (U)-1 )
+ E::SafeIntOnOverflow();
+
+ result = (T)( t/u );
+ }
+};
+
+enum AdditionState
+{
+ AdditionState_CastIntCheckMax,
+ AdditionState_CastUintCheckOverflow,
+ AdditionState_CastUintCheckOverflowMax,
+ AdditionState_CastUint64CheckOverflow,
+ AdditionState_CastUint64CheckOverflowMax,
+ AdditionState_CastIntCheckSafeIntMinMax,
+ AdditionState_CastInt64CheckSafeIntMinMax,
+ AdditionState_CastInt64CheckMax,
+ AdditionState_CastUint64CheckSafeIntMinMax,
+ AdditionState_CastUint64CheckSafeIntMinMax2,
+ AdditionState_CastInt64CheckOverflow,
+ AdditionState_CastInt64CheckOverflowSafeIntMinMax,
+ AdditionState_CastInt64CheckOverflowMax,
+ AdditionState_ManualCheckInt64Uint64,
+ AdditionState_ManualCheck,
+ AdditionState_Error
+};
+
+template< typename T, typename U >
+class AdditionMethod
+{
+public:
+ enum
+ {
+ //unsigned-unsigned
+ method = (IntRegion< T,U >::IntZone_UintLT32_UintLT32 ? AdditionState_CastIntCheckMax :
+ (IntRegion< T,U >::IntZone_Uint32_UintLT64) ? AdditionState_CastUintCheckOverflow :
+ (IntRegion< T,U >::IntZone_UintLT32_Uint32) ? AdditionState_CastUintCheckOverflowMax :
+ (IntRegion< T,U >::IntZone_Uint64_Uint) ? AdditionState_CastUint64CheckOverflow :
+ (IntRegion< T,U >::IntZone_UintLT64_Uint64) ? AdditionState_CastUint64CheckOverflowMax :
+ //unsigned-signed
+ (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
+ IntRegion< T,U >::IntZone_UintLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Uint64_Int ||
+ IntRegion< T,U >::IntZone_Uint64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_UintLT64_Int64) ? AdditionState_CastUint64CheckSafeIntMinMax2 :
+ //signed-signed
+ (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? AdditionState_CastIntCheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
+ IntRegion< T,U >::IntZone_IntLT32_Int32) ? AdditionState_CastInt64CheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Int64_Int ||
+ IntRegion< T,U >::IntZone_Int64_Int64) ? AdditionState_CastInt64CheckOverflow :
+ (IntRegion< T,U >::IntZone_IntLT64_Int64) ? AdditionState_CastInt64CheckOverflowSafeIntMinMax :
+ //signed-unsigned
+ (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? AdditionState_CastIntCheckMax :
+ (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
+ IntRegion< T,U >::IntZone_IntLT64_Uint32) ? AdditionState_CastInt64CheckMax :
+ (IntRegion< T,U >::IntZone_Int64_UintLT64) ? AdditionState_CastInt64CheckOverflowMax :
+ (IntRegion< T,U >::IntZone_Int64_Uint64) ? AdditionState_ManualCheckInt64Uint64 :
+ (IntRegion< T,U >::IntZone_Int_Uint64) ? AdditionState_ManualCheck :
+ AdditionState_Error)
+ };
+};
+
+template < typename T, typename U, int method > class AdditionHelper;
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckMax >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ //16-bit or less unsigned addition
+ __int32 tmp = lhs + rhs;
+
+ if( tmp <= (__int32)IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ //16-bit or less unsigned addition
+ __int32 tmp = lhs + rhs;
+
+ if( tmp <= (__int32)IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflow >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // 32-bit or less - both are unsigned
+ unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
+
+ //we added didn't get smaller
+ if( tmp >= lhs )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // 32-bit or less - both are unsigned
+ unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
+
+ //we added didn't get smaller
+ if( tmp >= lhs )
+ {
+ result = (T)tmp;
+ return;
+ }
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUintCheckOverflowMax>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // 32-bit or less - both are unsigned
+ unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
+
+ // We added and it didn't get smaller or exceed maxInt
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ //32-bit or less - both are unsigned
+ unsigned __int32 tmp = (unsigned __int32)lhs + (unsigned __int32)rhs;
+
+ // We added and it didn't get smaller or exceed maxInt
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflow>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs unsigned __int64, rhs unsigned
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // We added and it didn't get smaller
+ if(tmp >= lhs)
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs unsigned __int64, rhs unsigned
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // We added and it didn't get smaller
+ if(tmp >= lhs)
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckOverflowMax >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ //lhs unsigned __int64, rhs unsigned
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // We added and it didn't get smaller
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ //lhs unsigned __int64, rhs unsigned
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // We added and it didn't get smaller
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastIntCheckSafeIntMinMax >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // 16-bit or less - one or both are signed
+ __int32 tmp = lhs + rhs;
+
+ if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // 16-bit or less - one or both are signed
+ __int32 tmp = lhs + rhs;
+
+ if( tmp <= (__int32)IntTraits< T >::maxInt && tmp >= (__int32)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckSafeIntMinMax >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // 32-bit or less - one or both are signed
+ __int64 tmp = (__int64)lhs + (__int64)rhs;
+
+ if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // 32-bit or less - one or both are signed
+ __int64 tmp = (__int64)lhs + (__int64)rhs;
+
+ if( tmp <= (__int64)IntTraits< T >::maxInt && tmp >= (__int64)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckMax >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // 32-bit or less - lhs signed, rhs unsigned
+ __int64 tmp = (__int64)lhs + (__int64)rhs;
+
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // 32-bit or less - lhs signed, rhs unsigned
+ __int64 tmp = (__int64)lhs + (__int64)rhs;
+
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax >
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is unsigned __int64, rhs signed
+ unsigned __int64 tmp;
+
+ if( rhs < 0 )
+ {
+ // So we're effectively subtracting
+ tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
+
+ if( tmp <= lhs )
+ {
+ result = lhs - tmp;
+ return true;
+ }
+ }
+ else
+ {
+ // now we know that rhs can be safely cast into an unsigned __int64
+ tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // We added and it did not become smaller
+ if( tmp >= lhs )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is unsigned __int64, rhs signed
+ unsigned __int64 tmp;
+
+ if( rhs < 0 )
+ {
+ // So we're effectively subtracting
+ tmp = AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
+
+ if( tmp <= lhs )
+ {
+ result = lhs - tmp;
+ return;
+ }
+ }
+ else
+ {
+ // now we know that rhs can be safely cast into an unsigned __int64
+ tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // We added and it did not become smaller
+ if( tmp >= lhs )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastUint64CheckSafeIntMinMax2>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is unsigned and < 64-bit, rhs signed __int64
+ if( rhs < 0 )
+ {
+ if( lhs >= ~(unsigned __int64)( rhs ) + 1 )//negation is safe, since rhs is 64-bit
+ {
+ result = (T)( lhs + rhs );
+ return true;
+ }
+ }
+ else
+ {
+ // now we know that rhs can be safely cast into an unsigned __int64
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff
+ // it is not possible for the operation above to overflow, so just check max
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is unsigned and < 64-bit, rhs signed __int64
+ if( rhs < 0 )
+ {
+ if( lhs >= ~(unsigned __int64)( rhs ) + 1) //negation is safe, since rhs is 64-bit
+ {
+ result = (T)( lhs + rhs );
+ return;
+ }
+ }
+ else
+ {
+ // now we know that rhs can be safely cast into an unsigned __int64
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ // special case - rhs cannot be larger than 0x7fffffffffffffff, lhs cannot be larger than 0xffffffff
+ // it is not possible for the operation above to overflow, so just check max
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflow>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is signed __int64, rhs signed
+ __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs);
+
+ if( lhs >= 0 )
+ {
+ // mixed sign cannot overflow
+ if( rhs >= 0 && tmp < lhs )
+ return false;
+ }
+ else
+ {
+ // lhs negative
+ if( rhs < 0 && tmp > lhs )
+ return false;
+ }
+
+ result = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is signed __int64, rhs signed
+ __int64 tmp = (__int64)((unsigned __int64)lhs + (unsigned __int64)rhs);
+
+ if( lhs >= 0 )
+ {
+ // mixed sign cannot overflow
+ if( rhs >= 0 && tmp < lhs )
+ E::SafeIntOnOverflow();
+ }
+ else
+ {
+ // lhs negative
+ if( rhs < 0 && tmp > lhs )
+ E::SafeIntOnOverflow();
+ }
+
+ result = (T)tmp;
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowSafeIntMinMax>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ //rhs is signed __int64, lhs signed
+ __int64 tmp;
+
+ if( AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::Addition( (__int64)lhs, (__int64)rhs, tmp ) &&
+ tmp <= IntTraits< T >::maxInt &&
+ tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ //rhs is signed __int64, lhs signed
+ __int64 tmp;
+
+ AdditionHelper< __int64, __int64, AdditionState_CastInt64CheckOverflow >::AdditionThrow< E >( (__int64)lhs, (__int64)rhs, tmp );
+
+ if( tmp <= IntTraits< T >::maxInt &&
+ tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_CastInt64CheckOverflowMax>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ //lhs is signed __int64, rhs unsigned < 64-bit
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ if( (__int64)tmp >= lhs )
+ {
+ result = (T)(__int64)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is signed __int64, rhs unsigned < 64-bit
+ // Some compilers get optimization-happy, let's thwart them
+
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)rhs;
+
+ if( (__int64)tmp >= lhs )
+ {
+ result = (T)(__int64)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheckInt64Uint64 >
+{
+public:
+ static bool Addition( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );
+ // rhs is unsigned __int64, lhs __int64
+ // cast everything to unsigned, perform addition, then
+ // cast back for check - this is done to stop optimizers from removing the code
+ unsigned __int64 tmp = (unsigned __int64)lhs + rhs;
+
+ if( (__int64)tmp >= lhs )
+ {
+ result = (__int64)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );
+ // rhs is unsigned __int64, lhs __int64
+ unsigned __int64 tmp = (unsigned __int64)lhs + rhs;
+
+ if( (__int64)tmp >= lhs )
+ {
+ result = (__int64)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class AdditionHelper < T, U, AdditionState_ManualCheck>
+{
+public:
+ static bool Addition( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // rhs is unsigned __int64, lhs signed, 32-bit or less
+ if( (unsigned __int32)( rhs >> 32 ) == 0 )
+ {
+ // Now it just happens to work out that the standard behavior does what we want
+ // Adding explicit casts to show exactly what's happening here
+ // Note - this is tweaked to keep optimizers from tossing out the code.
+ unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs;
+
+ if( (__int32)tmp >= lhs && SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( (__int32)tmp, result ) )
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void AdditionThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // rhs is unsigned __int64, lhs signed, 32-bit or less
+
+ if( (unsigned __int32)( rhs >> 32 ) == 0 )
+ {
+ // Now it just happens to work out that the standard behavior does what we want
+ // Adding explicit casts to show exactly what's happening here
+ unsigned __int32 tmp = (unsigned __int32)rhs + (unsigned __int32)lhs;
+
+ if( (__int32)tmp >= lhs )
+ {
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( (__int32)tmp, result );
+ return;
+ }
+ }
+ E::SafeIntOnOverflow();
+ }
+};
+
+enum SubtractionState
+{
+ SubtractionState_BothUnsigned,
+ SubtractionState_CastIntCheckSafeIntMinMax,
+ SubtractionState_CastIntCheckMin,
+ SubtractionState_CastInt64CheckSafeIntMinMax,
+ SubtractionState_CastInt64CheckMin,
+ SubtractionState_Uint64Int,
+ SubtractionState_UintInt64,
+ SubtractionState_Int64Int,
+ SubtractionState_IntInt64,
+ SubtractionState_Int64Uint,
+ SubtractionState_IntUint64,
+ SubtractionState_Int64Uint64,
+ // states for SubtractionMethod2
+ SubtractionState_BothUnsigned2,
+ SubtractionState_CastIntCheckSafeIntMinMax2,
+ SubtractionState_CastInt64CheckSafeIntMinMax2,
+ SubtractionState_Uint64Int2,
+ SubtractionState_UintInt642,
+ SubtractionState_Int64Int2,
+ SubtractionState_IntInt642,
+ SubtractionState_Int64Uint2,
+ SubtractionState_IntUint642,
+ SubtractionState_Int64Uint642,
+ SubtractionState_Error
+};
+
+template < typename T, typename U > class SubtractionMethod
+{
+public:
+ enum
+ {
+ // unsigned-unsigned
+ method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||
+ (IntRegion< T,U >::IntZone_Uint32_UintLT64) ||
+ (IntRegion< T,U >::IntZone_UintLT32_Uint32) ||
+ (IntRegion< T,U >::IntZone_Uint64_Uint) ||
+ (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned :
+ // unsigned-signed
+ (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
+ IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Uint64_Int ||
+ IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int :
+ (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt64 :
+ // signed-signed
+ (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
+ IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax :
+ (IntRegion< T,U >::IntZone_Int64_Int ||
+ IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int :
+ (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt64 :
+ // signed-unsigned
+ (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckMin :
+ (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
+ IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckMin :
+ (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint :
+ (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint64 :
+ (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint64 :
+ SubtractionState_Error)
+ };
+};
+
+// this is for the case of U - SafeInt< T, E >
+template < typename T, typename U > class SubtractionMethod2
+{
+public:
+ enum
+ {
+ // unsigned-unsigned
+ method = ((IntRegion< T,U >::IntZone_UintLT32_UintLT32 ||
+ (IntRegion< T,U >::IntZone_Uint32_UintLT64) ||
+ (IntRegion< T,U >::IntZone_UintLT32_Uint32) ||
+ (IntRegion< T,U >::IntZone_Uint64_Uint) ||
+ (IntRegion< T,U >::IntZone_UintLT64_Uint64)) ? SubtractionState_BothUnsigned2 :
+ // unsigned-signed
+ (IntRegion< T,U >::IntZone_UintLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 :
+ (IntRegion< T,U >::IntZone_Uint32_IntLT64 ||
+ IntRegion< T,U >::IntZone_UintLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 :
+ (IntRegion< T,U >::IntZone_Uint64_Int ||
+ IntRegion< T,U >::IntZone_Uint64_Int64) ? SubtractionState_Uint64Int2 :
+ (IntRegion< T,U >::IntZone_UintLT64_Int64) ? SubtractionState_UintInt642 :
+ // signed-signed
+ (IntRegion< T,U >::IntZone_IntLT32_IntLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 :
+ (IntRegion< T,U >::IntZone_Int32_IntLT64 ||
+ IntRegion< T,U >::IntZone_IntLT32_Int32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 :
+ (IntRegion< T,U >::IntZone_Int64_Int ||
+ IntRegion< T,U >::IntZone_Int64_Int64) ? SubtractionState_Int64Int2 :
+ (IntRegion< T,U >::IntZone_IntLT64_Int64) ? SubtractionState_IntInt642 :
+ // signed-unsigned
+ (IntRegion< T,U >::IntZone_IntLT32_UintLT32) ? SubtractionState_CastIntCheckSafeIntMinMax2 :
+ (IntRegion< T,U >::IntZone_Int32_UintLT32 ||
+ IntRegion< T,U >::IntZone_IntLT64_Uint32) ? SubtractionState_CastInt64CheckSafeIntMinMax2 :
+ (IntRegion< T,U >::IntZone_Int64_UintLT64) ? SubtractionState_Int64Uint2 :
+ (IntRegion< T,U >::IntZone_Int_Uint64) ? SubtractionState_IntUint642 :
+ (IntRegion< T,U >::IntZone_Int64_Uint64) ? SubtractionState_Int64Uint642 :
+ SubtractionState_Error)
+ };
+};
+
+template < typename T, typename U, int method > class SubtractionHelper;
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both are unsigned - easy case
+ if( rhs <= lhs )
+ {
+ result = (T)( lhs - rhs );
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both are unsigned - easy case
+ if( rhs <= lhs )
+ {
+ result = (T)( lhs - rhs );
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_BothUnsigned2 >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, U& result ) SAFEINT_NOTHROW
+ {
+ // both are unsigned - easy case
+ // Except we do have to check for overflow - lhs could be larger than result can hold
+ if( rhs <= lhs )
+ {
+ T tmp = (T)(lhs - rhs);
+ return SafeCastHelper< U, T, GetCastMethod::method>::Cast( tmp, result);
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, U& result ) SAFEINT_CPP_THROW
+ {
+ // both are unsigned - easy case
+ if( rhs <= lhs )
+ {
+ T tmp = (T)(lhs - rhs);
+ SafeCastHelper< U, T, GetCastMethod::method >::template CastThrow( tmp, result);
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckSafeIntMinMax >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both values are 16-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int32 tmp = lhs - rhs;
+
+ if( SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result ) )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both values are 16-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int32 tmp = lhs - rhs;
+
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result );
+ }
+};
+
+template class SubtractionHelper< U, T, SubtractionState_CastIntCheckSafeIntMinMax2 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both values are 16-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int32 tmp = lhs - rhs;
+
+ return SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::Cast( tmp, result );
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both values are 16-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int32 tmp = lhs - rhs;
+
+ SafeCastHelper< T, __int32, GetCastMethod< T, __int32 >::method >::template CastThrow< E >( tmp, result );
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastIntCheckMin >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both values are 16-bit or less
+ // rhs is unsigned - check only minimum
+ __int32 tmp = lhs - rhs;
+
+ if( tmp >= (__int32)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both values are 16-bit or less
+ // rhs is unsigned - check only minimum
+ __int32 tmp = lhs - rhs;
+
+ if( tmp >= (__int32)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckSafeIntMinMax >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both values are 32-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int64 tmp = (__int64)lhs - (__int64)rhs;
+
+ return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result );
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both values are 32-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int64 tmp = (__int64)lhs - (__int64)rhs;
+
+ SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result );
+ }
+};
+
+template class SubtractionHelper< U, T, SubtractionState_CastInt64CheckSafeIntMinMax2 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both values are 32-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int64 tmp = (__int64)lhs - (__int64)rhs;
+
+ return SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::Cast( tmp, result );
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both values are 32-bit or less
+ // rhs is signed, so could end up increasing or decreasing
+ __int64 tmp = (__int64)lhs - (__int64)rhs;
+
+ SafeCastHelper< T, __int64, GetCastMethod< T, __int64 >::method >::template CastThrow< E >( tmp, result );
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_CastInt64CheckMin >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // both values are 32-bit or less
+ // rhs is unsigned - check only minimum
+ __int64 tmp = (__int64)lhs - (__int64)rhs;
+
+ if( tmp >= (__int64)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // both values are 32-bit or less
+ // rhs is unsigned - check only minimum
+ __int64 tmp = (__int64)lhs - (__int64)rhs;
+
+ if( tmp >= (__int64)IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Uint64Int >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is an unsigned __int64, rhs signed
+ // must first see if rhs is positive or negative
+ if( rhs >= 0 )
+ {
+ if( (unsigned __int64)rhs <= lhs )
+ {
+ result = (T)( lhs - (unsigned __int64)rhs );
+ return true;
+ }
+ }
+ else
+ {
+ T tmp = lhs;
+ // we're now effectively adding
+ result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
+
+ if(result >= tmp)
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is an unsigned __int64, rhs signed
+ // must first see if rhs is positive or negative
+ if( rhs >= 0 )
+ {
+ if( (unsigned __int64)rhs <= lhs )
+ {
+ result = (T)( lhs - (unsigned __int64)rhs );
+ return;
+ }
+ }
+ else
+ {
+ T tmp = lhs;
+ // we're now effectively adding
+ result = lhs + AbsValueHelper< U, GetAbsMethod< U >::method >::Abs( rhs );
+
+ if(result >= tmp)
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Uint64Int2 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // U is unsigned __int64, T is signed
+ if( rhs < 0 )
+ {
+ // treat this as addition
+ unsigned __int64 tmp;
+
+ tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs );
+
+ // must check for addition overflow and max
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+ else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works
+ {
+ // result is negative
+ // implies that lhs must fit into T, and result cannot overflow
+ // Also allows us to drop to 32-bit math, which is faster on a 32-bit system
+ result = (T)lhs - (T)rhs;
+ return true;
+ }
+ else
+ {
+ // result is positive
+ unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
+
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // U is unsigned __int64, T is signed
+ if( rhs < 0 )
+ {
+ // treat this as addition
+ unsigned __int64 tmp;
+
+ tmp = lhs + (unsigned __int64)AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( rhs );
+
+ // must check for addition overflow and max
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+ else if( (unsigned __int64)rhs > lhs ) // now both are positive, so comparison always works
+ {
+ // result is negative
+ // implies that lhs must fit into T, and result cannot overflow
+ // Also allows us to drop to 32-bit math, which is faster on a 32-bit system
+ result = (T)lhs - (T)rhs;
+ return;
+ }
+ else
+ {
+ // result is positive
+ unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
+
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_UintInt64 >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is an unsigned int32 or smaller, rhs signed __int64
+ // must first see if rhs is positive or negative
+ if( rhs >= 0 )
+ {
+ if( (unsigned __int64)rhs <= lhs )
+ {
+ result = (T)( lhs - (T)rhs );
+ return true;
+ }
+ }
+ else
+ {
+ // we're now effectively adding
+ // since lhs is 32-bit, and rhs cannot exceed 2^63
+ // this addition cannot overflow
+ unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe
+
+ // but we could exceed MaxInt
+ if(tmp <= IntTraits< T >::maxInt)
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is an unsigned int32 or smaller, rhs signed __int64
+ // must first see if rhs is positive or negative
+ if( rhs >= 0 )
+ {
+ if( (unsigned __int64)rhs <= lhs )
+ {
+ result = (T)( lhs - (T)rhs );
+ return;
+ }
+ }
+ else
+ {
+ // we're now effectively adding
+ // since lhs is 32-bit, and rhs cannot exceed 2^63
+ // this addition cannot overflow
+ unsigned __int64 tmp = lhs + ~(unsigned __int64)( rhs ) + 1; // negation safe
+
+ // but we could exceed MaxInt
+ if(tmp <= IntTraits< T >::maxInt)
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template class SubtractionHelper< U, T, SubtractionState_UintInt642 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // U unsigned 32-bit or less, T __int64
+ if( rhs >= 0 )
+ {
+ // overflow not possible
+ result = (T)( (__int64)lhs - rhs );
+ return true;
+ }
+ else
+ {
+ // we effectively have an addition
+ // which cannot overflow internally
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );
+
+ if( tmp <= (unsigned __int64)IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // U unsigned 32-bit or less, T __int64
+ if( rhs >= 0 )
+ {
+ // overflow not possible
+ result = (T)( (__int64)lhs - rhs );
+ return;
+ }
+ else
+ {
+ // we effectively have an addition
+ // which cannot overflow internally
+ unsigned __int64 tmp = (unsigned __int64)lhs + (unsigned __int64)( -rhs );
+
+ if( tmp <= (unsigned __int64)IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Int >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is an __int64, rhs signed (up to 64-bit)
+ // we have essentially 4 cases:
+ //
+ // 1) lhs positive, rhs positive - overflow not possible
+ // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
+ // 3) lhs negative, rhs positive - check result <= lhs
+ // 4) lhs negative, rhs negative - overflow not possible
+
+ __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);
+
+ // Note - ideally, we can order these so that true conditionals
+ // lead to success, which enables better pipelining
+ // It isn't practical here
+ if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2
+ ( rhs >= 0 && tmp > lhs ) ) // condition 3
+ {
+ return false;
+ }
+
+ result = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is an __int64, rhs signed (up to 64-bit)
+ // we have essentially 4 cases:
+ //
+ // 1) lhs positive, rhs positive - overflow not possible
+ // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
+ // 3) lhs negative, rhs positive - check result <= lhs
+ // 4) lhs negative, rhs negative - overflow not possible
+
+ __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);
+
+ // Note - ideally, we can order these so that true conditionals
+ // lead to success, which enables better pipelining
+ // It isn't practical here
+ if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) || // condition 2
+ ( rhs >= 0 && tmp > lhs ) ) // condition 3
+ {
+ E::SafeIntOnOverflow();
+ }
+
+ result = (T)tmp;
+ }
+};
+
+template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Int2 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs __int64, rhs any signed int (including __int64)
+ __int64 tmp = lhs - rhs;
+
+ // we have essentially 4 cases:
+ //
+ // 1) lhs positive, rhs positive - overflow not possible in tmp
+ // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
+ // 3) lhs negative, rhs positive - check result <= lhs
+ // 4) lhs negative, rhs negative - overflow not possible in tmp
+
+ if( lhs >= 0 )
+ {
+ // if both positive, overflow to negative not possible
+ // which is why we'll explicitly check maxInt, and not call SafeCast
+ if( ( IntTraits< T >::isLT64Bit && tmp > IntTraits< T >::maxInt ) ||
+ ( rhs < 0 && tmp < lhs ) )
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // lhs negative
+ if( ( IntTraits< T >::isLT64Bit && tmp < IntTraits< T >::minInt) ||
+ ( rhs >=0 && tmp > lhs ) )
+ {
+ return false;
+ }
+ }
+
+ result = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs __int64, rhs any signed int (including __int64)
+ __int64 tmp = lhs - rhs;
+
+ // we have essentially 4 cases:
+ //
+ // 1) lhs positive, rhs positive - overflow not possible in tmp
+ // 2) lhs positive, rhs negative - equivalent to addition - result >= lhs or error
+ // 3) lhs negative, rhs positive - check result <= lhs
+ // 4) lhs negative, rhs negative - overflow not possible in tmp
+
+ if( lhs >= 0 )
+ {
+ // if both positive, overflow to negative not possible
+ // which is why we'll explicitly check maxInt, and not call SafeCast
+ if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp > IntTraits< T >::maxInt ) ||
+ ( rhs < 0 && tmp < lhs ) )
+ {
+ E::SafeIntOnOverflow();
+ }
+ }
+ else
+ {
+ // lhs negative
+ if( ( CompileConst< IntTraits< T >::isLT64Bit >::Value() && tmp < IntTraits< T >::minInt) ||
+ ( rhs >=0 && tmp > lhs ) )
+ {
+ E::SafeIntOnOverflow();
+ }
+ }
+
+ result = (T)tmp;
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntInt64 >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is a 32-bit int or less, rhs __int64
+ // we have essentially 4 cases:
+ //
+ // lhs positive, rhs positive - rhs could be larger than lhs can represent
+ // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int
+ // lhs negative, rhs positive - check tmp <= lhs and tmp < min int
+ // lhs negative, rhs negative - addition cannot internally overflow, check against max
+
+ __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);
+
+ if( lhs >= 0 )
+ {
+ // first case
+ if( rhs >= 0 )
+ {
+ if( tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+ else
+ {
+ // second case
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ // lhs < 0
+ // third case
+ if( rhs >= 0 )
+ {
+ if( tmp <= lhs && tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+ else
+ {
+ // fourth case
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is a 32-bit int or less, rhs __int64
+ // we have essentially 4 cases:
+ //
+ // lhs positive, rhs positive - rhs could be larger than lhs can represent
+ // lhs positive, rhs negative - additive case - check tmp >= lhs and tmp > max int
+ // lhs negative, rhs positive - check tmp <= lhs and tmp < min int
+ // lhs negative, rhs negative - addition cannot internally overflow, check against max
+
+ __int64 tmp = (__int64)((unsigned __int64)lhs - (unsigned __int64)rhs);
+
+ if( lhs >= 0 )
+ {
+ // first case
+ if( rhs >= 0 )
+ {
+ if( tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+ else
+ {
+ // second case
+ if( tmp >= lhs && tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+ }
+ else
+ {
+ // lhs < 0
+ // third case
+ if( rhs >= 0 )
+ {
+ if( tmp <= lhs && tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+ else
+ {
+ // fourth case
+ if( tmp <= IntTraits< T >::maxInt )
+ {
+ result = (T)tmp;
+ return;
+ }
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntInt642 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is any signed int32 or smaller, rhs is int64
+ __int64 tmp = (__int64)lhs - rhs;
+
+ if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||
+ ( rhs > 0 && tmp > lhs ) )
+ {
+ return false;
+ //else OK
+ }
+
+ result = (T)tmp;
+ return true;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is any signed int32 or smaller, rhs is int64
+ __int64 tmp = (__int64)lhs - rhs;
+
+ if( ( lhs >= 0 && rhs < 0 && tmp < lhs ) ||
+ ( rhs > 0 && tmp > lhs ) )
+ {
+ E::SafeIntOnOverflow();
+ //else OK
+ }
+
+ result = (T)tmp;
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is a 64-bit int, rhs unsigned int32 or smaller
+ // perform test as unsigned to prevent unwanted optimizations
+ unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
+
+ if( (__int64)tmp <= lhs )
+ {
+ result = (T)(__int64)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is a 64-bit int, rhs unsigned int32 or smaller
+ // perform test as unsigned to prevent unwanted optimizations
+ unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
+
+ if( (__int64)tmp <= lhs )
+ {
+ result = (T)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint2 >
+{
+public:
+ // lhs is __int64, rhs is unsigned 32-bit or smaller
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // Do this as unsigned to prevent unwanted optimizations
+ unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
+
+ if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)(__int64)tmp;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // Do this as unsigned to prevent unwanted optimizations
+ unsigned __int64 tmp = (unsigned __int64)lhs - (unsigned __int64)rhs;
+
+ if( (__int64)tmp <= IntTraits< T >::maxInt && (__int64)tmp >= IntTraits< T >::minInt )
+ {
+ result = (T)(__int64)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_IntUint64 >
+{
+public:
+ static bool Subtract( const T& lhs, const U& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // lhs is any signed int, rhs unsigned int64
+ // check against available range
+
+ // We need the absolute value of IntTraits< T >::minInt
+ // This will give it to us without extraneous compiler warnings
+ const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;
+
+ if( lhs < 0 )
+ {
+ if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) )
+ {
+ result = (T)( lhs - rhs );
+ return true;
+ }
+ }
+ else
+ {
+ if( rhs <= AbsMinIntT + (unsigned __int64)lhs )
+ {
+ result = (T)( lhs - rhs );
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const T& lhs, const U& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // lhs is any signed int, rhs unsigned int64
+ // check against available range
+
+ // We need the absolute value of IntTraits< T >::minInt
+ // This will give it to us without extraneous compiler warnings
+ const unsigned __int64 AbsMinIntT = (unsigned __int64)IntTraits< T >::maxInt + 1;
+
+ if( lhs < 0 )
+ {
+ if( rhs <= AbsMinIntT - AbsValueHelper< T, GetAbsMethod< T >::method >::Abs( lhs ) )
+ {
+ result = (T)( lhs - rhs );
+ return;
+ }
+ }
+ else
+ {
+ if( rhs <= AbsMinIntT + (unsigned __int64)lhs )
+ {
+ result = (T)( lhs - rhs );
+ return;
+ }
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_IntUint642 >
+{
+public:
+ static bool Subtract( const U& lhs, const T& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ // We run into upcasting problems on comparison - needs 2 checks
+ if( lhs >= 0 && (T)lhs >= rhs )
+ {
+ result = (T)((U)lhs - (U)rhs);
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const U& lhs, const T& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ // We run into upcasting problems on comparison - needs 2 checks
+ if( lhs >= 0 && (T)lhs >= rhs )
+ {
+ result = (T)((U)lhs - (U)rhs);
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+
+};
+
+template < typename T, typename U > class SubtractionHelper< T, U, SubtractionState_Int64Uint64 >
+{
+public:
+ static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, __int64& result ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );
+ // if we subtract, and it gets larger, there's a problem
+ // Perform test as unsigned to prevent unwanted optimizations
+ unsigned __int64 tmp = (unsigned __int64)lhs - rhs;
+
+ if( (__int64)tmp <= lhs )
+ {
+ result = (__int64)tmp;
+ return true;
+ }
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits< T >::isInt64 && IntTraits< U >::isUint64 );
+ // if we subtract, and it gets larger, there's a problem
+ // Perform test as unsigned to prevent unwanted optimizations
+ unsigned __int64 tmp = (unsigned __int64)lhs - rhs;
+
+ if( (__int64)tmp <= lhs )
+ {
+ result = (__int64)tmp;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+
+};
+
+template < typename U, typename T > class SubtractionHelper< U, T, SubtractionState_Int64Uint642 >
+{
+public:
+ // If lhs is negative, immediate problem - return must be positive, and subtracting only makes it
+ // get smaller. If rhs > lhs, then it would also go negative, which is the other case
+ static bool Subtract( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 );
+ if( lhs >= 0 && (unsigned __int64)lhs >= rhs )
+ {
+ result = (unsigned __int64)lhs - rhs;
+ return true;
+ }
+
+ return false;
+ }
+
+ template < typename E >
+ static void SubtractThrow( const __int64& lhs, const unsigned __int64& rhs, T& result ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( IntTraits< T >::isUint64 && IntTraits< U >::isInt64 );
+ if( lhs >= 0 && (unsigned __int64)lhs >= rhs )
+ {
+ result = (unsigned __int64)lhs - rhs;
+ return;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+
+};
+
+enum BinaryState
+{
+ BinaryState_OK,
+ BinaryState_Int8,
+ BinaryState_Int16,
+ BinaryState_Int32
+};
+
+template < typename T, typename U > class BinaryMethod
+{
+public:
+ enum
+ {
+ // If both operands are unsigned OR
+ // return type is smaller than rhs OR
+ // return type is larger and rhs is unsigned
+ // Then binary operations won't produce unexpected results
+ method = ( sizeof( T ) <= sizeof( U ) ||
+ SafeIntCompare< T, U >::isBothUnsigned ||
+ !IntTraits< U >::isSigned ) ? BinaryState_OK :
+ IntTraits< U >::isInt8 ? BinaryState_Int8 :
+ IntTraits< U >::isInt16 ? BinaryState_Int16
+ : BinaryState_Int32
+ };
+};
+
+#ifdef SAFEINT_DISABLE_BINARY_ASSERT
+#define BinaryAssert(x)
+#else
+#define BinaryAssert(x) SAFEINT_ASSERT(x)
+#endif
+
+template < typename T, typename U, int method > class BinaryAndHelper;
+
+template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_OK >
+{
+public:
+ static T And( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs & rhs ); }
+};
+
+template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int8 >
+{
+public:
+ static T And( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ // cast forces sign extension to be zeros
+ BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int8)rhs ) );
+ return (T)( lhs & (unsigned __int8)rhs );
+ }
+};
+
+template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int16 >
+{
+public:
+ static T And( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ //cast forces sign extension to be zeros
+ BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int16)rhs ) );
+ return (T)( lhs & (unsigned __int16)rhs );
+ }
+};
+
+template < typename T, typename U > class BinaryAndHelper< T, U, BinaryState_Int32 >
+{
+public:
+ static T And( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ //cast forces sign extension to be zeros
+ BinaryAssert( ( lhs & rhs ) == ( lhs & (unsigned __int32)rhs ) );
+ return (T)( lhs & (unsigned __int32)rhs );
+ }
+};
+
+template < typename T, typename U, int method > class BinaryOrHelper;
+
+template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_OK >
+{
+public:
+ static T Or( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs | rhs ); }
+};
+
+template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int8 >
+{
+public:
+ static T Or( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ //cast forces sign extension to be zeros
+ BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int8)rhs ) );
+ return (T)( lhs | (unsigned __int8)rhs );
+ }
+};
+
+template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int16 >
+{
+public:
+ static T Or( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ //cast forces sign extension to be zeros
+ BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int16)rhs ) );
+ return (T)( lhs | (unsigned __int16)rhs );
+ }
+};
+
+template < typename T, typename U > class BinaryOrHelper< T, U, BinaryState_Int32 >
+{
+public:
+ static T Or( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ //cast forces sign extension to be zeros
+ BinaryAssert( ( lhs | rhs ) == ( lhs | (unsigned __int32)rhs ) );
+ return (T)( lhs | (unsigned __int32)rhs );
+ }
+};
+
+template class BinaryXorHelper;
+
+template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_OK >
+{
+public:
+ static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW { return (T)( lhs ^ rhs ); }
+};
+
+template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int8 >
+{
+public:
+ static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ // cast forces sign extension to be zeros
+ BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int8)rhs ) );
+ return (T)( lhs ^ (unsigned __int8)rhs );
+ }
+};
+
+template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int16 >
+{
+public:
+ static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ // cast forces sign extension to be zeros
+ BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int16)rhs ) );
+ return (T)( lhs ^ (unsigned __int16)rhs );
+ }
+};
+
+template < typename T, typename U > class BinaryXorHelper< T, U, BinaryState_Int32 >
+{
+public:
+ static T Xor( T lhs, U rhs ) SAFEINT_NOTHROW
+ {
+ // cast forces sign extension to be zeros
+ BinaryAssert( ( lhs ^ rhs ) == ( lhs ^ (unsigned __int32)rhs ) );
+ return (T)( lhs ^ (unsigned __int32)rhs );
+ }
+};
+
+/***************** External functions ****************************************/
+
+// External functions that can be used where you only need to check one operation
+// non-class helper function so that you can check for a cast's validity
+// and handle errors how you like
+template < typename T, typename U >
+inline bool SafeCast( const T From, U& To ) SAFEINT_NOTHROW
+{
+ return SafeCastHelper< U, T, GetCastMethod< U, T >::method >::Cast( From, To );
+}
+
+template < typename T, typename U >
+inline bool SafeEquals( const T t, const U u ) SAFEINT_NOTHROW
+{
+ return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u );
+}
+
+template < typename T, typename U >
+inline bool SafeNotEquals( const T t, const U u ) SAFEINT_NOTHROW
+{
+ return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( t, u );
+}
+
+template < typename T, typename U >
+inline bool SafeGreaterThan( const T t, const U u ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u );
+}
+
+template < typename T, typename U >
+inline bool SafeGreaterThanEquals( const T t, const U u ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t );
+}
+
+template < typename T, typename U >
+inline bool SafeLessThan( const T t, const U u ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( u, t );
+}
+
+template < typename T, typename U >
+inline bool SafeLessThanEquals( const T t, const U u ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( t, u );
+}
+
+template < typename T, typename U >
+inline bool SafeModulus( const T& t, const U& u, T& result ) SAFEINT_NOTHROW
+{
+ return ( ModulusHelper< T, U, ValidComparison< T, U >::method >::Modulus( t, u, result ) == SafeIntNoError );
+}
+
+template < typename T, typename U >
+inline bool SafeMultiply( T t, U u, T& result ) SAFEINT_NOTHROW
+{
+ return MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::Multiply( t, u, result );
+}
+
+template < typename T, typename U >
+inline bool SafeDivide( T t, U u, T& result ) SAFEINT_NOTHROW
+{
+ return ( DivisionHelper< T, U, DivisionMethod< T, U >::method >::Divide( t, u, result ) == SafeIntNoError );
+}
+
+template < typename T, typename U >
+inline bool SafeAdd( T t, U u, T& result ) SAFEINT_NOTHROW
+{
+ return AdditionHelper< T, U, AdditionMethod< T, U >::method >::Addition( t, u, result );
+}
+
+template < typename T, typename U >
+inline bool SafeSubtract( T t, U u, T& result ) SAFEINT_NOTHROW
+{
+ return SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::Subtract( t, u, result );
+}
+
+/***************** end external functions ************************************/
+
+// Main SafeInt class
+// Assumes exceptions can be thrown
+template < typename T, typename E = SafeIntDefaultExceptionHandler > class SafeInt
+{
+public:
+ SafeInt() SAFEINT_NOTHROW
+ {
+ C_ASSERT( NumericType< T >::isInt );
+ m_int = 0;
+ }
+
+ // Having a constructor for every type of int
+ // avoids having the compiler evade our checks when doing implicit casts -
+ // e.g., SafeInt s = 0x7fffffff;
+ SafeInt( const T& i ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( NumericType< T >::isInt );
+ //always safe
+ m_int = i;
+ }
+
+ // provide explicit boolean converter
+ SafeInt( bool b ) SAFEINT_NOTHROW
+ {
+ C_ASSERT( NumericType< T >::isInt );
+ m_int = (T)( b ? 1 : 0 );
+ }
+
+ template < typename U >
+ SafeInt(const SafeInt< U, E >& u) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( NumericType< T >::isInt );
+ *this = SafeInt< T, E >( (U)u );
+ }
+
+ template < typename U >
+ SafeInt( const U& i ) SAFEINT_CPP_THROW
+ {
+ C_ASSERT( NumericType< T >::isInt );
+ // SafeCast will throw exceptions if i won't fit in type T
+ SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( i, m_int );
+ }
+
+ // The destructor is intentionally commented out - no destructor
+ // vs. a do-nothing destructor makes a huge difference in
+ // inlining characteristics. It wasn't doing anything anyway.
+ // ~SafeInt(){};
+
+
+ // now start overloading operators
+ // assignment operator
+ // constructors exist for all int types and will ensure safety
+
+ template < typename U >
+ SafeInt< T, E >& operator =( const U& rhs ) SAFEINT_CPP_THROW
+ {
+ // use constructor to test size
+ // constructor is optimized to do minimal checking based
+ // on whether T can contain U
+ // note - do not change this
+ *this = SafeInt< T, E >( rhs );
+ return *this;
+ }
+
+ SafeInt< T, E >& operator =( const T& rhs ) SAFEINT_NOTHROW
+ {
+ m_int = rhs;
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator =( const SafeInt< U, E >& rhs ) SAFEINT_CPP_THROW
+ {
+ SafeCastHelper< T, U, GetCastMethod< T, U >::method >::template CastThrow< E >( rhs.Ref(), m_int );
+ return *this;
+ }
+
+ SafeInt< T, E >& operator =( const SafeInt< T, E >& rhs ) SAFEINT_NOTHROW
+ {
+ m_int = rhs.m_int;
+ return *this;
+ }
+
+ // Casting operators
+
+ operator bool() const SAFEINT_NOTHROW
+ {
+ return !!m_int;
+ }
+
+ operator char() const SAFEINT_CPP_THROW
+ {
+ char val;
+ SafeCastHelper< char, T, GetCastMethod< char, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator signed char() const SAFEINT_CPP_THROW
+ {
+ signed char val;
+ SafeCastHelper< signed char, T, GetCastMethod< signed char, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator unsigned char() const SAFEINT_CPP_THROW
+ {
+ unsigned char val;
+ SafeCastHelper< unsigned char, T, GetCastMethod< unsigned char, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator __int16() const SAFEINT_CPP_THROW
+ {
+ __int16 val;
+ SafeCastHelper< __int16, T, GetCastMethod< __int16, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator unsigned __int16() const SAFEINT_CPP_THROW
+ {
+ unsigned __int16 val;
+ SafeCastHelper< unsigned __int16, T, GetCastMethod< unsigned __int16, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator __int32() const SAFEINT_CPP_THROW
+ {
+ __int32 val;
+ SafeCastHelper< __int32, T, GetCastMethod< __int32, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator unsigned __int32() const SAFEINT_CPP_THROW
+ {
+ unsigned __int32 val;
+ SafeCastHelper< unsigned __int32, T, GetCastMethod< unsigned __int32, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ // The compiler knows that int == __int32
+ // but not that long == __int32
+ operator long() const SAFEINT_CPP_THROW
+ {
+ long val;
+ SafeCastHelper< long, T, GetCastMethod< long, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator unsigned long() const SAFEINT_CPP_THROW
+ {
+ unsigned long val;
+ SafeCastHelper< unsigned long, T, GetCastMethod< unsigned long, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator __int64() const SAFEINT_CPP_THROW
+ {
+ __int64 val;
+ SafeCastHelper< __int64, T, GetCastMethod< __int64, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator unsigned __int64() const SAFEINT_CPP_THROW
+ {
+ unsigned __int64 val;
+ SafeCastHelper< unsigned __int64, T, GetCastMethod< unsigned __int64, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED
+ operator wchar_t() const SAFEINT_CPP_THROW
+ {
+ wchar_t val;
+ SafeCastHelper< wchar_t, T, GetCastMethod< wchar_t, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+#endif
+
+#ifdef SIZE_T_CAST_NEEDED
+ // We also need an explicit cast to size_t, or the compiler will complain
+ // Apparently, only SOME compilers complain, and cl 14.00.50727.42 isn't one of them
+ // Leave here in case we decide to backport this to an earlier compiler
+ operator size_t() const SAFEINT_CPP_THROW
+ {
+ size_t val;
+ SafeCastHelper< size_t, T, GetCastMethod< size_t, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+#endif
+
+ // Also provide a cast operator for floating point types
+ operator float() const SAFEINT_CPP_THROW
+ {
+ float val;
+ SafeCastHelper< float, T, GetCastMethod< float, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ operator double() const SAFEINT_CPP_THROW
+ {
+ double val;
+ SafeCastHelper< double, T, GetCastMethod< double, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+ operator long double() const SAFEINT_CPP_THROW
+ {
+ long double val;
+ SafeCastHelper< long double, T, GetCastMethod< long double, T >::method >::template CastThrow< E >( m_int, val );
+ return val;
+ }
+
+ // If you need a pointer to the data
+ // this could be dangerous, but allows you to correctly pass
+ // instances of this class to APIs that take a pointer to an integer
+ // also see overloaded address-of operator below
+ T* Ptr() SAFEINT_NOTHROW { return &m_int; }
+ const T* Ptr() const SAFEINT_NOTHROW { return &m_int; }
+ const T& Ref() const SAFEINT_NOTHROW { return m_int; }
+
+ // Or if SafeInt< T, E >::Ptr() is inconvenient, use the overload
+ // operator &
+ // This allows you to do unsafe things!
+ // It is meant to allow you to more easily
+ // pass a SafeInt into things like ReadFile
+ T* operator &() SAFEINT_NOTHROW { return &m_int; }
+ const T* operator &() const SAFEINT_NOTHROW { return &m_int; }
+
+ // Unary operators
+ bool operator !() const SAFEINT_NOTHROW { return (!m_int) ? true : false; }
+
+ // operator + (unary)
+ // note - normally, the '+' and '-' operators will upcast to a signed int
+ // for T < 32 bits. This class changes behavior to preserve type
+ const SafeInt< T, E >& operator +() const SAFEINT_NOTHROW { return *this; }
+
+ //unary -
+
+ SafeInt< T, E > operator -() const SAFEINT_CPP_THROW
+ {
+ // Note - unsigned still performs the bitwise manipulation
+ // will warn at level 2 or higher if the value is 32-bit or larger
+ return SafeInt(NegationHelper::isSigned>::template NegativeThrow(m_int));
+ }
+
+ // prefix increment operator
+ SafeInt< T, E >& operator ++() SAFEINT_CPP_THROW
+ {
+ if( m_int != IntTraits< T >::maxInt )
+ {
+ ++m_int;
+ return *this;
+ }
+ E::SafeIntOnOverflow();
+ }
+
+ // prefix decrement operator
+ SafeInt< T, E >& operator --() SAFEINT_CPP_THROW
+ {
+ if( m_int != IntTraits< T >::minInt )
+ {
+ --m_int;
+ return *this;
+ }
+ E::SafeIntOnOverflow();
+ }
+
+ // note that postfix operators have inherently worse perf
+ // characteristics
+
+ // postfix increment operator
+ SafeInt< T, E > operator ++( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec
+ {
+ if( m_int != IntTraits< T >::maxInt )
+ {
+ SafeInt< T, E > tmp( m_int );
+
+ m_int++;
+ return tmp;
+ }
+ E::SafeIntOnOverflow();
+ }
+
+ // postfix decrement operator
+ SafeInt< T, E > operator --( int ) SAFEINT_CPP_THROW // dummy arg to comply with spec
+ {
+ if( m_int != IntTraits< T >::minInt )
+ {
+ SafeInt< T, E > tmp( m_int );
+ m_int--;
+ return tmp;
+ }
+ E::SafeIntOnOverflow();
+ }
+
+ // One's complement
+ // Note - this operator will normally change size to an int
+ // cast in return improves perf and maintains type
+ SafeInt< T, E > operator ~() const SAFEINT_NOTHROW { return SafeInt< T, E >( (T)~m_int ); }
+
+ // Binary operators
+ //
+ // arithmetic binary operators
+ // % modulus
+ // * multiplication
+ // / division
+ // + addition
+ // - subtraction
+ //
+ // For each of the arithmetic operators, you will need to
+ // use them as follows:
+ //
+ // SafeInt c = 2;
+ // SafeInt i = 3;
+ //
+ // SafeInt i2 = i op (char)c;
+ // OR
+ // SafeInt i2 = (int)i op c;
+ //
+ // The base problem is that if the lhs and rhs inputs are different SafeInt types
+ // it is not possible in this implementation to determine what type of SafeInt
+ // should be returned. You have to let the class know which of the two inputs
+ // need to be the return type by forcing the other value to the base integer type.
+ //
+ // Note - as per feedback from Scott Meyers, I'm exploring how to get around this.
+ // 3.0 update - I'm still thinking about this. It can be done with template metaprogramming,
+ // but it is tricky, and there's a perf vs. correctness tradeoff where the right answer
+ // is situational.
+ //
+ // The case of:
+ //
+ // SafeInt< T, E > i, j, k;
+ // i = j op k;
+ //
+ // works just fine and no unboxing is needed because the return type is not ambiguous.
+
+ // Modulus
+ // Modulus has some convenient properties -
+ // first, the magnitude of the return can never be
+ // larger than the lhs operand, and it must be the same sign
+ // as well. It does, however, suffer from the same promotion
+ // problems as comparisons, division and other operations
+ template < typename U >
+ SafeInt< T, E > operator %( U rhs ) const SAFEINT_CPP_THROW
+ {
+ T result;
+ ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, result );
+ return SafeInt< T, E >( result );
+ }
+
+ SafeInt< T, E > operator %( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
+ {
+ T result;
+ ModulusHelper< T, T, ValidComparison< T, T >::method >::template ModulusThrow< E >( m_int, rhs, result );
+ return SafeInt< T, E >( result );
+ }
+
+ // Modulus assignment
+ template < typename U >
+ SafeInt< T, E >& operator %=( U rhs ) SAFEINT_CPP_THROW
+ {
+ ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator %=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+ {
+ ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( m_int, (U)rhs, m_int );
+ return *this;
+ }
+
+ // Multiplication
+ template < typename U >
+ SafeInt< T, E > operator *( U rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ SafeInt< T, E > operator *( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ // Multiplication assignment
+ SafeInt< T, E >& operator *=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+ {
+ MultiplicationHelper< T, T, MultiplicationMethod< T, T >::method >::template MultiplyThrow< E >( m_int, (T)rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator *=( U rhs ) SAFEINT_CPP_THROW
+ {
+ MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator *=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+ {
+ MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( m_int, rhs.Ref(), m_int );
+ return *this;
+ }
+
+ // Division
+ template < typename U >
+ SafeInt< T, E > operator /( U rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ SafeInt< T, E > operator /( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ // Division assignment
+ SafeInt< T, E >& operator /=( SafeInt< T, E > i ) SAFEINT_CPP_THROW
+ {
+ DivisionHelper< T, T, DivisionMethod< T, T >::method >::template DivideThrow< E >( m_int, (T)i, m_int );
+ return *this;
+ }
+
+ template < typename U > SafeInt< T, E >& operator /=( U i ) SAFEINT_CPP_THROW
+ {
+ DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, i, m_int );
+ return *this;
+ }
+
+ template < typename U > SafeInt< T, E >& operator /=( SafeInt< U, E > i )
+ {
+ DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( m_int, (U)i, m_int );
+ return *this;
+ }
+
+ // For addition and subtraction
+
+ // Addition
+ SafeInt< T, E > operator +( SafeInt< T, E > rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ template < typename U >
+ SafeInt< T, E > operator +( U rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ //addition assignment
+ SafeInt< T, E >& operator +=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+ {
+ AdditionHelper< T, T, AdditionMethod< T, T >::method >::template AdditionThrow< E >( m_int, (T)rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator +=( U rhs ) SAFEINT_CPP_THROW
+ {
+ AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator +=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+ {
+ AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( m_int, (U)rhs, m_int );
+ return *this;
+ }
+
+ // Subtraction
+ template < typename U >
+ SafeInt< T, E > operator -( U rhs ) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ SafeInt< T, E > operator -(SafeInt< T, E > rhs) const SAFEINT_CPP_THROW
+ {
+ T ret( 0 );
+ SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, ret );
+ return SafeInt< T, E >( ret );
+ }
+
+ // Subtraction assignment
+ SafeInt< T, E >& operator -=( SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+ {
+ SubtractionHelper< T, T, SubtractionMethod< T, T >::method >::template SubtractThrow< E >( m_int, (T)rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator -=( U rhs ) SAFEINT_CPP_THROW
+ {
+ SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, rhs, m_int );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator -=( SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+ {
+ SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( m_int, (U)rhs, m_int );
+ return *this;
+ }
+
+ // Shift operators
+ // Note - shift operators ALWAYS return the same type as the lhs
+ // specific version for SafeInt< T, E > not needed -
+ // code path is exactly the same as for SafeInt< U, E > as rhs
+
+ // Left shift
+ // Also, shifting > bitcount is undefined - trap in debug
+#ifdef SAFEINT_DISABLE_SHIFT_ASSERT
+ #define ShiftAssert(x)
+#else
+ #define ShiftAssert(x) SAFEINT_ASSERT(x)
+#endif
+
+ template < typename U >
+ SafeInt< T, E > operator <<( U bits ) const SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );
+ ShiftAssert( bits < (int)IntTraits< T >::bitCount );
+
+ return SafeInt< T, E >( (T)( m_int << bits ) );
+ }
+
+ template < typename U >
+ SafeInt< T, E > operator <<( SafeInt< U, E > bits ) const SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );
+ ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount );
+
+ return SafeInt< T, E >( (T)( m_int << (U)bits ) );
+ }
+
+ // Left shift assignment
+
+ template < typename U >
+ SafeInt< T, E >& operator <<=( U bits ) SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );
+ ShiftAssert( bits < (int)IntTraits< T >::bitCount );
+
+ m_int <<= bits;
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator <<=( SafeInt< U, E > bits ) SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );
+ ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount );
+
+ m_int <<= (U)bits;
+ return *this;
+ }
+
+ // Right shift
+ template < typename U >
+ SafeInt< T, E > operator >>( U bits ) const SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );
+ ShiftAssert( bits < (int)IntTraits< T >::bitCount );
+
+ return SafeInt< T, E >( (T)( m_int >> bits ) );
+ }
+
+ template < typename U >
+ SafeInt< T, E > operator >>( SafeInt< U, E > bits ) const SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );
+ ShiftAssert( bits < (int)IntTraits< T >::bitCount );
+
+ return SafeInt< T, E >( (T)(m_int >> (U)bits) );
+ }
+
+ // Right shift assignment
+ template < typename U >
+ SafeInt< T, E >& operator >>=( U bits ) SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || bits >= 0 );
+ ShiftAssert( bits < (int)IntTraits< T >::bitCount );
+
+ m_int >>= bits;
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator >>=( SafeInt< U, E > bits ) SAFEINT_NOTHROW
+ {
+ ShiftAssert( !IntTraits< U >::isSigned || (U)bits >= 0 );
+ ShiftAssert( (U)bits < (int)IntTraits< T >::bitCount );
+
+ m_int >>= (U)bits;
+ return *this;
+ }
+
+ // Bitwise operators
+ // This only makes sense if we're dealing with the same type and size
+ // demand a type T, or something that fits into a type T
+
+ // Bitwise &
+ SafeInt< T, E > operator &( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW
+ {
+ return SafeInt< T, E >( m_int & (T)rhs );
+ }
+
+ template < typename U >
+ SafeInt< T, E > operator &( U rhs ) const SAFEINT_NOTHROW
+ {
+ // we want to avoid setting bits by surprise
+ // consider the case of lhs = int, value = 0xffffffff
+ // rhs = char, value = 0xff
+ //
+ // programmer intent is to get only the lower 8 bits
+ // normal behavior is to upcast both sides to an int
+ // which then sign extends rhs, setting all the bits
+
+ // If you land in the assert, this is because the bitwise operator
+ // was causing unexpected behavior. Fix is to properly cast your inputs
+ // so that it works like you meant, not unexpectedly
+
+ return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs ) );
+ }
+
+ // Bitwise & assignment
+ SafeInt< T, E >& operator &=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+ {
+ m_int &= (T)rhs;
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator &=( U rhs ) SAFEINT_NOTHROW
+ {
+ m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, rhs );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator &=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+ {
+ m_int = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( m_int, (U)rhs );
+ return *this;
+ }
+
+ // XOR
+ SafeInt< T, E > operator ^( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW
+ {
+ return SafeInt< T, E >( (T)( m_int ^ (T)rhs ) );
+ }
+
+ template < typename U >
+ SafeInt< T, E > operator ^( U rhs ) const SAFEINT_NOTHROW
+ {
+ // If you land in the assert, this is because the bitwise operator
+ // was causing unexpected behavior. Fix is to properly cast your inputs
+ // so that it works like you meant, not unexpectedly
+
+ return SafeInt< T, E >( BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs ) );
+ }
+
+ // XOR assignment
+ SafeInt< T, E >& operator ^=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+ {
+ m_int ^= (T)rhs;
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator ^=( U rhs ) SAFEINT_NOTHROW
+ {
+ m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, rhs );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator ^=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+ {
+ m_int = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( m_int, (U)rhs );
+ return *this;
+ }
+
+ // bitwise OR
+ SafeInt< T, E > operator |( SafeInt< T, E > rhs ) const SAFEINT_NOTHROW
+ {
+ return SafeInt< T, E >( (T)( m_int | (T)rhs ) );
+ }
+
+ template < typename U >
+ SafeInt< T, E > operator |( U rhs ) const SAFEINT_NOTHROW
+ {
+ return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs ) );
+ }
+
+ // bitwise OR assignment
+ SafeInt< T, E >& operator |=( SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+ {
+ m_int |= (T)rhs;
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator |=( U rhs ) SAFEINT_NOTHROW
+ {
+ m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, rhs );
+ return *this;
+ }
+
+ template < typename U >
+ SafeInt< T, E >& operator |=( SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+ {
+ m_int = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( m_int, (U)rhs );
+ return *this;
+ }
+
+ // Miscellaneous helper functions
+ SafeInt< T, E > Min( SafeInt< T, E > test, const T floor = IntTraits< T >::minInt ) const SAFEINT_NOTHROW
+ {
+ T tmp = test < m_int ? (T)test : m_int;
+ return tmp < floor ? floor : tmp;
+ }
+
+ SafeInt< T, E > Max( SafeInt< T, E > test, const T upper = IntTraits< T >::maxInt ) const SAFEINT_NOTHROW
+ {
+ T tmp = test > m_int ? (T)test : m_int;
+ return tmp > upper ? upper : tmp;
+ }
+
+ void Swap( SafeInt< T, E >& with ) SAFEINT_NOTHROW
+ {
+ T temp( m_int );
+ m_int = with.m_int;
+ with.m_int = temp;
+ }
+
+ static SafeInt< T, E > SafeAtoI( const char* input ) SAFEINT_CPP_THROW
+ {
+ return SafeTtoI( input );
+ }
+
+ static SafeInt< T, E > SafeWtoI( const wchar_t* input )
+ {
+ return SafeTtoI( input );
+ }
+
+ enum alignBits
+ {
+ align2 = 1,
+ align4 = 2,
+ align8 = 3,
+ align16 = 4,
+ align32 = 5,
+ align64 = 6,
+ align128 = 7,
+ align256 = 8
+ };
+
+ template < alignBits bits >
+ const SafeInt< T, E >& Align() SAFEINT_CPP_THROW
+ {
+ // Zero is always aligned
+ if( m_int == 0 )
+ return *this;
+
+ // We don't support aligning negative numbers at this time
+ // Can't align unsigned numbers on bitCount (e.g., 8 bits = 256, unsigned char max = 255)
+ // or signed numbers on bitCount-1 (e.g., 7 bits = 128, signed char max = 127).
+ // Also makes no sense to try to align on negative or no bits.
+
+ ShiftAssert( ( ( IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount - 1 )
+ || ( !IntTraits::isSigned && bits < (int)IntTraits< T >::bitCount ) ) &&
+ bits >= 0 && ( !IntTraits::isSigned || m_int > 0 ) );
+
+ const T AlignValue = ( (T)1 << bits ) - 1;
+
+ m_int = (T)( ( m_int + AlignValue ) & ~AlignValue );
+
+ if( m_int <= 0 )
+ E::SafeIntOnOverflow();
+
+ return *this;
+ }
+
+ // Commonly needed alignments:
+ const SafeInt< T, E >& Align2() { return Align< align2 >(); }
+ const SafeInt< T, E >& Align4() { return Align< align4 >(); }
+ const SafeInt< T, E >& Align8() { return Align< align8 >(); }
+ const SafeInt< T, E >& Align16() { return Align< align16 >(); }
+ const SafeInt< T, E >& Align32() { return Align< align32 >(); }
+ const SafeInt< T, E >& Align64() { return Align< align64 >(); }
+private:
+
+ // This is almost certainly not the best optimized version of atoi,
+ // but it does not display a typical bug where it isn't possible to set MinInt
+ // and it won't allow you to overflow your integer.
+ // This is here because it is useful, and it is an example of what
+ // can be done easily with SafeInt.
+ template < typename U >
+ static SafeInt< T, E > SafeTtoI( U* input ) SAFEINT_CPP_THROW
+ {
+ U* tmp = input;
+ SafeInt< T, E > s;
+ bool negative = false;
+
+ // Bad input, or empty string
+ if( input == nullptr || input[0] == 0 )
+ E::SafeIntOnOverflow();
+
+ switch( *tmp )
+ {
+ case '-':
+ tmp++;
+ negative = true;
+ break;
+ case '+':
+ tmp++;
+ break;
+ }
+
+ while( *tmp != 0 )
+ {
+ if( *tmp < '0' || *tmp > '9' )
+ break;
+
+ if( (T)s != 0 )
+ s *= (T)10;
+
+ if( !negative )
+ s += (T)( *tmp - '0' );
+ else
+ s -= (T)( *tmp - '0' );
+
+ tmp++;
+ }
+
+ return s;
+ }
+
+ T m_int;
+};
+
+// Helper function used to subtract pointers.
+// Used to squelch warnings
+template
+SafeInt SafePtrDiff(const P* p1, const P* p2) SAFEINT_CPP_THROW
+{
+ return SafeInt( p1 - p2 );
+}
+
+// Comparison operators
+
+//Less than
+template < typename T, typename U, typename E >
+bool operator <( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator <( SafeInt lhs, U rhs ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator <( SafeInt< U, E > lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, (U)lhs );
+}
+
+// Greater than
+template < typename T, typename U, typename E >
+bool operator >( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator >( SafeInt lhs, U rhs ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator >( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ return GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs );
+}
+
+// Greater than or equal
+template < typename T, typename U, typename E >
+bool operator >=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)rhs, lhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator >=( SafeInt lhs, U rhs ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( rhs, (T)lhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator >=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( (U)rhs, (T)lhs );
+}
+
+// Less than or equal
+template < typename T, typename U, typename E >
+bool operator <=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< U, T, ValidComparison< U, T >::method >::GreaterThan( lhs, (T)rhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator <=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, rhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator <=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ return !GreaterThanTest< T, U, ValidComparison< T, U >::method >::GreaterThan( (T)lhs, (U)rhs );
+}
+
+// equality
+// explicit overload for bool
+template < typename T, typename E >
+bool operator ==( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return lhs == ( (T)rhs == 0 ? false : true );
+}
+
+template < typename T, typename E >
+bool operator ==( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW
+{
+ return rhs == ( (T)lhs == 0 ? false : true );
+}
+
+template < typename T, typename U, typename E >
+bool operator ==( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals((T)rhs, lhs);
+}
+
+template < typename T, typename U, typename E >
+bool operator ==( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW
+{
+ return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator ==( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ return EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, (U)rhs );
+}
+
+//not equals
+template < typename T, typename U, typename E >
+bool operator !=( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)rhs, lhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator !=( SafeInt< T, E > lhs, U rhs ) SAFEINT_NOTHROW
+{
+ return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( (T)lhs, rhs );
+}
+
+template < typename T, typename U, typename E >
+bool operator !=( SafeInt< T, E > lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ return !EqualityTest< T, U, ValidComparison< T, U >::method >::IsEquals( lhs, rhs );
+}
+
+
+template < typename T, typename E >
+bool operator !=( bool lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return ( (T)rhs == 0 ? false : true ) != lhs;
+}
+
+template < typename T, typename E >
+bool operator !=( SafeInt< T, E > lhs, bool rhs ) SAFEINT_NOTHROW
+{
+ return ( (T)lhs == 0 ? false : true ) != rhs;
+}
+
+
+template < typename T, typename U, typename E, int method > class ModulusSimpleCaseHelper;
+
+template < typename T, typename E, int method > class ModulusSignedCaseHelper;
+
+template < typename T, typename E > class ModulusSignedCaseHelper < T, E, true >
+{
+public:
+ static bool SignedCase( SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_NOTHROW
+ {
+ if( (T)rhs == (T)-1 )
+ {
+ result = 0;
+ return true;
+ }
+ return false;
+ }
+};
+
+template < typename T, typename E > class ModulusSignedCaseHelper < T, E, false >
+{
+public:
+ static bool SignedCase( SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW
+ {
+ return false;
+ }
+};
+
+template < typename T, typename U, typename E >
+class ModulusSimpleCaseHelper < T, U, E, true >
+{
+public:
+ static bool ModulusSimpleCase( U lhs, SafeInt< T, E > rhs, SafeInt< T, E >& result ) SAFEINT_CPP_THROW
+ {
+ if( rhs != 0 )
+ {
+ if( ModulusSignedCaseHelper< T, E, IntTraits< T >::isSigned >::SignedCase( rhs, result ) )
+ return true;
+
+ result = SafeInt< T, E >( (T)( lhs % (T)rhs ) );
+ return true;
+ }
+
+ E::SafeIntOnDivZero();
+ }
+};
+
+template< typename T, typename U, typename E >
+class ModulusSimpleCaseHelper < T, U, E, false >
+{
+public:
+ static bool ModulusSimpleCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt< T, E >& /*result*/ ) SAFEINT_NOTHROW
+ {
+ return false;
+ }
+};
+
+// Modulus
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator %( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+{
+ // Value of return depends on sign of lhs
+ // This one may not be safe - bounds check in constructor
+ // if lhs is negative and rhs is unsigned, this will throw an exception.
+
+ // Fast-track the simple case
+ // same size and same sign
+ SafeInt< T, E > result;
+
+ if( ModulusSimpleCaseHelper< T, U, E,
+ sizeof(T) == sizeof(U) && (bool)IntTraits< T >::isSigned == (bool)IntTraits< U >::isSigned >::ModulusSimpleCase( lhs, rhs, result ) )
+ return result;
+
+ return SafeInt< T, E >( ( SafeInt< U, E >( lhs ) % (T)rhs ) );
+}
+
+// Multiplication
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator *( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( (T)rhs, lhs, ret );
+ return SafeInt< T, E >(ret);
+}
+
+template < typename T, typename U, typename E, int method > class DivisionNegativeCornerCaseHelper;
+
+template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, true >
+{
+public:
+ static bool NegativeCornerCase( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW
+ {
+ // Problem case - normal casting behavior changes meaning
+ // flip rhs to positive
+ // any operator casts now do the right thing
+ U tmp;
+
+ if( CompileConst< sizeof(T) == 4 >::Value() )
+ tmp = lhs/(U)( ~(unsigned __int32)(T)rhs + 1 );
+ else
+ tmp = lhs/(U)( ~(unsigned __int64)(T)rhs + 1 );
+
+ if( tmp <= (U)IntTraits< T >::maxInt )
+ {
+ result = SafeInt< T, E >( (T)(~(unsigned __int64)tmp + 1) );
+ return true;
+ }
+
+ // Corner case
+ T maxT = IntTraits< T >::maxInt;
+ if( tmp == (U)maxT + 1 )
+ {
+ T minT = IntTraits< T >::minInt;
+ result = SafeInt< T, E >( minT );
+ return true;
+ }
+
+ E::SafeIntOnOverflow();
+ }
+};
+
+template < typename T, typename U, typename E > class DivisionNegativeCornerCaseHelper< T, U, E, false >
+{
+public:
+ static bool NegativeCornerCase( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW
+ {
+ return false;
+ }
+};
+
+template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper;
+
+template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, true >
+{
+public:
+ static bool DivisionCornerCase1( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW
+ {
+ if( (T)rhs > 0 )
+ {
+ result = SafeInt< T, E >( lhs/(T)rhs );
+ return true;
+ }
+
+ // Now rhs is either negative, or zero
+ if( (T)rhs != 0 )
+ {
+ if( DivisionNegativeCornerCaseHelper< T, U, E, sizeof( U ) >= 4 && sizeof( T ) <= sizeof( U ) >::NegativeCornerCase( lhs, rhs, result ) )
+ return true;
+
+ result = SafeInt< T, E >(lhs/(T)rhs);
+ return true;
+ }
+
+ E::SafeIntOnDivZero();
+ }
+};
+
+template < typename T, typename U, typename E > class DivisionCornerCaseHelper < T, U, E, false >
+{
+public:
+ static bool DivisionCornerCase1( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW
+ {
+ return false;
+ }
+};
+
+template < typename T, typename U, typename E, int method > class DivisionCornerCaseHelper2;
+
+template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, true >
+{
+public:
+ static bool DivisionCornerCase2( U lhs, SafeInt< T, E > rhs, SafeInt& result ) SAFEINT_CPP_THROW
+ {
+ if( lhs == IntTraits< U >::minInt && (T)rhs == -1 )
+ {
+ // corner case of a corner case - lhs = min int, rhs = -1,
+ // but rhs is the return type, so in essence, we can return -lhs
+ // if rhs is a larger type than lhs
+ // If types are wrong, throws
+
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+#pragma warning(push)
+//cast truncates constant value
+#pragma warning(disable:4310)
+#endif
+
+ if( CompileConst::Value() )
+ result = SafeInt< T, E >( (T)( -(T)IntTraits< U >::minInt ) );
+ else
+ E::SafeIntOnOverflow();
+
+#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
+#pragma warning(pop)
+#endif
+
+ return true;
+ }
+
+ return false;
+ }
+};
+
+template < typename T, typename U, typename E > class DivisionCornerCaseHelper2 < T, U, E, false >
+{
+public:
+ static bool DivisionCornerCase2( U /*lhs*/, SafeInt< T, E > /*rhs*/, SafeInt& /*result*/ ) SAFEINT_NOTHROW
+ {
+ return false;
+ }
+};
+
+// Division
+template < typename T, typename U, typename E > SafeInt< T, E > operator /( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+{
+ // Corner case - has to be handled seperately
+ SafeInt< T, E > result;
+ if( DivisionCornerCaseHelper< T, U, E, (int)DivisionMethod< U, T >::method == (int)DivisionState_UnsignedSigned >::DivisionCornerCase1( lhs, rhs, result ) )
+ return result;
+
+ if( DivisionCornerCaseHelper2< T, U, E, SafeIntCompare< T, U >::isBothSigned >::DivisionCornerCase2( lhs, rhs, result ) )
+ return result;
+
+ // Otherwise normal logic works with addition of bounds check when casting from U->T
+ U ret;
+ DivisionHelper< U, T, DivisionMethod< U, T >::method >::template DivideThrow< E >( lhs, (T)rhs, ret );
+ return SafeInt< T, E >( ret );
+}
+
+// Addition
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator +( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( (T)rhs, lhs, ret );
+ return SafeInt< T, E >( ret );
+}
+
+// Subtraction
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator -( U lhs, SafeInt< T, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ SubtractionHelper< U, T, SubtractionMethod2< U, T >::method >::template SubtractThrow< E >( lhs, rhs.Ref(), ret );
+
+ return SafeInt< T, E >( ret );
+}
+
+// Overrides designed to deal with cases where a SafeInt is assigned out
+// to a normal int - this at least makes the last operation safe
+// +=
+template < typename T, typename U, typename E >
+T& operator +=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ AdditionHelper< T, U, AdditionMethod< T, U >::method >::template AdditionThrow< E >( lhs, (U)rhs, ret );
+ lhs = ret;
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator -=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ SubtractionHelper< T, U, SubtractionMethod< T, U >::method >::template SubtractThrow< E >( lhs, (U)rhs, ret );
+ lhs = ret;
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator *=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ MultiplicationHelper< T, U, MultiplicationMethod< T, U >::method >::template MultiplyThrow< E >( lhs, (U)rhs, ret );
+ lhs = ret;
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator /=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ DivisionHelper< T, U, DivisionMethod< T, U >::method >::template DivideThrow< E >( lhs, (U)rhs, ret );
+ lhs = ret;
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator %=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ T ret( 0 );
+ ModulusHelper< T, U, ValidComparison< T, U >::method >::template ModulusThrow< E >( lhs, (U)rhs, ret );
+ lhs = ret;
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator &=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ lhs = BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( lhs, (U)rhs );
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator ^=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ lhs = BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( lhs, (U)rhs );
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator |=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ lhs = BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( lhs, (U)rhs );
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator <<=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ lhs = (T)( SafeInt< T, E >( lhs ) << (U)rhs );
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T& operator >>=( T& lhs, SafeInt< U, E > rhs ) SAFEINT_NOTHROW
+{
+ lhs = (T)( SafeInt< T, E >( lhs ) >> (U)rhs );
+ return lhs;
+}
+
+// Specific pointer overrides
+// Note - this function makes no attempt to ensure
+// that the resulting pointer is still in the buffer, only
+// that no int overflows happened on the way to getting the new pointer
+template < typename T, typename U, typename E >
+T*& operator +=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ // Cast the pointer to a number so we can do arithmetic
+ SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs );
+ // Check first that rhs is valid for the type of ptrdiff_t
+ // and that multiplying by sizeof( T ) doesn't overflow a ptrdiff_t
+ // Next, we need to add 2 SafeInts of different types, so unbox the ptr_diff
+ // Finally, cast the number back to a pointer of the correct type
+ lhs = reinterpret_cast< T* >( (size_t)( ptr_val + (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T*& operator -=( T*& lhs, SafeInt< U, E > rhs ) SAFEINT_CPP_THROW
+{
+ // Cast the pointer to a number so we can do arithmetic
+ SafeInt< size_t, E > ptr_val = reinterpret_cast< size_t >( lhs );
+ // See above for comments
+ lhs = reinterpret_cast< T* >( (size_t)( ptr_val - (ptrdiff_t)( SafeInt< ptrdiff_t, E >( rhs ) * sizeof( T ) ) ) );
+ return lhs;
+}
+
+template < typename T, typename U, typename E >
+T*& operator *=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator /=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator %=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator &=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator ^=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator |=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator <<=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+template < typename T, typename U, typename E >
+T*& operator >>=( T*& lhs, SafeInt< U, E > ) SAFEINT_NOTHROW
+{
+ // This operator explicitly not supported
+ C_ASSERT( sizeof(T) == 0 );
+ return (lhs = NULL);
+}
+
+// Shift operators
+// NOTE - shift operators always return the type of the lhs argument
+
+// Left shift
+template < typename T, typename U, typename E >
+SafeInt< U, E > operator <<( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW
+{
+ ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 );
+ ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount );
+
+ return SafeInt< U, E >( (U)( lhs << (T)bits ) );
+}
+
+// Right shift
+template < typename T, typename U, typename E >
+SafeInt< U, E > operator >>( U lhs, SafeInt< T, E > bits ) SAFEINT_NOTHROW
+{
+ ShiftAssert( !IntTraits< T >::isSigned || (T)bits >= 0 );
+ ShiftAssert( (T)bits < (int)IntTraits< U >::bitCount );
+
+ return SafeInt< U, E >( (U)( lhs >> (T)bits ) );
+}
+
+// Bitwise operators
+// This only makes sense if we're dealing with the same type and size
+// demand a type T, or something that fits into a type T.
+
+// Bitwise &
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator &( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return SafeInt< T, E >( BinaryAndHelper< T, U, BinaryMethod< T, U >::method >::And( (T)rhs, lhs ) );
+}
+
+// Bitwise XOR
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator ^( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return SafeInt< T, E >(BinaryXorHelper< T, U, BinaryMethod< T, U >::method >::Xor( (T)rhs, lhs ) );
+}
+
+// Bitwise OR
+template < typename T, typename U, typename E >
+SafeInt< T, E > operator |( U lhs, SafeInt< T, E > rhs ) SAFEINT_NOTHROW
+{
+ return SafeInt< T, E >( BinaryOrHelper< T, U, BinaryMethod< T, U >::method >::Or( (T)rhs, lhs ) );
+}
+
+#if SAFEINT_COMPILER == GCC_COMPILER
+#pragma GCC diagnostic pop
+#endif
+
+#if SAFEINT_COMPILER == CLANG_COMPILER
+#pragma clang diagnostic pop
+#endif
+
+} // utilities
+} // safeint3
+
diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h b/src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h
new file mode 100755
index 000000000..ea28f8260
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h
@@ -0,0 +1,140 @@
+/***
+* ==++==
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* ==--==
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* Platform-dependent type definitions
+*
+* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "cpprest/details/cpprest_compat.h"
+
+#ifndef _WIN32
+# define __STDC_LIMIT_MACROS
+# include
+#else
+#include
+#endif
+
+#include "cpprest/details/SafeInt3.hpp"
+
+namespace utility
+{
+
+#ifdef _WIN32
+#define _UTF16_STRINGS
+#endif
+
+// We should be using a 64-bit size type for most situations that do
+// not involve specifying the size of a memory allocation or buffer.
+typedef uint64_t size64_t;
+
+#ifndef _WIN32
+typedef uint32_t HRESULT; // Needed for PPLX
+#endif
+
+#ifdef _UTF16_STRINGS
+//
+// On Windows, all strings are wide
+//
+typedef wchar_t char_t ;
+typedef std::wstring string_t;
+#define _XPLATSTR(x) L ## x
+typedef std::wostringstream ostringstream_t;
+typedef std::wofstream ofstream_t;
+typedef std::wostream ostream_t;
+typedef std::wistream istream_t;
+typedef std::wifstream ifstream_t;
+typedef std::wistringstream istringstream_t;
+typedef std::wstringstream stringstream_t;
+#define ucout std::wcout
+#define ucin std::wcin
+#define ucerr std::wcerr
+#else
+//
+// On POSIX platforms, all strings are narrow
+//
+typedef char char_t;
+typedef std::string string_t;
+#define _XPLATSTR(x) x
+typedef std::ostringstream ostringstream_t;
+typedef std::ofstream ofstream_t;
+typedef std::ostream ostream_t;
+typedef std::istream istream_t;
+typedef std::ifstream ifstream_t;
+typedef std::istringstream istringstream_t;
+typedef std::stringstream stringstream_t;
+#define ucout std::cout
+#define ucin std::cin
+#define ucerr std::cerr
+#endif // endif _UTF16_STRINGS
+
+#ifndef _TURN_OFF_PLATFORM_STRING
+#define U(x) _XPLATSTR(x)
+#endif // !_TURN_OFF_PLATFORM_STRING
+
+}// namespace utility
+
+typedef char utf8char;
+typedef std::string utf8string;
+typedef std::stringstream utf8stringstream;
+typedef std::ostringstream utf8ostringstream;
+typedef std::ostream utf8ostream;
+typedef std::istream utf8istream;
+typedef std::istringstream utf8istringstream;
+
+#ifdef _UTF16_STRINGS
+typedef wchar_t utf16char;
+typedef std::wstring utf16string;
+typedef std::wstringstream utf16stringstream;
+typedef std::wostringstream utf16ostringstream;
+typedef std::wostream utf16ostream;
+typedef std::wistream utf16istream;
+typedef std::wistringstream utf16istringstream;
+#else
+typedef char16_t utf16char;
+typedef std::u16string utf16string;
+typedef std::basic_stringstream utf16stringstream;
+typedef std::basic_ostringstream utf16ostringstream;
+typedef std::basic_ostream utf16ostream;
+typedef std::basic_istream utf16istream;
+typedef std::basic_istringstream utf16istringstream;
+#endif
+
+
+#if defined(_WIN32)
+// Include on everything except Windows Desktop ARM, unless explicitly excluded.
+#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)
+#if defined(WINAPI_FAMILY)
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && defined(_M_ARM)
+#define CPPREST_EXCLUDE_WEBSOCKETS
+#endif
+#else
+#if defined(_M_ARM)
+#define CPPREST_EXCLUDE_WEBSOCKETS
+#endif
+#endif
+#endif
+#endif
diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h b/src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h
new file mode 100755
index 000000000..240a33899
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h
@@ -0,0 +1,97 @@
+/***
+* ==++==
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* ==--==
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* Standard macros and definitions.
+* This header has minimal dependency on windows headers and is safe for use in the public API
+*
+* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+
+#pragma once
+
+#if defined(_WIN32) // Settings specific to Windows
+
+#if _MSC_VER >= 1900
+#define CPPREST_NOEXCEPT noexcept
+#else
+#define CPPREST_NOEXCEPT
+#endif
+
+#define CASABLANCA_UNREFERENCED_PARAMETER(x) (x)
+
+#include
+
+#else // End settings specific to Windows
+
+// Settings common to all but Windows
+
+#define __declspec(x) __attribute__ ((x))
+#define dllimport
+#define novtable /* no novtable equivalent */
+#define __assume(x) do { if (!(x)) __builtin_unreachable(); } while (false)
+#define CASABLANCA_UNREFERENCED_PARAMETER(x) (void)x
+#define CPPREST_NOEXCEPT noexcept
+
+#include
+#define _ASSERTE(x) assert(x)
+
+// No SAL on non Windows platforms
+#include "cpprest/details/nosal.h"
+
+#if not defined __cdecl
+#if defined cdecl
+#define __cdecl __attribute__ ((cdecl))
+#else
+#define __cdecl
+#endif
+
+#if defined(__ANDROID__)
+// This is needed to disable the use of __thread inside the boost library.
+// Android does not support thread local storage -- if boost is included
+// without this macro defined, it will create references to __tls_get_addr
+// which (while able to link) will not be available at runtime and prevent
+// the .so from loading.
+#define BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION
+#endif
+
+#ifdef __clang__
+#include
+#endif
+
+#endif // defined(__APPLE__)
+
+#endif
+
+
+#ifdef _NO_ASYNCRTIMP
+#define _ASYNCRTIMP
+#else
+#ifdef _ASYNCRT_EXPORT
+#define _ASYNCRTIMP __declspec(dllexport)
+#else
+#define _ASYNCRTIMP __declspec(dllimport)
+#endif
+#endif
+
+#ifdef CASABLANCA_DEPRECATION_NO_WARNINGS
+#define CASABLANCA_DEPRECATED(x)
+#else
+#define CASABLANCA_DEPRECATED(x) __declspec(deprecated(x))
+#endif
diff --git a/src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h b/src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h
new file mode 100755
index 000000000..4d7e583a7
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h
@@ -0,0 +1,89 @@
+/***
+* ==++==
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* ==--==
+*
+* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
+*
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+***/
+
+#pragma once
+// selected MS SAL annotations
+
+#ifdef _In_
+#undef _In_
+#endif
+#define _In_
+
+#ifdef _Inout_
+#undef _Inout_
+#endif
+#define _Inout_
+
+#ifdef _Out_
+#undef _Out_
+#endif
+#define _Out_
+
+#ifdef _In_z_
+#undef _In_z_
+#endif
+#define _In_z_
+
+#ifdef _Out_z_
+#undef _Out_z_
+#endif
+#define _Out_z_
+
+#ifdef _Inout_z_
+#undef _Inout_z_
+#endif
+#define _Inout_z_
+
+#ifdef _In_opt_
+#undef _In_opt_
+#endif
+#define _In_opt_
+
+#ifdef _Out_opt_
+#undef _Out_opt_
+#endif
+#define _Out_opt_
+
+#ifdef _Inout_opt_
+#undef _Inout_opt_
+#endif
+#define _Inout_opt_
+
+#ifdef _Out_writes_
+#undef _Out_writes_
+#endif
+#define _Out_writes_(x)
+
+#ifdef _Out_writes_opt_
+#undef _Out_writes_opt_
+#endif
+#define _Out_writes_opt_(x)
+
+#ifdef _In_reads_
+#undef _In_reads_
+#endif
+#define _In_reads_(x)
+
+#ifdef _Inout_updates_bytes_
+#undef _Inout_updates_bytes_
+#endif
+#define _Inout_updates_bytes_(x)
\ No newline at end of file
diff --git a/src/corehost/cli/json/casablanca/include/cpprest/json.h b/src/corehost/cli/json/casablanca/include/cpprest/json.h
new file mode 100755
index 000000000..704cbfad9
--- /dev/null
+++ b/src/corehost/cli/json/casablanca/include/cpprest/json.h
@@ -0,0 +1,1936 @@
+/***
+* ==++==
+*
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+* ==--==
+* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*
+* HTTP Library: JSON parser and writer
+*
+* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
+*
+* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+****/
+#pragma once
+
+#ifndef _CASA_JSON_H
+#define _CASA_JSON_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "cpprest/details/basic_types.h"
+#include "cpprest/asyncrt_utils.h"
+
+namespace web
+{
+/// Library for parsing and serializing JSON values to and from C++ types.
+namespace json
+{
+ // Various forward declarations.
+ namespace details
+ {
+ class _Value;
+ class _Number;
+ class _Null;
+ class _Boolean;
+ class _String;
+ class _Object;
+ class _Array;
+ template class JSON_Parser;
+ }
+
+ namespace details
+ {
+ extern bool g_keep_json_object_unsorted;
+ }
+
+ ///
+ /// Preserve the order of the name/value pairs when parsing a JSON object.
+ /// The default is false, which can yield better performance.
+ ///
+ /// true if ordering should be preserved when parsing, false otherwise.
+ /// Note this is a global setting and affects all JSON parsing done.
+ void _ASYNCRTIMP __cdecl keep_object_element_order(bool keep_order);
+
+#ifdef _WIN32
+#ifdef _DEBUG
+#define ENABLE_JSON_VALUE_VISUALIZER
+#endif
+#endif
+
+ class number;
+ class array;
+ class object;
+
+ ///
+ /// A JSON value represented as a C++ class.
+ ///
+ class value
+ {
+ public:
+ ///
+ /// This enumeration represents the various kinds of JSON values.
+ ///
+ enum value_type
+ {
+ /// Number value
+ Number,
+ /// Boolean value
+ Boolean,
+ /// String value
+ String,
+ /// Object value
+ Object,
+ /// Array value
+ Array,
+ /// Null value
+ Null
+ };
+
+ ///
+ /// Constructor creating a null value
+ ///
+ _ASYNCRTIMP value();
+
+ ///
+ /// Constructor creating a JSON number value
+ ///
+ /// The C++ value to create a JSON value from
+ _ASYNCRTIMP value(int32_t value);
+
+ ///
+ /// Constructor creating a JSON number value
+ ///
+ /// The C++ value to create a JSON value from
+ _ASYNCRTIMP value(uint32_t value);
+
+ ///
+ /// Constructor creating a JSON number value
+ ///
+ /// The C++ value to create a JSON value from
+ _ASYNCRTIMP value(int64_t value);
+
+ ///
+ /// Constructor creating a JSON number value
+ ///
+ /// The C++ value to create a JSON value from
+ _ASYNCRTIMP value(uint64_t value);
+
+ ///
+ /// Constructor creating a JSON number value
+ ///
+ /// The C++ value to create a JSON value from
+ _ASYNCRTIMP value(double value);
+
+ ///
+ /// Constructor creating a JSON Boolean value
+ ///
+ /// The C++ value to create a JSON value from
+ _ASYNCRTIMP explicit value(bool value);
+
+ ///
+ /// Constructor creating a JSON string value
+ ///
+ /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width
+ ///
+ /// This constructor has O(n) performance because it tries to determine if
+ /// specified string has characters that should be properly escaped in JSON.
+ ///
+ _ASYNCRTIMP explicit value(utility::string_t value);
+
+ ///
+ /// Constructor creating a JSON string value specifying if the string contains characters to escape
+ ///
+ /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width
+ /// Whether contains characters
+ /// that should be escaped in JSON value
+ ///
+ /// This constructor has O(1) performance.
+ ///
+ _ASYNCRTIMP explicit value(utility::string_t value, bool has_escape_chars);
+
+ ///
+ /// Constructor creating a JSON string value
+ ///
+ /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width
+ ///
+ ///
+ /// This constructor has O(n) performance because it tries to determine if
+ /// specified string has characters that should be properly escaped in JSON.
+ ///
+ ///
+ /// This constructor exists in order to avoid string literals matching another constructor,
+ /// as is very likely. For example, conversion to bool does not require a user-defined conversion,
+ /// and will therefore match first, which means that the JSON value turns up as a boolean.
+ ///
+ ///
+ _ASYNCRTIMP explicit value(const utility::char_t* value);
+
+ ///
+ /// Constructor creating a JSON string value
+ ///
+ /// The C++ value to create a JSON value from, a C++ STL string of the platform-native character width
+ /// Whether contains characters
+ ///
+ ///
+ /// This overload has O(1) performance.
+ ///
+ ///
+ /// This constructor exists in order to avoid string literals matching another constructor,
+ /// as is very likely. For example, conversion to bool does not require a user-defined conversion,
+ /// and will therefore match first, which means that the JSON value turns up as a boolean.
+ ///
+ ///
+ _ASYNCRTIMP explicit value(const utility::char_t* value, bool has_escape_chars);
+
+ ///
+ /// Copy constructor
+ ///
+ _ASYNCRTIMP value(const value &);
+
+ ///
+ /// Move constructor
+ ///
+ _ASYNCRTIMP value(value &&) CPPREST_NOEXCEPT ;
+
+ ///
+ /// Assignment operator.
+ ///
+ /// The JSON value object that contains the result of the assignment.
+ _ASYNCRTIMP value &operator=(const value &);
+
+ ///
+ /// Move assignment operator.
+ ///
+ /// The JSON value object that contains the result of the assignment.
+ _ASYNCRTIMP value &operator=(value &&) CPPREST_NOEXCEPT ;
+
+ // Static factories
+
+ ///
+ /// Creates a null value
+ ///
+ /// A JSON null value
+ static _ASYNCRTIMP value __cdecl null();
+
+ ///
+ /// Creates a number value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON number value
+ static _ASYNCRTIMP value __cdecl number(double value);
+
+ ///
+ /// Creates a number value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON number value
+ static _ASYNCRTIMP value __cdecl number(int32_t value);
+
+ ///
+ /// Creates a number value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON number value
+ static _ASYNCRTIMP value __cdecl number(uint32_t value);
+
+ ///
+ /// Creates a number value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON number value
+ static _ASYNCRTIMP value __cdecl number(int64_t value);
+
+ ///
+ /// Creates a number value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON number value
+ static _ASYNCRTIMP value __cdecl number(uint64_t value);
+
+ ///
+ /// Creates a Boolean value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON Boolean value
+ static _ASYNCRTIMP value __cdecl boolean(bool value);
+
+ ///
+ /// Creates a string value
+ ///
+ /// The C++ value to create a JSON value from
+ /// A JSON string value
+ ///
+ /// This overload has O(n) performance because it tries to determine if
+ /// specified string has characters that should be properly escaped in JSON.
+ ///
+ static _ASYNCRTIMP value __cdecl string(utility::string_t value);
+
+ ///
+ /// Creates a string value specifying if the string contains characters to escape
+ ///
+ /// The C++ value to create a JSON value from
+ /// Whether contains characters
+ /// that should be escaped in JSON value
+ /// A JSON string value
+ ///
+ /// This overload has O(1) performance.
+ ///
+ static _ASYNCRTIMP value __cdecl string(utility::string_t value, bool has_escape_chars);
+
+#ifdef _WIN32
+private:
+ // Only used internally by JSON parser.
+ static _ASYNCRTIMP value __cdecl string(const std::string &value);
+public:
+#endif
+
+ ///
+ /// Creates an object value
+ ///
+ /// Whether to preserve the original order of the fields
+ /// An empty JSON object value
+ static _ASYNCRTIMP json::value __cdecl object(bool keep_order = false);
+
+ ///
+ /// Creates an object value from a collection of field/values
+ ///
+ /// Field names associated with JSON values
+ /// Whether to preserve the original order of the fields
+ /// A non-empty JSON object value
+ static _ASYNCRTIMP json::value __cdecl object(std::vector> fields, bool keep_order = false);
+
+ ///
+ /// Creates an empty JSON array
+ ///
+ /// An empty JSON array value
+ static _ASYNCRTIMP json::value __cdecl array();
+
+ ///
+ /// Creates a JSON array
+ ///
+ /// The initial number of elements of the JSON value
+ /// A JSON array value
+ static _ASYNCRTIMP json::value __cdecl array(size_t size);
+
+ ///
+ /// Creates a JSON array
+ ///
+ /// A vector of JSON values
+ /// A JSON array value
+ static _ASYNCRTIMP json::value __cdecl array(std::vector elements);
+
+ ///
+ /// Accesses the type of JSON value the current value instance is
+ ///
+ /// The value's type
+ _ASYNCRTIMP json::value::value_type type() const;
+
+ ///
+ /// Is the current value a null value?
+ ///
+ /// true if the value is a null value, false otherwise
+ bool is_null() const { return type() == Null; };
+
+ ///
+ /// Is the current value a number value?
+ ///
+ /// true if the value is a number value, false otherwise
+ bool is_number() const { return type() == Number; }
+
+ ///
+ /// Is the current value represented as an integer number value?
+ ///
+ ///
+ /// Note that if a json value is a number but represented as a double it can still
+ /// be retrieved as a integer using as_integer(), however the value will be truncated.
+ ///
+ /// true if the value is an integer value, false otherwise.
+ _ASYNCRTIMP bool is_integer() const;
+
+ ///
+ /// Is the current value represented as an double number value?
+ ///
+ ///
+ /// Note that if a json value is a number but represented as a int it can still
+ /// be retrieved as a double using as_double().
+ ///
+ /// true if the value is an double value, false otherwise.
+ _ASYNCRTIMP bool is_double() const;
+
+ ///
+ /// Is the current value a Boolean value?
+ ///
+ /// true if the value is a Boolean value, false otherwise
+ bool is_boolean() const { return type() == Boolean; }
+
+ ///
+ /// Is the current value a string value?
+ ///
+ /// true if the value is a string value, false otherwise
+ bool is_string() const { return type() == String; }
+
+ ///
+ /// Is the current value an array?
+ ///
+ /// true if the value is an array, false otherwise
+ bool is_array() const { return type() == Array; }
+
+ ///
+ /// Is the current value an object?
+ ///
+ /// true if the value is an object, false otherwise
+ bool is_object() const { return type() == Object; }
+
+ ///
+ /// Gets the number of children of the value.
+ ///
+ /// The number of children. 0 for all non-composites.
+ size_t size() const;
+
+ ///
+ /// Parses a string and construct a JSON value.
+ ///
+ /// The C++ value to create a JSON value from, a C++ STL double-byte string
+ _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value);
+
+ ///
+ /// Attempts to parse a string and construct a JSON value.
+ ///
+ /// The C++ value to create a JSON value from, a C++ STL double-byte string
+ /// If parsing fails, the error code is greater than 0
+ /// The parsed object. Returns web::json::value::null if failed
+ _ASYNCRTIMP static value __cdecl parse(const utility::string_t &value, std::error_code &errorCode);
+
+ ///
+ /// Serializes the current JSON value to a C++ string.
+ ///
+ /// A string representation of the value
+ _ASYNCRTIMP utility::string_t serialize() const;
+
+ ///
+ /// Serializes the current JSON value to a C++ string.
+ ///
+ /// A string representation of the value
+ CASABLANCA_DEPRECATED("This API is deprecated and has been renamed to avoid confusion with as_string(), use ::web::json::value::serialize() instead.")
+ _ASYNCRTIMP utility::string_t to_string() const;
+
+ ///
+ /// Parses a JSON value from the contents of an input stream using the native platform character width.
+ ///
+ /// The stream to read the JSON value from
+ /// The JSON value object created from the input stream.
+ _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input);
+
+ ///
+ /// Parses a JSON value from the contents of an input stream using the native platform character width.
+ ///
+ /// The stream to read the JSON value from
+ /// If parsing fails, the error code is greater than 0
+ /// The parsed object. Returns web::json::value::null if failed
+ _ASYNCRTIMP static value __cdecl parse(utility::istream_t &input, std::error_code &errorCode);
+
+ ///
+ /// Writes the current JSON value to a stream with the native platform character width.
+ ///
+ /// The stream that the JSON string representation should be written to.
+ _ASYNCRTIMP void serialize(utility::ostream_t &stream) const;
+
+#ifdef _WIN32
+ ///
+ /// Parses a JSON value from the contents of a single-byte (UTF8) stream.
+ ///
+ /// The stream to read the JSON value from
+ _ASYNCRTIMP static value __cdecl parse(std::istream& stream);
+
+ ///
+ /// Parses a JSON value from the contents of a single-byte (UTF8) stream.
+ ///
+ /// The stream to read the JSON value from
+ /// If parsing fails, the error code is greater than 0
+ /// The parsed object. Returns web::json::value::null if failed
+ _ASYNCRTIMP static value __cdecl parse(std::istream& stream, std::error_code& error);
+
+ ///
+ /// Serializes the content of the value into a single-byte (UTF8) stream.
+ ///
+ /// The stream that the JSON string representation should be written to.
+ _ASYNCRTIMP void serialize(std::ostream& stream) const;
+#endif
+
+ ///
+ /// Converts the JSON value to a C++ double, if and only if it is a number value.
+ /// Throws if the value is not a number
+ ///
+ /// A double representation of the value
+ _ASYNCRTIMP double as_double() const;
+
+ ///
+ /// Converts the JSON value to a C++ integer, if and only if it is a number value.
+ /// Throws if the value is not a number
+ ///
+ /// An integer representation of the value
+ _ASYNCRTIMP int as_integer() const;
+
+ ///
+ /// Converts the JSON value to a number class, if and only if it is a number value.
+ /// Throws if the value is not a number
+ ///
+ /// An instance of number class
+ _ASYNCRTIMP const json::number& as_number() const;
+
+ ///
+ /// Converts the JSON value to a C++ bool, if and only if it is a Boolean value.
+ ///
+ /// A C++ bool representation of the value
+ _ASYNCRTIMP bool as_bool() const;
+
+ ///
+ /// Converts the JSON value to a json array, if and only if it is an array value.
+ ///
+ /// The returned json::array should have the same or shorter lifetime as this
+ /// An array representation of the value
+ _ASYNCRTIMP json::array& as_array();
+
+ ///
+ /// Converts the JSON value to a json array, if and only if it is an array value.
+ ///
+ /// The returned json::array should have the same or shorter lifetime as this
+ /// An array representation of the value
+ _ASYNCRTIMP const json::array& as_array() const;
+
+ ///
+ /// Converts the JSON value to a json object, if and only if it is an object value.
+ ///
+ /// An object representation of the value
+ _ASYNCRTIMP json::object& as_object();
+
+ ///
+ /// Converts the JSON value to a json object, if and only if it is an object value.
+ ///
+ /// An object representation of the value
+ _ASYNCRTIMP const json::object& as_object() const;
+
+ ///
+ /// Converts the JSON value to a C++ STL string, if and only if it is a string value.
+ ///
+ /// A C++ STL string representation of the value
+ _ASYNCRTIMP const utility::string_t& as_string() const;
+
+ ///
+ /// Compares two JSON values for equality.
+ ///
+ /// The JSON value to compare with.
+ /// True iff the values are equal.
+ _ASYNCRTIMP bool operator==(const value& other) const;
+
+ ///
+ /// Compares two JSON values for inequality.
+ ///
+ /// The JSON value to compare with.
+ /// True iff the values are unequal.
+ bool operator!=(const value& other) const
+ {
+ return !((*this) == other);
+ }
+
+ ///
+ /// Tests for the presence of a field.
+ ///
+ /// The name of the field
+ /// True if the field exists, false otherwise.
+ bool has_field(const utility::string_t &key) const;
+
+ ///
+ /// Accesses a field of a JSON object.
+ ///
+ /// The name of the field
+ /// The value kept in the field; null if the field does not exist
+ CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, use json::value::at() instead.")
+ value get(const utility::string_t &key) const;
+
+ ///
+ /// Erases an element of a JSON array. Throws if index is out of bounds.
+ ///
+ /// The index of the element to erase in the JSON array.
+ _ASYNCRTIMP void erase(size_t index);
+
+ ///
+ /// Erases an element of a JSON object. Throws if the key doesn't exist.
+ ///
+ /// The key of the element to erase in the JSON object.
+ _ASYNCRTIMP void erase(const utility::string_t &key);
+
+ ///
+ /// Accesses an element of a JSON array. Throws when index out of bounds.
+ ///
+ /// The index of an element in the JSON array.
+ /// A reference to the value.
+ _ASYNCRTIMP json::value& at(size_t index);
+
+ ///
+ /// Accesses an element of a JSON array. Throws when index out of bounds.
+ ///
+ /// The index of an element in the JSON array.
+ /// A reference to the value.
+ _ASYNCRTIMP const json::value& at(size_t index) const;
+
+ ///
+ /// Accesses an element of a JSON object. If the key doesn't exist, this method throws.
+ ///
+ /// The key of an element in the JSON object.
+ /// If the key exists, a reference to the value.
+ _ASYNCRTIMP json::value& at(const utility::string_t& key);
+
+ ///
+ /// Accesses an element of a JSON object. If the key doesn't exist, this method throws.
+ ///
+ /// The key of an element in the JSON object.
+ /// If the key exists, a reference to the value.
+ _ASYNCRTIMP const json::value& at(const utility::string_t& key) const;
+
+ ///
+ /// Accesses a field of a JSON object.
+ ///
+ /// The name of the field
+ /// A reference to the value kept in the field.
+ _ASYNCRTIMP value & operator [] (const utility::string_t &key);
+
+#ifdef _WIN32
+private:
+ // Only used internally by JSON parser
+ _ASYNCRTIMP value & operator [] (const std::string &key)
+ {
+ // JSON object stores its field map as a unordered_map of string_t, so this conversion is hard to avoid
+ return operator[](utility::conversions::to_string_t(key));
+ }
+public:
+#endif
+
+ ///
+ /// Accesses an element of a JSON array.
+ ///
+ /// The index of an element in the JSON array
+ /// The value kept at the array index; null if outside the boundaries of the array
+ CASABLANCA_DEPRECATED("This API is deprecated and will be removed in a future release, use json::value::at() instead.")
+ value get(size_t index) const;
+
+ ///
+ /// Accesses an element of a JSON array.
+ ///
+ /// The index of an element in the JSON array.
+ /// A reference to the value kept in the field.
+ _ASYNCRTIMP value & operator [] (size_t index);
+
+ private:
+ friend class web::json::details::_Object;
+ friend class web::json::details::_Array;
+ template friend class web::json::details::JSON_Parser;
+
+#ifdef _WIN32
+ ///
+ /// Writes the current JSON value as a double-byte string to a string instance.
+ ///
+ /// The string that the JSON representation should be written to.
+ _ASYNCRTIMP void format(std::basic_string &string) const;
+#endif
+ ///
+ /// Serializes the content of the value into a string instance in UTF8 format
+ ///
+ /// The string that the JSON representation should be written to
+ _ASYNCRTIMP void format(std::basic_string& string) const;
+
+#ifdef ENABLE_JSON_VALUE_VISUALIZER
+ explicit value(std::unique_ptr v, value_type kind) : m_value(std::move(v)), m_kind(kind)
+#else
+ explicit value(std::unique_ptr v) : m_value(std::move(v))
+#endif
+ {}
+
+ std::unique_ptr m_value;
+#ifdef ENABLE_JSON_VALUE_VISUALIZER
+ value_type m_kind;
+#endif
+ };
+
+ ///
+ /// A single exception type to represent errors in parsing, converting, and accessing
+ /// elements of JSON values.
+ ///
+ class json_exception : public std::exception
+ {
+ private:
+ std::string _message;
+ public:
+ json_exception(const utility::char_t * const &message) : _message(utility::conversions::to_utf8string(message)) { }
+
+ // Must be narrow string because it derives from std::exception
+ const char* what() const CPPREST_NOEXCEPT
+ {
+ return _message.c_str();
+ }
+ };
+
+ namespace details
+ {
+ enum json_error
+ {
+ left_over_character_in_stream = 1,
+ malformed_array_literal,
+ malformed_comment,
+ malformed_literal,
+ malformed_object_literal,
+ malformed_numeric_literal,
+ malformed_string_literal,
+ malformed_token,
+ mismatched_brances,
+ nesting,
+ unexpected_token
+ };
+
+ class json_error_category_impl : public std::error_category
+ {
+ public:
+ virtual const char* name() const CPPREST_NOEXCEPT override
+ {
+ return "json";
+ }
+
+ virtual std::string message(int ev) const override
+ {
+ switch (ev)
+ {
+ case json_error::left_over_character_in_stream:
+ return "Left-over characters in stream after parsing a JSON value";
+ case json_error::malformed_array_literal:
+ return "Malformed array literal";
+ case json_error::malformed_comment:
+ return "Malformed comment";
+ case json_error::malformed_literal:
+ return "Malformed literal";
+ case json_error::malformed_object_literal:
+ return "Malformed object literal";
+ case json_error::malformed_numeric_literal:
+ return "Malformed numeric literal";
+ case json_error::malformed_string_literal:
+ return "Malformed string literal";
+ case json_error::malformed_token:
+ return "Malformed token";
+ case json_error::mismatched_brances:
+ return "Mismatched braces";
+ case json_error::nesting:
+ return "Nesting too deep";
+ case json_error::unexpected_token:
+ return "Unexpected token";
+ default:
+ return "Unknown json error";
+ }
+ }
+ };
+
+ const json_error_category_impl& json_error_category();
+ }
+
+ ///
+ /// A JSON array represented as a C++ class.
+ ///
+ class array
+ {
+ typedef std::vector storage_type;
+
+ public:
+ typedef storage_type::iterator iterator;
+ typedef storage_type::const_iterator const_iterator;
+ typedef storage_type::reverse_iterator reverse_iterator;
+ typedef storage_type::const_reverse_iterator const_reverse_iterator;
+ typedef storage_type::size_type size_type;
+
+ private:
+ array() : m_elements() { }
+ array(size_type size) : m_elements(size) { }
+ array(storage_type elements) : m_elements(std::move(elements)) { }
+
+ public:
+ ///