Shared FX and Portable Support for Unified Host
- Add Casablanca CPP Rest SDK to corehost
    - Correct understanding of portable runtimeTargets section
    - Fix minor issues and automation for RID
    - CLI Build Integration
    - Add API to consume deps files
    - Unix doesn't like major as a variable name
    - Define NOMINMAX for Windows.h
    - Support APP_CONTEXT_DEPS_FILES
    - mscorlib.ni can come from native
    - Append Dotnet.dll to sdk path
    - Muxer vs standalone distinction based on own name.dll
	
	
This commit is contained in:
		
					parent
					
						
							
								6bd9d80fed
							
						
					
				
			
			
				commit
				
					
						f615f74a39
					
				
			
		
					 49 changed files with 14979 additions and 592 deletions
				
			
		| 
						 | 
				
			
			@ -70,15 +70,20 @@ namespace Microsoft.DotNet.Cli.Build
 | 
			
		|||
            var configuration = c.BuildContext.Get<string>("Configuration");
 | 
			
		||||
 | 
			
		||||
            // Run the build
 | 
			
		||||
            string version = DotNetCli.Stage0.Exec("", "--version").CaptureStdOut().Execute().StdOut;
 | 
			
		||||
            string rid = Array.Find<string>(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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
             
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -42,7 +41,7 @@ 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,24 +77,27 @@ 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<pal::string_t, pal::string_t> opts;
 | 
			
		||||
    std::vector<pal::string_t> 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())
 | 
			
		||||
    {
 | 
			
		||||
        const auto& app_base = args.app_dir;
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										144
									
								
								src/corehost/cli/deps_entry.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/corehost/cli/deps_entry.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								src/corehost/cli/deps_entry.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/corehost/cli/deps_entry.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#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_
 | 
			
		||||
							
								
								
									
										305
									
								
								src/corehost/cli/deps_format.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								src/corehost/cli/deps_format.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <unordered_set>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
const std::array<const pal::char_t*, deps_entry_t::asset_types::count> 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<bool(const pal::string_t&)>& library_exists_fn,
 | 
			
		||||
    const std::function<const std::vector<pal::string_t>&(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<pal::string_t>& {
 | 
			
		||||
        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<pal::string_t>& {
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										113
									
								
								src/corehost/cli/deps_format.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/corehost/cli/deps_format.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "pal.h"
 | 
			
		||||
#include "deps_entry.h"
 | 
			
		||||
#include "cpprest/json.h"
 | 
			
		||||
 | 
			
		||||
class deps_json_t
 | 
			
		||||
{
 | 
			
		||||
    typedef web::json::value json_value;
 | 
			
		||||
    typedef std::array<std::vector<pal::string_t>, deps_entry_t::asset_types::count> vectors_t;
 | 
			
		||||
    typedef std::unordered_map<pal::string_t, vectors_t> str_to_vectors_map_t;
 | 
			
		||||
    typedef std::unordered_map<pal::string_t, std::vector<pal::string_t>> 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<pal::string_t, str_to_vectors_map_t> 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<deps_entry_t>& 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<bool(const pal::string_t&)>& library_exists_fn,
 | 
			
		||||
        const std::function<const std::vector<pal::string_t>&(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<const pal::char_t*, deps_entry_t::asset_types::count> s_known_asset_types;
 | 
			
		||||
 | 
			
		||||
    std::vector<deps_entry_t> m_deps_entries[deps_entry_t::asset_types::count];
 | 
			
		||||
 | 
			
		||||
	std::unordered_map<pal::string_t, int> 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<deps_entry_t>& get_entries() { return m_deps_entries; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::vector<deps_entry_t> m_deps_entries;
 | 
			
		||||
    bool m_valid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // __DEPS_FORMAT_H_
 | 
			
		||||
| 
						 | 
				
			
			@ -6,80 +6,12 @@
 | 
			
		|||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
#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<pal::string_t>* 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<pal::char_t> 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<std::vector<deps_entry_t>, 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<pal::string_t, pal::string_t>* 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<deps_entry_t> 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<pal::string_t> 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<pal::string_t(const pal::string_t&)> culture = [] (const pal::string_t& str) {
 | 
			
		||||
    std::function<pal::string_t(const pal::string_t&)> 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<pal::string_t(const pal::string_t&)> native = [] (const pal::string_t& str) {
 | 
			
		||||
        return get_directory(str);
 | 
			
		||||
    };
 | 
			
		||||
    std::function<pal::string_t(const pal::string_t&)>& action = (asset_type == _X("culture")) ? culture : native;
 | 
			
		||||
 | 
			
		||||
    std::function<pal::string_t(const pal::string_t&)>& 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<pal::string_t> items;
 | 
			
		||||
 | 
			
		||||
    std::vector<deps_entry_t> 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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<deps_json_t>(new deps_json_t(false, m_fx_deps_file));
 | 
			
		||||
            m_deps = std::unique_ptr<deps_json_t>(new deps_json_t(true, m_deps_file, m_fx_deps->get_rid_fallback_graph()));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            m_deps = std::unique_ptr<deps_json_t>(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<pal::string_t, pal::string_t>* 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<pal::string_t, pal::string_t> m_local_assemblies;
 | 
			
		||||
 | 
			
		||||
    // Entries in the dep file
 | 
			
		||||
    std::vector<deps_entry_t> m_deps_entries;
 | 
			
		||||
    // Map of simple name -> full path of local/fx assemblies populated
 | 
			
		||||
    // in priority order of their extensions.
 | 
			
		||||
    std::unordered_map<pal::string_t, pal::string_t> 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<deps_json_t> m_fx_deps;
 | 
			
		||||
 | 
			
		||||
    // Deps files for the app
 | 
			
		||||
    std::unique_ptr<deps_json_t>  m_deps;
 | 
			
		||||
 | 
			
		||||
    // Is the deps file valid
 | 
			
		||||
    bool m_deps_valid;
 | 
			
		||||
 | 
			
		||||
    // Is the deps file portable app?
 | 
			
		||||
    bool m_portable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // DEPS_RESOLVER_H
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										45
									
								
								src/corehost/cli/fxr/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/corehost/cli/fxr/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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($<$<CONFIG:RelWithDebInfo>:/MT>)
 | 
			
		||||
    add_compile_options($<$<CONFIG:Release>:/MT>)
 | 
			
		||||
    add_compile_options($<$<CONFIG:Debug>:/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})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										298
									
								
								src/corehost/cli/fxr/fx_muxer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								src/corehost/cli/fxr/fx_muxer.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <cassert>
 | 
			
		||||
#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<pal::string_t> 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<pal::string_t> 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<pal::string_t> known_opts = { _X("--depsfile"), _X("--additionalprobingpath") };
 | 
			
		||||
 | 
			
		||||
            int num_args = 0;
 | 
			
		||||
            std::unordered_map<pal::string_t, pal::string_t> 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<const pal::char_t*> 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<const pal::char_t*> 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/corehost/cli/fxr/fx_muxer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/corehost/cli/fxr/fx_muxer.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										168
									
								
								src/corehost/cli/fxr/fx_ver.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/corehost/cli/fxr/fx_ver.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <cassert>
 | 
			
		||||
#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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/corehost/cli/fxr/fx_ver.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/corehost/cli/fxr/fx_ver.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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,21 +61,23 @@ 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
 | 
			
		||||
        tpa_paths_cstr.c_str(),
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								src/corehost/cli/json/casablanca/LICENSE.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/corehost/cli/json/casablanca/LICENSE.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
https://github.com/Microsoft/cpprestsdk
 | 
			
		||||
							
								
								
									
										600
									
								
								src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										600
									
								
								src/corehost/cli/json/casablanca/include/cpprest/asyncrt_utils.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <system_error>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <locale.h>
 | 
			
		||||
 | 
			
		||||
#include "cpprest/details/basic_types.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(_WIN32) || (_MSC_VER >= 1700)
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
//#include <boost/algorithm/string.hpp>
 | 
			
		||||
#if !defined(ANDROID) && !defined(__ANDROID__) // CodePlex 269
 | 
			
		||||
#include <xlocale.h>
 | 
			
		||||
#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
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts a timespan/interval in seconds to xml duration string as specified by
 | 
			
		||||
    /// http://www.w3.org/TR/xmlschema-2/#duration
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl seconds_to_xml_duration(utility::seconds numSecs);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts an xml duration to timespan/interval in seconds
 | 
			
		||||
    /// http://www.w3.org/TR/xmlschema-2/#duration
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    _ASYNCRTIMP utility::seconds __cdecl xml_duration_to_seconds(const utility::string_t ×panString);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Functions for Unicode string conversions.
 | 
			
		||||
namespace conversions
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts a UTF-16 string to a UTF-8 string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="w">A two byte character UTF-16 string.</param>
 | 
			
		||||
    /// <returns>A single byte character UTF-8 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts a UTF-8 string to a UTF-16
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A two byte character UTF-16 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts a ASCII (us-ascii) string to a UTF-16 string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A single byte character us-ascii string.</param>
 | 
			
		||||
    /// <returns>A two byte character UTF-16 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utf16string __cdecl usascii_to_utf16(const std::string &s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts a Latin1 (iso-8859-1) string to a UTF-16 string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A two byte character UTF-16 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utf16string __cdecl latin1_to_utf16(const std::string &s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts a Latin1 (iso-8859-1) string to a UTF-8 string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A single byte character UTF-8 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utf8string __cdecl latin1_to_utf8(const std::string &s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a platform dependent Unicode string type.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A platform dependent string type.</returns>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(std::string &&s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a platform dependent Unicode string type.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A two byte character UTF-16 string.</param>
 | 
			
		||||
    /// <returns>A platform dependent string type.</returns>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(utf16string &&s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a platform dependent Unicode string type.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A platform dependent string type.</returns>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(const std::string &s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a platform dependent Unicode string type.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="s">A two byte character UTF-16 string.</param>
 | 
			
		||||
    /// <returns>A platform dependent string type.</returns>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl to_string_t(const utf16string &s);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a UTF-16 from string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="value">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A two byte character UTF-16 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utf16string __cdecl to_utf16string(const std::string &value);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a UTF-16 from string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="value">A two byte character UTF-16 string.</param>
 | 
			
		||||
    /// <returns>A two byte character UTF-16 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utf16string __cdecl to_utf16string(utf16string value);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a UTF-8 string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="value">A single byte character UTF-8 string.</param>
 | 
			
		||||
    /// <returns>A single byte character UTF-8 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP std::string __cdecl to_utf8string(std::string value);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Converts to a UTF-8 string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="value">A two byte character UTF-16 string.</param>
 | 
			
		||||
    /// <returns>A single byte character UTF-8 string.</returns>
 | 
			
		||||
    _ASYNCRTIMP std::string __cdecl to_utf8string(const utf16string &value);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Encode the given byte array into a base64 string
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl to_base64(const std::vector<unsigned char>& data);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Encode the given 8-byte integer into a base64 string
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t __cdecl to_base64(uint64_t data);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Decode the given base64 string to a byte array
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    _ASYNCRTIMP std::vector<unsigned char> __cdecl from_base64(const utility::string_t& str);
 | 
			
		||||
 | 
			
		||||
    template <typename Source>
 | 
			
		||||
    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 <typename Source>
 | 
			
		||||
    utility::string_t print_string(const Source &val)
 | 
			
		||||
    {
 | 
			
		||||
        return print_string(val, std::locale());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Target>
 | 
			
		||||
    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 <typename Target>
 | 
			
		||||
    Target scan_string(const utility::string_t &str)
 | 
			
		||||
    {
 | 
			
		||||
        return scan_string<Target>(str, std::locale());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace details
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Cross platform RAII container for setting thread local locale.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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 &);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Our own implementation of alpha numeric instead of std::isalnum to avoid
 | 
			
		||||
    /// taking global lock for performance reasons.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    inline bool __cdecl is_alnum(char ch)
 | 
			
		||||
    {
 | 
			
		||||
        return (ch >= '0' && ch <= '9')
 | 
			
		||||
            || (ch >= 'A' && ch <= 'Z')
 | 
			
		||||
            || (ch >= 'a' && ch <= 'z');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
 | 
			
		||||
    /// and therefore not be compatible with Dev10.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    template <typename _Type>
 | 
			
		||||
    std::unique_ptr<_Type> make_unique() {
 | 
			
		||||
        return std::unique_ptr<_Type>(new _Type());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename _Type, typename _Arg1>
 | 
			
		||||
    std::unique_ptr<_Type> make_unique(_Arg1&& arg1) {
 | 
			
		||||
        return std::unique_ptr<_Type>(new _Type(std::forward<_Arg1>(arg1)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename _Type, typename _Arg1, typename _Arg2>
 | 
			
		||||
    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 <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3>
 | 
			
		||||
    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 <typename _Type, typename _Arg1, typename _Arg2, typename _Arg3, typename _Arg4>
 | 
			
		||||
    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)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Cross platform utility function for performing case insensitive string comparision.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="left">First string to compare.</param>
 | 
			
		||||
    /// <param name="right">Second strong to compare.</param>
 | 
			
		||||
    /// <returns>true if the strings are equivalent, false otherwise</returns>
 | 
			
		||||
/*    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
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Category error type for Windows OS errors.
 | 
			
		||||
/// </summary>
 | 
			
		||||
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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Gets the one global instance of the windows error category.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// </returns>An error category instance.</returns>
 | 
			
		||||
_ASYNCRTIMP const std::error_category & __cdecl windows_category();
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Gets the one global instance of the linux error category.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// </returns>An error category instance.</returns>
 | 
			
		||||
_ASYNCRTIMP const std::error_category & __cdecl linux_category();
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Gets the one global instance of the current platform's error category.
 | 
			
		||||
/// <summary>
 | 
			
		||||
_ASYNCRTIMP const std::error_category & __cdecl platform_category();
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Creates an instance of std::system_error from a OS error code.
 | 
			
		||||
/// </summary>
 | 
			
		||||
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());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Creates a std::error_code from a OS error code.
 | 
			
		||||
/// </summary>
 | 
			
		||||
inline std::error_code __cdecl create_error_code(unsigned long errorCode)
 | 
			
		||||
{
 | 
			
		||||
    return std::error_code((int)errorCode, platform_category());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Creates the corresponding error message from a OS error code.
 | 
			
		||||
/// </summary>
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Defines the supported date and time string formats.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    enum date_format { RFC_1123, ISO_8601 };
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the current UTC time.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    // static _ASYNCRTIMP datetime __cdecl utc_now();
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// An invalid UTC timestamp value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    enum:interval_type { utc_timestamp_invalid = static_cast<interval_type>(-1) };
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns seconds since Unix/POSIX time epoch at 01-01-1970 00:00:00.
 | 
			
		||||
    /// If time is before epoch, utc_timestamp_invalid is returned.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /*
 | 
			
		||||
    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)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Creates <c>datetime</c> from a string representing time in UTC in RFC 1123 format.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>Returns a <c>datetime</c> of zero if not successful.</returns>
 | 
			
		||||
    // static _ASYNCRTIMP datetime __cdecl from_string(const utility::string_t& timestring, date_format format = RFC_1123);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns a string representation of the <c>datetime</c>.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t to_string(date_format format = RFC_1123) const;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the integral time value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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<interval_type>(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<char>(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<int>(diff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Nonce string generator class.
 | 
			
		||||
/// </summary>
 | 
			
		||||
class nonce_generator
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Define default nonce length.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    enum { default_length = 32 };
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Nonce generator constructor.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="length">Length of the generated nonce string.</param>
 | 
			
		||||
    nonce_generator(int length=default_length) :
 | 
			
		||||
        m_random(static_cast<unsigned int>(utility::datetime::utc_timestamp())),
 | 
			
		||||
        m_length(length)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Generate a nonce string containing random alphanumeric characters (A-Za-z0-9).
 | 
			
		||||
    /// Length of the generated string is set by length().
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>The generated nonce string.</returns>
 | 
			
		||||
    _ASYNCRTIMP utility::string_t generate();
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Get length of generated nonce string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>Nonce string length.</returns>
 | 
			
		||||
    int length() const { return m_length; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Set length of the generated nonce string.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="length">Lenght of nonce string.</param>
 | 
			
		||||
    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;
 | 
			
		||||
							
								
								
									
										7048
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7048
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/SafeInt3.hpp
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										140
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										140
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/basic_types.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -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 <string>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include "cpprest/details/cpprest_compat.h"
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
# define __STDC_LIMIT_MACROS
 | 
			
		||||
# include <stdint.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#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<utf16char> utf16stringstream;
 | 
			
		||||
typedef std::basic_ostringstream<utf16char> utf16ostringstream;
 | 
			
		||||
typedef std::basic_ostream<utf16char> utf16ostream;
 | 
			
		||||
typedef std::basic_istream<utf16char> utf16istream;
 | 
			
		||||
typedef std::basic_istringstream<utf16char> 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
 | 
			
		||||
							
								
								
									
										97
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										97
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/cpprest_compat.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -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 <sal.h>
 | 
			
		||||
 | 
			
		||||
#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 <assert.h>
 | 
			
		||||
#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 <cstdio>
 | 
			
		||||
#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
 | 
			
		||||
							
								
								
									
										89
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										89
									
								
								src/corehost/cli/json/casablanca/include/cpprest/details/nosal.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
							
								
								
									
										1936
									
								
								src/corehost/cli/json/casablanca/include/cpprest/json.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1936
									
								
								src/corehost/cli/json/casablanca/include/cpprest/json.h
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										109
									
								
								src/corehost/cli/json/casablanca/include/stdafx.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/corehost/cli/json/casablanca/include/stdafx.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,109 @@
 | 
			
		|||
/***
 | 
			
		||||
* ==++==
 | 
			
		||||
*
 | 
			
		||||
* 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.
 | 
			
		||||
*
 | 
			
		||||
* ==--==
 | 
			
		||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 | 
			
		||||
*
 | 
			
		||||
* Pre-compiled headers
 | 
			
		||||
*
 | 
			
		||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
 | 
			
		||||
*
 | 
			
		||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 | 
			
		||||
****/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma clang diagnostic ignored "-Wunused-local-typedef"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#ifdef CPPREST_TARGET_XP
 | 
			
		||||
#include <winsdkver.h>
 | 
			
		||||
#ifndef _WIN32_WINNT
 | 
			
		||||
#define _WIN32_WINNT _WIN32_WINNT_WS03 //Windows XP with SP2
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
#include <SDKDDKVer.h>
 | 
			
		||||
// use the debug version of the CRT if _DEBUG is defined
 | 
			
		||||
#ifdef _DEBUG
 | 
			
		||||
    #define _CRTDBG_MAP_ALLOC
 | 
			
		||||
    #include <stdlib.h>
 | 
			
		||||
    #include <crtdbg.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
 | 
			
		||||
// Windows Header Files:
 | 
			
		||||
#define NOMINMAX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <objbase.h>
 | 
			
		||||
 | 
			
		||||
// Windows Header Files:
 | 
			
		||||
#if !defined(__cplusplus_winrt)
 | 
			
		||||
#include <winhttp.h>
 | 
			
		||||
 | 
			
		||||
#endif // #if !defined(__cplusplus_winrt)
 | 
			
		||||
#else // LINUX or APPLE
 | 
			
		||||
#define __STDC_LIMIT_MACROS
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include "pthread.h"
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/syscall.h>
 | 
			
		||||
#endif // _WIN32
 | 
			
		||||
 | 
			
		||||
// Macro indicating the C++ Rest SDK product itself is being built.
 | 
			
		||||
// This is to help track how many developers are directly building from source themselves.
 | 
			
		||||
#define _CASA_BUILD_FROM_SRC
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <exception>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
// json
 | 
			
		||||
#include "cpprest/json.h"
 | 
			
		||||
 | 
			
		||||
#if defined(max)
 | 
			
		||||
#error: max macro defined -- make sure to #define NOMINMAX before including windows.h
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(min)
 | 
			
		||||
#error: min macro defined -- make sure to #define NOMINMAX before including windows.h
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										495
									
								
								src/corehost/cli/json/casablanca/src/json/json.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								src/corehost/cli/json/casablanca/src/json/json.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,495 @@
 | 
			
		|||
/***
 | 
			
		||||
* ==++==
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
*
 | 
			
		||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 | 
			
		||||
****/
 | 
			
		||||
 | 
			
		||||
#include "stdafx.h"
 | 
			
		||||
 | 
			
		||||
using namespace web;
 | 
			
		||||
 | 
			
		||||
bool json::details::g_keep_json_object_unsorted = false;
 | 
			
		||||
void json::keep_object_element_order(bool keep_order)
 | 
			
		||||
{
 | 
			
		||||
    json::details::g_keep_json_object_unsorted = keep_order;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::ostream_t& web::json::operator << (utility::ostream_t &os, const web::json::value &val)
 | 
			
		||||
{
 | 
			
		||||
    val.serialize(os);
 | 
			
		||||
    return os;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::istream_t& web::json::operator >> (utility::istream_t &is, json::value &val)
 | 
			
		||||
{
 | 
			
		||||
    val = json::value::parse(is);
 | 
			
		||||
    return is;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value::value() :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Null>())
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Null)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(int32_t value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Number>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Number)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(uint32_t value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Number>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Number)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(int64_t value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Number>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Number)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(uint64_t value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Number>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Number)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(double value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Number>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Number)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(bool value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_Boolean>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::Boolean)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(utility::string_t value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_String>(std::move(value)))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::String)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(utility::string_t value, bool has_escape_chars) :
 | 
			
		||||
m_value(utility::details::make_unique<web::json::details::_String>(std::move(value), has_escape_chars))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
, m_kind(value::String)
 | 
			
		||||
#endif
 | 
			
		||||
{ }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(const utility::char_t* value) :
 | 
			
		||||
    m_value(utility::details::make_unique<web::json::details::_String>(value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(value::String)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(const utility::char_t* value, bool has_escape_chars) :
 | 
			
		||||
m_value(utility::details::make_unique<web::json::details::_String>(utility::string_t(value), has_escape_chars))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
, m_kind(value::String)
 | 
			
		||||
#endif
 | 
			
		||||
{ }
 | 
			
		||||
 | 
			
		||||
web::json::value::value(const value &other) :
 | 
			
		||||
    m_value(other.m_value->_copy_value())
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(other.m_kind)
 | 
			
		||||
#endif
 | 
			
		||||
    { }
 | 
			
		||||
 | 
			
		||||
web::json::value &web::json::value::operator=(const value &other)
 | 
			
		||||
{
 | 
			
		||||
    if(this != &other)
 | 
			
		||||
    {
 | 
			
		||||
        m_value = std::unique_ptr<details::_Value>(other.m_value->_copy_value());
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
        m_kind = other.m_kind;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value::value(value &&other) CPPREST_NOEXCEPT :
 | 
			
		||||
    m_value(std::move(other.m_value))
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
    ,m_kind(other.m_kind)
 | 
			
		||||
#endif
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
web::json::value &web::json::value::operator=(web::json::value &&other) CPPREST_NOEXCEPT
 | 
			
		||||
{
 | 
			
		||||
    if(this != &other)
 | 
			
		||||
    {
 | 
			
		||||
        m_value.swap(other.m_value);
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
        m_kind = other.m_kind;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::null()
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::number(double value)
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::number(int32_t value)
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::number(uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::number(int64_t value)
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::number(uint64_t value)
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::boolean(bool value)
 | 
			
		||||
{
 | 
			
		||||
    return web::json::value(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::string(utility::string_t value)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(std::move(value));
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::String
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::string(utility::string_t value, bool has_escape_chars)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(std::move(value), has_escape_chars);
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::String
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
web::json::value web::json::value::string(const std::string &value)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_String>(utility::conversions::to_utf16string(value));
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::String
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::object(bool keep_order)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Object>(keep_order);
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::Object
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::object(std::vector<std::pair<::utility::string_t, value>> fields, bool keep_order)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Object>(std::move(fields), keep_order);
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::Object
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::array()
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>();
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::Array
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::array(size_t size)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(size);
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::Array
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value web::json::value::array(std::vector<value> elements)
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<details::_Value> ptr = utility::details::make_unique<details::_Array>(std::move(elements));
 | 
			
		||||
    return web::json::value(std::move(ptr)
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
            ,value::Array
 | 
			
		||||
#endif
 | 
			
		||||
            );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const web::json::number& web::json::value::as_number() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_number();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double web::json::value::as_double() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_double();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int web::json::value::as_integer() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_integer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool web::json::value::as_bool() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_bool();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json::array& web::json::value::as_array()
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_array();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const json::array& web::json::value::as_array() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_array();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json::object& web::json::value::as_object()
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_object();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const json::object& web::json::value::as_object() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_object();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool web::json::number::is_int32() const
 | 
			
		||||
{
 | 
			
		||||
    switch (m_type)
 | 
			
		||||
    {
 | 
			
		||||
    case signed_type : return m_intval >= std::numeric_limits<int32_t>::min() && m_intval <= std::numeric_limits<int32_t>::max();
 | 
			
		||||
    case unsigned_type : return m_uintval <= std::numeric_limits<int32_t>::max();
 | 
			
		||||
    case double_type :
 | 
			
		||||
    default :
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool web::json::number::is_uint32() const
 | 
			
		||||
{
 | 
			
		||||
    switch (m_type)
 | 
			
		||||
    {
 | 
			
		||||
    case signed_type : return m_intval >= 0 && m_intval <= std::numeric_limits<uint32_t>::max();
 | 
			
		||||
    case unsigned_type : return m_uintval <= std::numeric_limits<uint32_t>::max();
 | 
			
		||||
    case double_type :
 | 
			
		||||
    default :
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool web::json::number::is_int64() const
 | 
			
		||||
{
 | 
			
		||||
    switch (m_type)
 | 
			
		||||
    {
 | 
			
		||||
    case signed_type : return true;
 | 
			
		||||
    case unsigned_type : return m_uintval <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
 | 
			
		||||
    case double_type :
 | 
			
		||||
    default :
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool web::json::details::_String::has_escape_chars(const _String &str)
 | 
			
		||||
{
 | 
			
		||||
    return std::any_of(std::begin(str.m_string), std::end(str.m_string), [](utility::string_t::value_type const x)
 | 
			
		||||
    {
 | 
			
		||||
        if (x <= 31) { return true; }
 | 
			
		||||
        if (x == '"') { return true; }
 | 
			
		||||
        if (x == '\\') { return true; }
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value::value_type json::value::type() const { return m_value->type(); }
 | 
			
		||||
 | 
			
		||||
bool json::value::is_integer() const
 | 
			
		||||
{
 | 
			
		||||
    if(!is_number())
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return m_value->is_integer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool json::value::is_double() const
 | 
			
		||||
{
 | 
			
		||||
    if(!is_number())
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return m_value->is_double();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json::value& web::json::details::_Object::index(const utility::string_t &key)
 | 
			
		||||
{
 | 
			
		||||
    return m_object[key];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool web::json::details::_Object::has_field(const utility::string_t &key) const
 | 
			
		||||
{
 | 
			
		||||
    return m_object.find(key) != m_object.end();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::string_t json::value::to_string() const
 | 
			
		||||
{
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
    utility::details::scoped_c_thread_locale locale;
 | 
			
		||||
#endif
 | 
			
		||||
    return m_value->to_string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool json::value::operator==(const json::value &other) const
 | 
			
		||||
{
 | 
			
		||||
    if (this->m_value.get() == other.m_value.get())
 | 
			
		||||
        return true;
 | 
			
		||||
    if (this->type() != other.type())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    switch(this->type())
 | 
			
		||||
    {
 | 
			
		||||
    case Null:
 | 
			
		||||
        return true;
 | 
			
		||||
    case Number:
 | 
			
		||||
        return this->as_number() == other.as_number();
 | 
			
		||||
    case Boolean:
 | 
			
		||||
        return this->as_bool() == other.as_bool();
 | 
			
		||||
    case String:
 | 
			
		||||
        return this->as_string() == other.as_string();
 | 
			
		||||
    case Object:
 | 
			
		||||
        return static_cast<const json::details::_Object*>(this->m_value.get())->is_equal(static_cast<const json::details::_Object*>(other.m_value.get()));
 | 
			
		||||
    case Array:
 | 
			
		||||
        return static_cast<const json::details::_Array*>(this->m_value.get())->is_equal(static_cast<const json::details::_Array*>(other.m_value.get()));
 | 
			
		||||
    }
 | 
			
		||||
    __assume(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void web::json::value::erase(size_t index)
 | 
			
		||||
{
 | 
			
		||||
    return this->as_array().erase(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void web::json::value::erase(const utility::string_t &key)
 | 
			
		||||
{
 | 
			
		||||
    return this->as_object().erase(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// at() overloads
 | 
			
		||||
web::json::value& web::json::value::at(size_t index)
 | 
			
		||||
{
 | 
			
		||||
    return this->as_array().at(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const web::json::value& web::json::value::at(size_t index) const
 | 
			
		||||
{
 | 
			
		||||
    return this->as_array().at(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value& web::json::value::at(const utility::string_t& key)
 | 
			
		||||
{
 | 
			
		||||
    return this->as_object().at(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const web::json::value& web::json::value::at(const utility::string_t& key) const
 | 
			
		||||
{
 | 
			
		||||
    return this->as_object().at(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value& web::json::value::operator [] (const utility::string_t &key)
 | 
			
		||||
{
 | 
			
		||||
    if ( this->is_null() )
 | 
			
		||||
    {
 | 
			
		||||
        m_value.reset(new web::json::details::_Object(details::g_keep_json_object_unsorted));
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
        m_kind = value::Object;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return m_value->index(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
web::json::value& web::json::value::operator[](size_t index)
 | 
			
		||||
{
 | 
			
		||||
    if ( this->is_null() )
 | 
			
		||||
    {
 | 
			
		||||
        m_value.reset(new web::json::details::_Array());
 | 
			
		||||
#ifdef ENABLE_JSON_VALUE_VISUALIZER
 | 
			
		||||
        m_kind = value::Array;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return m_value->index(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove once VS 2013 is no longer supported.
 | 
			
		||||
#if defined(_WIN32) && _MSC_VER < 1900
 | 
			
		||||
static web::json::details::json_error_category_impl instance;
 | 
			
		||||
#endif
 | 
			
		||||
const web::json::details::json_error_category_impl& web::json::details::json_error_category()
 | 
			
		||||
{
 | 
			
		||||
#if !defined(_WIN32) || _MSC_VER >= 1900
 | 
			
		||||
    static web::json::details::json_error_category_impl instance;
 | 
			
		||||
#endif
 | 
			
		||||
    return instance;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1312
									
								
								src/corehost/cli/json/casablanca/src/json/json_parsing.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1312
									
								
								src/corehost/cli/json/casablanca/src/json/json_parsing.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										274
									
								
								src/corehost/cli/json/casablanca/src/json/json_serialization.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								src/corehost/cli/json/casablanca/src/json/json_serialization.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,274 @@
 | 
			
		|||
/***
 | 
			
		||||
* ==++==
 | 
			
		||||
*
 | 
			
		||||
* 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
 | 
			
		||||
*
 | 
			
		||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 | 
			
		||||
****/
 | 
			
		||||
 | 
			
		||||
#include "stdafx.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#define __STDC_FORMAT_MACROS
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using namespace web;
 | 
			
		||||
using namespace web::json;
 | 
			
		||||
using namespace utility;
 | 
			
		||||
using namespace utility::conversions;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// JSON Serialization
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
void web::json::value::serialize(std::ostream& stream) const
 | 
			
		||||
{
 | 
			
		||||
    // This has better performance than writing directly to stream.
 | 
			
		||||
    std::string str;
 | 
			
		||||
    m_value->serialize_impl(str);
 | 
			
		||||
    stream << str;
 | 
			
		||||
}
 | 
			
		||||
void web::json::value::format(std::basic_string<wchar_t> &string) const
 | 
			
		||||
{
 | 
			
		||||
    m_value->format(string);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void web::json::value::serialize(utility::ostream_t &stream) const
 | 
			
		||||
{
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
    utility::details::scoped_c_thread_locale locale;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // This has better performance than writing directly to stream.
 | 
			
		||||
    utility::string_t str;
 | 
			
		||||
    m_value->serialize_impl(str);
 | 
			
		||||
    stream << str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void web::json::value::format(std::basic_string<char>& string) const
 | 
			
		||||
{
 | 
			
		||||
    m_value->format(string);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename CharType>
 | 
			
		||||
void web::json::details::append_escape_string(std::basic_string<CharType>& str, const std::basic_string<CharType>& escaped)
 | 
			
		||||
{
 | 
			
		||||
    for (const auto &ch : escaped)
 | 
			
		||||
    {
 | 
			
		||||
        switch (ch)
 | 
			
		||||
        {
 | 
			
		||||
            case '\"':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += '\"';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\\':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\b':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += 'b';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\f':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += 'f';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\r':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += 'r';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\n':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += 'n';
 | 
			
		||||
                break;
 | 
			
		||||
            case '\t':
 | 
			
		||||
                str += '\\';
 | 
			
		||||
                str += 't';
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
 | 
			
		||||
                // If a control character then must unicode escaped.
 | 
			
		||||
                if (ch >= 0 && ch <= 0x1F)
 | 
			
		||||
                {
 | 
			
		||||
                    static const std::array<CharType, 16> intToHex = { { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } };
 | 
			
		||||
                    str += '\\';
 | 
			
		||||
                    str += 'u';
 | 
			
		||||
                    str += '0';
 | 
			
		||||
                    str += '0';
 | 
			
		||||
                    str += intToHex[(ch & 0xF0) >> 4];
 | 
			
		||||
                    str += intToHex[ch & 0x0F];
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    str += ch;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void web::json::details::format_string(const utility::string_t& key, utility::string_t& str)
 | 
			
		||||
{
 | 
			
		||||
    str.push_back('"');
 | 
			
		||||
    append_escape_string(str, key);
 | 
			
		||||
    str.push_back('"');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
void web::json::details::format_string(const utility::string_t& key, std::string& str)
 | 
			
		||||
{
 | 
			
		||||
    str.push_back('"');
 | 
			
		||||
    append_escape_string(str, utility::conversions::to_utf8string(key));
 | 
			
		||||
    str.push_back('"');
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void web::json::details::_String::format(std::basic_string<char>& str) const
 | 
			
		||||
{
 | 
			
		||||
    str.push_back('"');
 | 
			
		||||
 | 
			
		||||
    if(m_has_escape_char)
 | 
			
		||||
    {
 | 
			
		||||
        append_escape_string(str, utility::conversions::to_utf8string(m_string));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        str.append(utility::conversions::to_utf8string(m_string));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    str.push_back('"');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void web::json::details::_Number::format(std::basic_string<char>& stream) const
 | 
			
		||||
{
 | 
			
		||||
    if(m_number.m_type != number::type::double_type)
 | 
			
		||||
    {
 | 
			
		||||
        // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.
 | 
			
		||||
        const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;
 | 
			
		||||
        char tempBuffer[tempSize];
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        // This can be improved performance-wise if we implement our own routine
 | 
			
		||||
        if (m_number.m_type == number::type::signed_type)
 | 
			
		||||
            _i64toa_s(m_number.m_intval, tempBuffer, tempSize, 10);
 | 
			
		||||
        else
 | 
			
		||||
            _ui64toa_s(m_number.m_uintval, tempBuffer, tempSize, 10);
 | 
			
		||||
 | 
			
		||||
        const auto numChars = strnlen_s(tempBuffer, tempSize);
 | 
			
		||||
#else
 | 
			
		||||
        int numChars;
 | 
			
		||||
        if (m_number.m_type == number::type::signed_type)
 | 
			
		||||
            numChars = snprintf(tempBuffer, tempSize, "%" PRId64, m_number.m_intval);
 | 
			
		||||
        else
 | 
			
		||||
            numChars = snprintf(tempBuffer, tempSize, "%" PRIu64, m_number.m_uintval);
 | 
			
		||||
#endif
 | 
			
		||||
        stream.append(tempBuffer, numChars);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator
 | 
			
		||||
        const size_t tempSize = std::numeric_limits<double>::digits10 + 10;
 | 
			
		||||
        char tempBuffer[tempSize];
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        const auto numChars = _sprintf_s_l(
 | 
			
		||||
            tempBuffer,
 | 
			
		||||
            tempSize,
 | 
			
		||||
            "%.*g",
 | 
			
		||||
            utility::details::scoped_c_thread_locale::c_locale(),
 | 
			
		||||
            std::numeric_limits<double>::digits10 + 2,
 | 
			
		||||
            m_number.m_value);
 | 
			
		||||
#else
 | 
			
		||||
        const auto numChars = snprintf(tempBuffer, tempSize, "%.*g", std::numeric_limits<double>::digits10 + 2, m_number.m_value);
 | 
			
		||||
#endif
 | 
			
		||||
        stream.append(tempBuffer, numChars);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
void web::json::details::_String::format(std::basic_string<wchar_t>& str) const
 | 
			
		||||
{
 | 
			
		||||
    str.push_back(L'"');
 | 
			
		||||
 | 
			
		||||
    if(m_has_escape_char)
 | 
			
		||||
    {
 | 
			
		||||
        append_escape_string(str, m_string);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        str.append(m_string);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    str.push_back(L'"');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void web::json::details::_Number::format(std::basic_string<wchar_t>& stream) const
 | 
			
		||||
{
 | 
			
		||||
    if(m_number.m_type != number::type::double_type)
 | 
			
		||||
    {
 | 
			
		||||
        // #digits + 1 to avoid loss + 1 for the sign + 1 for null terminator.
 | 
			
		||||
        const size_t tempSize = std::numeric_limits<uint64_t>::digits10 + 3;
 | 
			
		||||
        wchar_t tempBuffer[tempSize];
 | 
			
		||||
 | 
			
		||||
        if (m_number.m_type == number::type::signed_type)
 | 
			
		||||
            _i64tow_s(m_number.m_intval, tempBuffer, tempSize, 10);
 | 
			
		||||
        else
 | 
			
		||||
            _ui64tow_s(m_number.m_uintval, tempBuffer, tempSize, 10);
 | 
			
		||||
 | 
			
		||||
        stream.append(tempBuffer, wcsnlen_s(tempBuffer, tempSize));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // #digits + 2 to avoid loss + 1 for the sign + 1 for decimal point + 5 for exponent (e+xxx) + 1 for null terminator
 | 
			
		||||
        const size_t tempSize = std::numeric_limits<double>::digits10 + 10;
 | 
			
		||||
        wchar_t tempBuffer[tempSize];
 | 
			
		||||
        const int numChars = _swprintf_s_l(
 | 
			
		||||
            tempBuffer,
 | 
			
		||||
            tempSize,
 | 
			
		||||
            L"%.*g",
 | 
			
		||||
            utility::details::scoped_c_thread_locale::c_locale(),
 | 
			
		||||
            std::numeric_limits<double>::digits10 + 2,
 | 
			
		||||
            m_number.m_value);
 | 
			
		||||
        stream.append(tempBuffer, numChars);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const utility::string_t & web::json::details::_String::as_string() const
 | 
			
		||||
{
 | 
			
		||||
    return m_string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const utility::string_t & web::json::value::as_string() const
 | 
			
		||||
{
 | 
			
		||||
    return m_value->as_string();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::string_t json::value::serialize() const
 | 
			
		||||
{
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
    utility::details::scoped_c_thread_locale locale;
 | 
			
		||||
#endif
 | 
			
		||||
    return m_value->to_string();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										496
									
								
								src/corehost/cli/json/casablanca/src/utilities/asyncrt_utils.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										496
									
								
								src/corehost/cli/json/casablanca/src/utilities/asyncrt_utils.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,496 @@
 | 
			
		|||
/***
 | 
			
		||||
* ==++==
 | 
			
		||||
*
 | 
			
		||||
* 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.
 | 
			
		||||
*
 | 
			
		||||
* ==--==
 | 
			
		||||
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 | 
			
		||||
*
 | 
			
		||||
* Utilities
 | 
			
		||||
*
 | 
			
		||||
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
 | 
			
		||||
*
 | 
			
		||||
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 | 
			
		||||
****/
 | 
			
		||||
 | 
			
		||||
#include "stdafx.h"
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma clang diagnostic ignored "-Wunused-local-typedef"
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Could use C++ standard library if not __GLIBCXX__,
 | 
			
		||||
// For testing purposes we just the handwritten on all platforms.
 | 
			
		||||
#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)
 | 
			
		||||
#include <codecvt>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using namespace web;
 | 
			
		||||
using namespace utility;
 | 
			
		||||
using namespace utility::conversions;
 | 
			
		||||
 | 
			
		||||
namespace utility
 | 
			
		||||
{
 | 
			
		||||
namespace details
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if !defined(ANDROID) && !defined(__ANDROID__)
 | 
			
		||||
std::once_flag g_c_localeFlag;
 | 
			
		||||
std::unique_ptr<scoped_c_thread_locale::xplat_locale, void(*)(scoped_c_thread_locale::xplat_locale *)> g_c_locale(nullptr, [](scoped_c_thread_locale::xplat_locale *){});
 | 
			
		||||
scoped_c_thread_locale::xplat_locale scoped_c_thread_locale::c_locale()
 | 
			
		||||
{
 | 
			
		||||
    std::call_once(g_c_localeFlag, [&]()
 | 
			
		||||
    {
 | 
			
		||||
        scoped_c_thread_locale::xplat_locale *clocale = new scoped_c_thread_locale::xplat_locale();
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        *clocale = _create_locale(LC_ALL, "C");
 | 
			
		||||
        if (*clocale == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("Unable to create 'C' locale.");
 | 
			
		||||
        }
 | 
			
		||||
        auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale)
 | 
			
		||||
        {
 | 
			
		||||
            _free_locale(*clocale);
 | 
			
		||||
            delete clocale;
 | 
			
		||||
        };
 | 
			
		||||
#else
 | 
			
		||||
        *clocale = newlocale(LC_ALL, "C", nullptr);
 | 
			
		||||
        if (*clocale == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("Unable to create 'C' locale.");
 | 
			
		||||
        }
 | 
			
		||||
        auto deleter = [](scoped_c_thread_locale::xplat_locale *clocale)
 | 
			
		||||
        {
 | 
			
		||||
            freelocale(*clocale);
 | 
			
		||||
            delete clocale;
 | 
			
		||||
        };
 | 
			
		||||
#endif
 | 
			
		||||
        g_c_locale = std::unique_ptr<scoped_c_thread_locale::xplat_locale, void(*)(scoped_c_thread_locale::xplat_locale *)>(clocale, deleter);
 | 
			
		||||
    });
 | 
			
		||||
    return *g_c_locale;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
scoped_c_thread_locale::scoped_c_thread_locale()
 | 
			
		||||
    : m_prevLocale(), m_prevThreadSetting(-1)
 | 
			
		||||
{
 | 
			
		||||
    char *prevLocale = setlocale(LC_ALL, nullptr);
 | 
			
		||||
    if (prevLocale == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("Unable to retrieve current locale.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (std::strcmp(prevLocale, "C") != 0)
 | 
			
		||||
    {
 | 
			
		||||
        m_prevLocale = prevLocale;
 | 
			
		||||
        m_prevThreadSetting = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
 | 
			
		||||
        if (m_prevThreadSetting == -1)
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("Unable to enable per thread locale.");
 | 
			
		||||
        }
 | 
			
		||||
        if (setlocale(LC_ALL, "C") == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
             _configthreadlocale(m_prevThreadSetting);
 | 
			
		||||
             throw std::runtime_error("Unable to set locale");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
scoped_c_thread_locale::~scoped_c_thread_locale()
 | 
			
		||||
{
 | 
			
		||||
    if (m_prevThreadSetting != -1)
 | 
			
		||||
    {
 | 
			
		||||
        setlocale(LC_ALL, m_prevLocale.c_str());
 | 
			
		||||
        _configthreadlocale(m_prevThreadSetting);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#elif (defined(ANDROID) || defined(__ANDROID__))
 | 
			
		||||
scoped_c_thread_locale::scoped_c_thread_locale() {}
 | 
			
		||||
scoped_c_thread_locale::~scoped_c_thread_locale() {}
 | 
			
		||||
#else
 | 
			
		||||
scoped_c_thread_locale::scoped_c_thread_locale()
 | 
			
		||||
    : m_prevLocale(nullptr)
 | 
			
		||||
{
 | 
			
		||||
    char *prevLocale = setlocale(LC_ALL, nullptr);
 | 
			
		||||
    if (prevLocale == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("Unable to retrieve current locale.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (std::strcmp(prevLocale, "C") != 0)
 | 
			
		||||
    {
 | 
			
		||||
        m_prevLocale = uselocale(c_locale());
 | 
			
		||||
        if (m_prevLocale == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("Unable to set locale");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
scoped_c_thread_locale::~scoped_c_thread_locale()
 | 
			
		||||
{
 | 
			
		||||
    if (m_prevLocale != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        uselocale(m_prevLocale);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace details
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
const std::error_category & __cdecl platform_category()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return windows_category();
 | 
			
		||||
#else
 | 
			
		||||
    return linux_category();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
// Remove once VS 2013 is no longer supported.
 | 
			
		||||
#if _MSC_VER < 1900
 | 
			
		||||
static details::windows_category_impl instance;
 | 
			
		||||
#endif
 | 
			
		||||
const std::error_category & __cdecl windows_category()
 | 
			
		||||
{
 | 
			
		||||
#if _MSC_VER >= 1900
 | 
			
		||||
    static details::windows_category_impl instance;
 | 
			
		||||
#endif
 | 
			
		||||
    return instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string windows_category_impl::message(int errorCode) const CPPREST_NOEXCEPT
 | 
			
		||||
{
 | 
			
		||||
    const size_t buffer_size = 4096;
 | 
			
		||||
    DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
 | 
			
		||||
    LPCVOID lpSource = NULL;
 | 
			
		||||
 | 
			
		||||
#if !defined(__cplusplus_winrt)
 | 
			
		||||
    if (errorCode >= 12000)
 | 
			
		||||
    {
 | 
			
		||||
        dwFlags = FORMAT_MESSAGE_FROM_HMODULE;
 | 
			
		||||
        lpSource = GetModuleHandleA("winhttp.dll"); // this handle DOES NOT need to be freed
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    std::wstring buffer;
 | 
			
		||||
    buffer.resize(buffer_size);
 | 
			
		||||
 | 
			
		||||
    const auto result = ::FormatMessageW(
 | 
			
		||||
        dwFlags,
 | 
			
		||||
        lpSource,
 | 
			
		||||
        errorCode,
 | 
			
		||||
        0,
 | 
			
		||||
        &buffer[0],
 | 
			
		||||
        buffer_size,
 | 
			
		||||
        NULL);
 | 
			
		||||
    if (result == 0)
 | 
			
		||||
    {
 | 
			
		||||
        std::ostringstream os;
 | 
			
		||||
        os << "Unable to get an error message for error code: " << errorCode << ".";
 | 
			
		||||
        return os.str();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return utility::conversions::to_utf8string(buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::error_condition windows_category_impl::default_error_condition(int errorCode) const CPPREST_NOEXCEPT
 | 
			
		||||
{
 | 
			
		||||
    // First see if the STL implementation can handle the mapping for common cases.
 | 
			
		||||
    const std::error_condition errCondition = std::system_category().default_error_condition(errorCode);
 | 
			
		||||
    const std::string errConditionMsg = errCondition.message();
 | 
			
		||||
    if(_stricmp(errConditionMsg.c_str(), "unknown error") != 0)
 | 
			
		||||
    {
 | 
			
		||||
        return errCondition;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch(errorCode)
 | 
			
		||||
    {
 | 
			
		||||
#ifndef __cplusplus_winrt
 | 
			
		||||
    case ERROR_WINHTTP_TIMEOUT:
 | 
			
		||||
        return std::errc::timed_out;
 | 
			
		||||
    case ERROR_WINHTTP_CANNOT_CONNECT:
 | 
			
		||||
        return std::errc::host_unreachable;
 | 
			
		||||
    case ERROR_WINHTTP_CONNECTION_ERROR:
 | 
			
		||||
        return std::errc::connection_aborted;
 | 
			
		||||
#endif
 | 
			
		||||
    case INET_E_RESOURCE_NOT_FOUND:
 | 
			
		||||
    case INET_E_CANNOT_CONNECT:
 | 
			
		||||
        return std::errc::host_unreachable;
 | 
			
		||||
    case INET_E_CONNECTION_TIMEOUT:
 | 
			
		||||
        return std::errc::timed_out;
 | 
			
		||||
    case INET_E_DOWNLOAD_FAILURE:
 | 
			
		||||
        return std::errc::connection_aborted;
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return std::error_condition(errorCode, *this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
const std::error_category & __cdecl linux_category()
 | 
			
		||||
{
 | 
			
		||||
    // On Linux we are using boost error codes which have the exact same
 | 
			
		||||
    // mapping and are equivalent with std::generic_category error codes.
 | 
			
		||||
    return std::generic_category();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define LOW_3BITS 0x7
 | 
			
		||||
#define LOW_4BITS 0xF
 | 
			
		||||
#define LOW_5BITS 0x1F
 | 
			
		||||
#define LOW_6BITS 0x3F
 | 
			
		||||
#define BIT4 0x8
 | 
			
		||||
#define BIT5 0x10
 | 
			
		||||
#define BIT6 0x20
 | 
			
		||||
#define BIT7 0x40
 | 
			
		||||
#define BIT8 0x80
 | 
			
		||||
#define L_SURROGATE_START 0xDC00
 | 
			
		||||
#define L_SURROGATE_END 0xDFFF
 | 
			
		||||
#define H_SURROGATE_START 0xD800
 | 
			
		||||
#define H_SURROGATE_END 0xDBFF
 | 
			
		||||
#define SURROGATE_PAIR_START 0x10000
 | 
			
		||||
 | 
			
		||||
utf16string __cdecl conversions::utf8_to_utf16(const std::string &s)
 | 
			
		||||
{
 | 
			
		||||
#if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)
 | 
			
		||||
    std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;
 | 
			
		||||
    return conversion.from_bytes(src);
 | 
			
		||||
#else
 | 
			
		||||
    utf16string dest;
 | 
			
		||||
    // Save repeated heap allocations, use less than source string size assuming some
 | 
			
		||||
    // of the characters are not just ASCII and collapse.
 | 
			
		||||
    dest.reserve(static_cast<size_t>(static_cast<double>(s.size()) * .70));
 | 
			
		||||
    
 | 
			
		||||
    for (auto src = s.begin(); src != s.end(); ++src)
 | 
			
		||||
    {
 | 
			
		||||
        if ((*src & BIT8) == 0) // single byte character, 0x0 to 0x7F
 | 
			
		||||
        {
 | 
			
		||||
            dest.push_back(utf16string::value_type(*src));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            unsigned char numContBytes = 0;
 | 
			
		||||
            uint32_t codePoint;
 | 
			
		||||
            if ((*src & BIT7) == 0)
 | 
			
		||||
            {
 | 
			
		||||
                throw std::range_error("UTF-8 string character can never start with 10xxxxxx");
 | 
			
		||||
            }
 | 
			
		||||
            else if ((*src & BIT6) == 0) // 2 byte character, 0x80 to 0x7FF
 | 
			
		||||
            {
 | 
			
		||||
                codePoint = *src & LOW_5BITS;
 | 
			
		||||
                numContBytes = 1;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((*src & BIT5) == 0) // 3 byte character, 0x800 to 0xFFFF
 | 
			
		||||
            {
 | 
			
		||||
                codePoint = *src & LOW_4BITS;
 | 
			
		||||
                numContBytes = 2;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((*src & BIT4) == 0) // 4 byte character, 0x10000 to 0x10FFFF
 | 
			
		||||
            {
 | 
			
		||||
                codePoint = *src & LOW_3BITS;
 | 
			
		||||
                numContBytes = 3;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                throw std::range_error("UTF-8 string has invalid Unicode code point");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (unsigned char i = 0; i < numContBytes; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                if (++src == s.end())
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::range_error("UTF-8 string is missing bytes in character");
 | 
			
		||||
                }
 | 
			
		||||
                if ((*src & BIT8) == 0 || (*src & BIT7) != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    throw std::range_error("UTF-8 continuation byte is missing leading byte");
 | 
			
		||||
                }
 | 
			
		||||
                codePoint <<= 6;
 | 
			
		||||
                codePoint |= *src & LOW_6BITS;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (codePoint >= SURROGATE_PAIR_START)
 | 
			
		||||
            {
 | 
			
		||||
                // In UTF-16 U+10000 to U+10FFFF are represented as two 16-bit code units, surrogate pairs.
 | 
			
		||||
                //  - 0x10000 is subtracted from the code point
 | 
			
		||||
                //  - high surrogate is 0xD800 added to the top ten bits
 | 
			
		||||
                //  - low surrogate is 0xDC00 added to the low ten bits
 | 
			
		||||
                codePoint -= SURROGATE_PAIR_START;
 | 
			
		||||
                dest.push_back(utf16string::value_type((codePoint >> 10) | H_SURROGATE_START));
 | 
			
		||||
                dest.push_back(utf16string::value_type((codePoint & 0x3FF) | L_SURROGATE_START));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // In UTF-16 U+0000 to U+D7FF and U+E000 to U+FFFF are represented exactly as the Unicode code point value.
 | 
			
		||||
                // U+D800 to U+DFFF are not valid characters, for simplicity we assume they are not present but will encode
 | 
			
		||||
                // them if encountered.
 | 
			
		||||
                dest.push_back(utf16string::value_type(codePoint));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return dest;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string __cdecl conversions::utf16_to_utf8(const utf16string &w)
 | 
			
		||||
{
 | 
			
		||||
 #if defined(CPPREST_STDLIB_UNICODE_CONVERSIONS)
 | 
			
		||||
     std::wstring_convert<std::codecvt_utf8_utf16<utf16char>, utf16char> conversion;
 | 
			
		||||
     return conversion.to_bytes(w);
 | 
			
		||||
 #else
 | 
			
		||||
    std::string dest;
 | 
			
		||||
    dest.reserve(w.size());
 | 
			
		||||
    for (auto src = w.begin(); src != w.end(); ++src)
 | 
			
		||||
    {
 | 
			
		||||
        // Check for high surrogate.
 | 
			
		||||
        if (*src >= H_SURROGATE_START && *src <= H_SURROGATE_END)
 | 
			
		||||
        {
 | 
			
		||||
            const auto highSurrogate = *src++;
 | 
			
		||||
            if (src == w.end())
 | 
			
		||||
            {
 | 
			
		||||
                throw std::range_error("UTF-16 string is missing low surrogate");
 | 
			
		||||
            }
 | 
			
		||||
            const auto lowSurrogate = *src;
 | 
			
		||||
            if (lowSurrogate < L_SURROGATE_START || lowSurrogate > L_SURROGATE_END)
 | 
			
		||||
            {
 | 
			
		||||
                throw std::range_error("UTF-16 string has invalid low surrogate");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // To get from surrogate pair to Unicode code point:
 | 
			
		||||
            // - subract 0xD800 from high surrogate, this forms top ten bits
 | 
			
		||||
            // - subract 0xDC00 from low surrogate, this forms low ten bits
 | 
			
		||||
            // - add 0x10000
 | 
			
		||||
            // Leaves a code point in U+10000 to U+10FFFF range.
 | 
			
		||||
            uint32_t codePoint = highSurrogate - H_SURROGATE_START;
 | 
			
		||||
            codePoint <<= 10;
 | 
			
		||||
            codePoint |= lowSurrogate - L_SURROGATE_START;
 | 
			
		||||
            codePoint += SURROGATE_PAIR_START;
 | 
			
		||||
 | 
			
		||||
            // 4 bytes need using 21 bits
 | 
			
		||||
            dest.push_back(char((codePoint >> 18) | 0xF0));                 // leading 3 bits
 | 
			
		||||
            dest.push_back(char(((codePoint >> 12) & LOW_6BITS) | BIT8));   // next 6 bits
 | 
			
		||||
            dest.push_back(char(((codePoint >> 6) & LOW_6BITS) | BIT8));    // next 6 bits
 | 
			
		||||
            dest.push_back(char((codePoint & LOW_6BITS) | BIT8));           // trailing 6 bits
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (*src <= 0x7F) // single byte character
 | 
			
		||||
            {
 | 
			
		||||
                dest.push_back(static_cast<char>(*src));
 | 
			
		||||
            }
 | 
			
		||||
            else if (*src <= 0x7FF) // 2 bytes needed (11 bits used)
 | 
			
		||||
            {
 | 
			
		||||
                dest.push_back(char((*src >> 6) | 0xC0));               // leading 5 bits
 | 
			
		||||
                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits
 | 
			
		||||
            }
 | 
			
		||||
            else // 3 bytes needed (16 bits used)
 | 
			
		||||
            {
 | 
			
		||||
                dest.push_back(char((*src >> 12) | 0xE0));              // leading 4 bits
 | 
			
		||||
                dest.push_back(char(((*src >> 6) & LOW_6BITS) | BIT8)); // middle 6 bits
 | 
			
		||||
                dest.push_back(char((*src & LOW_6BITS) | BIT8));        // trailing 6 bits
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return dest;
 | 
			
		||||
 #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utf16string __cdecl conversions::usascii_to_utf16(const std::string &s)
 | 
			
		||||
{
 | 
			
		||||
    // Ascii is a subset of UTF-8 so just convert to UTF-16
 | 
			
		||||
    return utf8_to_utf16(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utf16string __cdecl conversions::latin1_to_utf16(const std::string &s)
 | 
			
		||||
{
 | 
			
		||||
    // Latin1 is the first 256 code points in Unicode.
 | 
			
		||||
    // In UTF-16 encoding each of these is represented as exactly the numeric code point.
 | 
			
		||||
    utf16string dest;
 | 
			
		||||
    dest.resize(s.size());
 | 
			
		||||
    for (size_t i = 0; i < s.size(); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        dest[i] = utf16char(s[i]);
 | 
			
		||||
    }
 | 
			
		||||
    return dest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utf8string __cdecl conversions::latin1_to_utf8(const std::string &s)
 | 
			
		||||
{
 | 
			
		||||
    return utf16_to_utf8(latin1_to_utf16(s));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::string_t __cdecl conversions::to_string_t(utf16string &&s)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _UTF16_STRINGS
 | 
			
		||||
    return std::move(s);
 | 
			
		||||
#else
 | 
			
		||||
    return utf16_to_utf8(std::move(s));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::string_t __cdecl conversions::to_string_t(std::string &&s)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _UTF16_STRINGS
 | 
			
		||||
    return utf8_to_utf16(std::move(s));
 | 
			
		||||
#else
 | 
			
		||||
    return std::move(s);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::string_t __cdecl conversions::to_string_t(const utf16string &s)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _UTF16_STRINGS
 | 
			
		||||
    return s;
 | 
			
		||||
#else
 | 
			
		||||
    return utf16_to_utf8(s);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utility::string_t __cdecl conversions::to_string_t(const std::string &s)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _UTF16_STRINGS
 | 
			
		||||
    return utf8_to_utf16(s);
 | 
			
		||||
#else
 | 
			
		||||
    return s;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string __cdecl conversions::to_utf8string(std::string value) { return std::move(value); }
 | 
			
		||||
 | 
			
		||||
std::string __cdecl conversions::to_utf8string(const utf16string &value) { return utf16_to_utf8(value); }
 | 
			
		||||
 | 
			
		||||
utf16string __cdecl conversions::to_utf16string(const std::string &value) { return utf8_to_utf16(value); }
 | 
			
		||||
 | 
			
		||||
utf16string __cdecl conversions::to_utf16string(utf16string value) { return std::move(value); }
 | 
			
		||||
 | 
			
		||||
static bool is_digit(utility::char_t c) { return c >= _XPLATSTR('0') && c <= _XPLATSTR('9'); }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								src/corehost/cli/libhost.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/corehost/cli/libhost.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
// 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 "trace.h"
 | 
			
		||||
#include "libhost.h"
 | 
			
		||||
 | 
			
		||||
pal::string_t get_runtime_config_json(const pal::string_t& app_path)
 | 
			
		||||
{
 | 
			
		||||
    auto name = get_filename_without_ext(app_path);
 | 
			
		||||
    auto json_name = name + _X(".runtimeconfig.json");
 | 
			
		||||
    auto json_path = get_directory(app_path);
 | 
			
		||||
 | 
			
		||||
    append_path(&json_path, json_name.c_str());
 | 
			
		||||
    if (pal::file_exists(json_path))
 | 
			
		||||
    {
 | 
			
		||||
        return json_path;
 | 
			
		||||
    }
 | 
			
		||||
    return pal::string_t();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* p_own_dir)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t own_path;
 | 
			
		||||
    if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path))
 | 
			
		||||
    {
 | 
			
		||||
        trace::error(_X("Failed to locate current executable"));
 | 
			
		||||
        return host_mode_t::invalid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pal::string_t own_name = get_filename(own_path);
 | 
			
		||||
    pal::string_t own_dir = get_directory(own_path);
 | 
			
		||||
    if (p_own_dir)
 | 
			
		||||
    {
 | 
			
		||||
        p_own_dir->assign(own_dir);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pal::string_t own_dll_filename = strip_file_ext(own_name) + _X(".dll");
 | 
			
		||||
    pal::string_t own_dll = own_dir;
 | 
			
		||||
    append_path(&own_dll, own_dll_filename.c_str());
 | 
			
		||||
    trace::info(_X("Exists %s"), own_dll.c_str());
 | 
			
		||||
    if (coreclr_exists_in_dir(own_dir) || pal::file_exists(own_dll))
 | 
			
		||||
    {
 | 
			
		||||
        pal::string_t own_deps_json = own_dir;
 | 
			
		||||
        pal::string_t own_deps_filename = strip_file_ext(own_name) + _X(".deps.json");
 | 
			
		||||
        pal::string_t own_config_filename = strip_file_ext(own_name) + _X(".runtimeconfig.json");
 | 
			
		||||
        append_path(&own_deps_json, own_deps_filename.c_str());
 | 
			
		||||
        if (trace::is_enabled())
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Detecting mode... CoreCLR present in own dir [%s] and checking if [%s] file present=[%d]"),
 | 
			
		||||
                own_dir.c_str(), own_deps_filename.c_str(), pal::file_exists(own_deps_json));
 | 
			
		||||
        }
 | 
			
		||||
        return ((pal::file_exists(own_deps_json) || !pal::file_exists(own_config_filename)) && pal::file_exists(own_dll)) ? host_mode_t::standalone : host_mode_t::split_fx;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return host_mode_t::muxer;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,70 @@
 | 
			
		|||
// 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 __LIBHOST_H__
 | 
			
		||||
#define __LIBHOST_H__
 | 
			
		||||
 | 
			
		||||
#define LIBHOST_NAME MAKE_LIBNAME("hostpolicy")
 | 
			
		||||
 | 
			
		||||
enum host_mode_t
 | 
			
		||||
{
 | 
			
		||||
    invalid = 0,
 | 
			
		||||
    muxer,
 | 
			
		||||
    standalone,
 | 
			
		||||
    split_fx
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class runtime_config_t;
 | 
			
		||||
 | 
			
		||||
class corehost_init_t
 | 
			
		||||
{
 | 
			
		||||
    const pal::string_t m_probe_path;
 | 
			
		||||
    const pal::string_t m_deps_file;
 | 
			
		||||
    const pal::string_t m_fx_dir;
 | 
			
		||||
    host_mode_t m_host_mode;
 | 
			
		||||
    const runtime_config_t* m_runtime_config;
 | 
			
		||||
public:
 | 
			
		||||
    corehost_init_t(
 | 
			
		||||
        const pal::string_t& deps_file,
 | 
			
		||||
        const pal::string_t& probe_path,
 | 
			
		||||
        const pal::string_t& fx_dir,
 | 
			
		||||
        const host_mode_t mode,
 | 
			
		||||
        const runtime_config_t* runtime_config)
 | 
			
		||||
        : m_fx_dir(fx_dir)
 | 
			
		||||
        , m_runtime_config(runtime_config)
 | 
			
		||||
        , m_deps_file(deps_file)
 | 
			
		||||
        , m_probe_path(probe_path)
 | 
			
		||||
        , m_host_mode(mode)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const host_mode_t host_mode() const
 | 
			
		||||
    {
 | 
			
		||||
        return m_host_mode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const pal::string_t& deps_file() const
 | 
			
		||||
    {
 | 
			
		||||
        return m_deps_file;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const pal::string_t& probe_dir() const
 | 
			
		||||
    {
 | 
			
		||||
        return m_probe_path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const pal::string_t& fx_dir() const
 | 
			
		||||
    {
 | 
			
		||||
        return m_fx_dir;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const runtime_config_t* runtime_config() const
 | 
			
		||||
    {
 | 
			
		||||
        return m_runtime_config;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pal::string_t get_runtime_config_json(const pal::string_t& app_path);
 | 
			
		||||
host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* own_dir = nullptr);
 | 
			
		||||
 | 
			
		||||
#endif // __LIBHOST_H__
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										114
									
								
								src/corehost/cli/runtime_config.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/corehost/cli/runtime_config.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
// 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 "cpprest/json.h"
 | 
			
		||||
#include "runtime_config.h"
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
typedef web::json::value json_value;
 | 
			
		||||
 | 
			
		||||
runtime_config_t::runtime_config_t(const pal::string_t& path)
 | 
			
		||||
    : m_fx_roll_fwd(true)
 | 
			
		||||
    , m_path(path)
 | 
			
		||||
    , m_portable(false)
 | 
			
		||||
    , m_gc_server(_X("0"))
 | 
			
		||||
{
 | 
			
		||||
    m_valid = ensure_parsed();
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
void parse_fx(const json_value& opts, pal::string_t* name, pal::string_t* version, bool* roll_fwd, bool* portable)
 | 
			
		||||
{
 | 
			
		||||
    name->clear();
 | 
			
		||||
    version->clear();
 | 
			
		||||
    *roll_fwd = true;
 | 
			
		||||
    *portable = false;
 | 
			
		||||
 | 
			
		||||
    if (opts.is_null())
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto& opts_obj = opts.as_object();
 | 
			
		||||
    auto framework =  opts_obj.find(_X("framework"));
 | 
			
		||||
    if (framework == opts_obj.end())
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *portable = true;
 | 
			
		||||
 | 
			
		||||
    const auto& fx_obj = framework->second.as_object();
 | 
			
		||||
    *name = fx_obj.at(_X("name")).as_string();
 | 
			
		||||
    *version = fx_obj.at(_X("version")).as_string();
 | 
			
		||||
 | 
			
		||||
    auto value = fx_obj.find(_X("rollForward"));
 | 
			
		||||
    if (value == fx_obj.end())
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *roll_fwd = value->second.as_bool();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool runtime_config_t::ensure_parsed()
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t retval;
 | 
			
		||||
    if (!pal::file_exists(m_path))
 | 
			
		||||
    {
 | 
			
		||||
        // Not existing is not an error.
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pal::ifstream_t file(m_path);
 | 
			
		||||
    if (!file.good())
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        const auto root = json_value::parse(file);
 | 
			
		||||
        const auto& json = root.as_object();
 | 
			
		||||
        const auto iter = json.find(_X("runtimeOptions"));
 | 
			
		||||
        if (iter != json.end())
 | 
			
		||||
        {
 | 
			
		||||
            parse_fx(iter->second, &m_fx_name, &m_fx_ver, &m_fx_roll_fwd, &m_portable);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (...)
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const pal::string_t& runtime_config_t::get_gc_server() const
 | 
			
		||||
{
 | 
			
		||||
    assert(m_valid);
 | 
			
		||||
    return m_gc_server;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const pal::string_t& runtime_config_t::get_fx_name() const
 | 
			
		||||
{
 | 
			
		||||
    assert(m_valid);
 | 
			
		||||
    return m_fx_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const pal::string_t& runtime_config_t::get_fx_version() const
 | 
			
		||||
{
 | 
			
		||||
    assert(m_valid);
 | 
			
		||||
    return m_fx_ver;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool runtime_config_t::get_fx_roll_fwd() const
 | 
			
		||||
{
 | 
			
		||||
    assert(m_valid);
 | 
			
		||||
    return m_fx_roll_fwd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool runtime_config_t::get_portable() const
 | 
			
		||||
{
 | 
			
		||||
    return m_portable;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								src/corehost/cli/runtime_config.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/corehost/cli/runtime_config.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
// 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"
 | 
			
		||||
 | 
			
		||||
class runtime_config_t
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    runtime_config_t(const pal::string_t& path);
 | 
			
		||||
    bool is_valid() { return m_valid; }
 | 
			
		||||
    const pal::string_t& get_path() { return m_path; }
 | 
			
		||||
    const pal::string_t& get_gc_server() const;
 | 
			
		||||
    const pal::string_t& get_fx_version() const;
 | 
			
		||||
    const pal::string_t& get_fx_name() const;
 | 
			
		||||
    bool get_fx_roll_fwd() const;
 | 
			
		||||
    bool get_portable() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool ensure_parsed();
 | 
			
		||||
    
 | 
			
		||||
    pal::string_t m_gc_server;
 | 
			
		||||
    pal::string_t m_fx_name;
 | 
			
		||||
    pal::string_t m_fx_ver;
 | 
			
		||||
    bool m_fx_roll_fwd;
 | 
			
		||||
 | 
			
		||||
    pal::string_t m_path;
 | 
			
		||||
    bool m_portable;
 | 
			
		||||
    bool m_valid;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -38,18 +38,33 @@ bool servicing_index_t::find_redirection(
 | 
			
		|||
    auto iter = m_redirections.find(stream.str());
 | 
			
		||||
    if (iter != m_redirections.end())
 | 
			
		||||
    {
 | 
			
		||||
        pal::string_t full_path = m_patch_root;
 | 
			
		||||
        append_path(&full_path, iter->second.c_str());
 | 
			
		||||
        if (pal::file_exists(full_path))
 | 
			
		||||
        pal::string_t ni_root = m_patch_root;
 | 
			
		||||
        append_path(&ni_root, get_arch());
 | 
			
		||||
 | 
			
		||||
        // First prefer the architecture specific NI image.
 | 
			
		||||
        pal::string_t paths[2] = { ni_root, m_patch_root };
 | 
			
		||||
        for (pal::string_t& full_path : paths)
 | 
			
		||||
        {
 | 
			
		||||
            *redirection = full_path;
 | 
			
		||||
            trace::verbose(_X("Servicing %s with %s"), stream.str().c_str(), redirection->c_str());
 | 
			
		||||
            return true;
 | 
			
		||||
            append_path(&full_path, iter->second.c_str());
 | 
			
		||||
            if (pal::file_exists(full_path))
 | 
			
		||||
            {
 | 
			
		||||
                *redirection = full_path;
 | 
			
		||||
                if (trace::is_enabled())
 | 
			
		||||
                {
 | 
			
		||||
                    pal::string_t stream_str = stream.str();
 | 
			
		||||
                    trace::verbose(_X("Servicing %s with %s"), stream_str.c_str(), redirection->c_str());
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            trace::verbose(_X("Serviced file %s doesn't exist"), full_path.c_str());
 | 
			
		||||
        }
 | 
			
		||||
        trace::verbose(_X("Serviced file %s doesn't exist"), full_path.c_str());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    trace::verbose(_X("Entry %s not serviced or file doesn't exist"), stream.str().c_str());
 | 
			
		||||
    if (trace::is_enabled())
 | 
			
		||||
    {
 | 
			
		||||
        auto stream_str = stream.str();
 | 
			
		||||
        trace::verbose(_X("Entry %s not serviced or file doesn't exist"), stream_str.c_str());
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +127,8 @@ void servicing_index_t::ensure_redirections()
 | 
			
		|||
 | 
			
		||||
        if (trace::is_enabled())
 | 
			
		||||
        {
 | 
			
		||||
            trace::verbose(_X("Adding servicing entry %s => %s"), sstream.str().c_str(), str.substr(from).c_str());
 | 
			
		||||
            auto stream_str = sstream.str();
 | 
			
		||||
            trace::verbose(_X("Adding servicing entry %s => %s"), stream_str.c_str(), str.substr(from).c_str());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Store just the filename.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,4 +33,20 @@ if(WIN32)
 | 
			
		|||
    set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /DEBUG /OPT:REF /OPT:ICF")
 | 
			
		||||
    set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /DEBUG /OPT:REF /OPT:ICF")
 | 
			
		||||
    set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /DEBUG /OPT:REF /OPT:ICF")
 | 
			
		||||
else()
 | 
			
		||||
    add_compile_options(-Wno-unused-local-typedef)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(CLI_CMAKE_PLATFORM_ARCH_I386)
 | 
			
		||||
    add_definitions(-D_TARGET_X86_=1)
 | 
			
		||||
elseif(CLI_CMAKE_PLATFORM_ARCH_AMD64)
 | 
			
		||||
    add_definitions(-D_TARGET_AMD64_=1)
 | 
			
		||||
else()
 | 
			
		||||
    message(FATAL_ERROR "Unknown target architecture")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(${CLI_CMAKE_RUNTIME_ID} STREQUAL "")
 | 
			
		||||
    message(FATAL_ERROR "Runtime ID not specified")
 | 
			
		||||
else()
 | 
			
		||||
    add_definitions(-DTARGET_RUNTIME_ID="${CLI_CMAKE_RUNTIME_ID}")
 | 
			
		||||
endif()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,10 +15,12 @@
 | 
			
		|||
#include <unordered_map>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#define NOMINMAX
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
 | 
			
		||||
#define HOST_EXE_NAME L"corehost.exe"
 | 
			
		||||
#define xerr std::wcerr
 | 
			
		||||
| 
						 | 
				
			
			@ -93,11 +95,17 @@ namespace pal
 | 
			
		|||
    typedef HMODULE dll_t;
 | 
			
		||||
    typedef FARPROC proc_t;
 | 
			
		||||
 | 
			
		||||
    pal::string_t to_string(int value);
 | 
			
		||||
 | 
			
		||||
    bool getcwd(pal::string_t* recv);
 | 
			
		||||
 | 
			
		||||
    inline int strcmp(const char_t* str1, const char_t* str2) { return ::wcscmp(str1, str2); }
 | 
			
		||||
    inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::_wcsicmp(str1, str2); }
 | 
			
		||||
    inline int strncmp(const char_t* str1, const char_t* str2, int len) { return ::wcsncmp(str1, str2, len); }
 | 
			
		||||
    inline int strncasecmp(const char_t* str1, const char_t* str2, int len) { return ::_wcsnicmp(str1, str2, len); }
 | 
			
		||||
 | 
			
		||||
    pal::string_t to_lower(const pal::string_t& in);
 | 
			
		||||
 | 
			
		||||
    inline size_t strlen(const char_t* str) { return ::wcslen(str); }
 | 
			
		||||
    inline void err_vprintf(const char_t* format, va_list vl) { ::vfwprintf(stderr, format, vl); ::fputws(_X("\r\n"), stderr); }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -126,10 +134,17 @@ namespace pal
 | 
			
		|||
    typedef void* dll_t;
 | 
			
		||||
    typedef void* proc_t;
 | 
			
		||||
 | 
			
		||||
    pal::string_t to_string(int value);
 | 
			
		||||
 | 
			
		||||
    bool getcwd(pal::string_t* recv);
 | 
			
		||||
 | 
			
		||||
    inline int strcmp(const char_t* str1, const char_t* str2) { return ::strcmp(str1, str2); }
 | 
			
		||||
    inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::strcasecmp(str1, str2); }
 | 
			
		||||
    inline int strncmp(const char_t* str1, const char_t* str2, int len) { return ::strncmp(str1, str2, len); }
 | 
			
		||||
    inline int strncasecmp(const char_t* str1, const char_t* str2, int len) { return ::strncasecmp(str1, str2, len); }
 | 
			
		||||
 | 
			
		||||
    pal::string_t to_lower(const pal::string_t& in);
 | 
			
		||||
 | 
			
		||||
    inline size_t strlen(const char_t* str) { return ::strlen(str); }
 | 
			
		||||
    inline void err_vprintf(const char_t* format, va_list vl) { ::vfprintf(stderr, format, vl); ::fputc('\n', stderr); }
 | 
			
		||||
    inline pal::string_t to_palstring(const std::string& str) { return str; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,8 @@
 | 
			
		|||
#include <dirent.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
#include <mach-o/dyld.h>
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +22,33 @@
 | 
			
		|||
#define symlinkEntrypointExecutable "/proc/curproc/exe"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
pal::string_t pal::to_string(int value) { return std::to_string(value); }
 | 
			
		||||
 | 
			
		||||
pal::string_t pal::to_lower(const pal::string_t& in)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t ret = in;
 | 
			
		||||
    std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pal::getcwd(pal::string_t* recv)
 | 
			
		||||
{
 | 
			
		||||
    recv->clear();
 | 
			
		||||
    pal::char_t* buf = ::getcwd(nullptr, PATH_MAX + 1);
 | 
			
		||||
    if (buf == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        if (errno == ENOENT)
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        perror("getcwd()");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    recv->assign(buf);
 | 
			
		||||
    ::free(buf);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pal::find_coreclr(pal::string_t* recv)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t candidate;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,8 +162,7 @@ bool pal::getenv(const pal::char_t* name, pal::string_t* recv)
 | 
			
		|||
 | 
			
		||||
bool pal::realpath(pal::string_t* path)
 | 
			
		||||
{
 | 
			
		||||
    pal::char_t buf[PATH_MAX];
 | 
			
		||||
    auto resolved = ::realpath(path->c_str(), buf);
 | 
			
		||||
    auto resolved = ::realpath(path->c_str(), nullptr);
 | 
			
		||||
    if (resolved == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        if (errno == ENOENT)
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +173,7 @@ bool pal::realpath(pal::string_t* path)
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    path->assign(resolved);
 | 
			
		||||
    ::free(resolved);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,18 @@
 | 
			
		|||
 | 
			
		||||
static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> g_converter;
 | 
			
		||||
 | 
			
		||||
pal::string_t pal::to_lower(const pal::string_t& in)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t ret = in;
 | 
			
		||||
    std::transform(ret.begin(), ret.end(), ret.begin(), ::towlower);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pal::string_t pal::to_string(int value)
 | 
			
		||||
{
 | 
			
		||||
    return std::to_wstring(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pal::find_coreclr(pal::string_t* recv)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t candidate;
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +43,35 @@ bool pal::find_coreclr(pal::string_t* recv)
 | 
			
		|||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool pal::getcwd(pal::string_t* recv)
 | 
			
		||||
{
 | 
			
		||||
    recv->clear();
 | 
			
		||||
 | 
			
		||||
    pal::char_t buf[MAX_PATH];
 | 
			
		||||
    DWORD result = GetCurrentDirectoryW(MAX_PATH, buf);
 | 
			
		||||
    if (result < MAX_PATH)
 | 
			
		||||
    {
 | 
			
		||||
        recv->assign(buf);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (result != 0)
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<pal::char_t> str;
 | 
			
		||||
        str.resize(result);
 | 
			
		||||
        result = GetCurrentDirectoryW(str.size(), str.data());
 | 
			
		||||
        assert(result <= str.size());
 | 
			
		||||
        if (result != 0)
 | 
			
		||||
        {
 | 
			
		||||
            recv->assign(str.data());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    assert(result == 0);
 | 
			
		||||
    trace::error(_X("Failed to obtain working directory, HRESULT: 0x%X"), HRESULT_FROM_WIN32(GetLastError()));
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pal::load_library(const char_t* path, dll_t* dll)
 | 
			
		||||
{
 | 
			
		||||
    *dll = ::LoadLibraryW(path);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,16 +55,43 @@ pal::string_t get_executable(const pal::string_t& filename)
 | 
			
		|||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pal::string_t get_filename(const pal::string_t& path)
 | 
			
		||||
pal::string_t strip_file_ext(const pal::string_t& path)
 | 
			
		||||
{
 | 
			
		||||
    // Find the last dir separator
 | 
			
		||||
    auto path_sep = path.find_last_of(DIR_SEPARATOR);
 | 
			
		||||
    if (path_sep == pal::string_t::npos)
 | 
			
		||||
    if (path.empty())
 | 
			
		||||
    {
 | 
			
		||||
        return pal::string_t(path);
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
    return path.substr(0, path.rfind(_X('.')));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pal::string_t get_filename_without_ext(const pal::string_t& path)
 | 
			
		||||
{
 | 
			
		||||
    if (path.empty())
 | 
			
		||||
    {
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return path.substr(path_sep + 1);
 | 
			
		||||
    size_t name_pos = path.find_last_of(_X("/\\"));
 | 
			
		||||
    size_t dot_pos = path.rfind(_X('.'));
 | 
			
		||||
    size_t start_pos = (name_pos == pal::string_t::npos) ? 0 : (name_pos + 1);
 | 
			
		||||
    size_t count = (dot_pos == pal::string_t::npos) ? pal::string_t::npos : (dot_pos - start_pos);
 | 
			
		||||
    return path.substr(start_pos, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pal::string_t get_filename(const pal::string_t& path)
 | 
			
		||||
{
 | 
			
		||||
    if (path.empty())
 | 
			
		||||
    {
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto name_pos = path.find_last_of(DIR_SEPARATOR);
 | 
			
		||||
    if (name_pos == pal::string_t::npos)
 | 
			
		||||
    {
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return path.substr(name_pos + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pal::string_t get_directory(const pal::string_t& path)
 | 
			
		||||
| 
						 | 
				
			
			@ -87,3 +114,49 @@ void replace_char(pal::string_t* path, pal::char_t match, pal::char_t repl)
 | 
			
		|||
        (*path)[pos] = repl;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const pal::char_t* get_arch()
 | 
			
		||||
{
 | 
			
		||||
#if _TARGET_AMD64_
 | 
			
		||||
    return _X("x64");
 | 
			
		||||
#elif _TARGET_X86_
 | 
			
		||||
    return _X("x86");
 | 
			
		||||
#else
 | 
			
		||||
#error "Unknown target"
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool parse_known_args(
 | 
			
		||||
    const int argc,
 | 
			
		||||
    const pal::char_t* argv[],
 | 
			
		||||
    const std::vector<pal::string_t>& known_opts,
 | 
			
		||||
    std::unordered_map<pal::string_t, pal::string_t>* opts,
 | 
			
		||||
    int* num_args)
 | 
			
		||||
{
 | 
			
		||||
    int arg_i = *num_args;
 | 
			
		||||
    while (arg_i < argc)
 | 
			
		||||
    {
 | 
			
		||||
        pal::string_t arg = argv[arg_i];
 | 
			
		||||
        if (std::find(known_opts.begin(), known_opts.end(), pal::to_lower(arg)) == known_opts.end())
 | 
			
		||||
        {
 | 
			
		||||
            // Unknown argument.
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Known argument, so expect one more arg (value) to be present.
 | 
			
		||||
        if (arg_i + 1 >= argc)
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        (*opts)[arg] = argv[arg_i + 1];
 | 
			
		||||
 | 
			
		||||
        // Increment for both the option and its value.
 | 
			
		||||
        arg_i += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *num_args = arg_i;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,17 @@ bool ends_with(const pal::string_t& value, const pal::string_t& suffix, bool mat
 | 
			
		|||
bool starts_with(const pal::string_t& value, const pal::string_t& prefix, bool match_case);
 | 
			
		||||
pal::string_t get_executable(const pal::string_t& filename);
 | 
			
		||||
pal::string_t get_directory(const pal::string_t& path);
 | 
			
		||||
pal::string_t strip_file_ext(const pal::string_t& path);
 | 
			
		||||
pal::string_t get_filename(const pal::string_t& path);
 | 
			
		||||
pal::string_t get_filename_without_ext(const pal::string_t& path);
 | 
			
		||||
void append_path(pal::string_t* path1, const pal::char_t* path2);
 | 
			
		||||
bool coreclr_exists_in_dir(const pal::string_t& candidate);
 | 
			
		||||
void replace_char(pal::string_t* path, pal::char_t match, pal::char_t repl);
 | 
			
		||||
const pal::char_t* get_arch();
 | 
			
		||||
bool parse_known_args(
 | 
			
		||||
    const int argc,
 | 
			
		||||
    const pal::char_t* argv[],
 | 
			
		||||
    const std::vector<pal::string_t>& known_opts,
 | 
			
		||||
    std::unordered_map<pal::string_t, pal::string_t>* opts,
 | 
			
		||||
    int* num_args);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,64 +2,140 @@
 | 
			
		|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 | 
			
		||||
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "pal.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
#include "libhost.h"
 | 
			
		||||
#include "corehost.h"
 | 
			
		||||
#include "fx_ver.h"
 | 
			
		||||
#include "error_codes.h"
 | 
			
		||||
#include "policy_load.h"
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
extern int corehost_main(const int argc, const pal::char_t* argv[]);
 | 
			
		||||
#define LIBFXR_NAME MAKE_LIBNAME("hostfxr")
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
bool corehost_t::hostpolicy_exists_in_svc(pal::string_t* resolved_dir)
 | 
			
		||||
{
 | 
			
		||||
enum StatusCode
 | 
			
		||||
{
 | 
			
		||||
    Success                   = 0,
 | 
			
		||||
    CoreHostLibLoadFailure    = 0x41,
 | 
			
		||||
    CoreHostLibMissingFailure = 0x42,
 | 
			
		||||
    CoreHostEntryPointFailure = 0x43,
 | 
			
		||||
    CoreHostCurExeFindFailure = 0x44,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef int (*corehost_main_fn) (const int argc, const pal::char_t* argv[]);
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// Load the corehost library from the path specified
 | 
			
		||||
//
 | 
			
		||||
// Parameters:
 | 
			
		||||
//    lib_dir      - dir path to the corehost library
 | 
			
		||||
//    h_host       - handle to the library which will be kept live
 | 
			
		||||
//    main_fn      - Contains the entrypoint "corehost_main" when returns success.
 | 
			
		||||
//
 | 
			
		||||
// Returns:
 | 
			
		||||
//    Non-zero exit code on failure. "main_fn" contains "corehost_main"
 | 
			
		||||
//    entrypoint on success.
 | 
			
		||||
//
 | 
			
		||||
StatusCode load_host_lib(const pal::string_t& lib_dir, pal::dll_t* h_host, corehost_main_fn* main_fn)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t host_path = lib_dir;
 | 
			
		||||
    append_path(&host_path, LIBHOST_NAME);
 | 
			
		||||
 | 
			
		||||
    // Missing library
 | 
			
		||||
    if (!pal::file_exists(host_path))
 | 
			
		||||
#ifdef COREHOST_PACKAGE_SERVICING
 | 
			
		||||
    pal::string_t svc_dir;
 | 
			
		||||
    if (!pal::getenv(_X("DOTNET_SERVICING"), &svc_dir))
 | 
			
		||||
    {
 | 
			
		||||
        return StatusCode::CoreHostLibMissingFailure;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load library
 | 
			
		||||
    if (!pal::load_library(host_path.c_str(), h_host))
 | 
			
		||||
    pal::string_t path = svc_dir;
 | 
			
		||||
    append_path(&path, COREHOST_PACKAGE_NAME);
 | 
			
		||||
    append_path(&path, COREHOST_PACKAGE_VERSION);
 | 
			
		||||
    append_path(&path, COREHOST_PACKAGE_COREHOST_RELATIVE_DIR);
 | 
			
		||||
    if (library_exists_in_dir(path, LIBHOST_NAME))
 | 
			
		||||
    {
 | 
			
		||||
        trace::info(_X("Load library of %s failed"), host_path.c_str());
 | 
			
		||||
        resolved_dir->assign(path);
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
#else
 | 
			
		||||
    return false;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pal::string_t corehost_t::resolve_fxr_path(const pal::string_t& own_dir)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t fxr_path;
 | 
			
		||||
 | 
			
		||||
    pal::string_t fxr_dir = own_dir;
 | 
			
		||||
    append_path(&fxr_dir, _X("dotnethost"));
 | 
			
		||||
    append_path(&fxr_dir, _X("fxr"));
 | 
			
		||||
    if (pal::directory_exists(fxr_dir))
 | 
			
		||||
    {
 | 
			
		||||
        trace::info(_X("Reading fx resolver directory=[%s]"), fxr_dir.c_str());
 | 
			
		||||
 | 
			
		||||
        std::vector<pal::string_t> list;
 | 
			
		||||
        pal::readdir(fxr_dir, &list);
 | 
			
		||||
 | 
			
		||||
        fx_ver_t max_ver(-1, -1, -1);
 | 
			
		||||
        for (const auto& dir : list)
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Considering fxr version=[%s]..."), dir.c_str());
 | 
			
		||||
 | 
			
		||||
            pal::string_t ver = get_filename(dir);
 | 
			
		||||
 | 
			
		||||
            fx_ver_t fx_ver(-1, -1, -1);
 | 
			
		||||
            if (fx_ver_t::parse(ver, &fx_ver, false))
 | 
			
		||||
            {
 | 
			
		||||
                max_ver = std::max(max_ver, fx_ver);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pal::string_t max_ver_str = max_ver.as_str();
 | 
			
		||||
        append_path(&fxr_dir, max_ver_str.c_str());
 | 
			
		||||
        trace::info(_X("Detected latest fxr version=[%s]..."), fxr_dir.c_str());
 | 
			
		||||
    }   
 | 
			
		||||
 | 
			
		||||
    const pal::string_t* dirs[] = { &fxr_dir, &own_dir };
 | 
			
		||||
    for (const auto& dir : dirs)
 | 
			
		||||
    {
 | 
			
		||||
        trace::info(_X("Considering fxr dir=[%s]..."), fxr_dir.c_str());
 | 
			
		||||
        if (policy_load_t::library_exists_in_dir(*dir, LIBFXR_NAME, &fxr_path))
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Resolved fxr [%s]..."), fxr_path.c_str());
 | 
			
		||||
            return fxr_path;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return pal::string_t();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int corehost_t::resolve_fx_and_execute_app(const pal::string_t& own_dir, const int argc, const pal::char_t* argv[])
 | 
			
		||||
{
 | 
			
		||||
    pal::dll_t fxr;
 | 
			
		||||
 | 
			
		||||
    pal::string_t fxr_path = resolve_fxr_path(own_dir);
 | 
			
		||||
 | 
			
		||||
    // Load library
 | 
			
		||||
    if (!pal::load_library(fxr_path.c_str(), &fxr))
 | 
			
		||||
    {
 | 
			
		||||
        trace::info(_X("Load library of %s failed"), fxr_path.c_str());
 | 
			
		||||
        return StatusCode::CoreHostLibLoadFailure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Obtain entrypoint symbol
 | 
			
		||||
    *main_fn = (corehost_main_fn) pal::get_symbol(*h_host, "corehost_main");
 | 
			
		||||
 | 
			
		||||
    return (*main_fn != nullptr)
 | 
			
		||||
                ? StatusCode::Success
 | 
			
		||||
                : StatusCode::CoreHostEntryPointFailure;
 | 
			
		||||
    // Obtain entrypoint symbols
 | 
			
		||||
    hostfxr_main_fn main_fn = (hostfxr_main_fn) pal::get_symbol(fxr, "hostfxr_main");
 | 
			
		||||
    return main_fn(argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}; // end of anonymous namespace
 | 
			
		||||
int corehost_t::run(const int argc, const pal::char_t* argv[])
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t own_dir;
 | 
			
		||||
    auto mode = detect_operating_mode(argc, argv, &own_dir);
 | 
			
		||||
 | 
			
		||||
    switch (mode)
 | 
			
		||||
    {
 | 
			
		||||
    case muxer:
 | 
			
		||||
        trace::info(_X("Host operating in Muxer mode"));
 | 
			
		||||
        return resolve_fx_and_execute_app(own_dir, argc, argv);
 | 
			
		||||
 | 
			
		||||
    case split_fx:
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Host operating in split mode; own dir=[%s]"), own_dir.c_str());
 | 
			
		||||
            corehost_init_t init(_X(""), _X(""), own_dir, host_mode_t::split_fx, nullptr);
 | 
			
		||||
            return policy_load_t::execute_app(own_dir, &init, argc, argv);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    case standalone:
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Host operating from standalone app dir %s"), own_dir.c_str());
 | 
			
		||||
 | 
			
		||||
            pal::string_t svc_dir;
 | 
			
		||||
            corehost_init_t init(_X(""), _X(""), _X(""), host_mode_t::standalone, nullptr);
 | 
			
		||||
            return policy_load_t::execute_app(
 | 
			
		||||
                hostpolicy_exists_in_svc(&svc_dir) ? svc_dir : own_dir, &init, argc, argv);
 | 
			
		||||
        }
 | 
			
		||||
        return StatusCode::CoreHostLibMissingFailure;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        trace::error(_X("Unknown mode detected or could not resolve the mode."));
 | 
			
		||||
        return StatusCode::CoreHostResolveModeFailure;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
#include "deps_format.h"
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
int __cdecl wmain(const int argc, const pal::char_t* argv[])
 | 
			
		||||
| 
						 | 
				
			
			@ -69,56 +145,19 @@ int main(const int argc, const pal::char_t* argv[])
 | 
			
		|||
{
 | 
			
		||||
    trace::setup();
 | 
			
		||||
 | 
			
		||||
    pal::dll_t corehost;
 | 
			
		||||
    //deps_json_t deps(true, _X("H:\\code\\sharedfx\\PortableApp\\PortableAppWithNative.deps.json"));
 | 
			
		||||
    //deps_json_t deps2(false, _X("H:\\code\\sharedfx\\StandaloneApp\\StandaloneApp.deps.json"));
 | 
			
		||||
 | 
			
		||||
#ifdef COREHOST_PACKAGE_SERVICING
 | 
			
		||||
    // No custom host asked, so load the corehost if serviced first.
 | 
			
		||||
    pal::string_t svc_dir;
 | 
			
		||||
    if (pal::getenv(_X("DOTNET_SERVICING"), &svc_dir))
 | 
			
		||||
    if (trace::is_enabled())
 | 
			
		||||
    {
 | 
			
		||||
        pal::string_t path = svc_dir;
 | 
			
		||||
        append_path(&path, COREHOST_PACKAGE_NAME);
 | 
			
		||||
        append_path(&path, COREHOST_PACKAGE_VERSION);
 | 
			
		||||
        append_path(&path, COREHOST_PACKAGE_COREHOST_RELATIVE_DIR);
 | 
			
		||||
 | 
			
		||||
        corehost_main_fn host_main;
 | 
			
		||||
        StatusCode code = load_host_lib(path, &corehost, &host_main);
 | 
			
		||||
        if (code != StatusCode::Success)
 | 
			
		||||
        trace::info(_X("--- Invoked host main = {"));
 | 
			
		||||
        for (int i = 0; i < argc; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Failed to load host library from servicing dir: %s; Status=%08X"), path.c_str(), code);
 | 
			
		||||
            // Ignore all errors for the servicing case, and proceed to the next step.
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            trace::info(_X("Calling host entrypoint from library at servicing dir %s"), path.c_str());
 | 
			
		||||
            return host_main(argc, argv);
 | 
			
		||||
            trace::info(_X("%s"), argv[i]);
 | 
			
		||||
        }
 | 
			
		||||
        trace::info(_X("}"));
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Get current path to look for the library app locally.
 | 
			
		||||
    pal::string_t own_path;
 | 
			
		||||
    if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path))
 | 
			
		||||
    {
 | 
			
		||||
        trace::error(_X("Failed to locate current executable"));
 | 
			
		||||
        return StatusCode::CoreHostCurExeFindFailure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Local load of the corehost library.
 | 
			
		||||
    auto own_dir = get_directory(own_path);
 | 
			
		||||
 | 
			
		||||
    corehost_main_fn host_main;
 | 
			
		||||
    StatusCode code = load_host_lib(own_dir, &corehost, &host_main);
 | 
			
		||||
    switch (code)
 | 
			
		||||
    {
 | 
			
		||||
    // Success, call the entrypoint.
 | 
			
		||||
    case StatusCode::Success:
 | 
			
		||||
        trace::info(_X("Calling host entrypoint from library at own dir %s"), own_dir.c_str());
 | 
			
		||||
        return host_main(argc, argv);
 | 
			
		||||
 | 
			
		||||
    // Some other fatal error including StatusCode::CoreHostLibMissingFailure.
 | 
			
		||||
    default:
 | 
			
		||||
        trace::error(_X("Error loading the host library from own dir: %s; Status=%08X"), own_dir.c_str(), code);
 | 
			
		||||
        return code;
 | 
			
		||||
    }
 | 
			
		||||
    corehost_t corehost;
 | 
			
		||||
    return corehost.run(argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										36
									
								
								src/corehost/corehost.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/corehost/corehost.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
// 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 "libhost.h"
 | 
			
		||||
#include "policy_load.h"
 | 
			
		||||
 | 
			
		||||
typedef int(*hostfxr_main_fn) (const int argc, const pal::char_t* argv[]);
 | 
			
		||||
 | 
			
		||||
class corehost_t
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    int run(const int argc, const pal::char_t* argv[]);
 | 
			
		||||
    static int execute_app(
 | 
			
		||||
        const pal::string_t& policy_dir,
 | 
			
		||||
        const pal::string_t& fx_dir,
 | 
			
		||||
        const runtime_config_t* config,
 | 
			
		||||
        const int argc,
 | 
			
		||||
        const pal::char_t* argv[]);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    static int load_host_library(
 | 
			
		||||
        const pal::string_t& lib_dir,
 | 
			
		||||
        pal::dll_t* h_host,
 | 
			
		||||
        corehost_load_fn* load_fn,
 | 
			
		||||
        corehost_main_fn* main_fn,
 | 
			
		||||
        corehost_unload_fn* unload_fn);
 | 
			
		||||
 | 
			
		||||
    pal::string_t resolve_fxr_path(const pal::string_t& own_dir);
 | 
			
		||||
    int resolve_fx_and_execute_app(const pal::string_t& own_dir, const int argc, const pal::char_t* argv[]);
 | 
			
		||||
 | 
			
		||||
    static bool hostpolicy_exists_in_svc(pal::string_t* resolved_path);
 | 
			
		||||
    static bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_host_path);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										29
									
								
								src/corehost/error_codes.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/corehost/error_codes.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
// 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 __ERROR_CODES_H__
 | 
			
		||||
#define __ERROR_CODES_H__
 | 
			
		||||
enum StatusCode
 | 
			
		||||
{
 | 
			
		||||
    Success = 0,
 | 
			
		||||
    InvalidArgFailure = 0x81,
 | 
			
		||||
    CoreHostLibLoadFailure = 0x82,
 | 
			
		||||
    CoreHostLibMissingFailure = 0x83,
 | 
			
		||||
    CoreHostEntryPointFailure = 0x84,
 | 
			
		||||
    CoreHostCurExeFindFailure = 0x85,
 | 
			
		||||
    CoreHostResolveModeFailure = 0x86,
 | 
			
		||||
    CoreClrResolveFailure = 0x87,
 | 
			
		||||
    CoreClrBindFailure = 0x88,
 | 
			
		||||
    CoreClrInitFailure = 0x89,
 | 
			
		||||
    CoreClrExeFailure = 0x90,
 | 
			
		||||
    ResolverInitFailure = 0x91,
 | 
			
		||||
    ResolverResolveFailure = 0x92,
 | 
			
		||||
    LibHostCurExeFindFailure = 0x93,
 | 
			
		||||
    LibHostInitFailure = 0x94,
 | 
			
		||||
    LibHostMuxFailure = 0x95,
 | 
			
		||||
    LibHostExecModeFailure = 0x96,
 | 
			
		||||
    LibHostSdkFindFailure = 0x97,
 | 
			
		||||
    LibHostInvalidArgs = 0x98,
 | 
			
		||||
    InvalidConfigFile = 0x99,
 | 
			
		||||
};
 | 
			
		||||
#endif // __ERROR_CODES_H__
 | 
			
		||||
							
								
								
									
										79
									
								
								src/corehost/policy_load.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/corehost/policy_load.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
// 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 "policy_load.h"
 | 
			
		||||
#include "corehost.h"
 | 
			
		||||
 | 
			
		||||
bool policy_load_t::library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_host_path)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t host_path = lib_dir;
 | 
			
		||||
    append_path(&host_path, lib_name.c_str());
 | 
			
		||||
 | 
			
		||||
    if (!pal::file_exists(host_path))
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (p_host_path)
 | 
			
		||||
    {
 | 
			
		||||
        *p_host_path = host_path;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int policy_load_t::load_host_library(
 | 
			
		||||
    const pal::string_t& lib_dir,
 | 
			
		||||
    pal::dll_t* h_host,
 | 
			
		||||
    corehost_load_fn* load_fn,
 | 
			
		||||
    corehost_main_fn* main_fn,
 | 
			
		||||
    corehost_unload_fn* unload_fn)
 | 
			
		||||
{
 | 
			
		||||
    pal::string_t host_path;
 | 
			
		||||
    if (!library_exists_in_dir(lib_dir, LIBHOST_NAME, &host_path))
 | 
			
		||||
    {
 | 
			
		||||
        return StatusCode::CoreHostLibMissingFailure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load library
 | 
			
		||||
    if (!pal::load_library(host_path.c_str(), h_host))
 | 
			
		||||
    {
 | 
			
		||||
        trace::info(_X("Load library of %s failed"), host_path.c_str());
 | 
			
		||||
        return StatusCode::CoreHostLibLoadFailure;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Obtain entrypoint symbols
 | 
			
		||||
    *load_fn = (corehost_load_fn)pal::get_symbol(*h_host, "corehost_load");
 | 
			
		||||
    *main_fn = (corehost_main_fn)pal::get_symbol(*h_host, "corehost_main");
 | 
			
		||||
    *unload_fn = (corehost_unload_fn)pal::get_symbol(*h_host, "corehost_unload");
 | 
			
		||||
 | 
			
		||||
    return (*main_fn) && (*load_fn) && (*unload_fn)
 | 
			
		||||
        ? StatusCode::Success
 | 
			
		||||
        : StatusCode::CoreHostEntryPointFailure;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int policy_load_t::execute_app(
 | 
			
		||||
    const pal::string_t& impl_dll_dir,
 | 
			
		||||
    const corehost_init_t* init,
 | 
			
		||||
    const int argc,
 | 
			
		||||
    const pal::char_t* argv[])
 | 
			
		||||
{
 | 
			
		||||
    pal::dll_t corehost;
 | 
			
		||||
    corehost_main_fn host_main = nullptr;
 | 
			
		||||
    corehost_load_fn host_load = nullptr;
 | 
			
		||||
    corehost_unload_fn host_unload = nullptr;
 | 
			
		||||
 | 
			
		||||
    int code = load_host_library(impl_dll_dir, &corehost, &host_load, &host_main, &host_unload);
 | 
			
		||||
 | 
			
		||||
    if (code != StatusCode::Success)
 | 
			
		||||
    {
 | 
			
		||||
        trace::error(_X("Could not load host policy library [%s]"), impl_dll_dir.c_str());
 | 
			
		||||
        return code;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((code = host_load(init)) == 0)
 | 
			
		||||
    {
 | 
			
		||||
        code = host_main(argc, argv);
 | 
			
		||||
        (void) host_unload();
 | 
			
		||||
    }
 | 
			
		||||
    return code;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								src/corehost/policy_load.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/corehost/policy_load.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 __POLICY_LOAD_H__
 | 
			
		||||
#define __POLICY_LOAD_H__
 | 
			
		||||
 | 
			
		||||
#include "pal.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "error_codes.h"
 | 
			
		||||
 | 
			
		||||
class corehost_init_t;
 | 
			
		||||
class runtime_config_t;
 | 
			
		||||
 | 
			
		||||
typedef int(*corehost_load_fn) (const corehost_init_t* init);
 | 
			
		||||
typedef int(*corehost_main_fn) (const int argc, const pal::char_t* argv[]);
 | 
			
		||||
typedef int(*corehost_unload_fn) ();
 | 
			
		||||
 | 
			
		||||
class policy_load_t
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    static int execute_app(
 | 
			
		||||
        const pal::string_t& impl_dll_dir,
 | 
			
		||||
		const corehost_init_t* init,
 | 
			
		||||
        const int argc,
 | 
			
		||||
        const pal::char_t* argv[]);
 | 
			
		||||
 | 
			
		||||
    static bool library_exists_in_dir(const pal::string_t& lib_dir, const pal::string_t& lib_name, pal::string_t* p_host_path = nullptr);
 | 
			
		||||
 | 
			
		||||
    static int load_host_library(
 | 
			
		||||
        const pal::string_t& lib_dir,
 | 
			
		||||
        pal::dll_t* h_host,
 | 
			
		||||
        corehost_load_fn* load_fn,
 | 
			
		||||
        corehost_main_fn* main_fn,
 | 
			
		||||
        corehost_unload_fn* unload_fn);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // __POLICY_LOAD_H__
 | 
			
		||||
		Reference in a new issue